2 * Copyright (c) 2011 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 /* ***** SDIO interface chip backplane handle functions ***** */
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20 #include <linux/types.h>
21 #include <linux/netdevice.h>
22 #include <linux/mmc/card.h>
23 #include <linux/ssb/ssb_regs.h>
24 #include <linux/bcma/bcma.h>
26 #include <chipcommon.h>
27 #include <brcm_hw_ids.h>
28 #include <brcmu_wifi.h>
29 #include <brcmu_utils.h>
32 #include "sdio_host.h"
33 #include "sdio_chip.h"
35 /* chip core base & ramsize */
37 /* SDIO device core, ID 0x829 */
38 #define BCM4329_CORE_BUS_BASE 0x18011000
39 /* internal memory core, ID 0x80e */
40 #define BCM4329_CORE_SOCRAM_BASE 0x18003000
41 /* ARM Cortex M3 core, ID 0x82a */
42 #define BCM4329_CORE_ARM_BASE 0x18002000
43 #define BCM4329_RAMSIZE 0x48000
45 #define SBCOREREV(sbidh) \
46 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
47 ((sbidh) & SSB_IDHIGH_RCLO))
49 /* SOC Interconnect types (aka chip types) */
54 #define CIB_REV_MASK 0xff000000
55 #define CIB_REV_SHIFT 24
57 #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
58 /* SDIO Pad drive strength to select value mappings */
59 struct sdiod_drive_str
{
60 u8 strength
; /* Pad Drive Strength in mA */
61 u8 sel
; /* Chip-specific select value */
63 /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
64 static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8
[] = {
76 brcmf_sdio_chip_getinfidx(struct chip_info
*ci
, u16 coreid
)
80 for (idx
= 0; idx
< BRCMF_MAX_CORENUM
; idx
++)
81 if (coreid
== ci
->c_inf
[idx
].id
)
84 return BRCMF_MAX_CORENUM
;
88 brcmf_sdio_sb_corerev(struct brcmf_sdio_dev
*sdiodev
,
89 struct chip_info
*ci
, u16 coreid
)
94 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
96 regdata
= brcmf_sdio_regrl(sdiodev
,
97 CORE_SB(ci
->c_inf
[idx
].base
, sbidhigh
),
99 return SBCOREREV(regdata
);
103 brcmf_sdio_ai_corerev(struct brcmf_sdio_dev
*sdiodev
,
104 struct chip_info
*ci
, u16 coreid
)
108 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
110 return (ci
->c_inf
[idx
].cib
& CIB_REV_MASK
) >> CIB_REV_SHIFT
;
114 brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev
*sdiodev
,
115 struct chip_info
*ci
, u16 coreid
)
120 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
122 regdata
= brcmf_sdio_regrl(sdiodev
,
123 CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatelow
),
125 regdata
&= (SSB_TMSLOW_RESET
| SSB_TMSLOW_REJECT
|
126 SSB_IMSTATE_REJECT
| SSB_TMSLOW_CLOCK
);
127 return (SSB_TMSLOW_CLOCK
== regdata
);
131 brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev
*sdiodev
,
132 struct chip_info
*ci
, u16 coreid
)
138 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
140 regdata
= brcmf_sdio_regrl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_IOCTL
,
142 ret
= (regdata
& (BCMA_IOCTL_FGC
| BCMA_IOCTL_CLK
)) == BCMA_IOCTL_CLK
;
144 regdata
= brcmf_sdio_regrl(sdiodev
,
145 ci
->c_inf
[idx
].wrapbase
+BCMA_RESET_CTL
,
147 ret
= ret
&& ((regdata
& BCMA_RESET_CTL_RESET
) == 0);
153 brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev
*sdiodev
,
154 struct chip_info
*ci
, u16 coreid
)
159 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
160 base
= ci
->c_inf
[idx
].base
;
162 regdata
= brcmf_sdio_regrl(sdiodev
, CORE_SB(base
, sbtmstatelow
), NULL
);
163 if (regdata
& SSB_TMSLOW_RESET
)
166 regdata
= brcmf_sdio_regrl(sdiodev
, CORE_SB(base
, sbtmstatelow
), NULL
);
167 if ((regdata
& SSB_TMSLOW_CLOCK
) != 0) {
169 * set target reject and spin until busy is clear
170 * (preserve core-specific bits)
172 regdata
= brcmf_sdio_regrl(sdiodev
, CORE_SB(base
, sbtmstatelow
),
174 brcmf_sdio_regwl(sdiodev
, CORE_SB(base
, sbtmstatelow
),
175 regdata
| SSB_TMSLOW_REJECT
, NULL
);
177 regdata
= brcmf_sdio_regrl(sdiodev
, CORE_SB(base
, sbtmstatelow
),
180 SPINWAIT((brcmf_sdio_regrl(sdiodev
,
181 CORE_SB(base
, sbtmstatehigh
),
183 SSB_TMSHIGH_BUSY
), 100000);
185 regdata
= brcmf_sdio_regrl(sdiodev
,
186 CORE_SB(base
, sbtmstatehigh
),
188 if (regdata
& SSB_TMSHIGH_BUSY
)
189 brcmf_dbg(ERROR
, "core state still busy\n");
191 regdata
= brcmf_sdio_regrl(sdiodev
, CORE_SB(base
, sbidlow
),
193 if (regdata
& SSB_IDLOW_INITIATOR
) {
194 regdata
= brcmf_sdio_regrl(sdiodev
,
195 CORE_SB(base
, sbimstate
),
197 regdata
|= SSB_IMSTATE_REJECT
;
198 brcmf_sdio_regwl(sdiodev
, CORE_SB(base
, sbimstate
),
200 regdata
= brcmf_sdio_regrl(sdiodev
,
201 CORE_SB(base
, sbimstate
),
204 SPINWAIT((brcmf_sdio_regrl(sdiodev
,
205 CORE_SB(base
, sbimstate
),
207 SSB_IMSTATE_BUSY
), 100000);
210 /* set reset and reject while enabling the clocks */
211 regdata
= SSB_TMSLOW_FGC
| SSB_TMSLOW_CLOCK
|
212 SSB_TMSLOW_REJECT
| SSB_TMSLOW_RESET
;
213 brcmf_sdio_regwl(sdiodev
, CORE_SB(base
, sbtmstatelow
),
215 regdata
= brcmf_sdio_regrl(sdiodev
, CORE_SB(base
, sbtmstatelow
),
219 /* clear the initiator reject bit */
220 regdata
= brcmf_sdio_regrl(sdiodev
, CORE_SB(base
, sbidlow
),
222 if (regdata
& SSB_IDLOW_INITIATOR
) {
223 regdata
= brcmf_sdio_regrl(sdiodev
,
224 CORE_SB(base
, sbimstate
),
226 regdata
&= ~SSB_IMSTATE_REJECT
;
227 brcmf_sdio_regwl(sdiodev
, CORE_SB(base
, sbimstate
),
232 /* leave reset and reject asserted */
233 brcmf_sdio_regwl(sdiodev
, CORE_SB(base
, sbtmstatelow
),
234 (SSB_TMSLOW_REJECT
| SSB_TMSLOW_RESET
), NULL
);
239 brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev
*sdiodev
,
240 struct chip_info
*ci
, u16 coreid
)
245 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
247 /* if core is already in reset, just return */
248 regdata
= brcmf_sdio_regrl(sdiodev
,
249 ci
->c_inf
[idx
].wrapbase
+BCMA_RESET_CTL
,
251 if ((regdata
& BCMA_RESET_CTL_RESET
) != 0)
254 brcmf_sdio_regwl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_IOCTL
, 0, NULL
);
255 regdata
= brcmf_sdio_regrl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_IOCTL
,
259 brcmf_sdio_regwl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_RESET_CTL
,
260 BCMA_RESET_CTL_RESET
, NULL
);
265 brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev
*sdiodev
,
266 struct chip_info
*ci
, u16 coreid
)
271 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
274 * Must do the disable sequence first to work for
275 * arbitrary current core state.
277 brcmf_sdio_sb_coredisable(sdiodev
, ci
, coreid
);
280 * Now do the initialization sequence.
281 * set reset while enabling the clock and
282 * forcing them on throughout the core
284 brcmf_sdio_regwl(sdiodev
,
285 CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatelow
),
286 SSB_TMSLOW_FGC
| SSB_TMSLOW_CLOCK
| SSB_TMSLOW_RESET
,
288 regdata
= brcmf_sdio_regrl(sdiodev
,
289 CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatelow
),
293 /* clear any serror */
294 regdata
= brcmf_sdio_regrl(sdiodev
,
295 CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatehigh
),
297 if (regdata
& SSB_TMSHIGH_SERR
)
298 brcmf_sdio_regwl(sdiodev
,
299 CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatehigh
),
302 regdata
= brcmf_sdio_regrl(sdiodev
,
303 CORE_SB(ci
->c_inf
[idx
].base
, sbimstate
),
305 if (regdata
& (SSB_IMSTATE_IBE
| SSB_IMSTATE_TO
))
306 brcmf_sdio_regwl(sdiodev
,
307 CORE_SB(ci
->c_inf
[idx
].base
, sbimstate
),
308 regdata
& ~(SSB_IMSTATE_IBE
| SSB_IMSTATE_TO
),
311 /* clear reset and allow it to propagate throughout the core */
312 brcmf_sdio_regwl(sdiodev
, CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatelow
),
313 SSB_TMSLOW_FGC
| SSB_TMSLOW_CLOCK
, NULL
);
314 regdata
= brcmf_sdio_regrl(sdiodev
,
315 CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatelow
),
319 /* leave clock enabled */
320 brcmf_sdio_regwl(sdiodev
, CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatelow
),
321 SSB_TMSLOW_CLOCK
, NULL
);
322 regdata
= brcmf_sdio_regrl(sdiodev
,
323 CORE_SB(ci
->c_inf
[idx
].base
, sbtmstatelow
),
329 brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev
*sdiodev
,
330 struct chip_info
*ci
, u16 coreid
)
335 idx
= brcmf_sdio_chip_getinfidx(ci
, coreid
);
337 /* must disable first to work for arbitrary current core state */
338 brcmf_sdio_ai_coredisable(sdiodev
, ci
, coreid
);
340 /* now do initialization sequence */
341 brcmf_sdio_regwl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_IOCTL
,
342 BCMA_IOCTL_FGC
| BCMA_IOCTL_CLK
, NULL
);
343 regdata
= brcmf_sdio_regrl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_IOCTL
,
345 brcmf_sdio_regwl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_RESET_CTL
,
349 brcmf_sdio_regwl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_IOCTL
,
350 BCMA_IOCTL_CLK
, NULL
);
351 regdata
= brcmf_sdio_regrl(sdiodev
, ci
->c_inf
[idx
].wrapbase
+BCMA_IOCTL
,
356 static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev
*sdiodev
,
357 struct chip_info
*ci
, u32 regs
)
363 * Chipid is assume to be at offset 0 from regs arg
364 * For different chiptypes or old sdio hosts w/o chipcommon,
365 * other ways of recognition should be added here.
367 ci
->c_inf
[0].id
= BCMA_CORE_CHIPCOMMON
;
368 ci
->c_inf
[0].base
= regs
;
369 regdata
= brcmf_sdio_regrl(sdiodev
,
370 CORE_CC_REG(ci
->c_inf
[0].base
, chipid
),
372 ci
->chip
= regdata
& CID_ID_MASK
;
373 ci
->chiprev
= (regdata
& CID_REV_MASK
) >> CID_REV_SHIFT
;
374 ci
->socitype
= (regdata
& CID_TYPE_MASK
) >> CID_TYPE_SHIFT
;
376 brcmf_dbg(INFO
, "chipid=0x%x chiprev=%d\n", ci
->chip
, ci
->chiprev
);
378 /* Address of cores for new chips should be added here */
380 case BCM4329_CHIP_ID
:
381 ci
->c_inf
[1].id
= BCMA_CORE_SDIO_DEV
;
382 ci
->c_inf
[1].base
= BCM4329_CORE_BUS_BASE
;
383 ci
->c_inf
[2].id
= BCMA_CORE_INTERNAL_MEM
;
384 ci
->c_inf
[2].base
= BCM4329_CORE_SOCRAM_BASE
;
385 ci
->c_inf
[3].id
= BCMA_CORE_ARM_CM3
;
386 ci
->c_inf
[3].base
= BCM4329_CORE_ARM_BASE
;
387 ci
->ramsize
= BCM4329_RAMSIZE
;
389 case BCM4330_CHIP_ID
:
390 ci
->c_inf
[0].wrapbase
= 0x18100000;
391 ci
->c_inf
[0].cib
= 0x27004211;
392 ci
->c_inf
[1].id
= BCMA_CORE_SDIO_DEV
;
393 ci
->c_inf
[1].base
= 0x18002000;
394 ci
->c_inf
[1].wrapbase
= 0x18102000;
395 ci
->c_inf
[1].cib
= 0x07004211;
396 ci
->c_inf
[2].id
= BCMA_CORE_INTERNAL_MEM
;
397 ci
->c_inf
[2].base
= 0x18004000;
398 ci
->c_inf
[2].wrapbase
= 0x18104000;
399 ci
->c_inf
[2].cib
= 0x0d080401;
400 ci
->c_inf
[3].id
= BCMA_CORE_ARM_CM3
;
401 ci
->c_inf
[3].base
= 0x18003000;
402 ci
->c_inf
[3].wrapbase
= 0x18103000;
403 ci
->c_inf
[3].cib
= 0x03004211;
404 ci
->ramsize
= 0x48000;
406 case BCM4334_CHIP_ID
:
407 ci
->c_inf
[0].wrapbase
= 0x18100000;
408 ci
->c_inf
[0].cib
= 0x29004211;
409 ci
->c_inf
[1].id
= BCMA_CORE_SDIO_DEV
;
410 ci
->c_inf
[1].base
= 0x18002000;
411 ci
->c_inf
[1].wrapbase
= 0x18102000;
412 ci
->c_inf
[1].cib
= 0x0d004211;
413 ci
->c_inf
[2].id
= BCMA_CORE_INTERNAL_MEM
;
414 ci
->c_inf
[2].base
= 0x18004000;
415 ci
->c_inf
[2].wrapbase
= 0x18104000;
416 ci
->c_inf
[2].cib
= 0x13080401;
417 ci
->c_inf
[3].id
= BCMA_CORE_ARM_CM3
;
418 ci
->c_inf
[3].base
= 0x18003000;
419 ci
->c_inf
[3].wrapbase
= 0x18103000;
420 ci
->c_inf
[3].cib
= 0x07004211;
421 ci
->ramsize
= 0x80000;
424 brcmf_dbg(ERROR
, "chipid 0x%x is not supported\n", ci
->chip
);
428 switch (ci
->socitype
) {
430 ci
->iscoreup
= brcmf_sdio_sb_iscoreup
;
431 ci
->corerev
= brcmf_sdio_sb_corerev
;
432 ci
->coredisable
= brcmf_sdio_sb_coredisable
;
433 ci
->resetcore
= brcmf_sdio_sb_resetcore
;
436 ci
->iscoreup
= brcmf_sdio_ai_iscoreup
;
437 ci
->corerev
= brcmf_sdio_ai_corerev
;
438 ci
->coredisable
= brcmf_sdio_ai_coredisable
;
439 ci
->resetcore
= brcmf_sdio_ai_resetcore
;
442 brcmf_dbg(ERROR
, "socitype %u not supported\n", ci
->socitype
);
450 brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev
*sdiodev
)
455 /* Try forcing SDIO core to do ALPAvail request only */
456 clkset
= SBSDIO_FORCE_HW_CLKREQ_OFF
| SBSDIO_ALP_AVAIL_REQ
;
457 brcmf_sdio_regwb(sdiodev
, SBSDIO_FUNC1_CHIPCLKCSR
, clkset
, &err
);
459 brcmf_dbg(ERROR
, "error writing for HT off\n");
463 /* If register supported, wait for ALPAvail and then force ALP */
464 /* This may take up to 15 milliseconds */
465 clkval
= brcmf_sdio_regrb(sdiodev
,
466 SBSDIO_FUNC1_CHIPCLKCSR
, NULL
);
468 if ((clkval
& ~SBSDIO_AVBITS
) != clkset
) {
469 brcmf_dbg(ERROR
, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
474 SPINWAIT(((clkval
= brcmf_sdio_regrb(sdiodev
,
475 SBSDIO_FUNC1_CHIPCLKCSR
, NULL
)),
476 !SBSDIO_ALPAV(clkval
)),
477 PMU_MAX_TRANSITION_DLY
);
478 if (!SBSDIO_ALPAV(clkval
)) {
479 brcmf_dbg(ERROR
, "timeout on ALPAV wait, clkval 0x%02x\n",
484 clkset
= SBSDIO_FORCE_HW_CLKREQ_OFF
| SBSDIO_FORCE_ALP
;
485 brcmf_sdio_regwb(sdiodev
, SBSDIO_FUNC1_CHIPCLKCSR
, clkset
, &err
);
488 /* Also, disable the extra SDIO pull-ups */
489 brcmf_sdio_regwb(sdiodev
, SBSDIO_FUNC1_SDIOPULLUP
, 0, NULL
);
495 brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev
*sdiodev
,
496 struct chip_info
*ci
)
498 u32 base
= ci
->c_inf
[0].base
;
500 /* get chipcommon rev */
501 ci
->c_inf
[0].rev
= ci
->corerev(sdiodev
, ci
, ci
->c_inf
[0].id
);
503 /* get chipcommon capabilites */
504 ci
->c_inf
[0].caps
= brcmf_sdio_regrl(sdiodev
,
505 CORE_CC_REG(base
, capabilities
),
508 /* get pmu caps & rev */
509 if (ci
->c_inf
[0].caps
& CC_CAP_PMU
) {
511 brcmf_sdio_regrl(sdiodev
,
512 CORE_CC_REG(base
, pmucapabilities
),
514 ci
->pmurev
= ci
->pmucaps
& PCAP_REV_MASK
;
517 ci
->c_inf
[1].rev
= ci
->corerev(sdiodev
, ci
, ci
->c_inf
[1].id
);
519 brcmf_dbg(INFO
, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
520 ci
->c_inf
[0].rev
, ci
->pmurev
,
521 ci
->c_inf
[1].rev
, ci
->c_inf
[1].id
);
524 * Make sure any on-chip ARM is off (in case strapping is wrong),
525 * or downloaded code was already running.
527 ci
->coredisable(sdiodev
, ci
, BCMA_CORE_ARM_CM3
);
530 int brcmf_sdio_chip_attach(struct brcmf_sdio_dev
*sdiodev
,
531 struct chip_info
**ci_ptr
, u32 regs
)
534 struct chip_info
*ci
;
536 brcmf_dbg(TRACE
, "Enter\n");
538 /* alloc chip_info_t */
539 ci
= kzalloc(sizeof(struct chip_info
), GFP_ATOMIC
);
543 ret
= brcmf_sdio_chip_buscoreprep(sdiodev
);
547 ret
= brcmf_sdio_chip_recognition(sdiodev
, ci
, regs
);
551 brcmf_sdio_chip_buscoresetup(sdiodev
, ci
);
553 brcmf_sdio_regwl(sdiodev
, CORE_CC_REG(ci
->c_inf
[0].base
, gpiopullup
),
555 brcmf_sdio_regwl(sdiodev
, CORE_CC_REG(ci
->c_inf
[0].base
, gpiopulldown
),
567 brcmf_sdio_chip_detach(struct chip_info
**ci_ptr
)
569 brcmf_dbg(TRACE
, "Enter\n");
575 static char *brcmf_sdio_chip_name(uint chipid
, char *buf
, uint len
)
579 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
580 snprintf(buf
, len
, fmt
, chipid
);
585 brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev
*sdiodev
,
586 struct chip_info
*ci
, u32 drivestrength
)
588 struct sdiod_drive_str
*str_tab
= NULL
;
592 u32 base
= ci
->c_inf
[0].base
;
594 if (!(ci
->c_inf
[0].caps
& CC_CAP_PMU
))
597 switch (SDIOD_DRVSTR_KEY(ci
->chip
, ci
->pmurev
)) {
598 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID
, 12):
599 str_tab
= (struct sdiod_drive_str
*)&sdiod_drvstr_tab1_1v8
;
600 str_mask
= 0x00003800;
604 brcmf_dbg(ERROR
, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
605 brcmf_sdio_chip_name(ci
->chip
, chn
, 8),
606 ci
->chiprev
, ci
->pmurev
);
610 if (str_tab
!= NULL
) {
611 u32 drivestrength_sel
= 0;
615 for (i
= 0; str_tab
[i
].strength
!= 0; i
++) {
616 if (drivestrength
>= str_tab
[i
].strength
) {
617 drivestrength_sel
= str_tab
[i
].sel
;
622 brcmf_sdio_regwl(sdiodev
, CORE_CC_REG(base
, chipcontrol_addr
),
625 brcmf_sdio_regrl(sdiodev
,
626 CORE_CC_REG(base
, chipcontrol_addr
),
628 cc_data_temp
&= ~str_mask
;
629 drivestrength_sel
<<= str_shift
;
630 cc_data_temp
|= drivestrength_sel
;
631 brcmf_sdio_regwl(sdiodev
, CORE_CC_REG(base
, chipcontrol_addr
),
634 brcmf_dbg(INFO
, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
635 drivestrength
, cc_data_temp
);