xref: /freebsd/sys/contrib/dev/broadcom/brcm80211/brcmfmac/bcmsdh.c (revision 9375e11f079d725d42c5b431de33044088ad14f7)
1b4c3e9b5SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2b4c3e9b5SBjoern A. Zeeb /*
3b4c3e9b5SBjoern A. Zeeb  * Copyright (c) 2010 Broadcom Corporation
4b4c3e9b5SBjoern A. Zeeb  */
5b4c3e9b5SBjoern A. Zeeb /* ****************** SDIO CARD Interface Functions **************************/
6b4c3e9b5SBjoern A. Zeeb 
7b4c3e9b5SBjoern A. Zeeb #include <linux/types.h>
8b4c3e9b5SBjoern A. Zeeb #include <linux/netdevice.h>
9b4c3e9b5SBjoern A. Zeeb #include <linux/pci.h>
10b4c3e9b5SBjoern A. Zeeb #include <linux/pci_ids.h>
11b4c3e9b5SBjoern A. Zeeb #include <linux/sched.h>
12b4c3e9b5SBjoern A. Zeeb #include <linux/completion.h>
13b4c3e9b5SBjoern A. Zeeb #include <linux/interrupt.h>
14b4c3e9b5SBjoern A. Zeeb #include <linux/scatterlist.h>
15b4c3e9b5SBjoern A. Zeeb #include <linux/mmc/sdio.h>
16b4c3e9b5SBjoern A. Zeeb #include <linux/mmc/core.h>
17b4c3e9b5SBjoern A. Zeeb #include <linux/mmc/sdio_func.h>
18b4c3e9b5SBjoern A. Zeeb #include <linux/mmc/card.h>
19b4c3e9b5SBjoern A. Zeeb #include <linux/mmc/host.h>
20b4c3e9b5SBjoern A. Zeeb #include <linux/pm_runtime.h>
21b4c3e9b5SBjoern A. Zeeb #include <linux/suspend.h>
22b4c3e9b5SBjoern A. Zeeb #include <linux/errno.h>
23b4c3e9b5SBjoern A. Zeeb #include <linux/module.h>
24b4c3e9b5SBjoern A. Zeeb #include <linux/acpi.h>
25b4c3e9b5SBjoern A. Zeeb #include <net/cfg80211.h>
26b4c3e9b5SBjoern A. Zeeb 
27b4c3e9b5SBjoern A. Zeeb #include <defs.h>
28b4c3e9b5SBjoern A. Zeeb #include <brcm_hw_ids.h>
29b4c3e9b5SBjoern A. Zeeb #include <brcmu_utils.h>
30b4c3e9b5SBjoern A. Zeeb #include <brcmu_wifi.h>
31b4c3e9b5SBjoern A. Zeeb #include <chipcommon.h>
32b4c3e9b5SBjoern A. Zeeb #include <soc.h>
33b4c3e9b5SBjoern A. Zeeb #include "chip.h"
34b4c3e9b5SBjoern A. Zeeb #include "bus.h"
35b4c3e9b5SBjoern A. Zeeb #include "debug.h"
36b4c3e9b5SBjoern A. Zeeb #include "sdio.h"
37b4c3e9b5SBjoern A. Zeeb #include "core.h"
38b4c3e9b5SBjoern A. Zeeb #include "common.h"
39b4c3e9b5SBjoern A. Zeeb 
40b4c3e9b5SBjoern A. Zeeb #define SDIOH_API_ACCESS_RETRY_LIMIT	2
41b4c3e9b5SBjoern A. Zeeb 
42b4c3e9b5SBjoern A. Zeeb #define DMA_ALIGN_MASK	0x03
43b4c3e9b5SBjoern A. Zeeb 
44b4c3e9b5SBjoern A. Zeeb #define SDIO_FUNC1_BLOCKSIZE		64
45b4c3e9b5SBjoern A. Zeeb #define SDIO_FUNC2_BLOCKSIZE		512
46b4c3e9b5SBjoern A. Zeeb #define SDIO_4373_FUNC2_BLOCKSIZE	256
47b4c3e9b5SBjoern A. Zeeb #define SDIO_435X_FUNC2_BLOCKSIZE	256
48b4c3e9b5SBjoern A. Zeeb #define SDIO_4329_FUNC2_BLOCKSIZE	128
49b4c3e9b5SBjoern A. Zeeb /* Maximum milliseconds to wait for F2 to come up */
50b4c3e9b5SBjoern A. Zeeb #define SDIO_WAIT_F2RDY	3000
51b4c3e9b5SBjoern A. Zeeb 
52b4c3e9b5SBjoern A. Zeeb #define BRCMF_DEFAULT_RXGLOM_SIZE	32  /* max rx frames in glom chain */
53b4c3e9b5SBjoern A. Zeeb 
54b4c3e9b5SBjoern A. Zeeb struct brcmf_sdiod_freezer {
55b4c3e9b5SBjoern A. Zeeb 	atomic_t freezing;
56b4c3e9b5SBjoern A. Zeeb 	atomic_t thread_count;
57b4c3e9b5SBjoern A. Zeeb 	u32 frozen_count;
58b4c3e9b5SBjoern A. Zeeb 	wait_queue_head_t thread_freeze;
59b4c3e9b5SBjoern A. Zeeb 	struct completion resumed;
60b4c3e9b5SBjoern A. Zeeb };
61b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_oob_irqhandler(int irq,void * dev_id)62b4c3e9b5SBjoern A. Zeeb static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
63b4c3e9b5SBjoern A. Zeeb {
64b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
65b4c3e9b5SBjoern A. Zeeb 	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
66b4c3e9b5SBjoern A. Zeeb 
67b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(INTR, "OOB intr triggered\n");
68b4c3e9b5SBjoern A. Zeeb 
69b4c3e9b5SBjoern A. Zeeb 	/* out-of-band interrupt is level-triggered which won't
70b4c3e9b5SBjoern A. Zeeb 	 * be cleared until dpc
71b4c3e9b5SBjoern A. Zeeb 	 */
72b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->irq_en) {
73b4c3e9b5SBjoern A. Zeeb 		disable_irq_nosync(irq);
74b4c3e9b5SBjoern A. Zeeb 		sdiodev->irq_en = false;
75b4c3e9b5SBjoern A. Zeeb 	}
76b4c3e9b5SBjoern A. Zeeb 
77b4c3e9b5SBjoern A. Zeeb 	brcmf_sdio_isr(sdiodev->bus, true);
78b4c3e9b5SBjoern A. Zeeb 
79b4c3e9b5SBjoern A. Zeeb 	return IRQ_HANDLED;
80b4c3e9b5SBjoern A. Zeeb }
81b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_ib_irqhandler(struct sdio_func * func)82b4c3e9b5SBjoern A. Zeeb static void brcmf_sdiod_ib_irqhandler(struct sdio_func *func)
83b4c3e9b5SBjoern A. Zeeb {
84b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
85b4c3e9b5SBjoern A. Zeeb 	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
86b4c3e9b5SBjoern A. Zeeb 
87b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(INTR, "IB intr triggered\n");
88b4c3e9b5SBjoern A. Zeeb 
89b4c3e9b5SBjoern A. Zeeb 	brcmf_sdio_isr(sdiodev->bus, false);
90b4c3e9b5SBjoern A. Zeeb }
91b4c3e9b5SBjoern A. Zeeb 
92b4c3e9b5SBjoern A. Zeeb /* dummy handler for SDIO function 2 interrupt */
brcmf_sdiod_dummy_irqhandler(struct sdio_func * func)93b4c3e9b5SBjoern A. Zeeb static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
94b4c3e9b5SBjoern A. Zeeb {
95b4c3e9b5SBjoern A. Zeeb }
96b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_intr_register(struct brcmf_sdio_dev * sdiodev)97b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
98b4c3e9b5SBjoern A. Zeeb {
99b4c3e9b5SBjoern A. Zeeb 	struct brcmfmac_sdio_pd *pdata;
100b4c3e9b5SBjoern A. Zeeb 	int ret = 0;
101b4c3e9b5SBjoern A. Zeeb 	u8 data;
102b4c3e9b5SBjoern A. Zeeb 	u32 addr, gpiocontrol;
103b4c3e9b5SBjoern A. Zeeb 
104b4c3e9b5SBjoern A. Zeeb 	pdata = &sdiodev->settings->bus.sdio;
105b4c3e9b5SBjoern A. Zeeb 	if (pdata->oob_irq_supported) {
106b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
107b4c3e9b5SBjoern A. Zeeb 			  pdata->oob_irq_nr);
108b4c3e9b5SBjoern A. Zeeb 		spin_lock_init(&sdiodev->irq_en_lock);
109b4c3e9b5SBjoern A. Zeeb 		sdiodev->irq_en = true;
110b4c3e9b5SBjoern A. Zeeb 
111b4c3e9b5SBjoern A. Zeeb 		ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler,
112b4c3e9b5SBjoern A. Zeeb 				  pdata->oob_irq_flags, "brcmf_oob_intr",
113b4c3e9b5SBjoern A. Zeeb 				  &sdiodev->func1->dev);
114b4c3e9b5SBjoern A. Zeeb 		if (ret != 0) {
115b4c3e9b5SBjoern A. Zeeb 			brcmf_err("request_irq failed %d\n", ret);
116b4c3e9b5SBjoern A. Zeeb 			return ret;
117b4c3e9b5SBjoern A. Zeeb 		}
118b4c3e9b5SBjoern A. Zeeb 		sdiodev->oob_irq_requested = true;
119b4c3e9b5SBjoern A. Zeeb 
120b4c3e9b5SBjoern A. Zeeb 		ret = enable_irq_wake(pdata->oob_irq_nr);
121b4c3e9b5SBjoern A. Zeeb 		if (ret != 0) {
122b4c3e9b5SBjoern A. Zeeb 			brcmf_err("enable_irq_wake failed %d\n", ret);
123b4c3e9b5SBjoern A. Zeeb 			return ret;
124b4c3e9b5SBjoern A. Zeeb 		}
125b4c3e9b5SBjoern A. Zeeb 		disable_irq_wake(pdata->oob_irq_nr);
126b4c3e9b5SBjoern A. Zeeb 
127b4c3e9b5SBjoern A. Zeeb 		sdio_claim_host(sdiodev->func1);
128b4c3e9b5SBjoern A. Zeeb 
129b4c3e9b5SBjoern A. Zeeb 		if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) {
130b4c3e9b5SBjoern A. Zeeb 			/* assign GPIO to SDIO core */
131b4c3e9b5SBjoern A. Zeeb 			addr = brcmf_chip_enum_base(sdiodev->func1->device);
132b4c3e9b5SBjoern A. Zeeb 			addr = CORE_CC_REG(addr, gpiocontrol);
133b4c3e9b5SBjoern A. Zeeb 			gpiocontrol = brcmf_sdiod_readl(sdiodev, addr, &ret);
134b4c3e9b5SBjoern A. Zeeb 			gpiocontrol |= 0x2;
135b4c3e9b5SBjoern A. Zeeb 			brcmf_sdiod_writel(sdiodev, addr, gpiocontrol, &ret);
136b4c3e9b5SBjoern A. Zeeb 
137b4c3e9b5SBjoern A. Zeeb 			brcmf_sdiod_writeb(sdiodev, SBSDIO_GPIO_SELECT,
138b4c3e9b5SBjoern A. Zeeb 					   0xf, &ret);
139b4c3e9b5SBjoern A. Zeeb 			brcmf_sdiod_writeb(sdiodev, SBSDIO_GPIO_OUT, 0, &ret);
140b4c3e9b5SBjoern A. Zeeb 			brcmf_sdiod_writeb(sdiodev, SBSDIO_GPIO_EN, 0x2, &ret);
141b4c3e9b5SBjoern A. Zeeb 		}
142b4c3e9b5SBjoern A. Zeeb 
143b4c3e9b5SBjoern A. Zeeb 		/* must configure SDIO_CCCR_IENx to enable irq */
144b4c3e9b5SBjoern A. Zeeb 		data = brcmf_sdiod_func0_rb(sdiodev, SDIO_CCCR_IENx, &ret);
145b4c3e9b5SBjoern A. Zeeb 		data |= SDIO_CCCR_IEN_FUNC1 | SDIO_CCCR_IEN_FUNC2 |
146b4c3e9b5SBjoern A. Zeeb 			SDIO_CCCR_IEN_FUNC0;
147b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_IENx, data, &ret);
148b4c3e9b5SBjoern A. Zeeb 
149b4c3e9b5SBjoern A. Zeeb 		/* redirect, configure and enable io for interrupt signal */
150b4c3e9b5SBjoern A. Zeeb 		data = SDIO_CCCR_BRCM_SEPINT_MASK | SDIO_CCCR_BRCM_SEPINT_OE;
151b4c3e9b5SBjoern A. Zeeb 		if (pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
152b4c3e9b5SBjoern A. Zeeb 			data |= SDIO_CCCR_BRCM_SEPINT_ACT_HI;
153b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_BRCM_SEPINT,
154b4c3e9b5SBjoern A. Zeeb 				     data, &ret);
155b4c3e9b5SBjoern A. Zeeb 		sdio_release_host(sdiodev->func1);
156b4c3e9b5SBjoern A. Zeeb 	} else {
157b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(SDIO, "Entering\n");
158b4c3e9b5SBjoern A. Zeeb 		sdio_claim_host(sdiodev->func1);
159b4c3e9b5SBjoern A. Zeeb 		sdio_claim_irq(sdiodev->func1, brcmf_sdiod_ib_irqhandler);
160b4c3e9b5SBjoern A. Zeeb 		sdio_claim_irq(sdiodev->func2, brcmf_sdiod_dummy_irqhandler);
161b4c3e9b5SBjoern A. Zeeb 		sdio_release_host(sdiodev->func1);
162b4c3e9b5SBjoern A. Zeeb 		sdiodev->sd_irq_requested = true;
163b4c3e9b5SBjoern A. Zeeb 	}
164b4c3e9b5SBjoern A. Zeeb 
165b4c3e9b5SBjoern A. Zeeb 	return 0;
166b4c3e9b5SBjoern A. Zeeb }
167b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev * sdiodev)168b4c3e9b5SBjoern A. Zeeb void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
169b4c3e9b5SBjoern A. Zeeb {
170b4c3e9b5SBjoern A. Zeeb 
171b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n",
172b4c3e9b5SBjoern A. Zeeb 		  sdiodev->oob_irq_requested,
173b4c3e9b5SBjoern A. Zeeb 		  sdiodev->sd_irq_requested);
174b4c3e9b5SBjoern A. Zeeb 
175b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->oob_irq_requested) {
176b4c3e9b5SBjoern A. Zeeb 		struct brcmfmac_sdio_pd *pdata;
177b4c3e9b5SBjoern A. Zeeb 
178b4c3e9b5SBjoern A. Zeeb 		pdata = &sdiodev->settings->bus.sdio;
179b4c3e9b5SBjoern A. Zeeb 		sdio_claim_host(sdiodev->func1);
180b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
181b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
182b4c3e9b5SBjoern A. Zeeb 		sdio_release_host(sdiodev->func1);
183b4c3e9b5SBjoern A. Zeeb 
184b4c3e9b5SBjoern A. Zeeb 		sdiodev->oob_irq_requested = false;
185b4c3e9b5SBjoern A. Zeeb 		free_irq(pdata->oob_irq_nr, &sdiodev->func1->dev);
186b4c3e9b5SBjoern A. Zeeb 		sdiodev->irq_en = false;
187b4c3e9b5SBjoern A. Zeeb 		sdiodev->oob_irq_requested = false;
188b4c3e9b5SBjoern A. Zeeb 	}
189b4c3e9b5SBjoern A. Zeeb 
190b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->sd_irq_requested) {
191b4c3e9b5SBjoern A. Zeeb 		sdio_claim_host(sdiodev->func1);
192b4c3e9b5SBjoern A. Zeeb 		sdio_release_irq(sdiodev->func2);
193b4c3e9b5SBjoern A. Zeeb 		sdio_release_irq(sdiodev->func1);
194b4c3e9b5SBjoern A. Zeeb 		sdio_release_host(sdiodev->func1);
195b4c3e9b5SBjoern A. Zeeb 		sdiodev->sd_irq_requested = false;
196b4c3e9b5SBjoern A. Zeeb 	}
197b4c3e9b5SBjoern A. Zeeb }
198b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_change_state(struct brcmf_sdio_dev * sdiodev,enum brcmf_sdiod_state state)199b4c3e9b5SBjoern A. Zeeb void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
200b4c3e9b5SBjoern A. Zeeb 			      enum brcmf_sdiod_state state)
201b4c3e9b5SBjoern A. Zeeb {
202b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM ||
203b4c3e9b5SBjoern A. Zeeb 	    state == sdiodev->state)
204b4c3e9b5SBjoern A. Zeeb 		return;
205b4c3e9b5SBjoern A. Zeeb 
206b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(TRACE, "%d -> %d\n", sdiodev->state, state);
207b4c3e9b5SBjoern A. Zeeb 	switch (sdiodev->state) {
208b4c3e9b5SBjoern A. Zeeb 	case BRCMF_SDIOD_DATA:
209b4c3e9b5SBjoern A. Zeeb 		/* any other state means bus interface is down */
210b4c3e9b5SBjoern A. Zeeb 		brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
211b4c3e9b5SBjoern A. Zeeb 		break;
212b4c3e9b5SBjoern A. Zeeb 	case BRCMF_SDIOD_DOWN:
213b4c3e9b5SBjoern A. Zeeb 		/* transition from DOWN to DATA means bus interface is up */
214b4c3e9b5SBjoern A. Zeeb 		if (state == BRCMF_SDIOD_DATA)
215b4c3e9b5SBjoern A. Zeeb 			brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_UP);
216b4c3e9b5SBjoern A. Zeeb 		break;
217b4c3e9b5SBjoern A. Zeeb 	default:
218b4c3e9b5SBjoern A. Zeeb 		break;
219b4c3e9b5SBjoern A. Zeeb 	}
220b4c3e9b5SBjoern A. Zeeb 	sdiodev->state = state;
221b4c3e9b5SBjoern A. Zeeb }
222b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_set_backplane_window(struct brcmf_sdio_dev * sdiodev,u32 addr)223b4c3e9b5SBjoern A. Zeeb static int brcmf_sdiod_set_backplane_window(struct brcmf_sdio_dev *sdiodev,
224b4c3e9b5SBjoern A. Zeeb 					    u32 addr)
225b4c3e9b5SBjoern A. Zeeb {
226b4c3e9b5SBjoern A. Zeeb 	u32 v, bar0 = addr & SBSDIO_SBWINDOW_MASK;
227b4c3e9b5SBjoern A. Zeeb 	int err = 0, i;
228b4c3e9b5SBjoern A. Zeeb 
229b4c3e9b5SBjoern A. Zeeb 	if (bar0 == sdiodev->sbwad)
230b4c3e9b5SBjoern A. Zeeb 		return 0;
231b4c3e9b5SBjoern A. Zeeb 
232b4c3e9b5SBjoern A. Zeeb 	v = bar0 >> 8;
233b4c3e9b5SBjoern A. Zeeb 
234b4c3e9b5SBjoern A. Zeeb 	for (i = 0 ; i < 3 && !err ; i++, v >>= 8)
235b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_writeb(sdiodev, SBSDIO_FUNC1_SBADDRLOW + i,
236b4c3e9b5SBjoern A. Zeeb 				   v & 0xff, &err);
237b4c3e9b5SBjoern A. Zeeb 
238b4c3e9b5SBjoern A. Zeeb 	if (!err)
239b4c3e9b5SBjoern A. Zeeb 		sdiodev->sbwad = bar0;
240b4c3e9b5SBjoern A. Zeeb 
241b4c3e9b5SBjoern A. Zeeb 	return err;
242b4c3e9b5SBjoern A. Zeeb }
243b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_readl(struct brcmf_sdio_dev * sdiodev,u32 addr,int * ret)244b4c3e9b5SBjoern A. Zeeb u32 brcmf_sdiod_readl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
245b4c3e9b5SBjoern A. Zeeb {
246b4c3e9b5SBjoern A. Zeeb 	u32 data = 0;
247b4c3e9b5SBjoern A. Zeeb 	int retval;
248b4c3e9b5SBjoern A. Zeeb 
249b4c3e9b5SBjoern A. Zeeb 	retval = brcmf_sdiod_set_backplane_window(sdiodev, addr);
250b4c3e9b5SBjoern A. Zeeb 	if (retval)
251b4c3e9b5SBjoern A. Zeeb 		goto out;
252b4c3e9b5SBjoern A. Zeeb 
253b4c3e9b5SBjoern A. Zeeb 	addr &= SBSDIO_SB_OFT_ADDR_MASK;
254b4c3e9b5SBjoern A. Zeeb 	addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
255b4c3e9b5SBjoern A. Zeeb 
256b4c3e9b5SBjoern A. Zeeb 	data = sdio_readl(sdiodev->func1, addr, &retval);
257b4c3e9b5SBjoern A. Zeeb 
258b4c3e9b5SBjoern A. Zeeb out:
259b4c3e9b5SBjoern A. Zeeb 	if (ret)
260b4c3e9b5SBjoern A. Zeeb 		*ret = retval;
261b4c3e9b5SBjoern A. Zeeb 
262b4c3e9b5SBjoern A. Zeeb 	return data;
263b4c3e9b5SBjoern A. Zeeb }
264b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_writel(struct brcmf_sdio_dev * sdiodev,u32 addr,u32 data,int * ret)265b4c3e9b5SBjoern A. Zeeb void brcmf_sdiod_writel(struct brcmf_sdio_dev *sdiodev, u32 addr,
266b4c3e9b5SBjoern A. Zeeb 			u32 data, int *ret)
267b4c3e9b5SBjoern A. Zeeb {
268b4c3e9b5SBjoern A. Zeeb 	int retval;
269b4c3e9b5SBjoern A. Zeeb 
270b4c3e9b5SBjoern A. Zeeb 	retval = brcmf_sdiod_set_backplane_window(sdiodev, addr);
271b4c3e9b5SBjoern A. Zeeb 	if (retval)
272b4c3e9b5SBjoern A. Zeeb 		goto out;
273b4c3e9b5SBjoern A. Zeeb 
274b4c3e9b5SBjoern A. Zeeb 	addr &= SBSDIO_SB_OFT_ADDR_MASK;
275b4c3e9b5SBjoern A. Zeeb 	addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
276b4c3e9b5SBjoern A. Zeeb 
277b4c3e9b5SBjoern A. Zeeb 	sdio_writel(sdiodev->func1, data, addr, &retval);
278b4c3e9b5SBjoern A. Zeeb 
279b4c3e9b5SBjoern A. Zeeb out:
280b4c3e9b5SBjoern A. Zeeb 	if (ret)
281b4c3e9b5SBjoern A. Zeeb 		*ret = retval;
282b4c3e9b5SBjoern A. Zeeb }
283b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_skbuff_read(struct brcmf_sdio_dev * sdiodev,struct sdio_func * func,u32 addr,struct sk_buff * skb)284b4c3e9b5SBjoern A. Zeeb static int brcmf_sdiod_skbuff_read(struct brcmf_sdio_dev *sdiodev,
285b4c3e9b5SBjoern A. Zeeb 				   struct sdio_func *func, u32 addr,
286b4c3e9b5SBjoern A. Zeeb 				   struct sk_buff *skb)
287b4c3e9b5SBjoern A. Zeeb {
288b4c3e9b5SBjoern A. Zeeb 	unsigned int req_sz;
289b4c3e9b5SBjoern A. Zeeb 	int err;
290b4c3e9b5SBjoern A. Zeeb 
291b4c3e9b5SBjoern A. Zeeb 	/* Single skb use the standard mmc interface */
292b4c3e9b5SBjoern A. Zeeb 	req_sz = skb->len + 3;
293b4c3e9b5SBjoern A. Zeeb 	req_sz &= (uint)~3;
294b4c3e9b5SBjoern A. Zeeb 
295b4c3e9b5SBjoern A. Zeeb 	switch (func->num) {
296b4c3e9b5SBjoern A. Zeeb 	case 1:
297b4c3e9b5SBjoern A. Zeeb 		err = sdio_memcpy_fromio(func, ((u8 *)(skb->data)), addr,
298b4c3e9b5SBjoern A. Zeeb 					 req_sz);
299b4c3e9b5SBjoern A. Zeeb 		break;
300b4c3e9b5SBjoern A. Zeeb 	case 2:
301b4c3e9b5SBjoern A. Zeeb 		err = sdio_readsb(func, ((u8 *)(skb->data)), addr, req_sz);
302b4c3e9b5SBjoern A. Zeeb 		break;
303b4c3e9b5SBjoern A. Zeeb 	default:
304b4c3e9b5SBjoern A. Zeeb 		/* bail out as things are really fishy here */
305b4c3e9b5SBjoern A. Zeeb 		WARN(1, "invalid sdio function number: %d\n", func->num);
306b4c3e9b5SBjoern A. Zeeb 		err = -ENOMEDIUM;
307b4c3e9b5SBjoern A. Zeeb 	}
308b4c3e9b5SBjoern A. Zeeb 
309b4c3e9b5SBjoern A. Zeeb 	if (err == -ENOMEDIUM)
310b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);
311b4c3e9b5SBjoern A. Zeeb 
312b4c3e9b5SBjoern A. Zeeb 	return err;
313b4c3e9b5SBjoern A. Zeeb }
314b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_skbuff_write(struct brcmf_sdio_dev * sdiodev,struct sdio_func * func,u32 addr,struct sk_buff * skb)315b4c3e9b5SBjoern A. Zeeb static int brcmf_sdiod_skbuff_write(struct brcmf_sdio_dev *sdiodev,
316b4c3e9b5SBjoern A. Zeeb 				    struct sdio_func *func, u32 addr,
317b4c3e9b5SBjoern A. Zeeb 				    struct sk_buff *skb)
318b4c3e9b5SBjoern A. Zeeb {
319b4c3e9b5SBjoern A. Zeeb 	unsigned int req_sz;
320b4c3e9b5SBjoern A. Zeeb 	int err;
321b4c3e9b5SBjoern A. Zeeb 
322b4c3e9b5SBjoern A. Zeeb 	/* Single skb use the standard mmc interface */
323b4c3e9b5SBjoern A. Zeeb 	req_sz = skb->len + 3;
324b4c3e9b5SBjoern A. Zeeb 	req_sz &= (uint)~3;
325b4c3e9b5SBjoern A. Zeeb 
326b4c3e9b5SBjoern A. Zeeb 	err = sdio_memcpy_toio(func, addr, ((u8 *)(skb->data)), req_sz);
327b4c3e9b5SBjoern A. Zeeb 
328b4c3e9b5SBjoern A. Zeeb 	if (err == -ENOMEDIUM)
329b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);
330b4c3e9b5SBjoern A. Zeeb 
331b4c3e9b5SBjoern A. Zeeb 	return err;
332b4c3e9b5SBjoern A. Zeeb }
333b4c3e9b5SBjoern A. Zeeb 
mmc_submit_one(struct mmc_data * md,struct mmc_request * mr,struct mmc_command * mc,int sg_cnt,int req_sz,int func_blk_sz,u32 * addr,struct brcmf_sdio_dev * sdiodev,struct sdio_func * func,int write)334b4c3e9b5SBjoern A. Zeeb static int mmc_submit_one(struct mmc_data *md, struct mmc_request *mr,
335b4c3e9b5SBjoern A. Zeeb 			  struct mmc_command *mc, int sg_cnt, int req_sz,
336b4c3e9b5SBjoern A. Zeeb 			  int func_blk_sz, u32 *addr,
337b4c3e9b5SBjoern A. Zeeb 			  struct brcmf_sdio_dev *sdiodev,
338b4c3e9b5SBjoern A. Zeeb 			  struct sdio_func *func, int write)
339b4c3e9b5SBjoern A. Zeeb {
340b4c3e9b5SBjoern A. Zeeb 	int ret;
341b4c3e9b5SBjoern A. Zeeb 
342b4c3e9b5SBjoern A. Zeeb 	md->sg_len = sg_cnt;
343b4c3e9b5SBjoern A. Zeeb 	md->blocks = req_sz / func_blk_sz;
344b4c3e9b5SBjoern A. Zeeb 	mc->arg |= (*addr & 0x1FFFF) << 9;	/* address */
345b4c3e9b5SBjoern A. Zeeb 	mc->arg |= md->blocks & 0x1FF;	/* block count */
346b4c3e9b5SBjoern A. Zeeb 	/* incrementing addr for function 1 */
347b4c3e9b5SBjoern A. Zeeb 	if (func->num == 1)
348b4c3e9b5SBjoern A. Zeeb 		*addr += req_sz;
349b4c3e9b5SBjoern A. Zeeb 
350b4c3e9b5SBjoern A. Zeeb 	mmc_set_data_timeout(md, func->card);
351b4c3e9b5SBjoern A. Zeeb 	mmc_wait_for_req(func->card->host, mr);
352b4c3e9b5SBjoern A. Zeeb 
353b4c3e9b5SBjoern A. Zeeb 	ret = mc->error ? mc->error : md->error;
354b4c3e9b5SBjoern A. Zeeb 	if (ret == -ENOMEDIUM) {
355b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);
356b4c3e9b5SBjoern A. Zeeb 	} else if (ret != 0) {
357b4c3e9b5SBjoern A. Zeeb 		brcmf_err("CMD53 sg block %s failed %d\n",
358b4c3e9b5SBjoern A. Zeeb 			  write ? "write" : "read", ret);
359b4c3e9b5SBjoern A. Zeeb 		ret = -EIO;
360b4c3e9b5SBjoern A. Zeeb 	}
361b4c3e9b5SBjoern A. Zeeb 
362b4c3e9b5SBjoern A. Zeeb 	return ret;
363b4c3e9b5SBjoern A. Zeeb }
364b4c3e9b5SBjoern A. Zeeb 
365b4c3e9b5SBjoern A. Zeeb /**
366b4c3e9b5SBjoern A. Zeeb  * brcmf_sdiod_sglist_rw - SDIO interface function for block data access
367b4c3e9b5SBjoern A. Zeeb  * @sdiodev: brcmfmac sdio device
368b4c3e9b5SBjoern A. Zeeb  * @func: SDIO function
369b4c3e9b5SBjoern A. Zeeb  * @write: direction flag
370b4c3e9b5SBjoern A. Zeeb  * @addr: dongle memory address as source/destination
371b4c3e9b5SBjoern A. Zeeb  * @pktlist: skb buffer head pointer
372b4c3e9b5SBjoern A. Zeeb  *
373b4c3e9b5SBjoern A. Zeeb  * This function takes the respbonsibility as the interface function to MMC
374b4c3e9b5SBjoern A. Zeeb  * stack for block data access. It assumes that the skb passed down by the
375b4c3e9b5SBjoern A. Zeeb  * caller has already been padded and aligned.
376b4c3e9b5SBjoern A. Zeeb  */
brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev * sdiodev,struct sdio_func * func,bool write,u32 addr,struct sk_buff_head * pktlist)377b4c3e9b5SBjoern A. Zeeb static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev,
378b4c3e9b5SBjoern A. Zeeb 				 struct sdio_func *func,
379b4c3e9b5SBjoern A. Zeeb 				 bool write, u32 addr,
380b4c3e9b5SBjoern A. Zeeb 				 struct sk_buff_head *pktlist)
381b4c3e9b5SBjoern A. Zeeb {
382b4c3e9b5SBjoern A. Zeeb 	unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset;
383b4c3e9b5SBjoern A. Zeeb 	unsigned int max_req_sz, src_offset, dst_offset;
384b4c3e9b5SBjoern A. Zeeb 	unsigned char *pkt_data, *orig_data, *dst_data;
385b4c3e9b5SBjoern A. Zeeb 	struct sk_buff_head local_list, *target_list;
386b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *pkt_next = NULL, *src;
387b4c3e9b5SBjoern A. Zeeb 	unsigned short max_seg_cnt;
388b4c3e9b5SBjoern A. Zeeb 	struct mmc_request mmc_req;
389b4c3e9b5SBjoern A. Zeeb 	struct mmc_command mmc_cmd;
390b4c3e9b5SBjoern A. Zeeb 	struct mmc_data mmc_dat;
391b4c3e9b5SBjoern A. Zeeb 	struct scatterlist *sgl;
392b4c3e9b5SBjoern A. Zeeb 	int ret = 0;
393b4c3e9b5SBjoern A. Zeeb 
394b4c3e9b5SBjoern A. Zeeb 	if (!pktlist->qlen)
395b4c3e9b5SBjoern A. Zeeb 		return -EINVAL;
396b4c3e9b5SBjoern A. Zeeb 
397b4c3e9b5SBjoern A. Zeeb 	target_list = pktlist;
398b4c3e9b5SBjoern A. Zeeb 	/* for host with broken sg support, prepare a page aligned list */
399b4c3e9b5SBjoern A. Zeeb 	__skb_queue_head_init(&local_list);
400b4c3e9b5SBjoern A. Zeeb 	if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
401b4c3e9b5SBjoern A. Zeeb 		req_sz = 0;
402b4c3e9b5SBjoern A. Zeeb 		skb_queue_walk(pktlist, pkt_next)
403b4c3e9b5SBjoern A. Zeeb 			req_sz += pkt_next->len;
404b4c3e9b5SBjoern A. Zeeb 		req_sz = ALIGN(req_sz, func->cur_blksize);
405b4c3e9b5SBjoern A. Zeeb 		while (req_sz > PAGE_SIZE) {
406b4c3e9b5SBjoern A. Zeeb 			pkt_next = brcmu_pkt_buf_get_skb(PAGE_SIZE);
407b4c3e9b5SBjoern A. Zeeb 			if (pkt_next == NULL) {
408b4c3e9b5SBjoern A. Zeeb 				ret = -ENOMEM;
409b4c3e9b5SBjoern A. Zeeb 				goto exit;
410b4c3e9b5SBjoern A. Zeeb 			}
411b4c3e9b5SBjoern A. Zeeb 			__skb_queue_tail(&local_list, pkt_next);
412b4c3e9b5SBjoern A. Zeeb 			req_sz -= PAGE_SIZE;
413b4c3e9b5SBjoern A. Zeeb 		}
414b4c3e9b5SBjoern A. Zeeb 		pkt_next = brcmu_pkt_buf_get_skb(req_sz);
415b4c3e9b5SBjoern A. Zeeb 		if (pkt_next == NULL) {
416b4c3e9b5SBjoern A. Zeeb 			ret = -ENOMEM;
417b4c3e9b5SBjoern A. Zeeb 			goto exit;
418b4c3e9b5SBjoern A. Zeeb 		}
419b4c3e9b5SBjoern A. Zeeb 		__skb_queue_tail(&local_list, pkt_next);
420b4c3e9b5SBjoern A. Zeeb 		target_list = &local_list;
421b4c3e9b5SBjoern A. Zeeb 	}
422b4c3e9b5SBjoern A. Zeeb 
423b4c3e9b5SBjoern A. Zeeb 	func_blk_sz = func->cur_blksize;
424b4c3e9b5SBjoern A. Zeeb 	max_req_sz = sdiodev->max_request_size;
425b4c3e9b5SBjoern A. Zeeb 	max_seg_cnt = min_t(unsigned short, sdiodev->max_segment_count,
426b4c3e9b5SBjoern A. Zeeb 			    target_list->qlen);
427b4c3e9b5SBjoern A. Zeeb 
428b4c3e9b5SBjoern A. Zeeb 	memset(&mmc_req, 0, sizeof(struct mmc_request));
429b4c3e9b5SBjoern A. Zeeb 	memset(&mmc_cmd, 0, sizeof(struct mmc_command));
430b4c3e9b5SBjoern A. Zeeb 	memset(&mmc_dat, 0, sizeof(struct mmc_data));
431b4c3e9b5SBjoern A. Zeeb 
432b4c3e9b5SBjoern A. Zeeb 	mmc_dat.sg = sdiodev->sgtable.sgl;
433b4c3e9b5SBjoern A. Zeeb 	mmc_dat.blksz = func_blk_sz;
434b4c3e9b5SBjoern A. Zeeb 	mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
435b4c3e9b5SBjoern A. Zeeb 	mmc_cmd.opcode = SD_IO_RW_EXTENDED;
436b4c3e9b5SBjoern A. Zeeb 	mmc_cmd.arg = write ? 1<<31 : 0;	/* write flag  */
437b4c3e9b5SBjoern A. Zeeb 	mmc_cmd.arg |= (func->num & 0x7) << 28;	/* SDIO func num */
438b4c3e9b5SBjoern A. Zeeb 	mmc_cmd.arg |= 1 << 27;			/* block mode */
439b4c3e9b5SBjoern A. Zeeb 	/* for function 1 the addr will be incremented */
440b4c3e9b5SBjoern A. Zeeb 	mmc_cmd.arg |= (func->num == 1) ? 1 << 26 : 0;
441b4c3e9b5SBjoern A. Zeeb 	mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
442b4c3e9b5SBjoern A. Zeeb 	mmc_req.cmd = &mmc_cmd;
443b4c3e9b5SBjoern A. Zeeb 	mmc_req.data = &mmc_dat;
444b4c3e9b5SBjoern A. Zeeb 
445b4c3e9b5SBjoern A. Zeeb 	req_sz = 0;
446b4c3e9b5SBjoern A. Zeeb 	sg_cnt = 0;
447b4c3e9b5SBjoern A. Zeeb 	sgl = sdiodev->sgtable.sgl;
448b4c3e9b5SBjoern A. Zeeb 	skb_queue_walk(target_list, pkt_next) {
449b4c3e9b5SBjoern A. Zeeb 		pkt_offset = 0;
450b4c3e9b5SBjoern A. Zeeb 		while (pkt_offset < pkt_next->len) {
451b4c3e9b5SBjoern A. Zeeb 			pkt_data = pkt_next->data + pkt_offset;
452b4c3e9b5SBjoern A. Zeeb 			sg_data_sz = pkt_next->len - pkt_offset;
453b4c3e9b5SBjoern A. Zeeb 			if (sg_data_sz > sdiodev->max_segment_size)
454b4c3e9b5SBjoern A. Zeeb 				sg_data_sz = sdiodev->max_segment_size;
455b4c3e9b5SBjoern A. Zeeb 			if (sg_data_sz > max_req_sz - req_sz)
456b4c3e9b5SBjoern A. Zeeb 				sg_data_sz = max_req_sz - req_sz;
457b4c3e9b5SBjoern A. Zeeb 
458b4c3e9b5SBjoern A. Zeeb 			if (!sgl) {
459b4c3e9b5SBjoern A. Zeeb 				/* out of (pre-allocated) scatterlist entries */
460b4c3e9b5SBjoern A. Zeeb 				ret = -ENOMEM;
461b4c3e9b5SBjoern A. Zeeb 				goto exit;
462b4c3e9b5SBjoern A. Zeeb 			}
463b4c3e9b5SBjoern A. Zeeb 			sg_set_buf(sgl, pkt_data, sg_data_sz);
464b4c3e9b5SBjoern A. Zeeb 			sg_cnt++;
465b4c3e9b5SBjoern A. Zeeb 
466b4c3e9b5SBjoern A. Zeeb 			sgl = sg_next(sgl);
467b4c3e9b5SBjoern A. Zeeb 			req_sz += sg_data_sz;
468b4c3e9b5SBjoern A. Zeeb 			pkt_offset += sg_data_sz;
469b4c3e9b5SBjoern A. Zeeb 			if (req_sz >= max_req_sz || sg_cnt >= max_seg_cnt) {
470b4c3e9b5SBjoern A. Zeeb 				ret = mmc_submit_one(&mmc_dat, &mmc_req, &mmc_cmd,
471b4c3e9b5SBjoern A. Zeeb 						     sg_cnt, req_sz, func_blk_sz,
472b4c3e9b5SBjoern A. Zeeb 						     &addr, sdiodev, func, write);
473b4c3e9b5SBjoern A. Zeeb 				if (ret)
474b4c3e9b5SBjoern A. Zeeb 					goto exit_queue_walk;
475b4c3e9b5SBjoern A. Zeeb 				req_sz = 0;
476b4c3e9b5SBjoern A. Zeeb 				sg_cnt = 0;
477b4c3e9b5SBjoern A. Zeeb 				sgl = sdiodev->sgtable.sgl;
478b4c3e9b5SBjoern A. Zeeb 			}
479b4c3e9b5SBjoern A. Zeeb 		}
480b4c3e9b5SBjoern A. Zeeb 	}
481b4c3e9b5SBjoern A. Zeeb 	if (sg_cnt)
482b4c3e9b5SBjoern A. Zeeb 		ret = mmc_submit_one(&mmc_dat, &mmc_req, &mmc_cmd,
483b4c3e9b5SBjoern A. Zeeb 				     sg_cnt, req_sz, func_blk_sz,
484b4c3e9b5SBjoern A. Zeeb 				     &addr, sdiodev, func, write);
485b4c3e9b5SBjoern A. Zeeb exit_queue_walk:
486b4c3e9b5SBjoern A. Zeeb 	if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
487b4c3e9b5SBjoern A. Zeeb 		src = __skb_peek(&local_list);
488b4c3e9b5SBjoern A. Zeeb 		src_offset = 0;
489b4c3e9b5SBjoern A. Zeeb 		skb_queue_walk(pktlist, pkt_next) {
490b4c3e9b5SBjoern A. Zeeb 			dst_offset = 0;
491b4c3e9b5SBjoern A. Zeeb 
492b4c3e9b5SBjoern A. Zeeb 			/* This is safe because we must have enough SKB data
493b4c3e9b5SBjoern A. Zeeb 			 * in the local list to cover everything in pktlist.
494b4c3e9b5SBjoern A. Zeeb 			 */
495b4c3e9b5SBjoern A. Zeeb 			while (1) {
496b4c3e9b5SBjoern A. Zeeb 				req_sz = pkt_next->len - dst_offset;
497b4c3e9b5SBjoern A. Zeeb 				if (req_sz > src->len - src_offset)
498b4c3e9b5SBjoern A. Zeeb 					req_sz = src->len - src_offset;
499b4c3e9b5SBjoern A. Zeeb 
500b4c3e9b5SBjoern A. Zeeb 				orig_data = src->data + src_offset;
501b4c3e9b5SBjoern A. Zeeb 				dst_data = pkt_next->data + dst_offset;
502b4c3e9b5SBjoern A. Zeeb 				memcpy(dst_data, orig_data, req_sz);
503b4c3e9b5SBjoern A. Zeeb 
504b4c3e9b5SBjoern A. Zeeb 				src_offset += req_sz;
505b4c3e9b5SBjoern A. Zeeb 				if (src_offset == src->len) {
506b4c3e9b5SBjoern A. Zeeb 					src_offset = 0;
507b4c3e9b5SBjoern A. Zeeb 					src = skb_peek_next(src, &local_list);
508b4c3e9b5SBjoern A. Zeeb 				}
509b4c3e9b5SBjoern A. Zeeb 				dst_offset += req_sz;
510b4c3e9b5SBjoern A. Zeeb 				if (dst_offset == pkt_next->len)
511b4c3e9b5SBjoern A. Zeeb 					break;
512b4c3e9b5SBjoern A. Zeeb 			}
513b4c3e9b5SBjoern A. Zeeb 		}
514b4c3e9b5SBjoern A. Zeeb 	}
515b4c3e9b5SBjoern A. Zeeb 
516b4c3e9b5SBjoern A. Zeeb exit:
517b4c3e9b5SBjoern A. Zeeb 	sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);
518b4c3e9b5SBjoern A. Zeeb 	while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
519b4c3e9b5SBjoern A. Zeeb 		brcmu_pkt_buf_free_skb(pkt_next);
520b4c3e9b5SBjoern A. Zeeb 
521b4c3e9b5SBjoern A. Zeeb 	return ret;
522b4c3e9b5SBjoern A. Zeeb }
523b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_recv_buf(struct brcmf_sdio_dev * sdiodev,u8 * buf,uint nbytes)524b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
525b4c3e9b5SBjoern A. Zeeb {
526b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *mypkt;
527b4c3e9b5SBjoern A. Zeeb 	int err;
528b4c3e9b5SBjoern A. Zeeb 
529b4c3e9b5SBjoern A. Zeeb 	mypkt = brcmu_pkt_buf_get_skb(nbytes);
530b4c3e9b5SBjoern A. Zeeb 	if (!mypkt) {
531b4c3e9b5SBjoern A. Zeeb 		brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
532b4c3e9b5SBjoern A. Zeeb 			  nbytes);
533b4c3e9b5SBjoern A. Zeeb 		return -EIO;
534b4c3e9b5SBjoern A. Zeeb 	}
535b4c3e9b5SBjoern A. Zeeb 
536b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_recv_pkt(sdiodev, mypkt);
537b4c3e9b5SBjoern A. Zeeb 	if (!err)
538b4c3e9b5SBjoern A. Zeeb 		memcpy(buf, mypkt->data, nbytes);
539b4c3e9b5SBjoern A. Zeeb 
540b4c3e9b5SBjoern A. Zeeb 	brcmu_pkt_buf_free_skb(mypkt);
541b4c3e9b5SBjoern A. Zeeb 	return err;
542b4c3e9b5SBjoern A. Zeeb }
543b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev * sdiodev,struct sk_buff * pkt)544b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt)
545b4c3e9b5SBjoern A. Zeeb {
546b4c3e9b5SBjoern A. Zeeb 	u32 addr = sdiodev->cc_core->base;
547b4c3e9b5SBjoern A. Zeeb 	int err = 0;
548b4c3e9b5SBjoern A. Zeeb 
549b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pkt->len);
550b4c3e9b5SBjoern A. Zeeb 
551b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_set_backplane_window(sdiodev, addr);
552b4c3e9b5SBjoern A. Zeeb 	if (err)
553b4c3e9b5SBjoern A. Zeeb 		goto done;
554b4c3e9b5SBjoern A. Zeeb 
555b4c3e9b5SBjoern A. Zeeb 	addr &= SBSDIO_SB_OFT_ADDR_MASK;
556b4c3e9b5SBjoern A. Zeeb 	addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
557b4c3e9b5SBjoern A. Zeeb 
558b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr, pkt);
559b4c3e9b5SBjoern A. Zeeb 
560b4c3e9b5SBjoern A. Zeeb done:
561b4c3e9b5SBjoern A. Zeeb 	return err;
562b4c3e9b5SBjoern A. Zeeb }
563b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_recv_chain(struct brcmf_sdio_dev * sdiodev,struct sk_buff_head * pktq,uint totlen)564b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
565b4c3e9b5SBjoern A. Zeeb 			   struct sk_buff_head *pktq, uint totlen)
566b4c3e9b5SBjoern A. Zeeb {
567b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *glom_skb = NULL;
568b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *skb;
569b4c3e9b5SBjoern A. Zeeb 	u32 addr = sdiodev->cc_core->base;
570b4c3e9b5SBjoern A. Zeeb 	int err = 0;
571b4c3e9b5SBjoern A. Zeeb 
572b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n",
573b4c3e9b5SBjoern A. Zeeb 		  addr, pktq->qlen);
574b4c3e9b5SBjoern A. Zeeb 
575b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_set_backplane_window(sdiodev, addr);
576b4c3e9b5SBjoern A. Zeeb 	if (err)
577b4c3e9b5SBjoern A. Zeeb 		goto done;
578b4c3e9b5SBjoern A. Zeeb 
579b4c3e9b5SBjoern A. Zeeb 	addr &= SBSDIO_SB_OFT_ADDR_MASK;
580b4c3e9b5SBjoern A. Zeeb 	addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
581b4c3e9b5SBjoern A. Zeeb 
582b4c3e9b5SBjoern A. Zeeb 	if (pktq->qlen == 1)
583b4c3e9b5SBjoern A. Zeeb 		err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr,
584b4c3e9b5SBjoern A. Zeeb 					      __skb_peek(pktq));
585b4c3e9b5SBjoern A. Zeeb 	else if (!sdiodev->sg_support) {
586b4c3e9b5SBjoern A. Zeeb 		glom_skb = brcmu_pkt_buf_get_skb(totlen);
587b4c3e9b5SBjoern A. Zeeb 		if (!glom_skb)
588b4c3e9b5SBjoern A. Zeeb 			return -ENOMEM;
589b4c3e9b5SBjoern A. Zeeb 		err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr,
590b4c3e9b5SBjoern A. Zeeb 					      glom_skb);
591b4c3e9b5SBjoern A. Zeeb 		if (err)
592b4c3e9b5SBjoern A. Zeeb 			goto done;
593b4c3e9b5SBjoern A. Zeeb 
594b4c3e9b5SBjoern A. Zeeb 		skb_queue_walk(pktq, skb) {
595b4c3e9b5SBjoern A. Zeeb 			memcpy(skb->data, glom_skb->data, skb->len);
596b4c3e9b5SBjoern A. Zeeb 			skb_pull(glom_skb, skb->len);
597b4c3e9b5SBjoern A. Zeeb 		}
598b4c3e9b5SBjoern A. Zeeb 	} else
599b4c3e9b5SBjoern A. Zeeb 		err = brcmf_sdiod_sglist_rw(sdiodev, sdiodev->func2, false,
600b4c3e9b5SBjoern A. Zeeb 					    addr, pktq);
601b4c3e9b5SBjoern A. Zeeb 
602b4c3e9b5SBjoern A. Zeeb done:
603b4c3e9b5SBjoern A. Zeeb 	brcmu_pkt_buf_free_skb(glom_skb);
604b4c3e9b5SBjoern A. Zeeb 	return err;
605b4c3e9b5SBjoern A. Zeeb }
606b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_send_buf(struct brcmf_sdio_dev * sdiodev,u8 * buf,uint nbytes)607b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
608b4c3e9b5SBjoern A. Zeeb {
609b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *mypkt;
610b4c3e9b5SBjoern A. Zeeb 	u32 addr = sdiodev->cc_core->base;
611b4c3e9b5SBjoern A. Zeeb 	int err;
612b4c3e9b5SBjoern A. Zeeb 
613b4c3e9b5SBjoern A. Zeeb 	mypkt = brcmu_pkt_buf_get_skb(nbytes);
614b4c3e9b5SBjoern A. Zeeb 
615b4c3e9b5SBjoern A. Zeeb 	if (!mypkt) {
616b4c3e9b5SBjoern A. Zeeb 		brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
617b4c3e9b5SBjoern A. Zeeb 			  nbytes);
618b4c3e9b5SBjoern A. Zeeb 		return -EIO;
619b4c3e9b5SBjoern A. Zeeb 	}
620b4c3e9b5SBjoern A. Zeeb 
621b4c3e9b5SBjoern A. Zeeb 	memcpy(mypkt->data, buf, nbytes);
622b4c3e9b5SBjoern A. Zeeb 
623b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_set_backplane_window(sdiodev, addr);
624b4c3e9b5SBjoern A. Zeeb 	if (err)
625b4c3e9b5SBjoern A. Zeeb 		goto out;
626b4c3e9b5SBjoern A. Zeeb 
627b4c3e9b5SBjoern A. Zeeb 	addr &= SBSDIO_SB_OFT_ADDR_MASK;
628b4c3e9b5SBjoern A. Zeeb 	addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
629b4c3e9b5SBjoern A. Zeeb 
630b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func2, addr, mypkt);
631b4c3e9b5SBjoern A. Zeeb out:
632b4c3e9b5SBjoern A. Zeeb 	brcmu_pkt_buf_free_skb(mypkt);
633b4c3e9b5SBjoern A. Zeeb 
634b4c3e9b5SBjoern A. Zeeb 	return err;
635b4c3e9b5SBjoern A. Zeeb }
636b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_send_pkt(struct brcmf_sdio_dev * sdiodev,struct sk_buff_head * pktq)637b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
638b4c3e9b5SBjoern A. Zeeb 			 struct sk_buff_head *pktq)
639b4c3e9b5SBjoern A. Zeeb {
640b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *skb;
641b4c3e9b5SBjoern A. Zeeb 	u32 addr = sdiodev->cc_core->base;
642b4c3e9b5SBjoern A. Zeeb 	int err;
643b4c3e9b5SBjoern A. Zeeb 
644b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pktq->qlen);
645b4c3e9b5SBjoern A. Zeeb 
646b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_set_backplane_window(sdiodev, addr);
647b4c3e9b5SBjoern A. Zeeb 	if (err)
648b4c3e9b5SBjoern A. Zeeb 		return err;
649b4c3e9b5SBjoern A. Zeeb 
650b4c3e9b5SBjoern A. Zeeb 	addr &= SBSDIO_SB_OFT_ADDR_MASK;
651b4c3e9b5SBjoern A. Zeeb 	addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
652b4c3e9b5SBjoern A. Zeeb 
653b4c3e9b5SBjoern A. Zeeb 	if (pktq->qlen == 1 || !sdiodev->sg_support) {
654b4c3e9b5SBjoern A. Zeeb 		skb_queue_walk(pktq, skb) {
655b4c3e9b5SBjoern A. Zeeb 			err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func2,
656b4c3e9b5SBjoern A. Zeeb 						       addr, skb);
657b4c3e9b5SBjoern A. Zeeb 			if (err)
658b4c3e9b5SBjoern A. Zeeb 				break;
659b4c3e9b5SBjoern A. Zeeb 		}
660b4c3e9b5SBjoern A. Zeeb 	} else {
661b4c3e9b5SBjoern A. Zeeb 		err = brcmf_sdiod_sglist_rw(sdiodev, sdiodev->func2, true,
662b4c3e9b5SBjoern A. Zeeb 					    addr, pktq);
663b4c3e9b5SBjoern A. Zeeb 	}
664b4c3e9b5SBjoern A. Zeeb 
665b4c3e9b5SBjoern A. Zeeb 	return err;
666b4c3e9b5SBjoern A. Zeeb }
667b4c3e9b5SBjoern A. Zeeb 
668b4c3e9b5SBjoern A. Zeeb int
brcmf_sdiod_ramrw(struct brcmf_sdio_dev * sdiodev,bool write,u32 address,u8 * data,uint size)669b4c3e9b5SBjoern A. Zeeb brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
670b4c3e9b5SBjoern A. Zeeb 		  u8 *data, uint size)
671b4c3e9b5SBjoern A. Zeeb {
672b4c3e9b5SBjoern A. Zeeb 	int err = 0;
673b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *pkt;
674b4c3e9b5SBjoern A. Zeeb 	u32 sdaddr;
675b4c3e9b5SBjoern A. Zeeb 	uint dsize;
676b4c3e9b5SBjoern A. Zeeb 
677b4c3e9b5SBjoern A. Zeeb 	dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
678b4c3e9b5SBjoern A. Zeeb 	pkt = dev_alloc_skb(dsize);
679b4c3e9b5SBjoern A. Zeeb 	if (!pkt) {
680b4c3e9b5SBjoern A. Zeeb 		brcmf_err("dev_alloc_skb failed: len %d\n", dsize);
681b4c3e9b5SBjoern A. Zeeb 		return -EIO;
682b4c3e9b5SBjoern A. Zeeb 	}
683b4c3e9b5SBjoern A. Zeeb 	pkt->priority = 0;
684b4c3e9b5SBjoern A. Zeeb 
685b4c3e9b5SBjoern A. Zeeb 	/* Determine initial transfer parameters */
686b4c3e9b5SBjoern A. Zeeb 	sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
687b4c3e9b5SBjoern A. Zeeb 	if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
688b4c3e9b5SBjoern A. Zeeb 		dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
689b4c3e9b5SBjoern A. Zeeb 	else
690b4c3e9b5SBjoern A. Zeeb 		dsize = size;
691b4c3e9b5SBjoern A. Zeeb 
692b4c3e9b5SBjoern A. Zeeb 	sdio_claim_host(sdiodev->func1);
693b4c3e9b5SBjoern A. Zeeb 
694b4c3e9b5SBjoern A. Zeeb 	/* Do the transfer(s) */
695b4c3e9b5SBjoern A. Zeeb 	while (size) {
696b4c3e9b5SBjoern A. Zeeb 		/* Set the backplane window to include the start address */
697b4c3e9b5SBjoern A. Zeeb 		err = brcmf_sdiod_set_backplane_window(sdiodev, address);
698b4c3e9b5SBjoern A. Zeeb 		if (err)
699b4c3e9b5SBjoern A. Zeeb 			break;
700b4c3e9b5SBjoern A. Zeeb 
701b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
702b4c3e9b5SBjoern A. Zeeb 			  write ? "write" : "read", dsize,
703b4c3e9b5SBjoern A. Zeeb 			  sdaddr, address & SBSDIO_SBWINDOW_MASK);
704b4c3e9b5SBjoern A. Zeeb 
705b4c3e9b5SBjoern A. Zeeb 		sdaddr &= SBSDIO_SB_OFT_ADDR_MASK;
706b4c3e9b5SBjoern A. Zeeb 		sdaddr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
707b4c3e9b5SBjoern A. Zeeb 
708b4c3e9b5SBjoern A. Zeeb 		skb_put(pkt, dsize);
709b4c3e9b5SBjoern A. Zeeb 
710b4c3e9b5SBjoern A. Zeeb 		if (write) {
711b4c3e9b5SBjoern A. Zeeb 			memcpy(pkt->data, data, dsize);
712b4c3e9b5SBjoern A. Zeeb 			err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func1,
713b4c3e9b5SBjoern A. Zeeb 						       sdaddr, pkt);
714b4c3e9b5SBjoern A. Zeeb 		} else {
715b4c3e9b5SBjoern A. Zeeb 			err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func1,
716b4c3e9b5SBjoern A. Zeeb 						      sdaddr, pkt);
717b4c3e9b5SBjoern A. Zeeb 		}
718b4c3e9b5SBjoern A. Zeeb 
719b4c3e9b5SBjoern A. Zeeb 		if (err) {
720b4c3e9b5SBjoern A. Zeeb 			brcmf_err("membytes transfer failed\n");
721b4c3e9b5SBjoern A. Zeeb 			break;
722b4c3e9b5SBjoern A. Zeeb 		}
723b4c3e9b5SBjoern A. Zeeb 		if (!write)
724b4c3e9b5SBjoern A. Zeeb 			memcpy(data, pkt->data, dsize);
725b4c3e9b5SBjoern A. Zeeb 		skb_trim(pkt, 0);
726b4c3e9b5SBjoern A. Zeeb 
727b4c3e9b5SBjoern A. Zeeb 		/* Adjust for next transfer (if any) */
728b4c3e9b5SBjoern A. Zeeb 		size -= dsize;
729b4c3e9b5SBjoern A. Zeeb 		if (size) {
730b4c3e9b5SBjoern A. Zeeb 			data += dsize;
731b4c3e9b5SBjoern A. Zeeb 			address += dsize;
732b4c3e9b5SBjoern A. Zeeb 			sdaddr = 0;
733b4c3e9b5SBjoern A. Zeeb 			dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
734b4c3e9b5SBjoern A. Zeeb 		}
735b4c3e9b5SBjoern A. Zeeb 	}
736b4c3e9b5SBjoern A. Zeeb 
737b4c3e9b5SBjoern A. Zeeb 	dev_kfree_skb(pkt);
738b4c3e9b5SBjoern A. Zeeb 
739b4c3e9b5SBjoern A. Zeeb 	sdio_release_host(sdiodev->func1);
740b4c3e9b5SBjoern A. Zeeb 
741b4c3e9b5SBjoern A. Zeeb 	return err;
742b4c3e9b5SBjoern A. Zeeb }
743b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_abort(struct brcmf_sdio_dev * sdiodev,struct sdio_func * func)744b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, struct sdio_func *func)
745b4c3e9b5SBjoern A. Zeeb {
746b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Enter\n");
747b4c3e9b5SBjoern A. Zeeb 
748b4c3e9b5SBjoern A. Zeeb 	/* Issue abort cmd52 command through F0 */
749b4c3e9b5SBjoern A. Zeeb 	brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_ABORT, func->num, NULL);
750b4c3e9b5SBjoern A. Zeeb 
751b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Exit\n");
752b4c3e9b5SBjoern A. Zeeb 	return 0;
753b4c3e9b5SBjoern A. Zeeb }
754b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev * sdiodev)755b4c3e9b5SBjoern A. Zeeb void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
756b4c3e9b5SBjoern A. Zeeb {
757b4c3e9b5SBjoern A. Zeeb 	struct sdio_func *func;
758b4c3e9b5SBjoern A. Zeeb 	struct mmc_host *host;
759b4c3e9b5SBjoern A. Zeeb 	uint max_blocks;
760b4c3e9b5SBjoern A. Zeeb 	uint nents;
761b4c3e9b5SBjoern A. Zeeb 	int err;
762b4c3e9b5SBjoern A. Zeeb 
763b4c3e9b5SBjoern A. Zeeb 	func = sdiodev->func2;
764b4c3e9b5SBjoern A. Zeeb 	host = func->card->host;
765b4c3e9b5SBjoern A. Zeeb 	sdiodev->sg_support = host->max_segs > 1;
766b4c3e9b5SBjoern A. Zeeb 	max_blocks = min_t(uint, host->max_blk_count, 511u);
767b4c3e9b5SBjoern A. Zeeb 	sdiodev->max_request_size = min_t(uint, host->max_req_size,
768b4c3e9b5SBjoern A. Zeeb 					  max_blocks * func->cur_blksize);
769b4c3e9b5SBjoern A. Zeeb 	sdiodev->max_segment_count = min_t(uint, host->max_segs,
770b4c3e9b5SBjoern A. Zeeb 					   SG_MAX_SINGLE_ALLOC);
771b4c3e9b5SBjoern A. Zeeb 	sdiodev->max_segment_size = host->max_seg_size;
772b4c3e9b5SBjoern A. Zeeb 
773b4c3e9b5SBjoern A. Zeeb 	if (!sdiodev->sg_support)
774b4c3e9b5SBjoern A. Zeeb 		return;
775b4c3e9b5SBjoern A. Zeeb 
776b4c3e9b5SBjoern A. Zeeb 	nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE,
777b4c3e9b5SBjoern A. Zeeb 		      sdiodev->settings->bus.sdio.txglomsz);
778b4c3e9b5SBjoern A. Zeeb 	nents *= 2;
779b4c3e9b5SBjoern A. Zeeb 
780b4c3e9b5SBjoern A. Zeeb 	WARN_ON(nents > sdiodev->max_segment_count);
781b4c3e9b5SBjoern A. Zeeb 
782b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(TRACE, "nents=%d\n", nents);
783b4c3e9b5SBjoern A. Zeeb 	err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL);
784b4c3e9b5SBjoern A. Zeeb 	if (err < 0) {
785b4c3e9b5SBjoern A. Zeeb 		brcmf_err("allocation failed: disable scatter-gather");
786b4c3e9b5SBjoern A. Zeeb 		sdiodev->sg_support = false;
787b4c3e9b5SBjoern A. Zeeb 	}
788b4c3e9b5SBjoern A. Zeeb 
789b4c3e9b5SBjoern A. Zeeb 	sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz;
790b4c3e9b5SBjoern A. Zeeb }
791b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_freezer_attach(struct brcmf_sdio_dev * sdiodev)792b4c3e9b5SBjoern A. Zeeb static int brcmf_sdiod_freezer_attach(struct brcmf_sdio_dev *sdiodev)
793b4c3e9b5SBjoern A. Zeeb {
794b4c3e9b5SBjoern A. Zeeb 	if (!IS_ENABLED(CONFIG_PM_SLEEP))
795b4c3e9b5SBjoern A. Zeeb 		return 0;
796b4c3e9b5SBjoern A. Zeeb 
797b4c3e9b5SBjoern A. Zeeb 	sdiodev->freezer = kzalloc(sizeof(*sdiodev->freezer), GFP_KERNEL);
798b4c3e9b5SBjoern A. Zeeb 	if (!sdiodev->freezer)
799b4c3e9b5SBjoern A. Zeeb 		return -ENOMEM;
800b4c3e9b5SBjoern A. Zeeb 	atomic_set(&sdiodev->freezer->thread_count, 0);
801b4c3e9b5SBjoern A. Zeeb 	atomic_set(&sdiodev->freezer->freezing, 0);
802b4c3e9b5SBjoern A. Zeeb 	init_waitqueue_head(&sdiodev->freezer->thread_freeze);
803b4c3e9b5SBjoern A. Zeeb 	init_completion(&sdiodev->freezer->resumed);
804b4c3e9b5SBjoern A. Zeeb 	return 0;
805b4c3e9b5SBjoern A. Zeeb }
806b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev * sdiodev)807b4c3e9b5SBjoern A. Zeeb static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
808b4c3e9b5SBjoern A. Zeeb {
809b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->freezer) {
810b4c3e9b5SBjoern A. Zeeb 		WARN_ON(atomic_read(&sdiodev->freezer->freezing));
811b4c3e9b5SBjoern A. Zeeb 		kfree(sdiodev->freezer);
812b4c3e9b5SBjoern A. Zeeb 		sdiodev->freezer = NULL;
813b4c3e9b5SBjoern A. Zeeb 	}
814b4c3e9b5SBjoern A. Zeeb }
815b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_freezer_on(struct brcmf_sdio_dev * sdiodev)816b4c3e9b5SBjoern A. Zeeb static int brcmf_sdiod_freezer_on(struct brcmf_sdio_dev *sdiodev)
817b4c3e9b5SBjoern A. Zeeb {
818b4c3e9b5SBjoern A. Zeeb 	atomic_t *expect = &sdiodev->freezer->thread_count;
819b4c3e9b5SBjoern A. Zeeb 	int res = 0;
820b4c3e9b5SBjoern A. Zeeb 
821b4c3e9b5SBjoern A. Zeeb 	sdiodev->freezer->frozen_count = 0;
822b4c3e9b5SBjoern A. Zeeb 	reinit_completion(&sdiodev->freezer->resumed);
823b4c3e9b5SBjoern A. Zeeb 	atomic_set(&sdiodev->freezer->freezing, 1);
824b4c3e9b5SBjoern A. Zeeb 	brcmf_sdio_trigger_dpc(sdiodev->bus);
825b4c3e9b5SBjoern A. Zeeb 	wait_event(sdiodev->freezer->thread_freeze,
826b4c3e9b5SBjoern A. Zeeb 		   atomic_read(expect) == sdiodev->freezer->frozen_count);
827b4c3e9b5SBjoern A. Zeeb 	sdio_claim_host(sdiodev->func1);
828b4c3e9b5SBjoern A. Zeeb 	res = brcmf_sdio_sleep(sdiodev->bus, true);
829b4c3e9b5SBjoern A. Zeeb 	sdio_release_host(sdiodev->func1);
830b4c3e9b5SBjoern A. Zeeb 	return res;
831b4c3e9b5SBjoern A. Zeeb }
832b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_freezer_off(struct brcmf_sdio_dev * sdiodev)833b4c3e9b5SBjoern A. Zeeb static void brcmf_sdiod_freezer_off(struct brcmf_sdio_dev *sdiodev)
834b4c3e9b5SBjoern A. Zeeb {
835b4c3e9b5SBjoern A. Zeeb 	sdio_claim_host(sdiodev->func1);
836b4c3e9b5SBjoern A. Zeeb 	brcmf_sdio_sleep(sdiodev->bus, false);
837b4c3e9b5SBjoern A. Zeeb 	sdio_release_host(sdiodev->func1);
838b4c3e9b5SBjoern A. Zeeb 	atomic_set(&sdiodev->freezer->freezing, 0);
839b4c3e9b5SBjoern A. Zeeb 	complete_all(&sdiodev->freezer->resumed);
840b4c3e9b5SBjoern A. Zeeb }
841b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_freezing(struct brcmf_sdio_dev * sdiodev)842b4c3e9b5SBjoern A. Zeeb bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev)
843b4c3e9b5SBjoern A. Zeeb {
844b4c3e9b5SBjoern A. Zeeb 	return IS_ENABLED(CONFIG_PM_SLEEP) &&
845b4c3e9b5SBjoern A. Zeeb 		atomic_read(&sdiodev->freezer->freezing);
846b4c3e9b5SBjoern A. Zeeb }
847b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_try_freeze(struct brcmf_sdio_dev * sdiodev)848b4c3e9b5SBjoern A. Zeeb void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev)
849b4c3e9b5SBjoern A. Zeeb {
850b4c3e9b5SBjoern A. Zeeb 	if (!brcmf_sdiod_freezing(sdiodev))
851b4c3e9b5SBjoern A. Zeeb 		return;
852b4c3e9b5SBjoern A. Zeeb 	sdiodev->freezer->frozen_count++;
853b4c3e9b5SBjoern A. Zeeb 	wake_up(&sdiodev->freezer->thread_freeze);
854b4c3e9b5SBjoern A. Zeeb 	wait_for_completion(&sdiodev->freezer->resumed);
855b4c3e9b5SBjoern A. Zeeb }
856b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_freezer_count(struct brcmf_sdio_dev * sdiodev)857b4c3e9b5SBjoern A. Zeeb void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev)
858b4c3e9b5SBjoern A. Zeeb {
859b4c3e9b5SBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_PM_SLEEP))
860b4c3e9b5SBjoern A. Zeeb 		atomic_inc(&sdiodev->freezer->thread_count);
861b4c3e9b5SBjoern A. Zeeb }
862b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev * sdiodev)863b4c3e9b5SBjoern A. Zeeb void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev)
864b4c3e9b5SBjoern A. Zeeb {
865b4c3e9b5SBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_PM_SLEEP))
866b4c3e9b5SBjoern A. Zeeb 		atomic_dec(&sdiodev->freezer->thread_count);
867b4c3e9b5SBjoern A. Zeeb }
868b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_remove(struct brcmf_sdio_dev * sdiodev)869b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
870b4c3e9b5SBjoern A. Zeeb {
871b4c3e9b5SBjoern A. Zeeb 	sdiodev->state = BRCMF_SDIOD_DOWN;
872b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->bus) {
873b4c3e9b5SBjoern A. Zeeb 		brcmf_sdio_remove(sdiodev->bus);
874b4c3e9b5SBjoern A. Zeeb 		sdiodev->bus = NULL;
875b4c3e9b5SBjoern A. Zeeb 	}
876b4c3e9b5SBjoern A. Zeeb 
877b4c3e9b5SBjoern A. Zeeb 	brcmf_sdiod_freezer_detach(sdiodev);
878b4c3e9b5SBjoern A. Zeeb 
879b4c3e9b5SBjoern A. Zeeb 	/* Disable functions 2 then 1. */
880b4c3e9b5SBjoern A. Zeeb 	sdio_claim_host(sdiodev->func1);
881b4c3e9b5SBjoern A. Zeeb 	sdio_disable_func(sdiodev->func2);
882b4c3e9b5SBjoern A. Zeeb 	sdio_disable_func(sdiodev->func1);
883b4c3e9b5SBjoern A. Zeeb 	sdio_release_host(sdiodev->func1);
884b4c3e9b5SBjoern A. Zeeb 
885b4c3e9b5SBjoern A. Zeeb 	sg_free_table(&sdiodev->sgtable);
886b4c3e9b5SBjoern A. Zeeb 	sdiodev->sbwad = 0;
887b4c3e9b5SBjoern A. Zeeb 
888b4c3e9b5SBjoern A. Zeeb 	pm_runtime_allow(sdiodev->func1->card->host->parent);
889b4c3e9b5SBjoern A. Zeeb 	return 0;
890b4c3e9b5SBjoern A. Zeeb }
891b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_host_fixup(struct mmc_host * host)892b4c3e9b5SBjoern A. Zeeb static void brcmf_sdiod_host_fixup(struct mmc_host *host)
893b4c3e9b5SBjoern A. Zeeb {
894b4c3e9b5SBjoern A. Zeeb 	/* runtime-pm powers off the device */
895b4c3e9b5SBjoern A. Zeeb 	pm_runtime_forbid(host->parent);
896b4c3e9b5SBjoern A. Zeeb 	/* avoid removal detection upon resume */
897b4c3e9b5SBjoern A. Zeeb 	host->caps |= MMC_CAP_NONREMOVABLE;
898b4c3e9b5SBjoern A. Zeeb }
899b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_probe(struct brcmf_sdio_dev * sdiodev)900b4c3e9b5SBjoern A. Zeeb int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
901b4c3e9b5SBjoern A. Zeeb {
902b4c3e9b5SBjoern A. Zeeb 	int ret = 0;
903b4c3e9b5SBjoern A. Zeeb 	unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE;
904b4c3e9b5SBjoern A. Zeeb 
905b4c3e9b5SBjoern A. Zeeb 	sdio_claim_host(sdiodev->func1);
906b4c3e9b5SBjoern A. Zeeb 
907b4c3e9b5SBjoern A. Zeeb 	ret = sdio_set_block_size(sdiodev->func1, SDIO_FUNC1_BLOCKSIZE);
908b4c3e9b5SBjoern A. Zeeb 	if (ret) {
909b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Failed to set F1 blocksize\n");
910b4c3e9b5SBjoern A. Zeeb 		sdio_release_host(sdiodev->func1);
911b4c3e9b5SBjoern A. Zeeb 		return ret;
912b4c3e9b5SBjoern A. Zeeb 	}
913b4c3e9b5SBjoern A. Zeeb 	switch (sdiodev->func2->device) {
914b4c3e9b5SBjoern A. Zeeb 	case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
915b4c3e9b5SBjoern A. Zeeb 		f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;
916b4c3e9b5SBjoern A. Zeeb 		break;
917b4c3e9b5SBjoern A. Zeeb 	case SDIO_DEVICE_ID_BROADCOM_4359:
918b4c3e9b5SBjoern A. Zeeb 	case SDIO_DEVICE_ID_BROADCOM_4354:
919b4c3e9b5SBjoern A. Zeeb 	case SDIO_DEVICE_ID_BROADCOM_4356:
920b4c3e9b5SBjoern A. Zeeb 		f2_blksz = SDIO_435X_FUNC2_BLOCKSIZE;
921b4c3e9b5SBjoern A. Zeeb 		break;
922b4c3e9b5SBjoern A. Zeeb 	case SDIO_DEVICE_ID_BROADCOM_4329:
923b4c3e9b5SBjoern A. Zeeb 		f2_blksz = SDIO_4329_FUNC2_BLOCKSIZE;
924b4c3e9b5SBjoern A. Zeeb 		break;
925b4c3e9b5SBjoern A. Zeeb 	default:
926b4c3e9b5SBjoern A. Zeeb 		break;
927b4c3e9b5SBjoern A. Zeeb 	}
928b4c3e9b5SBjoern A. Zeeb 
929b4c3e9b5SBjoern A. Zeeb 	ret = sdio_set_block_size(sdiodev->func2, f2_blksz);
930b4c3e9b5SBjoern A. Zeeb 	if (ret) {
931b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Failed to set F2 blocksize\n");
932b4c3e9b5SBjoern A. Zeeb 		sdio_release_host(sdiodev->func1);
933b4c3e9b5SBjoern A. Zeeb 		return ret;
934b4c3e9b5SBjoern A. Zeeb 	} else {
935b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(SDIO, "set F2 blocksize to %d\n", f2_blksz);
936b4c3e9b5SBjoern A. Zeeb 	}
937b4c3e9b5SBjoern A. Zeeb 
938b4c3e9b5SBjoern A. Zeeb 	/* increase F2 timeout */
939b4c3e9b5SBjoern A. Zeeb 	sdiodev->func2->enable_timeout = SDIO_WAIT_F2RDY;
940b4c3e9b5SBjoern A. Zeeb 
941b4c3e9b5SBjoern A. Zeeb 	/* Enable Function 1 */
942b4c3e9b5SBjoern A. Zeeb 	ret = sdio_enable_func(sdiodev->func1);
943b4c3e9b5SBjoern A. Zeeb 	sdio_release_host(sdiodev->func1);
944b4c3e9b5SBjoern A. Zeeb 	if (ret) {
945b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Failed to enable F1: err=%d\n", ret);
946b4c3e9b5SBjoern A. Zeeb 		goto out;
947b4c3e9b5SBjoern A. Zeeb 	}
948b4c3e9b5SBjoern A. Zeeb 
949b4c3e9b5SBjoern A. Zeeb 	ret = brcmf_sdiod_freezer_attach(sdiodev);
950b4c3e9b5SBjoern A. Zeeb 	if (ret)
951b4c3e9b5SBjoern A. Zeeb 		goto out;
952b4c3e9b5SBjoern A. Zeeb 
953b4c3e9b5SBjoern A. Zeeb 	/* try to attach to the target device */
954b4c3e9b5SBjoern A. Zeeb 	sdiodev->bus = brcmf_sdio_probe(sdiodev);
955b4c3e9b5SBjoern A. Zeeb 	if (IS_ERR(sdiodev->bus)) {
956b4c3e9b5SBjoern A. Zeeb 		ret = PTR_ERR(sdiodev->bus);
957b4c3e9b5SBjoern A. Zeeb 		goto out;
958b4c3e9b5SBjoern A. Zeeb 	}
959b4c3e9b5SBjoern A. Zeeb 	brcmf_sdiod_host_fixup(sdiodev->func2->card->host);
960b4c3e9b5SBjoern A. Zeeb out:
961b4c3e9b5SBjoern A. Zeeb 	if (ret)
962b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_remove(sdiodev);
963b4c3e9b5SBjoern A. Zeeb 
964b4c3e9b5SBjoern A. Zeeb 	return ret;
965b4c3e9b5SBjoern A. Zeeb }
966b4c3e9b5SBjoern A. Zeeb 
967b4c3e9b5SBjoern A. Zeeb #define BRCMF_SDIO_DEVICE(dev_id, fw_vend) \
968b4c3e9b5SBjoern A. Zeeb 	{ \
969b4c3e9b5SBjoern A. Zeeb 		SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id), \
970b4c3e9b5SBjoern A. Zeeb 		.driver_data = BRCMF_FWVENDOR_ ## fw_vend \
971b4c3e9b5SBjoern A. Zeeb 	}
972b4c3e9b5SBjoern A. Zeeb 
973b4c3e9b5SBjoern A. Zeeb #define CYW_SDIO_DEVICE(dev_id, fw_vend) \
974b4c3e9b5SBjoern A. Zeeb 	{ \
975b4c3e9b5SBjoern A. Zeeb 		SDIO_DEVICE(SDIO_VENDOR_ID_CYPRESS, dev_id), \
976b4c3e9b5SBjoern A. Zeeb 		.driver_data = BRCMF_FWVENDOR_ ## fw_vend \
977b4c3e9b5SBjoern A. Zeeb 	}
978b4c3e9b5SBjoern A. Zeeb 
979b4c3e9b5SBjoern A. Zeeb /* devices we support, null terminated */
980b4c3e9b5SBjoern A. Zeeb static const struct sdio_device_id brcmf_sdmmc_ids[] = {
981b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143, WCC),
982b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241, WCC),
983b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329, WCC),
984b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330, WCC),
985b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334, WCC),
986b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340, WCC),
987b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341, WCC),
988b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362, WCC),
989b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364, WCC),
990b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339, WCC),
991b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339, WCC),
992b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430, WCC),
993b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43439, WCC),
994b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345, WCC),
995b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455, WCC),
996b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC),
997b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC),
998b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC),
999b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43751, WCC),
1000*9375e11fSBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43752, WCC),
1001b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW),
1002b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW),
1003b4c3e9b5SBjoern A. Zeeb 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW),
1004b4c3e9b5SBjoern A. Zeeb 	CYW_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW),
1005b4c3e9b5SBjoern A. Zeeb 	{ /* end: all zeroes */ }
1006b4c3e9b5SBjoern A. Zeeb };
1007b4c3e9b5SBjoern A. Zeeb MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
1008b4c3e9b5SBjoern A. Zeeb 
1009b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_acpi_save_power_manageable(struct brcmf_sdio_dev * sdiodev)1010b4c3e9b5SBjoern A. Zeeb static void brcmf_sdiod_acpi_save_power_manageable(struct brcmf_sdio_dev *sdiodev)
1011b4c3e9b5SBjoern A. Zeeb {
1012b4c3e9b5SBjoern A. Zeeb #if IS_ENABLED(CONFIG_ACPI)
1013b4c3e9b5SBjoern A. Zeeb 	struct acpi_device *adev;
1014b4c3e9b5SBjoern A. Zeeb 
1015b4c3e9b5SBjoern A. Zeeb 	adev = ACPI_COMPANION(&sdiodev->func1->dev);
1016b4c3e9b5SBjoern A. Zeeb 	if (adev)
1017b4c3e9b5SBjoern A. Zeeb 		sdiodev->func1_power_manageable = adev->flags.power_manageable;
1018b4c3e9b5SBjoern A. Zeeb 
1019b4c3e9b5SBjoern A. Zeeb 	adev = ACPI_COMPANION(&sdiodev->func2->dev);
1020b4c3e9b5SBjoern A. Zeeb 	if (adev)
1021b4c3e9b5SBjoern A. Zeeb 		sdiodev->func2_power_manageable = adev->flags.power_manageable;
1022b4c3e9b5SBjoern A. Zeeb #endif
1023b4c3e9b5SBjoern A. Zeeb }
1024b4c3e9b5SBjoern A. Zeeb 
brcmf_sdiod_acpi_set_power_manageable(struct brcmf_sdio_dev * sdiodev,int enable)1025b4c3e9b5SBjoern A. Zeeb static void brcmf_sdiod_acpi_set_power_manageable(struct brcmf_sdio_dev *sdiodev,
1026b4c3e9b5SBjoern A. Zeeb 						  int enable)
1027b4c3e9b5SBjoern A. Zeeb {
1028b4c3e9b5SBjoern A. Zeeb #if IS_ENABLED(CONFIG_ACPI)
1029b4c3e9b5SBjoern A. Zeeb 	struct acpi_device *adev;
1030b4c3e9b5SBjoern A. Zeeb 
1031b4c3e9b5SBjoern A. Zeeb 	adev = ACPI_COMPANION(&sdiodev->func1->dev);
1032b4c3e9b5SBjoern A. Zeeb 	if (adev)
1033b4c3e9b5SBjoern A. Zeeb 		adev->flags.power_manageable = enable ? sdiodev->func1_power_manageable : 0;
1034b4c3e9b5SBjoern A. Zeeb 
1035b4c3e9b5SBjoern A. Zeeb 	adev = ACPI_COMPANION(&sdiodev->func2->dev);
1036b4c3e9b5SBjoern A. Zeeb 	if (adev)
1037b4c3e9b5SBjoern A. Zeeb 		adev->flags.power_manageable = enable ? sdiodev->func2_power_manageable : 0;
1038b4c3e9b5SBjoern A. Zeeb #endif
1039b4c3e9b5SBjoern A. Zeeb }
1040b4c3e9b5SBjoern A. Zeeb 
brcmf_ops_sdio_probe(struct sdio_func * func,const struct sdio_device_id * id)1041b4c3e9b5SBjoern A. Zeeb static int brcmf_ops_sdio_probe(struct sdio_func *func,
1042b4c3e9b5SBjoern A. Zeeb 				const struct sdio_device_id *id)
1043b4c3e9b5SBjoern A. Zeeb {
1044b4c3e9b5SBjoern A. Zeeb 	int err;
1045b4c3e9b5SBjoern A. Zeeb 	struct brcmf_sdio_dev *sdiodev;
1046b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if;
1047b4c3e9b5SBjoern A. Zeeb 
1048b4c3e9b5SBjoern A. Zeeb 	if (!id) {
1049b4c3e9b5SBjoern A. Zeeb 		dev_err(&func->dev, "Error no sdio_device_id passed for %x:%x\n", func->vendor, func->device);
1050b4c3e9b5SBjoern A. Zeeb 		return -ENODEV;
1051b4c3e9b5SBjoern A. Zeeb 	}
1052b4c3e9b5SBjoern A. Zeeb 
1053b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Enter\n");
1054b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Class=%x\n", func->class);
1055b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
1056b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
1057b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Function#: %d\n", func->num);
1058b4c3e9b5SBjoern A. Zeeb 
1059b4c3e9b5SBjoern A. Zeeb 	/* Set MMC_QUIRK_LENIENT_FN0 for this card */
1060b4c3e9b5SBjoern A. Zeeb 	func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
1061b4c3e9b5SBjoern A. Zeeb 
1062b4c3e9b5SBjoern A. Zeeb 	/* Consume func num 1 but dont do anything with it. */
1063b4c3e9b5SBjoern A. Zeeb 	if (func->num == 1)
1064b4c3e9b5SBjoern A. Zeeb 		return 0;
1065b4c3e9b5SBjoern A. Zeeb 
1066b4c3e9b5SBjoern A. Zeeb 	/* Ignore anything but func 2 */
1067b4c3e9b5SBjoern A. Zeeb 	if (func->num != 2)
1068b4c3e9b5SBjoern A. Zeeb 		return -ENODEV;
1069b4c3e9b5SBjoern A. Zeeb 
1070b4c3e9b5SBjoern A. Zeeb 	bus_if = kzalloc(sizeof(*bus_if), GFP_KERNEL);
1071b4c3e9b5SBjoern A. Zeeb 	if (!bus_if)
1072b4c3e9b5SBjoern A. Zeeb 		return -ENOMEM;
1073b4c3e9b5SBjoern A. Zeeb 	sdiodev = kzalloc(sizeof(*sdiodev), GFP_KERNEL);
1074b4c3e9b5SBjoern A. Zeeb 	if (!sdiodev) {
1075b4c3e9b5SBjoern A. Zeeb 		kfree(bus_if);
1076b4c3e9b5SBjoern A. Zeeb 		return -ENOMEM;
1077b4c3e9b5SBjoern A. Zeeb 	}
1078b4c3e9b5SBjoern A. Zeeb 
1079b4c3e9b5SBjoern A. Zeeb 	/* store refs to functions used. mmc_card does
1080b4c3e9b5SBjoern A. Zeeb 	 * not hold the F0 function pointer.
1081b4c3e9b5SBjoern A. Zeeb 	 */
1082b4c3e9b5SBjoern A. Zeeb 	sdiodev->func1 = func->card->sdio_func[0];
1083b4c3e9b5SBjoern A. Zeeb 	sdiodev->func2 = func;
1084b4c3e9b5SBjoern A. Zeeb 
1085b4c3e9b5SBjoern A. Zeeb 	sdiodev->bus_if = bus_if;
1086b4c3e9b5SBjoern A. Zeeb 	bus_if->bus_priv.sdio = sdiodev;
1087b4c3e9b5SBjoern A. Zeeb 	bus_if->proto_type = BRCMF_PROTO_BCDC;
1088b4c3e9b5SBjoern A. Zeeb 	bus_if->fwvid = id->driver_data;
1089b4c3e9b5SBjoern A. Zeeb 	dev_set_drvdata(&func->dev, bus_if);
1090b4c3e9b5SBjoern A. Zeeb 	dev_set_drvdata(&sdiodev->func1->dev, bus_if);
1091b4c3e9b5SBjoern A. Zeeb 	sdiodev->dev = &sdiodev->func1->dev;
1092b4c3e9b5SBjoern A. Zeeb 
1093b4c3e9b5SBjoern A. Zeeb 	brcmf_sdiod_acpi_save_power_manageable(sdiodev);
1094b4c3e9b5SBjoern A. Zeeb 	brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
1095b4c3e9b5SBjoern A. Zeeb 
1096b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
1097b4c3e9b5SBjoern A. Zeeb 	err = brcmf_sdiod_probe(sdiodev);
1098b4c3e9b5SBjoern A. Zeeb 	if (err) {
1099b4c3e9b5SBjoern A. Zeeb 		brcmf_err("F2 error, probe failed %d...\n", err);
1100b4c3e9b5SBjoern A. Zeeb 		goto fail;
1101b4c3e9b5SBjoern A. Zeeb 	}
1102b4c3e9b5SBjoern A. Zeeb 
1103b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "F2 init completed...\n");
1104b4c3e9b5SBjoern A. Zeeb 	return 0;
1105b4c3e9b5SBjoern A. Zeeb 
1106b4c3e9b5SBjoern A. Zeeb fail:
1107b4c3e9b5SBjoern A. Zeeb 	dev_set_drvdata(&func->dev, NULL);
1108b4c3e9b5SBjoern A. Zeeb 	dev_set_drvdata(&sdiodev->func1->dev, NULL);
1109b4c3e9b5SBjoern A. Zeeb 	kfree(sdiodev);
1110b4c3e9b5SBjoern A. Zeeb 	kfree(bus_if);
1111b4c3e9b5SBjoern A. Zeeb 	return err;
1112b4c3e9b5SBjoern A. Zeeb }
1113b4c3e9b5SBjoern A. Zeeb 
brcmf_ops_sdio_remove(struct sdio_func * func)1114b4c3e9b5SBjoern A. Zeeb static void brcmf_ops_sdio_remove(struct sdio_func *func)
1115b4c3e9b5SBjoern A. Zeeb {
1116b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if;
1117b4c3e9b5SBjoern A. Zeeb 	struct brcmf_sdio_dev *sdiodev;
1118b4c3e9b5SBjoern A. Zeeb 
1119b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Enter\n");
1120b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
1121b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
1122b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Function: %d\n", func->num);
1123b4c3e9b5SBjoern A. Zeeb 
1124b4c3e9b5SBjoern A. Zeeb 	bus_if = dev_get_drvdata(&func->dev);
1125b4c3e9b5SBjoern A. Zeeb 	if (bus_if) {
1126b4c3e9b5SBjoern A. Zeeb 		sdiodev = bus_if->bus_priv.sdio;
1127b4c3e9b5SBjoern A. Zeeb 
1128b4c3e9b5SBjoern A. Zeeb 		/* start by unregistering irqs */
1129b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_intr_unregister(sdiodev);
1130b4c3e9b5SBjoern A. Zeeb 
1131b4c3e9b5SBjoern A. Zeeb 		if (func->num != 1)
1132b4c3e9b5SBjoern A. Zeeb 			return;
1133b4c3e9b5SBjoern A. Zeeb 
1134b4c3e9b5SBjoern A. Zeeb 		/* only proceed with rest of cleanup if func 1 */
1135b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_remove(sdiodev);
1136b4c3e9b5SBjoern A. Zeeb 
1137b4c3e9b5SBjoern A. Zeeb 		dev_set_drvdata(&sdiodev->func1->dev, NULL);
1138b4c3e9b5SBjoern A. Zeeb 		dev_set_drvdata(&sdiodev->func2->dev, NULL);
1139b4c3e9b5SBjoern A. Zeeb 
1140b4c3e9b5SBjoern A. Zeeb 		kfree(bus_if);
1141b4c3e9b5SBjoern A. Zeeb 		kfree(sdiodev);
1142b4c3e9b5SBjoern A. Zeeb 	}
1143b4c3e9b5SBjoern A. Zeeb 
1144b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Exit\n");
1145b4c3e9b5SBjoern A. Zeeb }
1146b4c3e9b5SBjoern A. Zeeb 
brcmf_sdio_wowl_config(struct device * dev,bool enabled)1147b4c3e9b5SBjoern A. Zeeb void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
1148b4c3e9b5SBjoern A. Zeeb {
1149b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1150b4c3e9b5SBjoern A. Zeeb 	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
1151b4c3e9b5SBjoern A. Zeeb 	mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(sdiodev->func1);
1152b4c3e9b5SBjoern A. Zeeb 
1153b4c3e9b5SBjoern A. Zeeb 	/* Power must be preserved to be able to support WOWL. */
1154b4c3e9b5SBjoern A. Zeeb 	if (!(pm_caps & MMC_PM_KEEP_POWER))
1155b4c3e9b5SBjoern A. Zeeb 		goto notsup;
1156b4c3e9b5SBjoern A. Zeeb 
1157b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->settings->bus.sdio.oob_irq_supported ||
1158b4c3e9b5SBjoern A. Zeeb 	    pm_caps & MMC_PM_WAKE_SDIO_IRQ) {
1159b4c3e9b5SBjoern A. Zeeb 		/* Stop ACPI from turning off the device when wowl is enabled */
1160b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_acpi_set_power_manageable(sdiodev, !enabled);
1161b4c3e9b5SBjoern A. Zeeb 		sdiodev->wowl_enabled = enabled;
1162b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
1163b4c3e9b5SBjoern A. Zeeb 		return;
1164b4c3e9b5SBjoern A. Zeeb 	}
1165b4c3e9b5SBjoern A. Zeeb 
1166b4c3e9b5SBjoern A. Zeeb notsup:
1167b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "WOWL not supported\n");
1168b4c3e9b5SBjoern A. Zeeb }
1169b4c3e9b5SBjoern A. Zeeb 
brcmf_ops_sdio_suspend(struct device * dev)1170b4c3e9b5SBjoern A. Zeeb static int brcmf_ops_sdio_suspend(struct device *dev)
1171b4c3e9b5SBjoern A. Zeeb {
1172b4c3e9b5SBjoern A. Zeeb 	struct sdio_func *func;
1173b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if;
1174b4c3e9b5SBjoern A. Zeeb 	struct brcmf_sdio_dev *sdiodev;
1175b4c3e9b5SBjoern A. Zeeb 	mmc_pm_flag_t sdio_flags;
1176b4c3e9b5SBjoern A. Zeeb 	bool cap_power_off;
1177b4c3e9b5SBjoern A. Zeeb 	int ret = 0;
1178b4c3e9b5SBjoern A. Zeeb 
1179b4c3e9b5SBjoern A. Zeeb 	func = container_of(dev, struct sdio_func, dev);
1180b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
1181b4c3e9b5SBjoern A. Zeeb 	if (func->num != 1)
1182b4c3e9b5SBjoern A. Zeeb 		return 0;
1183b4c3e9b5SBjoern A. Zeeb 
1184b4c3e9b5SBjoern A. Zeeb 	cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);
1185b4c3e9b5SBjoern A. Zeeb 
1186b4c3e9b5SBjoern A. Zeeb 	bus_if = dev_get_drvdata(dev);
1187b4c3e9b5SBjoern A. Zeeb 	sdiodev = bus_if->bus_priv.sdio;
1188b4c3e9b5SBjoern A. Zeeb 
1189b4c3e9b5SBjoern A. Zeeb 	if (sdiodev->wowl_enabled || !cap_power_off) {
1190b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_freezer_on(sdiodev);
1191b4c3e9b5SBjoern A. Zeeb 		brcmf_sdio_wd_timer(sdiodev->bus, 0);
1192b4c3e9b5SBjoern A. Zeeb 
1193b4c3e9b5SBjoern A. Zeeb 		sdio_flags = MMC_PM_KEEP_POWER;
1194b4c3e9b5SBjoern A. Zeeb 
1195b4c3e9b5SBjoern A. Zeeb 		if (sdiodev->wowl_enabled) {
1196b4c3e9b5SBjoern A. Zeeb 			if (sdiodev->settings->bus.sdio.oob_irq_supported)
1197b4c3e9b5SBjoern A. Zeeb 				enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
1198b4c3e9b5SBjoern A. Zeeb 			else
1199b4c3e9b5SBjoern A. Zeeb 				sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
1200b4c3e9b5SBjoern A. Zeeb 		}
1201b4c3e9b5SBjoern A. Zeeb 
1202b4c3e9b5SBjoern A. Zeeb 		if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
1203b4c3e9b5SBjoern A. Zeeb 			brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
1204b4c3e9b5SBjoern A. Zeeb 
1205b4c3e9b5SBjoern A. Zeeb 	} else {
1206b4c3e9b5SBjoern A. Zeeb 		/* power will be cut so remove device, probe again in resume */
1207b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_intr_unregister(sdiodev);
1208b4c3e9b5SBjoern A. Zeeb 		ret = brcmf_sdiod_remove(sdiodev);
1209b4c3e9b5SBjoern A. Zeeb 		if (ret)
1210b4c3e9b5SBjoern A. Zeeb 			brcmf_err("Failed to remove device on suspend\n");
1211b4c3e9b5SBjoern A. Zeeb 	}
1212b4c3e9b5SBjoern A. Zeeb 
1213b4c3e9b5SBjoern A. Zeeb 	return ret;
1214b4c3e9b5SBjoern A. Zeeb }
1215b4c3e9b5SBjoern A. Zeeb 
brcmf_ops_sdio_resume(struct device * dev)1216b4c3e9b5SBjoern A. Zeeb static int brcmf_ops_sdio_resume(struct device *dev)
1217b4c3e9b5SBjoern A. Zeeb {
1218b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1219b4c3e9b5SBjoern A. Zeeb 	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
1220b4c3e9b5SBjoern A. Zeeb 	struct sdio_func *func = container_of(dev, struct sdio_func, dev);
1221b4c3e9b5SBjoern A. Zeeb 	int ret = 0;
1222b4c3e9b5SBjoern A. Zeeb 	bool cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);
1223b4c3e9b5SBjoern A. Zeeb 
1224b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
1225b4c3e9b5SBjoern A. Zeeb 	if (func->num != 2)
1226b4c3e9b5SBjoern A. Zeeb 		return 0;
1227b4c3e9b5SBjoern A. Zeeb 
1228b4c3e9b5SBjoern A. Zeeb 	if (!sdiodev->wowl_enabled && cap_power_off) {
1229b4c3e9b5SBjoern A. Zeeb 		/* bus was powered off and device removed, probe again */
1230b4c3e9b5SBjoern A. Zeeb 		ret = brcmf_sdiod_probe(sdiodev);
1231b4c3e9b5SBjoern A. Zeeb 		if (ret)
1232b4c3e9b5SBjoern A. Zeeb 			brcmf_err("Failed to probe device on resume\n");
1233b4c3e9b5SBjoern A. Zeeb 	} else {
1234b4c3e9b5SBjoern A. Zeeb 		if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)
1235b4c3e9b5SBjoern A. Zeeb 			disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
1236b4c3e9b5SBjoern A. Zeeb 
1237b4c3e9b5SBjoern A. Zeeb 		brcmf_sdiod_freezer_off(sdiodev);
1238b4c3e9b5SBjoern A. Zeeb 	}
1239b4c3e9b5SBjoern A. Zeeb 
1240b4c3e9b5SBjoern A. Zeeb 	return ret;
1241b4c3e9b5SBjoern A. Zeeb }
1242b4c3e9b5SBjoern A. Zeeb 
1243b4c3e9b5SBjoern A. Zeeb static DEFINE_SIMPLE_DEV_PM_OPS(brcmf_sdio_pm_ops,
1244b4c3e9b5SBjoern A. Zeeb 				brcmf_ops_sdio_suspend,
1245b4c3e9b5SBjoern A. Zeeb 				brcmf_ops_sdio_resume);
1246b4c3e9b5SBjoern A. Zeeb 
1247b4c3e9b5SBjoern A. Zeeb static struct sdio_driver brcmf_sdmmc_driver = {
1248b4c3e9b5SBjoern A. Zeeb 	.probe = brcmf_ops_sdio_probe,
1249b4c3e9b5SBjoern A. Zeeb 	.remove = brcmf_ops_sdio_remove,
1250b4c3e9b5SBjoern A. Zeeb 	.name = KBUILD_MODNAME,
1251b4c3e9b5SBjoern A. Zeeb 	.id_table = brcmf_sdmmc_ids,
1252b4c3e9b5SBjoern A. Zeeb 	.drv = {
1253b4c3e9b5SBjoern A. Zeeb 		.pm = pm_sleep_ptr(&brcmf_sdio_pm_ops),
1254b4c3e9b5SBjoern A. Zeeb 		.coredump = brcmf_dev_coredump,
1255b4c3e9b5SBjoern A. Zeeb 	},
1256b4c3e9b5SBjoern A. Zeeb };
1257b4c3e9b5SBjoern A. Zeeb 
brcmf_sdio_register(void)1258b4c3e9b5SBjoern A. Zeeb int brcmf_sdio_register(void)
1259b4c3e9b5SBjoern A. Zeeb {
1260b4c3e9b5SBjoern A. Zeeb 	return sdio_register_driver(&brcmf_sdmmc_driver);
1261b4c3e9b5SBjoern A. Zeeb }
1262b4c3e9b5SBjoern A. Zeeb 
brcmf_sdio_exit(void)1263b4c3e9b5SBjoern A. Zeeb void brcmf_sdio_exit(void)
1264b4c3e9b5SBjoern A. Zeeb {
1265b4c3e9b5SBjoern A. Zeeb 	brcmf_dbg(SDIO, "Enter\n");
1266b4c3e9b5SBjoern A. Zeeb 
1267b4c3e9b5SBjoern A. Zeeb 	sdio_unregister_driver(&brcmf_sdmmc_driver);
1268b4c3e9b5SBjoern A. Zeeb }
1269b4c3e9b5SBjoern A. Zeeb 
1270