Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sdio_chip.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Broadcom Corporation
3  *
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.
7  *
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.
15  */
16 /* ***** SDIO interface chip backplane handle functions ***** */
17 
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 
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>
25 
26 #include <chipcommon.h>
27 #include <brcm_hw_ids.h>
28 #include <brcmu_wifi.h>
29 #include <brcmu_utils.h>
30 #include <soc.h>
31 #include "dhd_dbg.h"
32 #include "sdio_host.h"
33 #include "sdio_chip.h"
34 
35 /* chip core base & ramsize */
36 /* bcm4329 */
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
44 
45 #define SBCOREREV(sbidh) \
46  ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
47  ((sbidh) & SSB_IDHIGH_RCLO))
48 
49 /* SOC Interconnect types (aka chip types) */
50 #define SOCI_SB 0
51 #define SOCI_AI 1
52 
53 /* EROM CompIdentB */
54 #define CIB_REV_MASK 0xff000000
55 #define CIB_REV_SHIFT 24
56 
57 #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
58 /* SDIO Pad drive strength to select value mappings */
60  u8 strength; /* Pad Drive Strength in mA */
61  u8 sel; /* Chip-specific select value */
62 };
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[] = {
65  {32, 0x6},
66  {26, 0x7},
67  {22, 0x4},
68  {16, 0x5},
69  {12, 0x2},
70  {8, 0x3},
71  {4, 0x0},
72  {0, 0x1}
73 };
74 
75 u8
76 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
77 {
78  u8 idx;
79 
80  for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
81  if (coreid == ci->c_inf[idx].id)
82  return idx;
83 
84  return BRCMF_MAX_CORENUM;
85 }
86 
87 static u32
88 brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
89  struct chip_info *ci, u16 coreid)
90 {
91  u32 regdata;
92  u8 idx;
93 
94  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
95 
96  regdata = brcmf_sdio_regrl(sdiodev,
97  CORE_SB(ci->c_inf[idx].base, sbidhigh),
98  NULL);
99  return SBCOREREV(regdata);
100 }
101 
102 static u32
103 brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
104  struct chip_info *ci, u16 coreid)
105 {
106  u8 idx;
107 
108  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
109 
110  return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
111 }
112 
113 static bool
114 brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
115  struct chip_info *ci, u16 coreid)
116 {
117  u32 regdata;
118  u8 idx;
119 
120  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
121 
122  regdata = brcmf_sdio_regrl(sdiodev,
123  CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
124  NULL);
125  regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
127  return (SSB_TMSLOW_CLOCK == regdata);
128 }
129 
130 static bool
131 brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
132  struct chip_info *ci, u16 coreid)
133 {
134  u32 regdata;
135  u8 idx;
136  bool ret;
137 
138  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
139 
140  regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
141  NULL);
142  ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
143 
144  regdata = brcmf_sdio_regrl(sdiodev,
145  ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
146  NULL);
147  ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
148 
149  return ret;
150 }
151 
152 static void
153 brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
154  struct chip_info *ci, u16 coreid)
155 {
156  u32 regdata, base;
157  u8 idx;
158 
159  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
160  base = ci->c_inf[idx].base;
161 
162  regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
163  if (regdata & SSB_TMSLOW_RESET)
164  return;
165 
166  regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
167  if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
168  /*
169  * set target reject and spin until busy is clear
170  * (preserve core-specific bits)
171  */
172  regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
173  NULL);
174  brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
175  regdata | SSB_TMSLOW_REJECT, NULL);
176 
177  regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
178  NULL);
179  udelay(1);
180  SPINWAIT((brcmf_sdio_regrl(sdiodev,
181  CORE_SB(base, sbtmstatehigh),
182  NULL) &
183  SSB_TMSHIGH_BUSY), 100000);
184 
185  regdata = brcmf_sdio_regrl(sdiodev,
186  CORE_SB(base, sbtmstatehigh),
187  NULL);
188  if (regdata & SSB_TMSHIGH_BUSY)
189  brcmf_dbg(ERROR, "core state still busy\n");
190 
191  regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
192  NULL);
193  if (regdata & SSB_IDLOW_INITIATOR) {
194  regdata = brcmf_sdio_regrl(sdiodev,
195  CORE_SB(base, sbimstate),
196  NULL);
197  regdata |= SSB_IMSTATE_REJECT;
198  brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
199  regdata, NULL);
200  regdata = brcmf_sdio_regrl(sdiodev,
201  CORE_SB(base, sbimstate),
202  NULL);
203  udelay(1);
204  SPINWAIT((brcmf_sdio_regrl(sdiodev,
205  CORE_SB(base, sbimstate),
206  NULL) &
207  SSB_IMSTATE_BUSY), 100000);
208  }
209 
210  /* set reset and reject while enabling the clocks */
211  regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
213  brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
214  regdata, NULL);
215  regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
216  NULL);
217  udelay(10);
218 
219  /* clear the initiator reject bit */
220  regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
221  NULL);
222  if (regdata & SSB_IDLOW_INITIATOR) {
223  regdata = brcmf_sdio_regrl(sdiodev,
224  CORE_SB(base, sbimstate),
225  NULL);
226  regdata &= ~SSB_IMSTATE_REJECT;
227  brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
228  regdata, NULL);
229  }
230  }
231 
232  /* leave reset and reject asserted */
233  brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
234  (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
235  udelay(1);
236 }
237 
238 static void
239 brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
240  struct chip_info *ci, u16 coreid)
241 {
242  u8 idx;
243  u32 regdata;
244 
245  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
246 
247  /* if core is already in reset, just return */
248  regdata = brcmf_sdio_regrl(sdiodev,
249  ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
250  NULL);
251  if ((regdata & BCMA_RESET_CTL_RESET) != 0)
252  return;
253 
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,
256  NULL);
257  udelay(10);
258 
259  brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
260  BCMA_RESET_CTL_RESET, NULL);
261  udelay(1);
262 }
263 
264 static void
265 brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
266  struct chip_info *ci, u16 coreid)
267 {
268  u32 regdata;
269  u8 idx;
270 
271  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
272 
273  /*
274  * Must do the disable sequence first to work for
275  * arbitrary current core state.
276  */
277  brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
278 
279  /*
280  * Now do the initialization sequence.
281  * set reset while enabling the clock and
282  * forcing them on throughout the core
283  */
284  brcmf_sdio_regwl(sdiodev,
285  CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
286  SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
287  NULL);
288  regdata = brcmf_sdio_regrl(sdiodev,
289  CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
290  NULL);
291  udelay(1);
292 
293  /* clear any serror */
294  regdata = brcmf_sdio_regrl(sdiodev,
295  CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
296  NULL);
297  if (regdata & SSB_TMSHIGH_SERR)
298  brcmf_sdio_regwl(sdiodev,
299  CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
300  0, NULL);
301 
302  regdata = brcmf_sdio_regrl(sdiodev,
303  CORE_SB(ci->c_inf[idx].base, sbimstate),
304  NULL);
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),
309  NULL);
310 
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),
316  NULL);
317  udelay(1);
318 
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),
324  NULL);
325  udelay(1);
326 }
327 
328 static void
329 brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
330  struct chip_info *ci, u16 coreid)
331 {
332  u8 idx;
333  u32 regdata;
334 
335  idx = brcmf_sdio_chip_getinfidx(ci, coreid);
336 
337  /* must disable first to work for arbitrary current core state */
338  brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
339 
340  /* now do initialization sequence */
341  brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
343  regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
344  NULL);
345  brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
346  0, NULL);
347  udelay(1);
348 
349  brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
351  regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
352  NULL);
353  udelay(1);
354 }
355 
356 static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
357  struct chip_info *ci, u32 regs)
358 {
359  u32 regdata;
360 
361  /*
362  * Get CC core rev
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.
366  */
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),
371  NULL);
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;
375 
376  brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
377 
378  /* Address of cores for new chips should be added here */
379  switch (ci->chip) {
380  case BCM43241_CHIP_ID:
381  ci->c_inf[0].wrapbase = 0x18100000;
382  ci->c_inf[0].cib = 0x2a084411;
383  ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
384  ci->c_inf[1].base = 0x18002000;
385  ci->c_inf[1].wrapbase = 0x18102000;
386  ci->c_inf[1].cib = 0x0e004211;
387  ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
388  ci->c_inf[2].base = 0x18004000;
389  ci->c_inf[2].wrapbase = 0x18104000;
390  ci->c_inf[2].cib = 0x14080401;
391  ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
392  ci->c_inf[3].base = 0x18003000;
393  ci->c_inf[3].wrapbase = 0x18103000;
394  ci->c_inf[3].cib = 0x07004211;
395  ci->ramsize = 0x90000;
396  break;
397  case BCM4329_CHIP_ID:
398  ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
399  ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
400  ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
401  ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
402  ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
403  ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
404  ci->ramsize = BCM4329_RAMSIZE;
405  break;
406  case BCM4330_CHIP_ID:
407  ci->c_inf[0].wrapbase = 0x18100000;
408  ci->c_inf[0].cib = 0x27004211;
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 = 0x07004211;
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 = 0x0d080401;
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 = 0x03004211;
421  ci->ramsize = 0x48000;
422  break;
423  case BCM4334_CHIP_ID:
424  ci->c_inf[0].wrapbase = 0x18100000;
425  ci->c_inf[0].cib = 0x29004211;
426  ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
427  ci->c_inf[1].base = 0x18002000;
428  ci->c_inf[1].wrapbase = 0x18102000;
429  ci->c_inf[1].cib = 0x0d004211;
430  ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
431  ci->c_inf[2].base = 0x18004000;
432  ci->c_inf[2].wrapbase = 0x18104000;
433  ci->c_inf[2].cib = 0x13080401;
434  ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
435  ci->c_inf[3].base = 0x18003000;
436  ci->c_inf[3].wrapbase = 0x18103000;
437  ci->c_inf[3].cib = 0x07004211;
438  ci->ramsize = 0x80000;
439  break;
440  default:
441  brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
442  return -ENODEV;
443  }
444 
445  switch (ci->socitype) {
446  case SOCI_SB:
447  ci->iscoreup = brcmf_sdio_sb_iscoreup;
448  ci->corerev = brcmf_sdio_sb_corerev;
449  ci->coredisable = brcmf_sdio_sb_coredisable;
450  ci->resetcore = brcmf_sdio_sb_resetcore;
451  break;
452  case SOCI_AI:
453  ci->iscoreup = brcmf_sdio_ai_iscoreup;
454  ci->corerev = brcmf_sdio_ai_corerev;
455  ci->coredisable = brcmf_sdio_ai_coredisable;
456  ci->resetcore = brcmf_sdio_ai_resetcore;
457  break;
458  default:
459  brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
460  return -ENODEV;
461  }
462 
463  return 0;
464 }
465 
466 static int
467 brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
468 {
469  int err = 0;
470  u8 clkval, clkset;
471 
472  /* Try forcing SDIO core to do ALPAvail request only */
474  brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
475  if (err) {
476  brcmf_dbg(ERROR, "error writing for HT off\n");
477  return err;
478  }
479 
480  /* If register supported, wait for ALPAvail and then force ALP */
481  /* This may take up to 15 milliseconds */
482  clkval = brcmf_sdio_regrb(sdiodev,
484 
485  if ((clkval & ~SBSDIO_AVBITS) != clkset) {
486  brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
487  clkset, clkval);
488  return -EACCES;
489  }
490 
491  SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
493  !SBSDIO_ALPAV(clkval)),
495  if (!SBSDIO_ALPAV(clkval)) {
496  brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
497  clkval);
498  return -EBUSY;
499  }
500 
502  brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
503  udelay(65);
504 
505  /* Also, disable the extra SDIO pull-ups */
507 
508  return 0;
509 }
510 
511 static void
512 brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
513  struct chip_info *ci)
514 {
515  u32 base = ci->c_inf[0].base;
516 
517  /* get chipcommon rev */
518  ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
519 
520  /* get chipcommon capabilites */
521  ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev,
522  CORE_CC_REG(base, capabilities),
523  NULL);
524 
525  /* get pmu caps & rev */
526  if (ci->c_inf[0].caps & CC_CAP_PMU) {
527  ci->pmucaps =
528  brcmf_sdio_regrl(sdiodev,
529  CORE_CC_REG(base, pmucapabilities),
530  NULL);
531  ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
532  }
533 
534  ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
535 
536  brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
537  ci->c_inf[0].rev, ci->pmurev,
538  ci->c_inf[1].rev, ci->c_inf[1].id);
539 
540  /*
541  * Make sure any on-chip ARM is off (in case strapping is wrong),
542  * or downloaded code was already running.
543  */
544  ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
545 }
546 
548  struct chip_info **ci_ptr, u32 regs)
549 {
550  int ret;
551  struct chip_info *ci;
552 
553  brcmf_dbg(TRACE, "Enter\n");
554 
555  /* alloc chip_info_t */
556  ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
557  if (!ci)
558  return -ENOMEM;
559 
560  ret = brcmf_sdio_chip_buscoreprep(sdiodev);
561  if (ret != 0)
562  goto err;
563 
564  ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
565  if (ret != 0)
566  goto err;
567 
568  brcmf_sdio_chip_buscoresetup(sdiodev, ci);
569 
570  brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
571  0, NULL);
572  brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
573  0, NULL);
574 
575  *ci_ptr = ci;
576  return 0;
577 
578 err:
579  kfree(ci);
580  return ret;
581 }
582 
583 void
584 brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
585 {
586  brcmf_dbg(TRACE, "Enter\n");
587 
588  kfree(*ci_ptr);
589  *ci_ptr = NULL;
590 }
591 
592 static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
593 {
594  const char *fmt;
595 
596  fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
597  snprintf(buf, len, fmt, chipid);
598  return buf;
599 }
600 
601 void
603  struct chip_info *ci, u32 drivestrength)
604 {
605  struct sdiod_drive_str *str_tab = NULL;
606  u32 str_mask = 0;
607  u32 str_shift = 0;
608  char chn[8];
609  u32 base = ci->c_inf[0].base;
610 
611  if (!(ci->c_inf[0].caps & CC_CAP_PMU))
612  return;
613 
614  switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
616  str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab1_1v8;
617  str_mask = 0x00003800;
618  str_shift = 11;
619  break;
620  default:
621  brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
622  brcmf_sdio_chip_name(ci->chip, chn, 8),
623  ci->chiprev, ci->pmurev);
624  break;
625  }
626 
627  if (str_tab != NULL) {
628  u32 drivestrength_sel = 0;
629  u32 cc_data_temp;
630  int i;
631 
632  for (i = 0; str_tab[i].strength != 0; i++) {
633  if (drivestrength >= str_tab[i].strength) {
634  drivestrength_sel = str_tab[i].sel;
635  break;
636  }
637  }
638 
639  brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
640  1, NULL);
641  cc_data_temp =
642  brcmf_sdio_regrl(sdiodev,
643  CORE_CC_REG(base, chipcontrol_addr),
644  NULL);
645  cc_data_temp &= ~str_mask;
646  drivestrength_sel <<= str_shift;
647  cc_data_temp |= drivestrength_sel;
648  brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
649  cc_data_temp, NULL);
650 
651  brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
652  drivestrength, cc_data_temp);
653  }
654 }