12be45b66SKalle Valo /* hermes.c
22be45b66SKalle Valo *
32be45b66SKalle Valo * Driver core for the "Hermes" wireless MAC controller, as used in
42be45b66SKalle Valo * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
52be45b66SKalle Valo * work on the hfa3841 and hfa3842 MAC controller chips used in the
62be45b66SKalle Valo * Prism II chipsets.
72be45b66SKalle Valo *
82be45b66SKalle Valo * This is not a complete driver, just low-level access routines for
92be45b66SKalle Valo * the MAC controller itself.
102be45b66SKalle Valo *
112be45b66SKalle Valo * Based on the prism2 driver from Absolute Value Systems' linux-wlan
122be45b66SKalle Valo * project, the Linux wvlan_cs driver, Lucent's HCF-Light
132be45b66SKalle Valo * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
142be45b66SKalle Valo * particular order).
152be45b66SKalle Valo *
162be45b66SKalle Valo * Copyright (C) 2000, David Gibson, Linuxcare Australia.
172be45b66SKalle Valo * (C) Copyright David Gibson, IBM Corp. 2001-2003.
182be45b66SKalle Valo *
192be45b66SKalle Valo * The contents of this file are subject to the Mozilla Public License
202be45b66SKalle Valo * Version 1.1 (the "License"); you may not use this file except in
212be45b66SKalle Valo * compliance with the License. You may obtain a copy of the License
222be45b66SKalle Valo * at http://www.mozilla.org/MPL/
232be45b66SKalle Valo *
242be45b66SKalle Valo * Software distributed under the License is distributed on an "AS IS"
252be45b66SKalle Valo * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
262be45b66SKalle Valo * the License for the specific language governing rights and
272be45b66SKalle Valo * limitations under the License.
282be45b66SKalle Valo *
292be45b66SKalle Valo * Alternatively, the contents of this file may be used under the
302be45b66SKalle Valo * terms of the GNU General Public License version 2 (the "GPL"), in
312be45b66SKalle Valo * which case the provisions of the GPL are applicable instead of the
322be45b66SKalle Valo * above. If you wish to allow the use of your version of this file
332be45b66SKalle Valo * only under the terms of the GPL and not to allow others to use your
342be45b66SKalle Valo * version of this file under the MPL, indicate your decision by
352be45b66SKalle Valo * deleting the provisions above and replace them with the notice and
362be45b66SKalle Valo * other provisions required by the GPL. If you do not delete the
372be45b66SKalle Valo * provisions above, a recipient may use your version of this file
382be45b66SKalle Valo * under either the MPL or the GPL.
392be45b66SKalle Valo */
402be45b66SKalle Valo
412be45b66SKalle Valo #include <linux/net.h>
422be45b66SKalle Valo #include <linux/module.h>
432be45b66SKalle Valo #include <linux/kernel.h>
442be45b66SKalle Valo #include <linux/delay.h>
452be45b66SKalle Valo
462be45b66SKalle Valo #include "hermes.h"
472be45b66SKalle Valo
482be45b66SKalle Valo /* These are maximum timeouts. Most often, card wil react much faster */
492be45b66SKalle Valo #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
502be45b66SKalle Valo #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
512be45b66SKalle Valo #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
522be45b66SKalle Valo #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
532be45b66SKalle Valo
542be45b66SKalle Valo /*
552be45b66SKalle Valo * AUX port access. To unlock the AUX port write the access keys to the
562be45b66SKalle Valo * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
572be45b66SKalle Valo * register. Then read it and make sure it's HERMES_AUX_ENABLED.
582be45b66SKalle Valo */
592be45b66SKalle Valo #define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
602be45b66SKalle Valo #define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
612be45b66SKalle Valo #define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
622be45b66SKalle Valo #define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
632be45b66SKalle Valo
642be45b66SKalle Valo #define HERMES_AUX_PW0 0xFE01
652be45b66SKalle Valo #define HERMES_AUX_PW1 0xDC23
662be45b66SKalle Valo #define HERMES_AUX_PW2 0xBA45
672be45b66SKalle Valo
682be45b66SKalle Valo /* HERMES_CMD_DOWNLD */
692be45b66SKalle Valo #define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
702be45b66SKalle Valo #define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
712be45b66SKalle Valo #define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
722be45b66SKalle Valo #define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
732be45b66SKalle Valo
742be45b66SKalle Valo /*
752be45b66SKalle Valo * Debugging helpers
762be45b66SKalle Valo */
772be45b66SKalle Valo
782be45b66SKalle Valo #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
792be45b66SKalle Valo printk(stuff); } while (0)
802be45b66SKalle Valo
812be45b66SKalle Valo #undef HERMES_DEBUG
822be45b66SKalle Valo #ifdef HERMES_DEBUG
832be45b66SKalle Valo
842be45b66SKalle Valo #define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff)
852be45b66SKalle Valo
862be45b66SKalle Valo #else /* ! HERMES_DEBUG */
872be45b66SKalle Valo
882be45b66SKalle Valo #define DEBUG(lvl, stuff...) do { } while (0)
892be45b66SKalle Valo
902be45b66SKalle Valo #endif /* ! HERMES_DEBUG */
912be45b66SKalle Valo
922be45b66SKalle Valo static const struct hermes_ops hermes_ops_local;
932be45b66SKalle Valo
942be45b66SKalle Valo /*
952be45b66SKalle Valo * Internal functions
962be45b66SKalle Valo */
972be45b66SKalle Valo
982be45b66SKalle Valo /* Issue a command to the chip. Waiting for it to complete is the caller's
992be45b66SKalle Valo problem.
1002be45b66SKalle Valo
1012be45b66SKalle Valo Returns -EBUSY if the command register is busy, 0 on success.
1022be45b66SKalle Valo
1032be45b66SKalle Valo Callable from any context.
1042be45b66SKalle Valo */
hermes_issue_cmd(struct hermes * hw,u16 cmd,u16 param0,u16 param1,u16 param2)1052be45b66SKalle Valo static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0,
1062be45b66SKalle Valo u16 param1, u16 param2)
1072be45b66SKalle Valo {
1082be45b66SKalle Valo int k = CMD_BUSY_TIMEOUT;
1092be45b66SKalle Valo u16 reg;
1102be45b66SKalle Valo
1112be45b66SKalle Valo /* First wait for the command register to unbusy */
1122be45b66SKalle Valo reg = hermes_read_regn(hw, CMD);
1132be45b66SKalle Valo while ((reg & HERMES_CMD_BUSY) && k) {
1142be45b66SKalle Valo k--;
1152be45b66SKalle Valo udelay(1);
1162be45b66SKalle Valo reg = hermes_read_regn(hw, CMD);
1172be45b66SKalle Valo }
1182be45b66SKalle Valo if (reg & HERMES_CMD_BUSY)
1192be45b66SKalle Valo return -EBUSY;
1202be45b66SKalle Valo
1212be45b66SKalle Valo hermes_write_regn(hw, PARAM2, param2);
1222be45b66SKalle Valo hermes_write_regn(hw, PARAM1, param1);
1232be45b66SKalle Valo hermes_write_regn(hw, PARAM0, param0);
1242be45b66SKalle Valo hermes_write_regn(hw, CMD, cmd);
1252be45b66SKalle Valo
1262be45b66SKalle Valo return 0;
1272be45b66SKalle Valo }
1282be45b66SKalle Valo
1292be45b66SKalle Valo /*
1302be45b66SKalle Valo * Function definitions
1312be45b66SKalle Valo */
1322be45b66SKalle Valo
1332be45b66SKalle Valo /* For doing cmds that wipe the magic constant in SWSUPPORT0 */
hermes_doicmd_wait(struct hermes * hw,u16 cmd,u16 parm0,u16 parm1,u16 parm2,struct hermes_response * resp)1342be45b66SKalle Valo static int hermes_doicmd_wait(struct hermes *hw, u16 cmd,
1352be45b66SKalle Valo u16 parm0, u16 parm1, u16 parm2,
1362be45b66SKalle Valo struct hermes_response *resp)
1372be45b66SKalle Valo {
1382be45b66SKalle Valo int err = 0;
1392be45b66SKalle Valo int k;
1402be45b66SKalle Valo u16 status, reg;
1412be45b66SKalle Valo
1422be45b66SKalle Valo err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
1432be45b66SKalle Valo if (err)
1442be45b66SKalle Valo return err;
1452be45b66SKalle Valo
1462be45b66SKalle Valo reg = hermes_read_regn(hw, EVSTAT);
1472be45b66SKalle Valo k = CMD_INIT_TIMEOUT;
1482be45b66SKalle Valo while ((!(reg & HERMES_EV_CMD)) && k) {
1492be45b66SKalle Valo k--;
1502be45b66SKalle Valo udelay(10);
1512be45b66SKalle Valo reg = hermes_read_regn(hw, EVSTAT);
1522be45b66SKalle Valo }
1532be45b66SKalle Valo
1542be45b66SKalle Valo hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
1552be45b66SKalle Valo
1562be45b66SKalle Valo if (!hermes_present(hw)) {
1572be45b66SKalle Valo DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
1582be45b66SKalle Valo hw->iobase);
1592be45b66SKalle Valo err = -ENODEV;
1602be45b66SKalle Valo goto out;
1612be45b66SKalle Valo }
1622be45b66SKalle Valo
1632be45b66SKalle Valo if (!(reg & HERMES_EV_CMD)) {
1642be45b66SKalle Valo printk(KERN_ERR "hermes @ %p: "
1652be45b66SKalle Valo "Timeout waiting for card to reset (reg=0x%04x)!\n",
1662be45b66SKalle Valo hw->iobase, reg);
1672be45b66SKalle Valo err = -ETIMEDOUT;
1682be45b66SKalle Valo goto out;
1692be45b66SKalle Valo }
1702be45b66SKalle Valo
1712be45b66SKalle Valo status = hermes_read_regn(hw, STATUS);
1722be45b66SKalle Valo if (resp) {
1732be45b66SKalle Valo resp->status = status;
1742be45b66SKalle Valo resp->resp0 = hermes_read_regn(hw, RESP0);
1752be45b66SKalle Valo resp->resp1 = hermes_read_regn(hw, RESP1);
1762be45b66SKalle Valo resp->resp2 = hermes_read_regn(hw, RESP2);
1772be45b66SKalle Valo }
1782be45b66SKalle Valo
1792be45b66SKalle Valo hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
1802be45b66SKalle Valo
1812be45b66SKalle Valo if (status & HERMES_STATUS_RESULT)
1822be45b66SKalle Valo err = -EIO;
1832be45b66SKalle Valo out:
1842be45b66SKalle Valo return err;
1852be45b66SKalle Valo }
1862be45b66SKalle Valo
hermes_struct_init(struct hermes * hw,void __iomem * address,int reg_spacing)1872be45b66SKalle Valo void hermes_struct_init(struct hermes *hw, void __iomem *address,
1882be45b66SKalle Valo int reg_spacing)
1892be45b66SKalle Valo {
1902be45b66SKalle Valo hw->iobase = address;
1912be45b66SKalle Valo hw->reg_spacing = reg_spacing;
1922be45b66SKalle Valo hw->inten = 0x0;
1932be45b66SKalle Valo hw->eeprom_pda = false;
1942be45b66SKalle Valo hw->ops = &hermes_ops_local;
1952be45b66SKalle Valo }
1962be45b66SKalle Valo EXPORT_SYMBOL(hermes_struct_init);
1972be45b66SKalle Valo
hermes_init(struct hermes * hw)1982be45b66SKalle Valo static int hermes_init(struct hermes *hw)
1992be45b66SKalle Valo {
2002be45b66SKalle Valo u16 reg;
2012be45b66SKalle Valo int err = 0;
2022be45b66SKalle Valo int k;
2032be45b66SKalle Valo
2042be45b66SKalle Valo /* We don't want to be interrupted while resetting the chipset */
2052be45b66SKalle Valo hw->inten = 0x0;
2062be45b66SKalle Valo hermes_write_regn(hw, INTEN, 0);
2072be45b66SKalle Valo hermes_write_regn(hw, EVACK, 0xffff);
2082be45b66SKalle Valo
2092be45b66SKalle Valo /* Normally it's a "can't happen" for the command register to
2102be45b66SKalle Valo be busy when we go to issue a command because we are
2112be45b66SKalle Valo serializing all commands. However we want to have some
2122be45b66SKalle Valo chance of resetting the card even if it gets into a stupid
2132be45b66SKalle Valo state, so we actually wait to see if the command register
2142be45b66SKalle Valo will unbusy itself here. */
2152be45b66SKalle Valo k = CMD_BUSY_TIMEOUT;
2162be45b66SKalle Valo reg = hermes_read_regn(hw, CMD);
2172be45b66SKalle Valo while (k && (reg & HERMES_CMD_BUSY)) {
2182be45b66SKalle Valo if (reg == 0xffff) /* Special case - the card has probably been
2192be45b66SKalle Valo removed, so don't wait for the timeout */
2202be45b66SKalle Valo return -ENODEV;
2212be45b66SKalle Valo
2222be45b66SKalle Valo k--;
2232be45b66SKalle Valo udelay(1);
2242be45b66SKalle Valo reg = hermes_read_regn(hw, CMD);
2252be45b66SKalle Valo }
2262be45b66SKalle Valo
2272be45b66SKalle Valo /* No need to explicitly handle the timeout - if we've timed
2282be45b66SKalle Valo out hermes_issue_cmd() will probably return -EBUSY below */
2292be45b66SKalle Valo
2302be45b66SKalle Valo /* According to the documentation, EVSTAT may contain
2312be45b66SKalle Valo obsolete event occurrence information. We have to acknowledge
2322be45b66SKalle Valo it by writing EVACK. */
2332be45b66SKalle Valo reg = hermes_read_regn(hw, EVSTAT);
2342be45b66SKalle Valo hermes_write_regn(hw, EVACK, reg);
2352be45b66SKalle Valo
2362be45b66SKalle Valo /* We don't use hermes_docmd_wait here, because the reset wipes
2372be45b66SKalle Valo the magic constant in SWSUPPORT0 away, and it gets confused */
2382be45b66SKalle Valo err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
2392be45b66SKalle Valo
2402be45b66SKalle Valo return err;
2412be45b66SKalle Valo }
2422be45b66SKalle Valo
2432be45b66SKalle Valo /* Issue a command to the chip, and (busy!) wait for it to
2442be45b66SKalle Valo * complete.
2452be45b66SKalle Valo *
2462be45b66SKalle Valo * Returns:
2472be45b66SKalle Valo * < 0 on internal error
2482be45b66SKalle Valo * 0 on success
2492be45b66SKalle Valo * > 0 on error returned by the firmware
2502be45b66SKalle Valo *
2512be45b66SKalle Valo * Callable from any context, but locking is your problem. */
hermes_docmd_wait(struct hermes * hw,u16 cmd,u16 parm0,struct hermes_response * resp)2522be45b66SKalle Valo static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
2532be45b66SKalle Valo struct hermes_response *resp)
2542be45b66SKalle Valo {
2552be45b66SKalle Valo int err;
2562be45b66SKalle Valo int k;
2572be45b66SKalle Valo u16 reg;
2582be45b66SKalle Valo u16 status;
2592be45b66SKalle Valo
2602be45b66SKalle Valo err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
2612be45b66SKalle Valo if (err) {
2622be45b66SKalle Valo if (!hermes_present(hw)) {
2632be45b66SKalle Valo if (net_ratelimit())
2642be45b66SKalle Valo printk(KERN_WARNING "hermes @ %p: "
2652be45b66SKalle Valo "Card removed while issuing command "
2662be45b66SKalle Valo "0x%04x.\n", hw->iobase, cmd);
2672be45b66SKalle Valo err = -ENODEV;
2682be45b66SKalle Valo } else
2692be45b66SKalle Valo if (net_ratelimit())
2702be45b66SKalle Valo printk(KERN_ERR "hermes @ %p: "
2712be45b66SKalle Valo "Error %d issuing command 0x%04x.\n",
2722be45b66SKalle Valo hw->iobase, err, cmd);
2732be45b66SKalle Valo goto out;
2742be45b66SKalle Valo }
2752be45b66SKalle Valo
2762be45b66SKalle Valo reg = hermes_read_regn(hw, EVSTAT);
2772be45b66SKalle Valo k = CMD_COMPL_TIMEOUT;
2782be45b66SKalle Valo while ((!(reg & HERMES_EV_CMD)) && k) {
2792be45b66SKalle Valo k--;
2802be45b66SKalle Valo udelay(10);
2812be45b66SKalle Valo reg = hermes_read_regn(hw, EVSTAT);
2822be45b66SKalle Valo }
2832be45b66SKalle Valo
2842be45b66SKalle Valo if (!hermes_present(hw)) {
2852be45b66SKalle Valo printk(KERN_WARNING "hermes @ %p: Card removed "
2862be45b66SKalle Valo "while waiting for command 0x%04x completion.\n",
2872be45b66SKalle Valo hw->iobase, cmd);
2882be45b66SKalle Valo err = -ENODEV;
2892be45b66SKalle Valo goto out;
2902be45b66SKalle Valo }
2912be45b66SKalle Valo
2922be45b66SKalle Valo if (!(reg & HERMES_EV_CMD)) {
2932be45b66SKalle Valo printk(KERN_ERR "hermes @ %p: Timeout waiting for "
2942be45b66SKalle Valo "command 0x%04x completion.\n", hw->iobase, cmd);
2952be45b66SKalle Valo err = -ETIMEDOUT;
2962be45b66SKalle Valo goto out;
2972be45b66SKalle Valo }
2982be45b66SKalle Valo
2992be45b66SKalle Valo status = hermes_read_regn(hw, STATUS);
3002be45b66SKalle Valo if (resp) {
3012be45b66SKalle Valo resp->status = status;
3022be45b66SKalle Valo resp->resp0 = hermes_read_regn(hw, RESP0);
3032be45b66SKalle Valo resp->resp1 = hermes_read_regn(hw, RESP1);
3042be45b66SKalle Valo resp->resp2 = hermes_read_regn(hw, RESP2);
3052be45b66SKalle Valo }
3062be45b66SKalle Valo
3072be45b66SKalle Valo hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
3082be45b66SKalle Valo
3092be45b66SKalle Valo if (status & HERMES_STATUS_RESULT)
3102be45b66SKalle Valo err = -EIO;
3112be45b66SKalle Valo
3122be45b66SKalle Valo out:
3132be45b66SKalle Valo return err;
3142be45b66SKalle Valo }
3152be45b66SKalle Valo
hermes_allocate(struct hermes * hw,u16 size,u16 * fid)3162be45b66SKalle Valo static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid)
3172be45b66SKalle Valo {
3182be45b66SKalle Valo int err = 0;
3192be45b66SKalle Valo int k;
3202be45b66SKalle Valo u16 reg;
3212be45b66SKalle Valo
3222be45b66SKalle Valo if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))
3232be45b66SKalle Valo return -EINVAL;
3242be45b66SKalle Valo
3252be45b66SKalle Valo err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
3262be45b66SKalle Valo if (err)
3272be45b66SKalle Valo return err;
3282be45b66SKalle Valo
3292be45b66SKalle Valo reg = hermes_read_regn(hw, EVSTAT);
3302be45b66SKalle Valo k = ALLOC_COMPL_TIMEOUT;
3312be45b66SKalle Valo while ((!(reg & HERMES_EV_ALLOC)) && k) {
3322be45b66SKalle Valo k--;
3332be45b66SKalle Valo udelay(10);
3342be45b66SKalle Valo reg = hermes_read_regn(hw, EVSTAT);
3352be45b66SKalle Valo }
3362be45b66SKalle Valo
3372be45b66SKalle Valo if (!hermes_present(hw)) {
3382be45b66SKalle Valo printk(KERN_WARNING "hermes @ %p: "
3392be45b66SKalle Valo "Card removed waiting for frame allocation.\n",
3402be45b66SKalle Valo hw->iobase);
3412be45b66SKalle Valo return -ENODEV;
3422be45b66SKalle Valo }
3432be45b66SKalle Valo
3442be45b66SKalle Valo if (!(reg & HERMES_EV_ALLOC)) {
3452be45b66SKalle Valo printk(KERN_ERR "hermes @ %p: "
3462be45b66SKalle Valo "Timeout waiting for frame allocation\n",
3472be45b66SKalle Valo hw->iobase);
3482be45b66SKalle Valo return -ETIMEDOUT;
3492be45b66SKalle Valo }
3502be45b66SKalle Valo
3512be45b66SKalle Valo *fid = hermes_read_regn(hw, ALLOCFID);
3522be45b66SKalle Valo hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
3532be45b66SKalle Valo
3542be45b66SKalle Valo return 0;
3552be45b66SKalle Valo }
3562be45b66SKalle Valo
3572be45b66SKalle Valo /* Set up a BAP to read a particular chunk of data from card's internal buffer.
3582be45b66SKalle Valo *
3592be45b66SKalle Valo * Returns:
3602be45b66SKalle Valo * < 0 on internal failure (errno)
3612be45b66SKalle Valo * 0 on success
3622be45b66SKalle Valo * > 0 on error
3632be45b66SKalle Valo * from firmware
3642be45b66SKalle Valo *
3652be45b66SKalle Valo * Callable from any context */
hermes_bap_seek(struct hermes * hw,int bap,u16 id,u16 offset)3662be45b66SKalle Valo static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset)
3672be45b66SKalle Valo {
3682be45b66SKalle Valo int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
3692be45b66SKalle Valo int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
3702be45b66SKalle Valo int k;
3712be45b66SKalle Valo u16 reg;
3722be45b66SKalle Valo
3732be45b66SKalle Valo /* Paranoia.. */
3742be45b66SKalle Valo if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2))
3752be45b66SKalle Valo return -EINVAL;
3762be45b66SKalle Valo
3772be45b66SKalle Valo k = HERMES_BAP_BUSY_TIMEOUT;
3782be45b66SKalle Valo reg = hermes_read_reg(hw, oreg);
3792be45b66SKalle Valo while ((reg & HERMES_OFFSET_BUSY) && k) {
3802be45b66SKalle Valo k--;
3812be45b66SKalle Valo udelay(1);
3822be45b66SKalle Valo reg = hermes_read_reg(hw, oreg);
3832be45b66SKalle Valo }
3842be45b66SKalle Valo
3852be45b66SKalle Valo if (reg & HERMES_OFFSET_BUSY)
3862be45b66SKalle Valo return -ETIMEDOUT;
3872be45b66SKalle Valo
3882be45b66SKalle Valo /* Now we actually set up the transfer */
3892be45b66SKalle Valo hermes_write_reg(hw, sreg, id);
3902be45b66SKalle Valo hermes_write_reg(hw, oreg, offset);
3912be45b66SKalle Valo
3922be45b66SKalle Valo /* Wait for the BAP to be ready */
3932be45b66SKalle Valo k = HERMES_BAP_BUSY_TIMEOUT;
3942be45b66SKalle Valo reg = hermes_read_reg(hw, oreg);
3952be45b66SKalle Valo while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
3962be45b66SKalle Valo k--;
3972be45b66SKalle Valo udelay(1);
3982be45b66SKalle Valo reg = hermes_read_reg(hw, oreg);
3992be45b66SKalle Valo }
4002be45b66SKalle Valo
4012be45b66SKalle Valo if (reg != offset) {
4022be45b66SKalle Valo printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
4032be45b66SKalle Valo "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
4042be45b66SKalle Valo (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
4052be45b66SKalle Valo reg, id, offset);
4062be45b66SKalle Valo
4072be45b66SKalle Valo if (reg & HERMES_OFFSET_BUSY)
4082be45b66SKalle Valo return -ETIMEDOUT;
4092be45b66SKalle Valo
4102be45b66SKalle Valo return -EIO; /* error or wrong offset */
4112be45b66SKalle Valo }
4122be45b66SKalle Valo
4132be45b66SKalle Valo return 0;
4142be45b66SKalle Valo }
4152be45b66SKalle Valo
4162be45b66SKalle Valo /* Read a block of data from the chip's buffer, via the
4172be45b66SKalle Valo * BAP. Synchronization/serialization is the caller's problem. len
4182be45b66SKalle Valo * must be even.
4192be45b66SKalle Valo *
4202be45b66SKalle Valo * Returns:
4212be45b66SKalle Valo * < 0 on internal failure (errno)
4222be45b66SKalle Valo * 0 on success
4232be45b66SKalle Valo * > 0 on error from firmware
4242be45b66SKalle Valo */
hermes_bap_pread(struct hermes * hw,int bap,void * buf,int len,u16 id,u16 offset)4252be45b66SKalle Valo static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len,
4262be45b66SKalle Valo u16 id, u16 offset)
4272be45b66SKalle Valo {
4282be45b66SKalle Valo int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
4292be45b66SKalle Valo int err = 0;
4302be45b66SKalle Valo
4312be45b66SKalle Valo if ((len < 0) || (len % 2))
4322be45b66SKalle Valo return -EINVAL;
4332be45b66SKalle Valo
4342be45b66SKalle Valo err = hermes_bap_seek(hw, bap, id, offset);
4352be45b66SKalle Valo if (err)
4362be45b66SKalle Valo goto out;
4372be45b66SKalle Valo
4382be45b66SKalle Valo /* Actually do the transfer */
4392be45b66SKalle Valo hermes_read_words(hw, dreg, buf, len / 2);
4402be45b66SKalle Valo
4412be45b66SKalle Valo out:
4422be45b66SKalle Valo return err;
4432be45b66SKalle Valo }
4442be45b66SKalle Valo
4452be45b66SKalle Valo /* Write a block of data to the chip's buffer, via the
4462be45b66SKalle Valo * BAP. Synchronization/serialization is the caller's problem.
4472be45b66SKalle Valo *
4482be45b66SKalle Valo * Returns:
4492be45b66SKalle Valo * < 0 on internal failure (errno)
4502be45b66SKalle Valo * 0 on success
4512be45b66SKalle Valo * > 0 on error from firmware
4522be45b66SKalle Valo */
hermes_bap_pwrite(struct hermes * hw,int bap,const void * buf,int len,u16 id,u16 offset)4532be45b66SKalle Valo static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf,
4542be45b66SKalle Valo int len, u16 id, u16 offset)
4552be45b66SKalle Valo {
4562be45b66SKalle Valo int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
4572be45b66SKalle Valo int err = 0;
4582be45b66SKalle Valo
4592be45b66SKalle Valo if (len < 0)
4602be45b66SKalle Valo return -EINVAL;
4612be45b66SKalle Valo
4622be45b66SKalle Valo err = hermes_bap_seek(hw, bap, id, offset);
4632be45b66SKalle Valo if (err)
4642be45b66SKalle Valo goto out;
4652be45b66SKalle Valo
4662be45b66SKalle Valo /* Actually do the transfer */
4672be45b66SKalle Valo hermes_write_bytes(hw, dreg, buf, len);
4682be45b66SKalle Valo
4692be45b66SKalle Valo out:
4702be45b66SKalle Valo return err;
4712be45b66SKalle Valo }
4722be45b66SKalle Valo
4732be45b66SKalle Valo /* Read a Length-Type-Value record from the card.
4742be45b66SKalle Valo *
4752be45b66SKalle Valo * If length is NULL, we ignore the length read from the card, and
4762be45b66SKalle Valo * read the entire buffer regardless. This is useful because some of
4772be45b66SKalle Valo * the configuration records appear to have incorrect lengths in
4782be45b66SKalle Valo * practice.
4792be45b66SKalle Valo *
4802be45b66SKalle Valo * Callable from user or bh context. */
hermes_read_ltv(struct hermes * hw,int bap,u16 rid,unsigned bufsize,u16 * length,void * buf)4812be45b66SKalle Valo static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid,
4822be45b66SKalle Valo unsigned bufsize, u16 *length, void *buf)
4832be45b66SKalle Valo {
4842be45b66SKalle Valo int err = 0;
4852be45b66SKalle Valo int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
4862be45b66SKalle Valo u16 rlength, rtype;
4872be45b66SKalle Valo unsigned nwords;
4882be45b66SKalle Valo
4892be45b66SKalle Valo if (bufsize % 2)
4902be45b66SKalle Valo return -EINVAL;
4912be45b66SKalle Valo
4922be45b66SKalle Valo err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
4932be45b66SKalle Valo if (err)
4942be45b66SKalle Valo return err;
4952be45b66SKalle Valo
4962be45b66SKalle Valo err = hermes_bap_seek(hw, bap, rid, 0);
4972be45b66SKalle Valo if (err)
4982be45b66SKalle Valo return err;
4992be45b66SKalle Valo
5002be45b66SKalle Valo rlength = hermes_read_reg(hw, dreg);
5012be45b66SKalle Valo
5022be45b66SKalle Valo if (!rlength)
5032be45b66SKalle Valo return -ENODATA;
5042be45b66SKalle Valo
5052be45b66SKalle Valo rtype = hermes_read_reg(hw, dreg);
5062be45b66SKalle Valo
5072be45b66SKalle Valo if (length)
5082be45b66SKalle Valo *length = rlength;
5092be45b66SKalle Valo
5102be45b66SKalle Valo if (rtype != rid)
5112be45b66SKalle Valo printk(KERN_WARNING "hermes @ %p: %s(): "
5122be45b66SKalle Valo "rid (0x%04x) does not match type (0x%04x)\n",
5132be45b66SKalle Valo hw->iobase, __func__, rid, rtype);
5142be45b66SKalle Valo if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
5152be45b66SKalle Valo printk(KERN_WARNING "hermes @ %p: "
5162be45b66SKalle Valo "Truncating LTV record from %d to %d bytes. "
5172be45b66SKalle Valo "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
5182be45b66SKalle Valo HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
5192be45b66SKalle Valo
5202be45b66SKalle Valo nwords = min((unsigned)rlength - 1, bufsize / 2);
5212be45b66SKalle Valo hermes_read_words(hw, dreg, buf, nwords);
5222be45b66SKalle Valo
5232be45b66SKalle Valo return 0;
5242be45b66SKalle Valo }
5252be45b66SKalle Valo
hermes_write_ltv(struct hermes * hw,int bap,u16 rid,u16 length,const void * value)5262be45b66SKalle Valo static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid,
5272be45b66SKalle Valo u16 length, const void *value)
5282be45b66SKalle Valo {
5292be45b66SKalle Valo int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
5302be45b66SKalle Valo int err = 0;
5312be45b66SKalle Valo unsigned count;
5322be45b66SKalle Valo
5332be45b66SKalle Valo if (length == 0)
5342be45b66SKalle Valo return -EINVAL;
5352be45b66SKalle Valo
5362be45b66SKalle Valo err = hermes_bap_seek(hw, bap, rid, 0);
5372be45b66SKalle Valo if (err)
5382be45b66SKalle Valo return err;
5392be45b66SKalle Valo
5402be45b66SKalle Valo hermes_write_reg(hw, dreg, length);
5412be45b66SKalle Valo hermes_write_reg(hw, dreg, rid);
5422be45b66SKalle Valo
5432be45b66SKalle Valo count = length - 1;
5442be45b66SKalle Valo
5452be45b66SKalle Valo hermes_write_bytes(hw, dreg, value, count << 1);
5462be45b66SKalle Valo
5472be45b66SKalle Valo err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
5482be45b66SKalle Valo rid, NULL);
5492be45b66SKalle Valo
5502be45b66SKalle Valo return err;
5512be45b66SKalle Valo }
5522be45b66SKalle Valo
5532be45b66SKalle Valo /*** Hermes AUX control ***/
5542be45b66SKalle Valo
5552be45b66SKalle Valo static inline void
hermes_aux_setaddr(struct hermes * hw,u32 addr)5562be45b66SKalle Valo hermes_aux_setaddr(struct hermes *hw, u32 addr)
5572be45b66SKalle Valo {
5582be45b66SKalle Valo hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
5592be45b66SKalle Valo hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
5602be45b66SKalle Valo }
5612be45b66SKalle Valo
5622be45b66SKalle Valo static inline int
hermes_aux_control(struct hermes * hw,int enabled)5632be45b66SKalle Valo hermes_aux_control(struct hermes *hw, int enabled)
5642be45b66SKalle Valo {
5652be45b66SKalle Valo int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
5662be45b66SKalle Valo int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
5672be45b66SKalle Valo int i;
5682be45b66SKalle Valo
5692be45b66SKalle Valo /* Already open? */
5702be45b66SKalle Valo if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
5712be45b66SKalle Valo return 0;
5722be45b66SKalle Valo
5732be45b66SKalle Valo hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
5742be45b66SKalle Valo hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
5752be45b66SKalle Valo hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
5762be45b66SKalle Valo hermes_write_reg(hw, HERMES_CONTROL, action);
5772be45b66SKalle Valo
5782be45b66SKalle Valo for (i = 0; i < 20; i++) {
5792be45b66SKalle Valo udelay(10);
5802be45b66SKalle Valo if (hermes_read_reg(hw, HERMES_CONTROL) ==
5812be45b66SKalle Valo desired_state)
5822be45b66SKalle Valo return 0;
5832be45b66SKalle Valo }
5842be45b66SKalle Valo
5852be45b66SKalle Valo return -EBUSY;
5862be45b66SKalle Valo }
5872be45b66SKalle Valo
5882be45b66SKalle Valo /*** Hermes programming ***/
5892be45b66SKalle Valo
5902be45b66SKalle Valo /* About to start programming data (Hermes I)
5912be45b66SKalle Valo * offset is the entry point
5922be45b66SKalle Valo *
5932be45b66SKalle Valo * Spectrum_cs' Symbol fw does not require this
5942be45b66SKalle Valo * wl_lkm Agere fw does
5952be45b66SKalle Valo * Don't know about intersil
5962be45b66SKalle Valo */
hermesi_program_init(struct hermes * hw,u32 offset)5972be45b66SKalle Valo static int hermesi_program_init(struct hermes *hw, u32 offset)
5982be45b66SKalle Valo {
5992be45b66SKalle Valo int err;
6002be45b66SKalle Valo
6012be45b66SKalle Valo /* Disable interrupts?*/
6022be45b66SKalle Valo /*hw->inten = 0x0;*/
6032be45b66SKalle Valo /*hermes_write_regn(hw, INTEN, 0);*/
6042be45b66SKalle Valo /*hermes_set_irqmask(hw, 0);*/
6052be45b66SKalle Valo
6062be45b66SKalle Valo /* Acknowledge any outstanding command */
6072be45b66SKalle Valo hermes_write_regn(hw, EVACK, 0xFFFF);
6082be45b66SKalle Valo
6092be45b66SKalle Valo /* Using init_cmd_wait rather than cmd_wait */
6102be45b66SKalle Valo err = hw->ops->init_cmd_wait(hw,
6112be45b66SKalle Valo 0x0100 | HERMES_CMD_INIT,
6122be45b66SKalle Valo 0, 0, 0, NULL);
6132be45b66SKalle Valo if (err)
6142be45b66SKalle Valo return err;
6152be45b66SKalle Valo
6162be45b66SKalle Valo err = hw->ops->init_cmd_wait(hw,
6172be45b66SKalle Valo 0x0000 | HERMES_CMD_INIT,
6182be45b66SKalle Valo 0, 0, 0, NULL);
6192be45b66SKalle Valo if (err)
6202be45b66SKalle Valo return err;
6212be45b66SKalle Valo
6222be45b66SKalle Valo err = hermes_aux_control(hw, 1);
6232be45b66SKalle Valo pr_debug("AUX enable returned %d\n", err);
6242be45b66SKalle Valo
6252be45b66SKalle Valo if (err)
6262be45b66SKalle Valo return err;
6272be45b66SKalle Valo
6282be45b66SKalle Valo pr_debug("Enabling volatile, EP 0x%08x\n", offset);
6292be45b66SKalle Valo err = hw->ops->init_cmd_wait(hw,
6302be45b66SKalle Valo HERMES_PROGRAM_ENABLE_VOLATILE,
6312be45b66SKalle Valo offset & 0xFFFFu,
6322be45b66SKalle Valo offset >> 16,
6332be45b66SKalle Valo 0,
6342be45b66SKalle Valo NULL);
6352be45b66SKalle Valo pr_debug("PROGRAM_ENABLE returned %d\n", err);
6362be45b66SKalle Valo
6372be45b66SKalle Valo return err;
6382be45b66SKalle Valo }
6392be45b66SKalle Valo
6402be45b66SKalle Valo /* Done programming data (Hermes I)
6412be45b66SKalle Valo *
6422be45b66SKalle Valo * Spectrum_cs' Symbol fw does not require this
6432be45b66SKalle Valo * wl_lkm Agere fw does
6442be45b66SKalle Valo * Don't know about intersil
6452be45b66SKalle Valo */
hermesi_program_end(struct hermes * hw)6462be45b66SKalle Valo static int hermesi_program_end(struct hermes *hw)
6472be45b66SKalle Valo {
6482be45b66SKalle Valo struct hermes_response resp;
6492be45b66SKalle Valo int rc = 0;
6502be45b66SKalle Valo int err;
6512be45b66SKalle Valo
6522be45b66SKalle Valo rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
6532be45b66SKalle Valo
6542be45b66SKalle Valo pr_debug("PROGRAM_DISABLE returned %d, "
6552be45b66SKalle Valo "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
6562be45b66SKalle Valo rc, resp.resp0, resp.resp1, resp.resp2);
6572be45b66SKalle Valo
6582be45b66SKalle Valo if ((rc == 0) &&
6592be45b66SKalle Valo ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
6602be45b66SKalle Valo rc = -EIO;
6612be45b66SKalle Valo
6622be45b66SKalle Valo err = hermes_aux_control(hw, 0);
6632be45b66SKalle Valo pr_debug("AUX disable returned %d\n", err);
6642be45b66SKalle Valo
6652be45b66SKalle Valo /* Acknowledge any outstanding command */
6662be45b66SKalle Valo hermes_write_regn(hw, EVACK, 0xFFFF);
6672be45b66SKalle Valo
6682be45b66SKalle Valo /* Reinitialise, ignoring return */
6692be45b66SKalle Valo (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
6702be45b66SKalle Valo 0, 0, 0, NULL);
6712be45b66SKalle Valo
6722be45b66SKalle Valo return rc ? rc : err;
6732be45b66SKalle Valo }
6742be45b66SKalle Valo
hermes_program_bytes(struct hermes * hw,const char * data,u32 addr,u32 len)6752be45b66SKalle Valo static int hermes_program_bytes(struct hermes *hw, const char *data,
6762be45b66SKalle Valo u32 addr, u32 len)
6772be45b66SKalle Valo {
6782be45b66SKalle Valo /* wl lkm splits the programming into chunks of 2000 bytes.
6792be45b66SKalle Valo * This restriction appears to come from USB. The PCMCIA
6802be45b66SKalle Valo * adapters can program the whole lot in one go */
6812be45b66SKalle Valo hermes_aux_setaddr(hw, addr);
6822be45b66SKalle Valo hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
6832be45b66SKalle Valo return 0;
6842be45b66SKalle Valo }
6852be45b66SKalle Valo
6862be45b66SKalle Valo /* Read PDA from the adapter */
hermes_read_pda(struct hermes * hw,__le16 * pda,u32 pda_addr,u16 pda_len)6872be45b66SKalle Valo static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr,
6882be45b66SKalle Valo u16 pda_len)
6892be45b66SKalle Valo {
6902be45b66SKalle Valo int ret;
6912be45b66SKalle Valo u16 pda_size;
6922be45b66SKalle Valo u16 data_len = pda_len;
6932be45b66SKalle Valo __le16 *data = pda;
6942be45b66SKalle Valo
6952be45b66SKalle Valo if (hw->eeprom_pda) {
6962be45b66SKalle Valo /* PDA of spectrum symbol is in eeprom */
6972be45b66SKalle Valo
6982be45b66SKalle Valo /* Issue command to read EEPROM */
6992be45b66SKalle Valo ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
7002be45b66SKalle Valo if (ret)
7012be45b66SKalle Valo return ret;
7022be45b66SKalle Valo } else {
7032be45b66SKalle Valo /* wl_lkm does not include PDA size in the PDA area.
7042be45b66SKalle Valo * We will pad the information into pda, so other routines
7052be45b66SKalle Valo * don't have to be modified */
7062be45b66SKalle Valo pda[0] = cpu_to_le16(pda_len - 2);
7072be45b66SKalle Valo /* Includes CFG_PROD_DATA but not itself */
7082be45b66SKalle Valo pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
7092be45b66SKalle Valo data_len = pda_len - 4;
7102be45b66SKalle Valo data = pda + 2;
7112be45b66SKalle Valo }
7122be45b66SKalle Valo
7132be45b66SKalle Valo /* Open auxiliary port */
7142be45b66SKalle Valo ret = hermes_aux_control(hw, 1);
7152be45b66SKalle Valo pr_debug("AUX enable returned %d\n", ret);
7162be45b66SKalle Valo if (ret)
7172be45b66SKalle Valo return ret;
7182be45b66SKalle Valo
7192be45b66SKalle Valo /* Read PDA */
7202be45b66SKalle Valo hermes_aux_setaddr(hw, pda_addr);
7212be45b66SKalle Valo hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
7222be45b66SKalle Valo
7232be45b66SKalle Valo /* Close aux port */
7242be45b66SKalle Valo ret = hermes_aux_control(hw, 0);
7252be45b66SKalle Valo pr_debug("AUX disable returned %d\n", ret);
7262be45b66SKalle Valo
7272be45b66SKalle Valo /* Check PDA length */
7282be45b66SKalle Valo pda_size = le16_to_cpu(pda[0]);
7292be45b66SKalle Valo pr_debug("Actual PDA length %d, Max allowed %d\n",
7302be45b66SKalle Valo pda_size, pda_len);
7312be45b66SKalle Valo if (pda_size > pda_len)
7322be45b66SKalle Valo return -EINVAL;
7332be45b66SKalle Valo
7342be45b66SKalle Valo return 0;
7352be45b66SKalle Valo }
7362be45b66SKalle Valo
hermes_lock_irqsave(spinlock_t * lock,unsigned long * flags)7372be45b66SKalle Valo static void hermes_lock_irqsave(spinlock_t *lock,
7382be45b66SKalle Valo unsigned long *flags) __acquires(lock)
7392be45b66SKalle Valo {
7402be45b66SKalle Valo spin_lock_irqsave(lock, *flags);
7412be45b66SKalle Valo }
7422be45b66SKalle Valo
hermes_unlock_irqrestore(spinlock_t * lock,unsigned long * flags)7432be45b66SKalle Valo static void hermes_unlock_irqrestore(spinlock_t *lock,
7442be45b66SKalle Valo unsigned long *flags) __releases(lock)
7452be45b66SKalle Valo {
7462be45b66SKalle Valo spin_unlock_irqrestore(lock, *flags);
7472be45b66SKalle Valo }
7482be45b66SKalle Valo
hermes_lock_irq(spinlock_t * lock)7492be45b66SKalle Valo static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
7502be45b66SKalle Valo {
7512be45b66SKalle Valo spin_lock_irq(lock);
7522be45b66SKalle Valo }
7532be45b66SKalle Valo
hermes_unlock_irq(spinlock_t * lock)7542be45b66SKalle Valo static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
7552be45b66SKalle Valo {
7562be45b66SKalle Valo spin_unlock_irq(lock);
7572be45b66SKalle Valo }
7582be45b66SKalle Valo
7592be45b66SKalle Valo /* Hermes operations for local buses */
7602be45b66SKalle Valo static const struct hermes_ops hermes_ops_local = {
7612be45b66SKalle Valo .init = hermes_init,
7622be45b66SKalle Valo .cmd_wait = hermes_docmd_wait,
7632be45b66SKalle Valo .init_cmd_wait = hermes_doicmd_wait,
7642be45b66SKalle Valo .allocate = hermes_allocate,
765*a3d8a259SSebastian Andrzej Siewior .read_ltv = hermes_read_ltv,
7662be45b66SKalle Valo .read_ltv_pr = hermes_read_ltv,
7672be45b66SKalle Valo .write_ltv = hermes_write_ltv,
7682be45b66SKalle Valo .bap_pread = hermes_bap_pread,
7692be45b66SKalle Valo .bap_pwrite = hermes_bap_pwrite,
7702be45b66SKalle Valo .read_pda = hermes_read_pda,
7712be45b66SKalle Valo .program_init = hermesi_program_init,
7722be45b66SKalle Valo .program_end = hermesi_program_end,
7732be45b66SKalle Valo .program = hermes_program_bytes,
7742be45b66SKalle Valo .lock_irqsave = hermes_lock_irqsave,
7752be45b66SKalle Valo .unlock_irqrestore = hermes_unlock_irqrestore,
7762be45b66SKalle Valo .lock_irq = hermes_lock_irq,
7772be45b66SKalle Valo .unlock_irq = hermes_unlock_irq,
778 };
779