xref: /openbmc/linux/drivers/net/wireless/marvell/libertas/if_cs.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*ca47d344SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f988d640SKalle Valo /*
3f988d640SKalle Valo 
4f988d640SKalle Valo   Driver for the Marvell 8385 based compact flash WLAN cards.
5f988d640SKalle Valo 
6f988d640SKalle Valo   (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
7f988d640SKalle Valo 
8f988d640SKalle Valo 
9f988d640SKalle Valo */
10f988d640SKalle Valo 
11f988d640SKalle Valo #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12f988d640SKalle Valo 
13f988d640SKalle Valo #include <linux/module.h>
14f988d640SKalle Valo #include <linux/slab.h>
15f988d640SKalle Valo #include <linux/delay.h>
16f988d640SKalle Valo #include <linux/moduleparam.h>
17f988d640SKalle Valo #include <linux/firmware.h>
18f988d640SKalle Valo #include <linux/netdevice.h>
19f988d640SKalle Valo 
20f988d640SKalle Valo #include <pcmcia/cistpl.h>
21f988d640SKalle Valo #include <pcmcia/ds.h>
22f988d640SKalle Valo 
23f988d640SKalle Valo #include <linux/io.h>
24f988d640SKalle Valo 
25f988d640SKalle Valo #define DRV_NAME "libertas_cs"
26f988d640SKalle Valo 
27f988d640SKalle Valo #include "decl.h"
28f988d640SKalle Valo #include "defs.h"
29f988d640SKalle Valo #include "dev.h"
30f988d640SKalle Valo 
31f988d640SKalle Valo 
32f988d640SKalle Valo /********************************************************************/
33f988d640SKalle Valo /* Module stuff                                                     */
34f988d640SKalle Valo /********************************************************************/
35f988d640SKalle Valo 
36f988d640SKalle Valo MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
37f988d640SKalle Valo MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
38f988d640SKalle Valo MODULE_LICENSE("GPL");
39f988d640SKalle Valo 
40f988d640SKalle Valo 
41f988d640SKalle Valo 
42f988d640SKalle Valo /********************************************************************/
43f988d640SKalle Valo /* Data structures                                                  */
44f988d640SKalle Valo /********************************************************************/
45f988d640SKalle Valo 
46f988d640SKalle Valo struct if_cs_card {
47f988d640SKalle Valo 	struct pcmcia_device *p_dev;
48f988d640SKalle Valo 	struct lbs_private *priv;
49f988d640SKalle Valo 	void __iomem *iobase;
50f988d640SKalle Valo 	bool align_regs;
51f988d640SKalle Valo 	u32 model;
52f988d640SKalle Valo };
53f988d640SKalle Valo 
54f988d640SKalle Valo 
55f988d640SKalle Valo enum {
56f988d640SKalle Valo 	MODEL_UNKNOWN = 0x00,
57f988d640SKalle Valo 	MODEL_8305 = 0x01,
58f988d640SKalle Valo 	MODEL_8381 = 0x02,
59f988d640SKalle Valo 	MODEL_8385 = 0x03
60f988d640SKalle Valo };
61f988d640SKalle Valo 
62f988d640SKalle Valo static const struct lbs_fw_table fw_table[] = {
63f988d640SKalle Valo 	{ MODEL_8305, "libertas/cf8305.bin", NULL },
64f988d640SKalle Valo 	{ MODEL_8305, "libertas_cs_helper.fw", NULL },
65f988d640SKalle Valo 	{ MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
66f988d640SKalle Valo 	{ MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
67f988d640SKalle Valo 	{ MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
68f988d640SKalle Valo 	{ MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
69f988d640SKalle Valo 	{ 0, NULL, NULL }
70f988d640SKalle Valo };
71f988d640SKalle Valo MODULE_FIRMWARE("libertas/cf8305.bin");
72f988d640SKalle Valo MODULE_FIRMWARE("libertas/cf8381_helper.bin");
73f988d640SKalle Valo MODULE_FIRMWARE("libertas/cf8381.bin");
74f988d640SKalle Valo MODULE_FIRMWARE("libertas/cf8385_helper.bin");
75f988d640SKalle Valo MODULE_FIRMWARE("libertas/cf8385.bin");
76f988d640SKalle Valo MODULE_FIRMWARE("libertas_cs_helper.fw");
77f988d640SKalle Valo MODULE_FIRMWARE("libertas_cs.fw");
78f988d640SKalle Valo 
79f988d640SKalle Valo 
80f988d640SKalle Valo /********************************************************************/
81f988d640SKalle Valo /* Hardware access                                                  */
82f988d640SKalle Valo /********************************************************************/
83f988d640SKalle Valo 
84f988d640SKalle Valo /* This define enables wrapper functions which allow you
85f988d640SKalle Valo    to dump all register accesses. You normally won't this,
86f988d640SKalle Valo    except for development */
87f988d640SKalle Valo /* #define DEBUG_IO */
88f988d640SKalle Valo 
89f988d640SKalle Valo #ifdef DEBUG_IO
90f988d640SKalle Valo static int debug_output = 0;
91f988d640SKalle Valo #else
92f988d640SKalle Valo /* This way the compiler optimizes the printk's away */
93f988d640SKalle Valo #define debug_output 0
94f988d640SKalle Valo #endif
95f988d640SKalle Valo 
if_cs_read8(struct if_cs_card * card,uint reg)96f988d640SKalle Valo static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
97f988d640SKalle Valo {
98f988d640SKalle Valo 	unsigned int val = ioread8(card->iobase + reg);
99f988d640SKalle Valo 	if (debug_output)
100f988d640SKalle Valo 		printk(KERN_INFO "inb %08x<%02x\n", reg, val);
101f988d640SKalle Valo 	return val;
102f988d640SKalle Valo }
if_cs_read16(struct if_cs_card * card,uint reg)103f988d640SKalle Valo static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
104f988d640SKalle Valo {
105f988d640SKalle Valo 	unsigned int val = ioread16(card->iobase + reg);
106f988d640SKalle Valo 	if (debug_output)
107f988d640SKalle Valo 		printk(KERN_INFO "inw %08x<%04x\n", reg, val);
108f988d640SKalle Valo 	return val;
109f988d640SKalle Valo }
if_cs_read16_rep(struct if_cs_card * card,uint reg,void * buf,unsigned long count)110f988d640SKalle Valo static inline void if_cs_read16_rep(
111f988d640SKalle Valo 	struct if_cs_card *card,
112f988d640SKalle Valo 	uint reg,
113f988d640SKalle Valo 	void *buf,
114f988d640SKalle Valo 	unsigned long count)
115f988d640SKalle Valo {
116f988d640SKalle Valo 	if (debug_output)
117f988d640SKalle Valo 		printk(KERN_INFO "insw %08x<(0x%lx words)\n",
118f988d640SKalle Valo 			reg, count);
119f988d640SKalle Valo 	ioread16_rep(card->iobase + reg, buf, count);
120f988d640SKalle Valo }
121f988d640SKalle Valo 
if_cs_write8(struct if_cs_card * card,uint reg,u8 val)122f988d640SKalle Valo static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
123f988d640SKalle Valo {
124f988d640SKalle Valo 	if (debug_output)
125f988d640SKalle Valo 		printk(KERN_INFO "outb %08x>%02x\n", reg, val);
126f988d640SKalle Valo 	iowrite8(val, card->iobase + reg);
127f988d640SKalle Valo }
128f988d640SKalle Valo 
if_cs_write16(struct if_cs_card * card,uint reg,u16 val)129f988d640SKalle Valo static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
130f988d640SKalle Valo {
131f988d640SKalle Valo 	if (debug_output)
132f988d640SKalle Valo 		printk(KERN_INFO "outw %08x>%04x\n", reg, val);
133f988d640SKalle Valo 	iowrite16(val, card->iobase + reg);
134f988d640SKalle Valo }
135f988d640SKalle Valo 
if_cs_write16_rep(struct if_cs_card * card,uint reg,const void * buf,unsigned long count)136f988d640SKalle Valo static inline void if_cs_write16_rep(
137f988d640SKalle Valo 	struct if_cs_card *card,
138f988d640SKalle Valo 	uint reg,
139f988d640SKalle Valo 	const void *buf,
140f988d640SKalle Valo 	unsigned long count)
141f988d640SKalle Valo {
142f988d640SKalle Valo 	if (debug_output)
143f988d640SKalle Valo 		printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
144f988d640SKalle Valo 			reg, count);
145f988d640SKalle Valo 	iowrite16_rep(card->iobase + reg, buf, count);
146f988d640SKalle Valo }
147f988d640SKalle Valo 
148f988d640SKalle Valo 
149f988d640SKalle Valo /*
150f988d640SKalle Valo  * I know that polling/delaying is frowned upon. However, this procedure
151f988d640SKalle Valo  * with polling is needed while downloading the firmware. At this stage,
152f988d640SKalle Valo  * the hardware does unfortunately not create any interrupts.
153f988d640SKalle Valo  *
154f988d640SKalle Valo  * Fortunately, this function is never used once the firmware is in
155f988d640SKalle Valo  * the card. :-)
156f988d640SKalle Valo  *
157f988d640SKalle Valo  * As a reference, see the "Firmware Specification v5.1", page 18
158f988d640SKalle Valo  * and 19. I did not follow their suggested timing to the word,
159f988d640SKalle Valo  * but this works nice & fast anyway.
160f988d640SKalle Valo  */
if_cs_poll_while_fw_download(struct if_cs_card * card,uint addr,u8 reg)161f988d640SKalle Valo static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
162f988d640SKalle Valo {
163f988d640SKalle Valo 	int i;
164f988d640SKalle Valo 
165f988d640SKalle Valo 	for (i = 0; i < 100000; i++) {
166f988d640SKalle Valo 		u8 val = if_cs_read8(card, addr);
167f988d640SKalle Valo 		if (val == reg)
168f988d640SKalle Valo 			return 0;
169f988d640SKalle Valo 		udelay(5);
170f988d640SKalle Valo 	}
171f988d640SKalle Valo 	return -ETIME;
172f988d640SKalle Valo }
173f988d640SKalle Valo 
174f988d640SKalle Valo 
175f988d640SKalle Valo 
176f988d640SKalle Valo /*
177f988d640SKalle Valo  * First the bitmasks for the host/card interrupt/status registers:
178f988d640SKalle Valo  */
179f988d640SKalle Valo #define IF_CS_BIT_TX			0x0001
180f988d640SKalle Valo #define IF_CS_BIT_RX			0x0002
181f988d640SKalle Valo #define IF_CS_BIT_COMMAND		0x0004
182f988d640SKalle Valo #define IF_CS_BIT_RESP			0x0008
183f988d640SKalle Valo #define IF_CS_BIT_EVENT			0x0010
184f988d640SKalle Valo #define	IF_CS_BIT_MASK			0x001f
185f988d640SKalle Valo 
186f988d640SKalle Valo 
187f988d640SKalle Valo 
188f988d640SKalle Valo /*
189f988d640SKalle Valo  * It's not really clear to me what the host status register is for. It
190f988d640SKalle Valo  * needs to be set almost in union with "host int cause". The following
191f988d640SKalle Valo  * bits from above are used:
192f988d640SKalle Valo  *
193f988d640SKalle Valo  *   IF_CS_BIT_TX         driver downloaded a data packet
194f988d640SKalle Valo  *   IF_CS_BIT_RX         driver got a data packet
195f988d640SKalle Valo  *   IF_CS_BIT_COMMAND    driver downloaded a command
196f988d640SKalle Valo  *   IF_CS_BIT_RESP       not used (has some meaning with powerdown)
197f988d640SKalle Valo  *   IF_CS_BIT_EVENT      driver read a host event
198f988d640SKalle Valo  */
199f988d640SKalle Valo #define IF_CS_HOST_STATUS		0x00000000
200f988d640SKalle Valo 
201f988d640SKalle Valo /*
202f988d640SKalle Valo  * With the host int cause register can the host (that is, Linux) cause
203f988d640SKalle Valo  * an interrupt in the firmware, to tell the firmware about those events:
204f988d640SKalle Valo  *
205f988d640SKalle Valo  *   IF_CS_BIT_TX         a data packet has been downloaded
206f988d640SKalle Valo  *   IF_CS_BIT_RX         a received data packet has retrieved
207f988d640SKalle Valo  *   IF_CS_BIT_COMMAND    a firmware block or a command has been downloaded
208f988d640SKalle Valo  *   IF_CS_BIT_RESP       not used (has some meaning with powerdown)
209f988d640SKalle Valo  *   IF_CS_BIT_EVENT      a host event (link lost etc) has been retrieved
210f988d640SKalle Valo  */
211f988d640SKalle Valo #define IF_CS_HOST_INT_CAUSE		0x00000002
212f988d640SKalle Valo 
213f988d640SKalle Valo /*
214f988d640SKalle Valo  * The host int mask register is used to enable/disable interrupt.  However,
215f988d640SKalle Valo  * I have the suspicion that disabled interrupts are lost.
216f988d640SKalle Valo  */
217f988d640SKalle Valo #define IF_CS_HOST_INT_MASK		0x00000004
218f988d640SKalle Valo 
219f988d640SKalle Valo /*
220f988d640SKalle Valo  * Used to send or receive data packets:
221f988d640SKalle Valo  */
222f988d640SKalle Valo #define IF_CS_WRITE			0x00000016
223f988d640SKalle Valo #define IF_CS_WRITE_LEN			0x00000014
224f988d640SKalle Valo #define IF_CS_READ			0x00000010
225f988d640SKalle Valo #define IF_CS_READ_LEN			0x00000024
226f988d640SKalle Valo 
227f988d640SKalle Valo /*
228f988d640SKalle Valo  * Used to send commands (and to send firmware block) and to
229f988d640SKalle Valo  * receive command responses:
230f988d640SKalle Valo  */
231f988d640SKalle Valo #define IF_CS_CMD			0x0000001A
232f988d640SKalle Valo #define IF_CS_CMD_LEN			0x00000018
233f988d640SKalle Valo #define IF_CS_RESP			0x00000012
234f988d640SKalle Valo #define IF_CS_RESP_LEN			0x00000030
235f988d640SKalle Valo 
236f988d640SKalle Valo /*
237f988d640SKalle Valo  * The card status registers shows what the card/firmware actually
238f988d640SKalle Valo  * accepts:
239f988d640SKalle Valo  *
240f988d640SKalle Valo  *   IF_CS_BIT_TX        you may send a data packet
241f988d640SKalle Valo  *   IF_CS_BIT_RX        you may retrieve a data packet
242f988d640SKalle Valo  *   IF_CS_BIT_COMMAND   you may send a command
243f988d640SKalle Valo  *   IF_CS_BIT_RESP      you may retrieve a command response
244f988d640SKalle Valo  *   IF_CS_BIT_EVENT     the card has a event for use (link lost, snr low etc)
245f988d640SKalle Valo  *
246f988d640SKalle Valo  * When reading this register several times, you will get back the same
247f988d640SKalle Valo  * results --- with one exception: the IF_CS_BIT_EVENT clear itself
248f988d640SKalle Valo  * automatically.
249f988d640SKalle Valo  *
250f988d640SKalle Valo  * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because
251f988d640SKalle Valo  * we handle this via the card int cause register.
252f988d640SKalle Valo  */
253f988d640SKalle Valo #define IF_CS_CARD_STATUS		0x00000020
254f988d640SKalle Valo #define IF_CS_CARD_STATUS_MASK		0x7f00
255f988d640SKalle Valo 
256f988d640SKalle Valo /*
257f988d640SKalle Valo  * The card int cause register is used by the card/firmware to notify us
258f988d640SKalle Valo  * about the following events:
259f988d640SKalle Valo  *
260f988d640SKalle Valo  *   IF_CS_BIT_TX        a data packet has successfully been sentx
261f988d640SKalle Valo  *   IF_CS_BIT_RX        a data packet has been received and can be retrieved
262f988d640SKalle Valo  *   IF_CS_BIT_COMMAND   not used
263f988d640SKalle Valo  *   IF_CS_BIT_RESP      the firmware has a command response for us
264f988d640SKalle Valo  *   IF_CS_BIT_EVENT     the card has a event for use (link lost, snr low etc)
265f988d640SKalle Valo  */
266f988d640SKalle Valo #define IF_CS_CARD_INT_CAUSE		0x00000022
267f988d640SKalle Valo 
268f988d640SKalle Valo /*
269f988d640SKalle Valo  * This is used to for handshaking with the card's bootloader/helper image
270f988d640SKalle Valo  * to synchronize downloading of firmware blocks.
271f988d640SKalle Valo  */
272f988d640SKalle Valo #define IF_CS_SQ_READ_LOW		0x00000028
273f988d640SKalle Valo #define IF_CS_SQ_HELPER_OK		0x10
274f988d640SKalle Valo 
275f988d640SKalle Valo /*
276f988d640SKalle Valo  * The scratch register tells us ...
277f988d640SKalle Valo  *
278f988d640SKalle Valo  * IF_CS_SCRATCH_BOOT_OK     the bootloader runs
279f988d640SKalle Valo  * IF_CS_SCRATCH_HELPER_OK   the helper firmware already runs
280f988d640SKalle Valo  */
281f988d640SKalle Valo #define IF_CS_SCRATCH			0x0000003F
282f988d640SKalle Valo #define IF_CS_SCRATCH_BOOT_OK		0x00
283f988d640SKalle Valo #define IF_CS_SCRATCH_HELPER_OK		0x5a
284f988d640SKalle Valo 
285f988d640SKalle Valo /*
286f988d640SKalle Valo  * Used to detect ancient chips:
287f988d640SKalle Valo  */
288f988d640SKalle Valo #define IF_CS_PRODUCT_ID		0x0000001C
289f988d640SKalle Valo #define IF_CS_CF8385_B1_REV		0x12
290f988d640SKalle Valo #define IF_CS_CF8381_B3_REV		0x04
291f988d640SKalle Valo #define IF_CS_CF8305_B1_REV		0x03
292f988d640SKalle Valo 
293f988d640SKalle Valo /*
294f988d640SKalle Valo  * Used to detect other cards than CF8385 since their revisions of silicon
295f988d640SKalle Valo  * doesn't match those from CF8385, eg. CF8381 B3 works with this driver.
296f988d640SKalle Valo  */
297f988d640SKalle Valo #define CF8305_MANFID		0x02db
298f988d640SKalle Valo #define CF8305_CARDID		0x8103
299f988d640SKalle Valo #define CF8381_MANFID		0x02db
300f988d640SKalle Valo #define CF8381_CARDID		0x6064
301f988d640SKalle Valo #define CF8385_MANFID		0x02df
302f988d640SKalle Valo #define CF8385_CARDID		0x8103
303f988d640SKalle Valo 
304f988d640SKalle Valo /*
305f988d640SKalle Valo  * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
306f988d640SKalle Valo  * that gets fixed.  Currently there's no way to access it from the probe hook.
307f988d640SKalle Valo  */
get_model(u16 manf_id,u16 card_id)308f988d640SKalle Valo static inline u32 get_model(u16 manf_id, u16 card_id)
309f988d640SKalle Valo {
310f988d640SKalle Valo 	/* NOTE: keep in sync with if_cs_ids */
311f988d640SKalle Valo 	if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
312f988d640SKalle Valo 		return MODEL_8305;
313f988d640SKalle Valo 	else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
314f988d640SKalle Valo 		return MODEL_8381;
315f988d640SKalle Valo 	else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
316f988d640SKalle Valo 		return MODEL_8385;
317f988d640SKalle Valo 	return MODEL_UNKNOWN;
318f988d640SKalle Valo }
319f988d640SKalle Valo 
320f988d640SKalle Valo /********************************************************************/
321f988d640SKalle Valo /* I/O and interrupt handling                                       */
322f988d640SKalle Valo /********************************************************************/
323f988d640SKalle Valo 
if_cs_enable_ints(struct if_cs_card * card)324f988d640SKalle Valo static inline void if_cs_enable_ints(struct if_cs_card *card)
325f988d640SKalle Valo {
326f988d640SKalle Valo 	if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
327f988d640SKalle Valo }
328f988d640SKalle Valo 
if_cs_disable_ints(struct if_cs_card * card)329f988d640SKalle Valo static inline void if_cs_disable_ints(struct if_cs_card *card)
330f988d640SKalle Valo {
331f988d640SKalle Valo 	if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
332f988d640SKalle Valo }
333f988d640SKalle Valo 
334f988d640SKalle Valo /*
335f988d640SKalle Valo  * Called from if_cs_host_to_card to send a command to the hardware
336f988d640SKalle Valo  */
if_cs_send_cmd(struct lbs_private * priv,u8 * buf,u16 nb)337f988d640SKalle Valo static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
338f988d640SKalle Valo {
339f988d640SKalle Valo 	struct if_cs_card *card = (struct if_cs_card *)priv->card;
340f988d640SKalle Valo 	int ret = -1;
341f988d640SKalle Valo 	int loops = 0;
342f988d640SKalle Valo 
343f988d640SKalle Valo 	if_cs_disable_ints(card);
344f988d640SKalle Valo 
345f988d640SKalle Valo 	/* Is hardware ready? */
346f988d640SKalle Valo 	while (1) {
347f988d640SKalle Valo 		u16 status = if_cs_read16(card, IF_CS_CARD_STATUS);
348f988d640SKalle Valo 		if (status & IF_CS_BIT_COMMAND)
349f988d640SKalle Valo 			break;
350f988d640SKalle Valo 		if (++loops > 100) {
351f988d640SKalle Valo 			netdev_err(priv->dev, "card not ready for commands\n");
352f988d640SKalle Valo 			goto done;
353f988d640SKalle Valo 		}
354f988d640SKalle Valo 		mdelay(1);
355f988d640SKalle Valo 	}
356f988d640SKalle Valo 
357f988d640SKalle Valo 	if_cs_write16(card, IF_CS_CMD_LEN, nb);
358f988d640SKalle Valo 
359f988d640SKalle Valo 	if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2);
360f988d640SKalle Valo 	/* Are we supposed to transfer an odd amount of bytes? */
361f988d640SKalle Valo 	if (nb & 1)
362f988d640SKalle Valo 		if_cs_write8(card, IF_CS_CMD, buf[nb-1]);
363f988d640SKalle Valo 
364f988d640SKalle Valo 	/* "Assert the download over interrupt command in the Host
365f988d640SKalle Valo 	 * status register" */
366f988d640SKalle Valo 	if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
367f988d640SKalle Valo 
368f988d640SKalle Valo 	/* "Assert the download over interrupt command in the Card
369f988d640SKalle Valo 	 * interrupt case register" */
370f988d640SKalle Valo 	if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
371f988d640SKalle Valo 	ret = 0;
372f988d640SKalle Valo 
373f988d640SKalle Valo done:
374f988d640SKalle Valo 	if_cs_enable_ints(card);
375f988d640SKalle Valo 	return ret;
376f988d640SKalle Valo }
377f988d640SKalle Valo 
378f988d640SKalle Valo /*
379f988d640SKalle Valo  * Called from if_cs_host_to_card to send a data to the hardware
380f988d640SKalle Valo  */
if_cs_send_data(struct lbs_private * priv,u8 * buf,u16 nb)381f988d640SKalle Valo static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
382f988d640SKalle Valo {
383f988d640SKalle Valo 	struct if_cs_card *card = (struct if_cs_card *)priv->card;
384f988d640SKalle Valo 	u16 status;
385f988d640SKalle Valo 
386f988d640SKalle Valo 	if_cs_disable_ints(card);
387f988d640SKalle Valo 
388f988d640SKalle Valo 	status = if_cs_read16(card, IF_CS_CARD_STATUS);
389f988d640SKalle Valo 	BUG_ON((status & IF_CS_BIT_TX) == 0);
390f988d640SKalle Valo 
391f988d640SKalle Valo 	if_cs_write16(card, IF_CS_WRITE_LEN, nb);
392f988d640SKalle Valo 
393f988d640SKalle Valo 	/* write even number of bytes, then odd byte if necessary */
394f988d640SKalle Valo 	if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2);
395f988d640SKalle Valo 	if (nb & 1)
396f988d640SKalle Valo 		if_cs_write8(card, IF_CS_WRITE, buf[nb-1]);
397f988d640SKalle Valo 
398f988d640SKalle Valo 	if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
399f988d640SKalle Valo 	if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
400f988d640SKalle Valo 	if_cs_enable_ints(card);
401f988d640SKalle Valo }
402f988d640SKalle Valo 
403f988d640SKalle Valo /*
404f988d640SKalle Valo  * Get the command result out of the card.
405f988d640SKalle Valo  */
if_cs_receive_cmdres(struct lbs_private * priv,u8 * data,u32 * len)406f988d640SKalle Valo static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
407f988d640SKalle Valo {
408f988d640SKalle Valo 	unsigned long flags;
409f988d640SKalle Valo 	int ret = -1;
410f988d640SKalle Valo 	u16 status;
411f988d640SKalle Valo 
412f988d640SKalle Valo 	/* is hardware ready? */
413f988d640SKalle Valo 	status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
414f988d640SKalle Valo 	if ((status & IF_CS_BIT_RESP) == 0) {
415f988d640SKalle Valo 		netdev_err(priv->dev, "no cmd response in card\n");
416f988d640SKalle Valo 		*len = 0;
417f988d640SKalle Valo 		goto out;
418f988d640SKalle Valo 	}
419f988d640SKalle Valo 
420f988d640SKalle Valo 	*len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
421f988d640SKalle Valo 	if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
422f988d640SKalle Valo 		netdev_err(priv->dev,
423f988d640SKalle Valo 			   "card cmd buffer has invalid # of bytes (%d)\n",
424f988d640SKalle Valo 			   *len);
425f988d640SKalle Valo 		goto out;
426f988d640SKalle Valo 	}
427f988d640SKalle Valo 
428f988d640SKalle Valo 	/* read even number of bytes, then odd byte if necessary */
429f988d640SKalle Valo 	if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16));
430f988d640SKalle Valo 	if (*len & 1)
431f988d640SKalle Valo 		data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP);
432f988d640SKalle Valo 
433f988d640SKalle Valo 	/* This is a workaround for a firmware that reports too much
434f988d640SKalle Valo 	 * bytes */
435f988d640SKalle Valo 	*len -= 8;
436f988d640SKalle Valo 	ret = 0;
437f988d640SKalle Valo 
438f988d640SKalle Valo 	/* Clear this flag again */
439f988d640SKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
440f988d640SKalle Valo 	priv->dnld_sent = DNLD_RES_RECEIVED;
441f988d640SKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
442f988d640SKalle Valo 
443f988d640SKalle Valo out:
444f988d640SKalle Valo 	return ret;
445f988d640SKalle Valo }
446f988d640SKalle Valo 
if_cs_receive_data(struct lbs_private * priv)447f988d640SKalle Valo static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
448f988d640SKalle Valo {
449f988d640SKalle Valo 	struct sk_buff *skb = NULL;
450f988d640SKalle Valo 	u16 len;
451f988d640SKalle Valo 	u8 *data;
452f988d640SKalle Valo 
453f988d640SKalle Valo 	len = if_cs_read16(priv->card, IF_CS_READ_LEN);
454f988d640SKalle Valo 	if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
455f988d640SKalle Valo 		netdev_err(priv->dev,
456f988d640SKalle Valo 			   "card data buffer has invalid # of bytes (%d)\n",
457f988d640SKalle Valo 			   len);
458f988d640SKalle Valo 		priv->dev->stats.rx_dropped++;
459f988d640SKalle Valo 		goto dat_err;
460f988d640SKalle Valo 	}
461f988d640SKalle Valo 
462f988d640SKalle Valo 	skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
463f988d640SKalle Valo 	if (!skb)
464f988d640SKalle Valo 		goto out;
465f988d640SKalle Valo 	skb_put(skb, len);
466f988d640SKalle Valo 	skb_reserve(skb, 2);/* 16 byte align */
467f988d640SKalle Valo 	data = skb->data;
468f988d640SKalle Valo 
469f988d640SKalle Valo 	/* read even number of bytes, then odd byte if necessary */
470f988d640SKalle Valo 	if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16));
471f988d640SKalle Valo 	if (len & 1)
472f988d640SKalle Valo 		data[len-1] = if_cs_read8(priv->card, IF_CS_READ);
473f988d640SKalle Valo 
474f988d640SKalle Valo dat_err:
475f988d640SKalle Valo 	if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX);
476f988d640SKalle Valo 	if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
477f988d640SKalle Valo 
478f988d640SKalle Valo out:
479f988d640SKalle Valo 	return skb;
480f988d640SKalle Valo }
481f988d640SKalle Valo 
if_cs_interrupt(int irq,void * data)482f988d640SKalle Valo static irqreturn_t if_cs_interrupt(int irq, void *data)
483f988d640SKalle Valo {
484f988d640SKalle Valo 	struct if_cs_card *card = data;
485f988d640SKalle Valo 	struct lbs_private *priv = card->priv;
486f988d640SKalle Valo 	u16 cause;
487f988d640SKalle Valo 
488f988d640SKalle Valo 	/* Ask card interrupt cause register if there is something for us */
489f988d640SKalle Valo 	cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
490f988d640SKalle Valo 	lbs_deb_cs("cause 0x%04x\n", cause);
491f988d640SKalle Valo 
492f988d640SKalle Valo 	if (cause == 0) {
493f988d640SKalle Valo 		/* Not for us */
494f988d640SKalle Valo 		return IRQ_NONE;
495f988d640SKalle Valo 	}
496f988d640SKalle Valo 
497f988d640SKalle Valo 	if (cause == 0xffff) {
498f988d640SKalle Valo 		/* Read in junk, the card has probably been removed */
499f988d640SKalle Valo 		card->priv->surpriseremoved = 1;
500f988d640SKalle Valo 		return IRQ_HANDLED;
501f988d640SKalle Valo 	}
502f988d640SKalle Valo 
503f988d640SKalle Valo 	if (cause & IF_CS_BIT_RX) {
504f988d640SKalle Valo 		struct sk_buff *skb;
505f988d640SKalle Valo 		lbs_deb_cs("rx packet\n");
506f988d640SKalle Valo 		skb = if_cs_receive_data(priv);
507f988d640SKalle Valo 		if (skb)
508f988d640SKalle Valo 			lbs_process_rxed_packet(priv, skb);
509f988d640SKalle Valo 	}
510f988d640SKalle Valo 
511f988d640SKalle Valo 	if (cause & IF_CS_BIT_TX) {
512f988d640SKalle Valo 		lbs_deb_cs("tx done\n");
513f988d640SKalle Valo 		lbs_host_to_card_done(priv);
514f988d640SKalle Valo 	}
515f988d640SKalle Valo 
516f988d640SKalle Valo 	if (cause & IF_CS_BIT_RESP) {
517f988d640SKalle Valo 		unsigned long flags;
518f988d640SKalle Valo 		u8 i;
519f988d640SKalle Valo 
520f988d640SKalle Valo 		lbs_deb_cs("cmd resp\n");
521f988d640SKalle Valo 		spin_lock_irqsave(&priv->driver_lock, flags);
522f988d640SKalle Valo 		i = (priv->resp_idx == 0) ? 1 : 0;
523f988d640SKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
524f988d640SKalle Valo 
525f988d640SKalle Valo 		BUG_ON(priv->resp_len[i]);
526f988d640SKalle Valo 		if_cs_receive_cmdres(priv, priv->resp_buf[i],
527f988d640SKalle Valo 			&priv->resp_len[i]);
528f988d640SKalle Valo 
529f988d640SKalle Valo 		spin_lock_irqsave(&priv->driver_lock, flags);
530f988d640SKalle Valo 		lbs_notify_command_response(priv, i);
531f988d640SKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
532f988d640SKalle Valo 	}
533f988d640SKalle Valo 
534f988d640SKalle Valo 	if (cause & IF_CS_BIT_EVENT) {
535f988d640SKalle Valo 		u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
536f988d640SKalle Valo 		if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE,
537f988d640SKalle Valo 			IF_CS_BIT_EVENT);
538f988d640SKalle Valo 		lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8);
539f988d640SKalle Valo 	}
540f988d640SKalle Valo 
541f988d640SKalle Valo 	/* Clear interrupt cause */
542f988d640SKalle Valo 	if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
543f988d640SKalle Valo 
544f988d640SKalle Valo 	return IRQ_HANDLED;
545f988d640SKalle Valo }
546f988d640SKalle Valo 
547f988d640SKalle Valo 
548f988d640SKalle Valo 
549f988d640SKalle Valo 
550f988d640SKalle Valo /********************************************************************/
551f988d640SKalle Valo /* Firmware                                                         */
552f988d640SKalle Valo /********************************************************************/
553f988d640SKalle Valo 
554f988d640SKalle Valo /*
555f988d640SKalle Valo  * Tries to program the helper firmware.
556f988d640SKalle Valo  *
557f988d640SKalle Valo  * Return 0 on success
558f988d640SKalle Valo  */
if_cs_prog_helper(struct if_cs_card * card,const struct firmware * fw)559f988d640SKalle Valo static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
560f988d640SKalle Valo {
561f988d640SKalle Valo 	int ret = 0;
562f988d640SKalle Valo 	int sent = 0;
563f988d640SKalle Valo 	u8  scratch;
564f988d640SKalle Valo 
565f988d640SKalle Valo 	/*
566f988d640SKalle Valo 	 * This is the only place where an unaligned register access happens on
567f988d640SKalle Valo 	 * the CF8305 card, therefore for the sake of speed of the driver, we do
568f988d640SKalle Valo 	 * the alignment correction here.
569f988d640SKalle Valo 	 */
570f988d640SKalle Valo 	if (card->align_regs)
571f988d640SKalle Valo 		scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8;
572f988d640SKalle Valo 	else
573f988d640SKalle Valo 		scratch = if_cs_read8(card, IF_CS_SCRATCH);
574f988d640SKalle Valo 
575f988d640SKalle Valo 	/* "If the value is 0x5a, the firmware is already
576f988d640SKalle Valo 	 * downloaded successfully"
577f988d640SKalle Valo 	 */
578f988d640SKalle Valo 	if (scratch == IF_CS_SCRATCH_HELPER_OK)
579f988d640SKalle Valo 		goto done;
580f988d640SKalle Valo 
581f988d640SKalle Valo 	/* "If the value is != 00, it is invalid value of register */
582f988d640SKalle Valo 	if (scratch != IF_CS_SCRATCH_BOOT_OK) {
583f988d640SKalle Valo 		ret = -ENODEV;
584f988d640SKalle Valo 		goto done;
585f988d640SKalle Valo 	}
586f988d640SKalle Valo 
587f988d640SKalle Valo 	lbs_deb_cs("helper size %td\n", fw->size);
588f988d640SKalle Valo 
589f988d640SKalle Valo 	/* "Set the 5 bytes of the helper image to 0" */
590f988d640SKalle Valo 	/* Not needed, this contains an ARM branch instruction */
591f988d640SKalle Valo 
592f988d640SKalle Valo 	for (;;) {
593f988d640SKalle Valo 		/* "the number of bytes to send is 256" */
594f988d640SKalle Valo 		int count = 256;
595f988d640SKalle Valo 		int remain = fw->size - sent;
596f988d640SKalle Valo 
597f988d640SKalle Valo 		if (remain < count)
598f988d640SKalle Valo 			count = remain;
599f988d640SKalle Valo 
600f988d640SKalle Valo 		/*
601f988d640SKalle Valo 		 * "write the number of bytes to be sent to the I/O Command
602f988d640SKalle Valo 		 * write length register"
603f988d640SKalle Valo 		 */
604f988d640SKalle Valo 		if_cs_write16(card, IF_CS_CMD_LEN, count);
605f988d640SKalle Valo 
606f988d640SKalle Valo 		/* "write this to I/O Command port register as 16 bit writes */
607f988d640SKalle Valo 		if (count)
608f988d640SKalle Valo 			if_cs_write16_rep(card, IF_CS_CMD,
609f988d640SKalle Valo 				&fw->data[sent],
610f988d640SKalle Valo 				count >> 1);
611f988d640SKalle Valo 
612f988d640SKalle Valo 		/*
613f988d640SKalle Valo 		 * "Assert the download over interrupt command in the Host
614f988d640SKalle Valo 		 * status register"
615f988d640SKalle Valo 		 */
616f988d640SKalle Valo 		if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
617f988d640SKalle Valo 
618f988d640SKalle Valo 		/*
619f988d640SKalle Valo 		 * "Assert the download over interrupt command in the Card
620f988d640SKalle Valo 		 * interrupt case register"
621f988d640SKalle Valo 		 */
622f988d640SKalle Valo 		if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
623f988d640SKalle Valo 
624f988d640SKalle Valo 		/*
625f988d640SKalle Valo 		 * "The host polls the Card Status register ... for 50 ms before
626f988d640SKalle Valo 		 * declaring a failure"
627f988d640SKalle Valo 		 */
628f988d640SKalle Valo 		ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
629f988d640SKalle Valo 			IF_CS_BIT_COMMAND);
630f988d640SKalle Valo 		if (ret < 0) {
631f988d640SKalle Valo 			pr_err("can't download helper at 0x%x, ret %d\n",
632f988d640SKalle Valo 			       sent, ret);
633f988d640SKalle Valo 			goto done;
634f988d640SKalle Valo 		}
635f988d640SKalle Valo 
636f988d640SKalle Valo 		if (count == 0)
637f988d640SKalle Valo 			break;
638f988d640SKalle Valo 
639f988d640SKalle Valo 		sent += count;
640f988d640SKalle Valo 	}
641f988d640SKalle Valo 
642f988d640SKalle Valo done:
643f988d640SKalle Valo 	return ret;
644f988d640SKalle Valo }
645f988d640SKalle Valo 
646f988d640SKalle Valo 
if_cs_prog_real(struct if_cs_card * card,const struct firmware * fw)647f988d640SKalle Valo static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
648f988d640SKalle Valo {
649f988d640SKalle Valo 	int ret = 0;
650f988d640SKalle Valo 	int retry = 0;
651f988d640SKalle Valo 	int len = 0;
652f988d640SKalle Valo 	int sent;
653f988d640SKalle Valo 
654f988d640SKalle Valo 	lbs_deb_cs("fw size %td\n", fw->size);
655f988d640SKalle Valo 
656f988d640SKalle Valo 	ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
657f988d640SKalle Valo 		IF_CS_SQ_HELPER_OK);
658f988d640SKalle Valo 	if (ret < 0) {
659f988d640SKalle Valo 		pr_err("helper firmware doesn't answer\n");
660f988d640SKalle Valo 		goto done;
661f988d640SKalle Valo 	}
662f988d640SKalle Valo 
663f988d640SKalle Valo 	for (sent = 0; sent < fw->size; sent += len) {
664f988d640SKalle Valo 		len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
665f988d640SKalle Valo 		if (len & 1) {
666f988d640SKalle Valo 			retry++;
667f988d640SKalle Valo 			pr_info("odd, need to retry this firmware block\n");
668f988d640SKalle Valo 		} else {
669f988d640SKalle Valo 			retry = 0;
670f988d640SKalle Valo 		}
671f988d640SKalle Valo 
672f988d640SKalle Valo 		if (retry > 20) {
673f988d640SKalle Valo 			pr_err("could not download firmware\n");
674f988d640SKalle Valo 			ret = -ENODEV;
675f988d640SKalle Valo 			goto done;
676f988d640SKalle Valo 		}
677f988d640SKalle Valo 		if (retry) {
678f988d640SKalle Valo 			sent -= len;
679f988d640SKalle Valo 		}
680f988d640SKalle Valo 
681f988d640SKalle Valo 
682f988d640SKalle Valo 		if_cs_write16(card, IF_CS_CMD_LEN, len);
683f988d640SKalle Valo 
684f988d640SKalle Valo 		if_cs_write16_rep(card, IF_CS_CMD,
685f988d640SKalle Valo 			&fw->data[sent],
686f988d640SKalle Valo 			(len+1) >> 1);
687f988d640SKalle Valo 		if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
688f988d640SKalle Valo 		if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
689f988d640SKalle Valo 
690f988d640SKalle Valo 		ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
691f988d640SKalle Valo 			IF_CS_BIT_COMMAND);
692f988d640SKalle Valo 		if (ret < 0) {
693f988d640SKalle Valo 			pr_err("can't download firmware at 0x%x\n", sent);
694f988d640SKalle Valo 			goto done;
695f988d640SKalle Valo 		}
696f988d640SKalle Valo 	}
697f988d640SKalle Valo 
698f988d640SKalle Valo 	ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
699f988d640SKalle Valo 	if (ret < 0)
700f988d640SKalle Valo 		pr_err("firmware download failed\n");
701f988d640SKalle Valo 
702f988d640SKalle Valo done:
703f988d640SKalle Valo 	return ret;
704f988d640SKalle Valo }
705f988d640SKalle Valo 
if_cs_prog_firmware(struct lbs_private * priv,int ret,const struct firmware * helper,const struct firmware * mainfw)706f988d640SKalle Valo static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
707f988d640SKalle Valo 				 const struct firmware *helper,
708f988d640SKalle Valo 				 const struct firmware *mainfw)
709f988d640SKalle Valo {
710f988d640SKalle Valo 	struct if_cs_card *card = priv->card;
711f988d640SKalle Valo 
712f988d640SKalle Valo 	if (ret) {
713f988d640SKalle Valo 		pr_err("failed to find firmware (%d)\n", ret);
714f988d640SKalle Valo 		return;
715f988d640SKalle Valo 	}
716f988d640SKalle Valo 
717f988d640SKalle Valo 	/* Load the firmware */
718f988d640SKalle Valo 	ret = if_cs_prog_helper(card, helper);
719f988d640SKalle Valo 	if (ret == 0 && (card->model != MODEL_8305))
720f988d640SKalle Valo 		ret = if_cs_prog_real(card, mainfw);
721f988d640SKalle Valo 	if (ret)
722f988d640SKalle Valo 		return;
723f988d640SKalle Valo 
724f988d640SKalle Valo 	/* Now actually get the IRQ */
725f988d640SKalle Valo 	ret = request_irq(card->p_dev->irq, if_cs_interrupt,
726f988d640SKalle Valo 		IRQF_SHARED, DRV_NAME, card);
727f988d640SKalle Valo 	if (ret) {
728f988d640SKalle Valo 		pr_err("error in request_irq\n");
729f988d640SKalle Valo 		return;
730f988d640SKalle Valo 	}
731f988d640SKalle Valo 
732f988d640SKalle Valo 	/*
733f988d640SKalle Valo 	 * Clear any interrupt cause that happened while sending
734f988d640SKalle Valo 	 * firmware/initializing card
735f988d640SKalle Valo 	 */
736f988d640SKalle Valo 	if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
737f988d640SKalle Valo 	if_cs_enable_ints(card);
738f988d640SKalle Valo 
739f988d640SKalle Valo 	/* And finally bring the card up */
740f988d640SKalle Valo 	priv->fw_ready = 1;
741f988d640SKalle Valo 	if (lbs_start_card(priv) != 0) {
742f988d640SKalle Valo 		pr_err("could not activate card\n");
743f988d640SKalle Valo 		free_irq(card->p_dev->irq, card);
744f988d640SKalle Valo 	}
745f988d640SKalle Valo }
746f988d640SKalle Valo 
747f988d640SKalle Valo 
748f988d640SKalle Valo /********************************************************************/
749f988d640SKalle Valo /* Callback functions for libertas.ko                               */
750f988d640SKalle Valo /********************************************************************/
751f988d640SKalle Valo 
752f988d640SKalle Valo /* Send commands or data packets to the card */
if_cs_host_to_card(struct lbs_private * priv,u8 type,u8 * buf,u16 nb)753f988d640SKalle Valo static int if_cs_host_to_card(struct lbs_private *priv,
754f988d640SKalle Valo 	u8 type,
755f988d640SKalle Valo 	u8 *buf,
756f988d640SKalle Valo 	u16 nb)
757f988d640SKalle Valo {
758f988d640SKalle Valo 	int ret = -1;
759f988d640SKalle Valo 
760f988d640SKalle Valo 	switch (type) {
761f988d640SKalle Valo 	case MVMS_DAT:
762f988d640SKalle Valo 		priv->dnld_sent = DNLD_DATA_SENT;
763f988d640SKalle Valo 		if_cs_send_data(priv, buf, nb);
764f988d640SKalle Valo 		ret = 0;
765f988d640SKalle Valo 		break;
766f988d640SKalle Valo 	case MVMS_CMD:
767f988d640SKalle Valo 		priv->dnld_sent = DNLD_CMD_SENT;
768f988d640SKalle Valo 		ret = if_cs_send_cmd(priv, buf, nb);
769f988d640SKalle Valo 		break;
770f988d640SKalle Valo 	default:
771f988d640SKalle Valo 		netdev_err(priv->dev, "%s: unsupported type %d\n",
772f988d640SKalle Valo 			   __func__, type);
773f988d640SKalle Valo 	}
774f988d640SKalle Valo 
775f988d640SKalle Valo 	return ret;
776f988d640SKalle Valo }
777f988d640SKalle Valo 
778f988d640SKalle Valo 
if_cs_release(struct pcmcia_device * p_dev)779f988d640SKalle Valo static void if_cs_release(struct pcmcia_device *p_dev)
780f988d640SKalle Valo {
781f988d640SKalle Valo 	struct if_cs_card *card = p_dev->priv;
782f988d640SKalle Valo 
783f988d640SKalle Valo 	free_irq(p_dev->irq, card);
784f988d640SKalle Valo 	pcmcia_disable_device(p_dev);
785f988d640SKalle Valo 	if (card->iobase)
786f988d640SKalle Valo 		ioport_unmap(card->iobase);
787f988d640SKalle Valo }
788f988d640SKalle Valo 
789f988d640SKalle Valo 
if_cs_ioprobe(struct pcmcia_device * p_dev,void * priv_data)790f988d640SKalle Valo static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
791f988d640SKalle Valo {
792f988d640SKalle Valo 	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
793f988d640SKalle Valo 	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
794f988d640SKalle Valo 
795f988d640SKalle Valo 	if (p_dev->resource[1]->end) {
796f988d640SKalle Valo 		pr_err("wrong CIS (check number of IO windows)\n");
797f988d640SKalle Valo 		return -ENODEV;
798f988d640SKalle Valo 	}
799f988d640SKalle Valo 
800f988d640SKalle Valo 	/* This reserves IO space but doesn't actually enable it */
801f988d640SKalle Valo 	return pcmcia_request_io(p_dev);
802f988d640SKalle Valo }
803f988d640SKalle Valo 
if_cs_probe(struct pcmcia_device * p_dev)804f988d640SKalle Valo static int if_cs_probe(struct pcmcia_device *p_dev)
805f988d640SKalle Valo {
806f988d640SKalle Valo 	int ret = -ENOMEM;
807f988d640SKalle Valo 	unsigned int prod_id;
808f988d640SKalle Valo 	struct lbs_private *priv;
809f988d640SKalle Valo 	struct if_cs_card *card;
810f988d640SKalle Valo 
811f988d640SKalle Valo 	card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
812f988d640SKalle Valo 	if (!card)
813f988d640SKalle Valo 		goto out;
814f988d640SKalle Valo 
815f988d640SKalle Valo 	card->p_dev = p_dev;
816f988d640SKalle Valo 	p_dev->priv = card;
817f988d640SKalle Valo 
818f988d640SKalle Valo 	p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
819f988d640SKalle Valo 
820f988d640SKalle Valo 	if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
821f988d640SKalle Valo 		pr_err("error in pcmcia_loop_config\n");
822f988d640SKalle Valo 		goto out1;
823f988d640SKalle Valo 	}
824f988d640SKalle Valo 
825f988d640SKalle Valo 	/*
826f988d640SKalle Valo 	 * Allocate an interrupt line.  Note that this does not assign
827f988d640SKalle Valo 	 * a handler to the interrupt, unless the 'Handler' member of
828f988d640SKalle Valo 	 * the irq structure is initialized.
829f988d640SKalle Valo 	 */
830f988d640SKalle Valo 	if (!p_dev->irq)
831f988d640SKalle Valo 		goto out1;
832f988d640SKalle Valo 
833f988d640SKalle Valo 	/* Initialize io access */
834f988d640SKalle Valo 	card->iobase = ioport_map(p_dev->resource[0]->start,
835f988d640SKalle Valo 				resource_size(p_dev->resource[0]));
836f988d640SKalle Valo 	if (!card->iobase) {
837f988d640SKalle Valo 		pr_err("error in ioport_map\n");
838f988d640SKalle Valo 		ret = -EIO;
839f988d640SKalle Valo 		goto out1;
840f988d640SKalle Valo 	}
841f988d640SKalle Valo 
842f988d640SKalle Valo 	ret = pcmcia_enable_device(p_dev);
843f988d640SKalle Valo 	if (ret) {
844f988d640SKalle Valo 		pr_err("error in pcmcia_enable_device\n");
845f988d640SKalle Valo 		goto out2;
846f988d640SKalle Valo 	}
847f988d640SKalle Valo 
848f988d640SKalle Valo 	/* Finally, report what we've done */
849f988d640SKalle Valo 	lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]);
850f988d640SKalle Valo 
851f988d640SKalle Valo 	/*
852f988d640SKalle Valo 	 * Most of the libertas cards can do unaligned register access, but some
853f988d640SKalle Valo 	 * weird ones cannot. That's especially true for the CF8305 card.
854f988d640SKalle Valo 	 */
855f988d640SKalle Valo 	card->align_regs = false;
856f988d640SKalle Valo 
857f988d640SKalle Valo 	card->model = get_model(p_dev->manf_id, p_dev->card_id);
858f988d640SKalle Valo 	if (card->model == MODEL_UNKNOWN) {
859f988d640SKalle Valo 		pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
860f988d640SKalle Valo 		       p_dev->manf_id, p_dev->card_id);
861f988d640SKalle Valo 		ret = -ENODEV;
862f988d640SKalle Valo 		goto out2;
863f988d640SKalle Valo 	}
864f988d640SKalle Valo 
865f988d640SKalle Valo 	/* Check if we have a current silicon */
866f988d640SKalle Valo 	prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
867f988d640SKalle Valo 	if (card->model == MODEL_8305) {
868f988d640SKalle Valo 		card->align_regs = true;
869f988d640SKalle Valo 		if (prod_id < IF_CS_CF8305_B1_REV) {
870f988d640SKalle Valo 			pr_err("8305 rev B0 and older are not supported\n");
871f988d640SKalle Valo 			ret = -ENODEV;
872f988d640SKalle Valo 			goto out2;
873f988d640SKalle Valo 		}
874f988d640SKalle Valo 	}
875f988d640SKalle Valo 
876f988d640SKalle Valo 	if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
877f988d640SKalle Valo 		pr_err("8381 rev B2 and older are not supported\n");
878f988d640SKalle Valo 		ret = -ENODEV;
879f988d640SKalle Valo 		goto out2;
880f988d640SKalle Valo 	}
881f988d640SKalle Valo 
882f988d640SKalle Valo 	if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
883f988d640SKalle Valo 		pr_err("8385 rev B0 and older are not supported\n");
884f988d640SKalle Valo 		ret = -ENODEV;
885f988d640SKalle Valo 		goto out2;
886f988d640SKalle Valo 	}
887f988d640SKalle Valo 
888f988d640SKalle Valo 	/* Make this card known to the libertas driver */
889f988d640SKalle Valo 	priv = lbs_add_card(card, &p_dev->dev);
890bbc2a101SLubomir Rintel 	if (IS_ERR(priv)) {
891bbc2a101SLubomir Rintel 		ret = PTR_ERR(priv);
892f988d640SKalle Valo 		goto out2;
893f988d640SKalle Valo 	}
894f988d640SKalle Valo 
895f988d640SKalle Valo 	/* Set up fields in lbs_private */
896f988d640SKalle Valo 	card->priv = priv;
897f988d640SKalle Valo 	priv->card = card;
898f988d640SKalle Valo 	priv->hw_host_to_card = if_cs_host_to_card;
899f988d640SKalle Valo 	priv->enter_deep_sleep = NULL;
900f988d640SKalle Valo 	priv->exit_deep_sleep = NULL;
901f988d640SKalle Valo 	priv->reset_deep_sleep_wakeup = NULL;
902f988d640SKalle Valo 
903f988d640SKalle Valo 	/* Get firmware */
904f988d640SKalle Valo 	ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table,
905f988d640SKalle Valo 				     if_cs_prog_firmware);
906f988d640SKalle Valo 	if (ret) {
907f988d640SKalle Valo 		pr_err("failed to find firmware (%d)\n", ret);
908f988d640SKalle Valo 		goto out3;
909f988d640SKalle Valo 	}
910f988d640SKalle Valo 
911f988d640SKalle Valo 	goto out;
912f988d640SKalle Valo 
913f988d640SKalle Valo out3:
914f988d640SKalle Valo 	lbs_remove_card(priv);
915f988d640SKalle Valo out2:
916f988d640SKalle Valo 	ioport_unmap(card->iobase);
917f988d640SKalle Valo out1:
918f988d640SKalle Valo 	pcmcia_disable_device(p_dev);
919f988d640SKalle Valo out:
920f988d640SKalle Valo 	return ret;
921f988d640SKalle Valo }
922f988d640SKalle Valo 
923f988d640SKalle Valo 
if_cs_detach(struct pcmcia_device * p_dev)924f988d640SKalle Valo static void if_cs_detach(struct pcmcia_device *p_dev)
925f988d640SKalle Valo {
926f988d640SKalle Valo 	struct if_cs_card *card = p_dev->priv;
927f988d640SKalle Valo 
928f988d640SKalle Valo 	lbs_stop_card(card->priv);
929f988d640SKalle Valo 	lbs_remove_card(card->priv);
930f988d640SKalle Valo 	if_cs_disable_ints(card);
931f988d640SKalle Valo 	if_cs_release(p_dev);
932f988d640SKalle Valo 	kfree(card);
933f988d640SKalle Valo }
934f988d640SKalle Valo 
935f988d640SKalle Valo 
936f988d640SKalle Valo 
937f988d640SKalle Valo /********************************************************************/
938f988d640SKalle Valo /* Module initialization                                            */
939f988d640SKalle Valo /********************************************************************/
940f988d640SKalle Valo 
941f988d640SKalle Valo static const struct pcmcia_device_id if_cs_ids[] = {
942f988d640SKalle Valo 	PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
943f988d640SKalle Valo 	PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
944f988d640SKalle Valo 	PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
945f988d640SKalle Valo 	/* NOTE: keep in sync with get_model() */
946f988d640SKalle Valo 	PCMCIA_DEVICE_NULL,
947f988d640SKalle Valo };
948f988d640SKalle Valo MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
949f988d640SKalle Valo 
950f988d640SKalle Valo static struct pcmcia_driver lbs_driver = {
951f988d640SKalle Valo 	.owner		= THIS_MODULE,
952f988d640SKalle Valo 	.name		= DRV_NAME,
953f988d640SKalle Valo 	.probe		= if_cs_probe,
954f988d640SKalle Valo 	.remove		= if_cs_detach,
955f988d640SKalle Valo 	.id_table       = if_cs_ids,
956f988d640SKalle Valo };
957f988d640SKalle Valo module_pcmcia_driver(lbs_driver);
958