18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Access to HP-HIL MLC through HP System Device Controller. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2001 Brian S. Julin 58c2ecf20Sopenharmony_ci * All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. The name of the author may not be used to endorse or promote products 148c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 178c2ecf20Sopenharmony_ci * GNU General Public License ("GPL"). 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 208c2ecf20Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 218c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 228c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 238c2ecf20Sopenharmony_ci * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 248c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 258c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 268c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 278c2ecf20Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * References: 308c2ecf20Sopenharmony_ci * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A 318c2ecf20Sopenharmony_ci * System Device Controller Microprocessor Firmware Theory of Operation 328c2ecf20Sopenharmony_ci * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/hil_mlc.h> 378c2ecf20Sopenharmony_ci#include <linux/hp_sdc.h> 388c2ecf20Sopenharmony_ci#include <linux/errno.h> 398c2ecf20Sopenharmony_ci#include <linux/kernel.h> 408c2ecf20Sopenharmony_ci#include <linux/module.h> 418c2ecf20Sopenharmony_ci#include <linux/init.h> 428c2ecf20Sopenharmony_ci#include <linux/string.h> 438c2ecf20Sopenharmony_ci#include <linux/semaphore.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define PREFIX "HP SDC MLC: " 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic hil_mlc hp_sdc_mlc; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); 508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines"); 518c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic struct hp_sdc_mlc_priv_s { 548c2ecf20Sopenharmony_ci int emtestmode; 558c2ecf20Sopenharmony_ci hp_sdc_transaction trans; 568c2ecf20Sopenharmony_ci u8 tseq[16]; 578c2ecf20Sopenharmony_ci int got5x; 588c2ecf20Sopenharmony_ci} hp_sdc_mlc_priv; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/************************* Interrupt context ******************************/ 618c2ecf20Sopenharmony_cistatic void hp_sdc_mlc_isr (int irq, void *dev_id, 628c2ecf20Sopenharmony_ci uint8_t status, uint8_t data) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci int idx; 658c2ecf20Sopenharmony_ci hil_mlc *mlc = &hp_sdc_mlc; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci write_lock(&mlc->lock); 688c2ecf20Sopenharmony_ci if (mlc->icount < 0) { 698c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "HIL Overflow!\n"); 708c2ecf20Sopenharmony_ci up(&mlc->isem); 718c2ecf20Sopenharmony_ci goto out; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci idx = 15 - mlc->icount; 748c2ecf20Sopenharmony_ci if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) { 758c2ecf20Sopenharmony_ci mlc->ipacket[idx] |= data | HIL_ERR_INT; 768c2ecf20Sopenharmony_ci mlc->icount--; 778c2ecf20Sopenharmony_ci if (hp_sdc_mlc_priv.got5x || !idx) 788c2ecf20Sopenharmony_ci goto check; 798c2ecf20Sopenharmony_ci if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) != 808c2ecf20Sopenharmony_ci (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) { 818c2ecf20Sopenharmony_ci mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK; 828c2ecf20Sopenharmony_ci mlc->ipacket[idx] |= (mlc->ipacket[idx - 1] 838c2ecf20Sopenharmony_ci & HIL_PKT_ADDR_MASK); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci goto check; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci /* We know status is 5X */ 888c2ecf20Sopenharmony_ci if (data & HP_SDC_HIL_ISERR) 898c2ecf20Sopenharmony_ci goto err; 908c2ecf20Sopenharmony_ci mlc->ipacket[idx] = 918c2ecf20Sopenharmony_ci (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT; 928c2ecf20Sopenharmony_ci hp_sdc_mlc_priv.got5x = 1; 938c2ecf20Sopenharmony_ci goto out; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci check: 968c2ecf20Sopenharmony_ci hp_sdc_mlc_priv.got5x = 0; 978c2ecf20Sopenharmony_ci if (mlc->imatch == 0) 988c2ecf20Sopenharmony_ci goto done; 998c2ecf20Sopenharmony_ci if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) 1008c2ecf20Sopenharmony_ci && (mlc->ipacket[idx] == (mlc->imatch | idx))) 1018c2ecf20Sopenharmony_ci goto done; 1028c2ecf20Sopenharmony_ci if (mlc->ipacket[idx] == mlc->imatch) 1038c2ecf20Sopenharmony_ci goto done; 1048c2ecf20Sopenharmony_ci goto out; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci err: 1078c2ecf20Sopenharmony_ci printk(KERN_DEBUG PREFIX "err code %x\n", data); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci switch (data) { 1108c2ecf20Sopenharmony_ci case HP_SDC_HIL_RC_DONE: 1118c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n"); 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci case HP_SDC_HIL_ERR: 1158c2ecf20Sopenharmony_ci mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | 1168c2ecf20Sopenharmony_ci HIL_ERR_FERR | HIL_ERR_FOF; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci case HP_SDC_HIL_TO: 1208c2ecf20Sopenharmony_ci mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci case HP_SDC_HIL_RC: 1248c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n"); 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci default: 1288c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Unknown HIL Error status (%x)!\n", data); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* No more data will be coming due to an error. */ 1338c2ecf20Sopenharmony_ci done: 1348c2ecf20Sopenharmony_ci tasklet_schedule(mlc->tasklet); 1358c2ecf20Sopenharmony_ci up(&mlc->isem); 1368c2ecf20Sopenharmony_ci out: 1378c2ecf20Sopenharmony_ci write_unlock(&mlc->lock); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/******************** Tasklet or userspace context functions ****************/ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct hp_sdc_mlc_priv_s *priv; 1468c2ecf20Sopenharmony_ci int rc = 2; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci priv = mlc->priv; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Try to down the semaphore */ 1518c2ecf20Sopenharmony_ci if (down_trylock(&mlc->isem)) { 1528c2ecf20Sopenharmony_ci if (priv->emtestmode) { 1538c2ecf20Sopenharmony_ci mlc->ipacket[0] = 1548c2ecf20Sopenharmony_ci HIL_ERR_INT | (mlc->opacket & 1558c2ecf20Sopenharmony_ci (HIL_PKT_CMD | 1568c2ecf20Sopenharmony_ci HIL_PKT_ADDR_MASK | 1578c2ecf20Sopenharmony_ci HIL_PKT_DATA_MASK)); 1588c2ecf20Sopenharmony_ci mlc->icount = 14; 1598c2ecf20Sopenharmony_ci /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ 1608c2ecf20Sopenharmony_ci goto wasup; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci if (time_after(jiffies, mlc->instart + mlc->intimeout)) { 1638c2ecf20Sopenharmony_ci /* printk("!%i %i", 1648c2ecf20Sopenharmony_ci tv.tv_usec - mlc->instart.tv_usec, 1658c2ecf20Sopenharmony_ci mlc->intimeout); 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci rc = 1; 1688c2ecf20Sopenharmony_ci up(&mlc->isem); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci goto done; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci wasup: 1738c2ecf20Sopenharmony_ci up(&mlc->isem); 1748c2ecf20Sopenharmony_ci rc = 0; 1758c2ecf20Sopenharmony_ci done: 1768c2ecf20Sopenharmony_ci return rc; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int hp_sdc_mlc_cts(hil_mlc *mlc) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct hp_sdc_mlc_priv_s *priv; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci priv = mlc->priv; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* Try to down the semaphores -- they should be up. */ 1868c2ecf20Sopenharmony_ci BUG_ON(down_trylock(&mlc->isem)); 1878c2ecf20Sopenharmony_ci BUG_ON(down_trylock(&mlc->osem)); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci up(&mlc->isem); 1908c2ecf20Sopenharmony_ci up(&mlc->osem); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (down_trylock(&mlc->csem)) { 1938c2ecf20Sopenharmony_ci if (priv->trans.act.semaphore != &mlc->csem) 1948c2ecf20Sopenharmony_ci goto poll; 1958c2ecf20Sopenharmony_ci else 1968c2ecf20Sopenharmony_ci goto busy; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) 2008c2ecf20Sopenharmony_ci goto done; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci poll: 2038c2ecf20Sopenharmony_ci priv->trans.act.semaphore = &mlc->csem; 2048c2ecf20Sopenharmony_ci priv->trans.actidx = 0; 2058c2ecf20Sopenharmony_ci priv->trans.idx = 1; 2068c2ecf20Sopenharmony_ci priv->trans.endidx = 5; 2078c2ecf20Sopenharmony_ci priv->tseq[0] = 2088c2ecf20Sopenharmony_ci HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; 2098c2ecf20Sopenharmony_ci priv->tseq[1] = HP_SDC_CMD_READ_USE; 2108c2ecf20Sopenharmony_ci priv->tseq[2] = 1; 2118c2ecf20Sopenharmony_ci priv->tseq[3] = 0; 2128c2ecf20Sopenharmony_ci priv->tseq[4] = 0; 2138c2ecf20Sopenharmony_ci return __hp_sdc_enqueue_transaction(&priv->trans); 2148c2ecf20Sopenharmony_ci busy: 2158c2ecf20Sopenharmony_ci return 1; 2168c2ecf20Sopenharmony_ci done: 2178c2ecf20Sopenharmony_ci priv->trans.act.semaphore = &mlc->osem; 2188c2ecf20Sopenharmony_ci up(&mlc->csem); 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int hp_sdc_mlc_out(hil_mlc *mlc) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct hp_sdc_mlc_priv_s *priv; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci priv = mlc->priv; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Try to down the semaphore -- it should be up. */ 2298c2ecf20Sopenharmony_ci BUG_ON(down_trylock(&mlc->osem)); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (mlc->opacket & HIL_DO_ALTER_CTRL) 2328c2ecf20Sopenharmony_ci goto do_control; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci do_data: 2358c2ecf20Sopenharmony_ci if (priv->emtestmode) { 2368c2ecf20Sopenharmony_ci up(&mlc->osem); 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci /* Shouldn't be sending commands when loop may be busy */ 2408c2ecf20Sopenharmony_ci BUG_ON(down_trylock(&mlc->csem)); 2418c2ecf20Sopenharmony_ci up(&mlc->csem); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci priv->trans.actidx = 0; 2448c2ecf20Sopenharmony_ci priv->trans.idx = 1; 2458c2ecf20Sopenharmony_ci priv->trans.act.semaphore = &mlc->osem; 2468c2ecf20Sopenharmony_ci priv->trans.endidx = 6; 2478c2ecf20Sopenharmony_ci priv->tseq[0] = 2488c2ecf20Sopenharmony_ci HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE; 2498c2ecf20Sopenharmony_ci priv->tseq[1] = 0x7; 2508c2ecf20Sopenharmony_ci priv->tseq[2] = 2518c2ecf20Sopenharmony_ci (mlc->opacket & 2528c2ecf20Sopenharmony_ci (HIL_PKT_ADDR_MASK | HIL_PKT_CMD)) 2538c2ecf20Sopenharmony_ci >> HIL_PKT_ADDR_SHIFT; 2548c2ecf20Sopenharmony_ci priv->tseq[3] = 2558c2ecf20Sopenharmony_ci (mlc->opacket & HIL_PKT_DATA_MASK) 2568c2ecf20Sopenharmony_ci >> HIL_PKT_DATA_SHIFT; 2578c2ecf20Sopenharmony_ci priv->tseq[4] = 0; /* No timeout */ 2588c2ecf20Sopenharmony_ci if (priv->tseq[3] == HIL_CMD_DHR) 2598c2ecf20Sopenharmony_ci priv->tseq[4] = 1; 2608c2ecf20Sopenharmony_ci priv->tseq[5] = HP_SDC_CMD_DO_HIL; 2618c2ecf20Sopenharmony_ci goto enqueue; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci do_control: 2648c2ecf20Sopenharmony_ci priv->emtestmode = mlc->opacket & HIL_CTRL_TEST; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* we cannot emulate this, it should not be used. */ 2678c2ecf20Sopenharmony_ci BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) 2708c2ecf20Sopenharmony_ci goto control_only; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Should not send command/data after engaging APE */ 2738c2ecf20Sopenharmony_ci BUG_ON(mlc->opacket & HIL_CTRL_APE); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Disengaging APE this way would not be valid either since 2768c2ecf20Sopenharmony_ci * the loop must be allowed to idle. 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * So, it works out that we really never actually send control 2798c2ecf20Sopenharmony_ci * and data when using SDC, we just send the data. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci goto do_data; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci control_only: 2848c2ecf20Sopenharmony_ci priv->trans.actidx = 0; 2858c2ecf20Sopenharmony_ci priv->trans.idx = 1; 2868c2ecf20Sopenharmony_ci priv->trans.act.semaphore = &mlc->osem; 2878c2ecf20Sopenharmony_ci priv->trans.endidx = 4; 2888c2ecf20Sopenharmony_ci priv->tseq[0] = 2898c2ecf20Sopenharmony_ci HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; 2908c2ecf20Sopenharmony_ci priv->tseq[1] = HP_SDC_CMD_SET_LPC; 2918c2ecf20Sopenharmony_ci priv->tseq[2] = 1; 2928c2ecf20Sopenharmony_ci /* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */ 2938c2ecf20Sopenharmony_ci priv->tseq[3] = 0; 2948c2ecf20Sopenharmony_ci if (mlc->opacket & HIL_CTRL_APE) { 2958c2ecf20Sopenharmony_ci priv->tseq[3] |= HP_SDC_LPC_APE_IPF; 2968c2ecf20Sopenharmony_ci BUG_ON(down_trylock(&mlc->csem)); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci enqueue: 2998c2ecf20Sopenharmony_ci return hp_sdc_enqueue_transaction(&priv->trans); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int __init hp_sdc_mlc_init(void) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci hil_mlc *mlc = &hp_sdc_mlc; 3058c2ecf20Sopenharmony_ci int err; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci#ifdef __mc68000__ 3088c2ecf20Sopenharmony_ci if (!MACH_IS_HP300) 3098c2ecf20Sopenharmony_ci return -ENODEV; 3108c2ecf20Sopenharmony_ci#endif 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n"); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci hp_sdc_mlc_priv.emtestmode = 0; 3158c2ecf20Sopenharmony_ci hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq; 3168c2ecf20Sopenharmony_ci hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem; 3178c2ecf20Sopenharmony_ci hp_sdc_mlc_priv.got5x = 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci mlc->cts = &hp_sdc_mlc_cts; 3208c2ecf20Sopenharmony_ci mlc->in = &hp_sdc_mlc_in; 3218c2ecf20Sopenharmony_ci mlc->out = &hp_sdc_mlc_out; 3228c2ecf20Sopenharmony_ci mlc->priv = &hp_sdc_mlc_priv; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci err = hil_mlc_register(mlc); 3258c2ecf20Sopenharmony_ci if (err) { 3268c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n"); 3278c2ecf20Sopenharmony_ci return err; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) { 3318c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n"); 3328c2ecf20Sopenharmony_ci if (hil_mlc_unregister(mlc)) 3338c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" 3348c2ecf20Sopenharmony_ci "This is bad. Could cause an oops.\n"); 3358c2ecf20Sopenharmony_ci return -EBUSY; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic void __exit hp_sdc_mlc_exit(void) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci hil_mlc *mlc = &hp_sdc_mlc; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) 3468c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n" 3478c2ecf20Sopenharmony_ci "This is bad. Could cause an oops.\n"); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (hil_mlc_unregister(mlc)) 3508c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" 3518c2ecf20Sopenharmony_ci "This is bad. Could cause an oops.\n"); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cimodule_init(hp_sdc_mlc_init); 3558c2ecf20Sopenharmony_cimodule_exit(hp_sdc_mlc_exit); 356