162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Access to HP-HIL MLC through HP System Device Controller. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2001 Brian S. Julin 562306a36Sopenharmony_ci * All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 862306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 962306a36Sopenharmony_ci * are met: 1062306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1162306a36Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 1262306a36Sopenharmony_ci * without modification. 1362306a36Sopenharmony_ci * 2. The name of the author may not be used to endorse or promote products 1462306a36Sopenharmony_ci * derived from this software without specific prior written permission. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 1762306a36Sopenharmony_ci * GNU General Public License ("GPL"). 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2062306a36Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2162306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2262306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2362306a36Sopenharmony_ci * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2462306a36Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2562306a36Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2662306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2762306a36Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * References: 3062306a36Sopenharmony_ci * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A 3162306a36Sopenharmony_ci * System Device Controller Microprocessor Firmware Theory of Operation 3262306a36Sopenharmony_ci * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/hil_mlc.h> 3762306a36Sopenharmony_ci#include <linux/hp_sdc.h> 3862306a36Sopenharmony_ci#include <linux/errno.h> 3962306a36Sopenharmony_ci#include <linux/kernel.h> 4062306a36Sopenharmony_ci#include <linux/module.h> 4162306a36Sopenharmony_ci#include <linux/init.h> 4262306a36Sopenharmony_ci#include <linux/string.h> 4362306a36Sopenharmony_ci#include <linux/semaphore.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define PREFIX "HP SDC MLC: " 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic hil_mlc hp_sdc_mlc; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciMODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); 5062306a36Sopenharmony_ciMODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines"); 5162306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic struct hp_sdc_mlc_priv_s { 5462306a36Sopenharmony_ci int emtestmode; 5562306a36Sopenharmony_ci hp_sdc_transaction trans; 5662306a36Sopenharmony_ci u8 tseq[16]; 5762306a36Sopenharmony_ci int got5x; 5862306a36Sopenharmony_ci} hp_sdc_mlc_priv; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/************************* Interrupt context ******************************/ 6162306a36Sopenharmony_cistatic void hp_sdc_mlc_isr (int irq, void *dev_id, 6262306a36Sopenharmony_ci uint8_t status, uint8_t data) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci int idx; 6562306a36Sopenharmony_ci hil_mlc *mlc = &hp_sdc_mlc; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci write_lock(&mlc->lock); 6862306a36Sopenharmony_ci if (mlc->icount < 0) { 6962306a36Sopenharmony_ci printk(KERN_WARNING PREFIX "HIL Overflow!\n"); 7062306a36Sopenharmony_ci up(&mlc->isem); 7162306a36Sopenharmony_ci goto out; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci idx = 15 - mlc->icount; 7462306a36Sopenharmony_ci if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) { 7562306a36Sopenharmony_ci mlc->ipacket[idx] |= data | HIL_ERR_INT; 7662306a36Sopenharmony_ci mlc->icount--; 7762306a36Sopenharmony_ci if (hp_sdc_mlc_priv.got5x || !idx) 7862306a36Sopenharmony_ci goto check; 7962306a36Sopenharmony_ci if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) != 8062306a36Sopenharmony_ci (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) { 8162306a36Sopenharmony_ci mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK; 8262306a36Sopenharmony_ci mlc->ipacket[idx] |= (mlc->ipacket[idx - 1] 8362306a36Sopenharmony_ci & HIL_PKT_ADDR_MASK); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci goto check; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci /* We know status is 5X */ 8862306a36Sopenharmony_ci if (data & HP_SDC_HIL_ISERR) 8962306a36Sopenharmony_ci goto err; 9062306a36Sopenharmony_ci mlc->ipacket[idx] = 9162306a36Sopenharmony_ci (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT; 9262306a36Sopenharmony_ci hp_sdc_mlc_priv.got5x = 1; 9362306a36Sopenharmony_ci goto out; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci check: 9662306a36Sopenharmony_ci hp_sdc_mlc_priv.got5x = 0; 9762306a36Sopenharmony_ci if (mlc->imatch == 0) 9862306a36Sopenharmony_ci goto done; 9962306a36Sopenharmony_ci if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) 10062306a36Sopenharmony_ci && (mlc->ipacket[idx] == (mlc->imatch | idx))) 10162306a36Sopenharmony_ci goto done; 10262306a36Sopenharmony_ci if (mlc->ipacket[idx] == mlc->imatch) 10362306a36Sopenharmony_ci goto done; 10462306a36Sopenharmony_ci goto out; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci err: 10762306a36Sopenharmony_ci printk(KERN_DEBUG PREFIX "err code %x\n", data); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci switch (data) { 11062306a36Sopenharmony_ci case HP_SDC_HIL_RC_DONE: 11162306a36Sopenharmony_ci printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n"); 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci case HP_SDC_HIL_ERR: 11562306a36Sopenharmony_ci mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | 11662306a36Sopenharmony_ci HIL_ERR_FERR | HIL_ERR_FOF; 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci case HP_SDC_HIL_TO: 12062306a36Sopenharmony_ci mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci case HP_SDC_HIL_RC: 12462306a36Sopenharmony_ci printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n"); 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci default: 12862306a36Sopenharmony_ci printk(KERN_WARNING PREFIX "Unknown HIL Error status (%x)!\n", data); 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* No more data will be coming due to an error. */ 13362306a36Sopenharmony_ci done: 13462306a36Sopenharmony_ci tasklet_schedule(mlc->tasklet); 13562306a36Sopenharmony_ci up(&mlc->isem); 13662306a36Sopenharmony_ci out: 13762306a36Sopenharmony_ci write_unlock(&mlc->lock); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/******************** Tasklet or userspace context functions ****************/ 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct hp_sdc_mlc_priv_s *priv; 14662306a36Sopenharmony_ci int rc = 2; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci priv = mlc->priv; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Try to down the semaphore */ 15162306a36Sopenharmony_ci if (down_trylock(&mlc->isem)) { 15262306a36Sopenharmony_ci if (priv->emtestmode) { 15362306a36Sopenharmony_ci mlc->ipacket[0] = 15462306a36Sopenharmony_ci HIL_ERR_INT | (mlc->opacket & 15562306a36Sopenharmony_ci (HIL_PKT_CMD | 15662306a36Sopenharmony_ci HIL_PKT_ADDR_MASK | 15762306a36Sopenharmony_ci HIL_PKT_DATA_MASK)); 15862306a36Sopenharmony_ci mlc->icount = 14; 15962306a36Sopenharmony_ci /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ 16062306a36Sopenharmony_ci goto wasup; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci if (time_after(jiffies, mlc->instart + mlc->intimeout)) { 16362306a36Sopenharmony_ci /* printk("!%i %i", 16462306a36Sopenharmony_ci tv.tv_usec - mlc->instart.tv_usec, 16562306a36Sopenharmony_ci mlc->intimeout); 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci rc = 1; 16862306a36Sopenharmony_ci up(&mlc->isem); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci goto done; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci wasup: 17362306a36Sopenharmony_ci up(&mlc->isem); 17462306a36Sopenharmony_ci rc = 0; 17562306a36Sopenharmony_ci done: 17662306a36Sopenharmony_ci return rc; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int hp_sdc_mlc_cts(hil_mlc *mlc) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct hp_sdc_mlc_priv_s *priv; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci priv = mlc->priv; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Try to down the semaphores -- they should be up. */ 18662306a36Sopenharmony_ci BUG_ON(down_trylock(&mlc->isem)); 18762306a36Sopenharmony_ci BUG_ON(down_trylock(&mlc->osem)); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci up(&mlc->isem); 19062306a36Sopenharmony_ci up(&mlc->osem); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (down_trylock(&mlc->csem)) { 19362306a36Sopenharmony_ci if (priv->trans.act.semaphore != &mlc->csem) 19462306a36Sopenharmony_ci goto poll; 19562306a36Sopenharmony_ci else 19662306a36Sopenharmony_ci goto busy; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) 20062306a36Sopenharmony_ci goto done; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci poll: 20362306a36Sopenharmony_ci priv->trans.act.semaphore = &mlc->csem; 20462306a36Sopenharmony_ci priv->trans.actidx = 0; 20562306a36Sopenharmony_ci priv->trans.idx = 1; 20662306a36Sopenharmony_ci priv->trans.endidx = 5; 20762306a36Sopenharmony_ci priv->tseq[0] = 20862306a36Sopenharmony_ci HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; 20962306a36Sopenharmony_ci priv->tseq[1] = HP_SDC_CMD_READ_USE; 21062306a36Sopenharmony_ci priv->tseq[2] = 1; 21162306a36Sopenharmony_ci priv->tseq[3] = 0; 21262306a36Sopenharmony_ci priv->tseq[4] = 0; 21362306a36Sopenharmony_ci return __hp_sdc_enqueue_transaction(&priv->trans); 21462306a36Sopenharmony_ci busy: 21562306a36Sopenharmony_ci return 1; 21662306a36Sopenharmony_ci done: 21762306a36Sopenharmony_ci priv->trans.act.semaphore = &mlc->osem; 21862306a36Sopenharmony_ci up(&mlc->csem); 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int hp_sdc_mlc_out(hil_mlc *mlc) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct hp_sdc_mlc_priv_s *priv; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci priv = mlc->priv; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* Try to down the semaphore -- it should be up. */ 22962306a36Sopenharmony_ci BUG_ON(down_trylock(&mlc->osem)); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (mlc->opacket & HIL_DO_ALTER_CTRL) 23262306a36Sopenharmony_ci goto do_control; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci do_data: 23562306a36Sopenharmony_ci if (priv->emtestmode) { 23662306a36Sopenharmony_ci up(&mlc->osem); 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci /* Shouldn't be sending commands when loop may be busy */ 24062306a36Sopenharmony_ci BUG_ON(down_trylock(&mlc->csem)); 24162306a36Sopenharmony_ci up(&mlc->csem); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci priv->trans.actidx = 0; 24462306a36Sopenharmony_ci priv->trans.idx = 1; 24562306a36Sopenharmony_ci priv->trans.act.semaphore = &mlc->osem; 24662306a36Sopenharmony_ci priv->trans.endidx = 6; 24762306a36Sopenharmony_ci priv->tseq[0] = 24862306a36Sopenharmony_ci HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE; 24962306a36Sopenharmony_ci priv->tseq[1] = 0x7; 25062306a36Sopenharmony_ci priv->tseq[2] = 25162306a36Sopenharmony_ci (mlc->opacket & 25262306a36Sopenharmony_ci (HIL_PKT_ADDR_MASK | HIL_PKT_CMD)) 25362306a36Sopenharmony_ci >> HIL_PKT_ADDR_SHIFT; 25462306a36Sopenharmony_ci priv->tseq[3] = 25562306a36Sopenharmony_ci (mlc->opacket & HIL_PKT_DATA_MASK) 25662306a36Sopenharmony_ci >> HIL_PKT_DATA_SHIFT; 25762306a36Sopenharmony_ci priv->tseq[4] = 0; /* No timeout */ 25862306a36Sopenharmony_ci if (priv->tseq[3] == HIL_CMD_DHR) 25962306a36Sopenharmony_ci priv->tseq[4] = 1; 26062306a36Sopenharmony_ci priv->tseq[5] = HP_SDC_CMD_DO_HIL; 26162306a36Sopenharmony_ci goto enqueue; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci do_control: 26462306a36Sopenharmony_ci priv->emtestmode = mlc->opacket & HIL_CTRL_TEST; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* we cannot emulate this, it should not be used. */ 26762306a36Sopenharmony_ci BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) 27062306a36Sopenharmony_ci goto control_only; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Should not send command/data after engaging APE */ 27362306a36Sopenharmony_ci BUG_ON(mlc->opacket & HIL_CTRL_APE); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Disengaging APE this way would not be valid either since 27662306a36Sopenharmony_ci * the loop must be allowed to idle. 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * So, it works out that we really never actually send control 27962306a36Sopenharmony_ci * and data when using SDC, we just send the data. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci goto do_data; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci control_only: 28462306a36Sopenharmony_ci priv->trans.actidx = 0; 28562306a36Sopenharmony_ci priv->trans.idx = 1; 28662306a36Sopenharmony_ci priv->trans.act.semaphore = &mlc->osem; 28762306a36Sopenharmony_ci priv->trans.endidx = 4; 28862306a36Sopenharmony_ci priv->tseq[0] = 28962306a36Sopenharmony_ci HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; 29062306a36Sopenharmony_ci priv->tseq[1] = HP_SDC_CMD_SET_LPC; 29162306a36Sopenharmony_ci priv->tseq[2] = 1; 29262306a36Sopenharmony_ci /* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */ 29362306a36Sopenharmony_ci priv->tseq[3] = 0; 29462306a36Sopenharmony_ci if (mlc->opacket & HIL_CTRL_APE) { 29562306a36Sopenharmony_ci priv->tseq[3] |= HP_SDC_LPC_APE_IPF; 29662306a36Sopenharmony_ci BUG_ON(down_trylock(&mlc->csem)); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci enqueue: 29962306a36Sopenharmony_ci return hp_sdc_enqueue_transaction(&priv->trans); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int __init hp_sdc_mlc_init(void) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci hil_mlc *mlc = &hp_sdc_mlc; 30562306a36Sopenharmony_ci int err; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci#ifdef __mc68000__ 30862306a36Sopenharmony_ci if (!MACH_IS_HP300) 30962306a36Sopenharmony_ci return -ENODEV; 31062306a36Sopenharmony_ci#endif 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n"); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci hp_sdc_mlc_priv.emtestmode = 0; 31562306a36Sopenharmony_ci hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq; 31662306a36Sopenharmony_ci hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem; 31762306a36Sopenharmony_ci hp_sdc_mlc_priv.got5x = 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci mlc->cts = &hp_sdc_mlc_cts; 32062306a36Sopenharmony_ci mlc->in = &hp_sdc_mlc_in; 32162306a36Sopenharmony_ci mlc->out = &hp_sdc_mlc_out; 32262306a36Sopenharmony_ci mlc->priv = &hp_sdc_mlc_priv; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci err = hil_mlc_register(mlc); 32562306a36Sopenharmony_ci if (err) { 32662306a36Sopenharmony_ci printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n"); 32762306a36Sopenharmony_ci return err; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) { 33162306a36Sopenharmony_ci printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n"); 33262306a36Sopenharmony_ci if (hil_mlc_unregister(mlc)) 33362306a36Sopenharmony_ci printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" 33462306a36Sopenharmony_ci "This is bad. Could cause an oops.\n"); 33562306a36Sopenharmony_ci return -EBUSY; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void __exit hp_sdc_mlc_exit(void) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci hil_mlc *mlc = &hp_sdc_mlc; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) 34662306a36Sopenharmony_ci printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n" 34762306a36Sopenharmony_ci "This is bad. Could cause an oops.\n"); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (hil_mlc_unregister(mlc)) 35062306a36Sopenharmony_ci printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" 35162306a36Sopenharmony_ci "This is bad. Could cause an oops.\n"); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cimodule_init(hp_sdc_mlc_init); 35562306a36Sopenharmony_cimodule_exit(hp_sdc_mlc_exit); 356