diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index 2827af28f79c..e2d5aa509b4c 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -485,6 +485,8 @@ static int dhdsdio_download_code_array(struct dhd_bus *bus); static void dhdsdio_chip_disablecore(bcmsdh_info_t *sdh, u32 corebase); static int dhdsdio_chip_attach(struct dhd_bus *bus, void *regs); static void dhdsdio_chip_resetcore(bcmsdh_info_t *sdh, u32 corebase); +static void dhdsdio_sdiod_drive_strength_init(struct dhd_bus *bus, + u32 drivestrength); static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) { @@ -2292,7 +2294,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, u32 actionid, case IOV_SVAL(IOV_SDIOD_DRIVE): dhd_sdiod_drive_strength = int_val; - si_sdiod_drive_strength_init(bus->sih, + dhdsdio_sdiod_drive_strength_init(bus, dhd_sdiod_drive_strength); break; @@ -5270,7 +5272,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, void *sdh, void *regsva, u16 devid) goto fail; } - si_sdiod_drive_strength_init(bus->sih, dhd_sdiod_drive_strength); + dhdsdio_sdiod_drive_strength_init(bus, dhd_sdiod_drive_strength); /* Get info on the ARM and SOCRAM cores... */ if (!DHD_NOPMU(bus)) { @@ -6316,3 +6318,111 @@ dhdsdio_chip_resetcore(bcmsdh_info_t *sdh, u32 corebase) (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); udelay(1); } + +/* SDIO Pad drive strength to select value mappings */ +struct sdiod_drive_str { + u8 strength; /* Pad Drive Strength in mA */ + u8 sel; /* Chip-specific select value */ +}; + +/* SDIO Drive Strength to sel value table for PMU Rev 1 */ +static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = { + { + 4, 0x2}, { + 2, 0x3}, { + 1, 0x0}, { + 0, 0x0} + }; + +/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ +static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = { + { + 12, 0x7}, { + 10, 0x6}, { + 8, 0x5}, { + 6, 0x4}, { + 4, 0x2}, { + 2, 0x1}, { + 0, 0x0} + }; + +/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ +static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = { + { + 32, 0x7}, { + 26, 0x6}, { + 22, 0x5}, { + 16, 0x4}, { + 12, 0x3}, { + 8, 0x2}, { + 4, 0x1}, { + 0, 0x0} + }; + +#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) + +static void +dhdsdio_sdiod_drive_strength_init(struct dhd_bus *bus, u32 drivestrength) { + struct sdiod_drive_str *str_tab = NULL; + u32 str_mask = 0; + u32 str_shift = 0; +#ifdef BCMDBG + char chn[8]; +#endif + + if (!(bus->ci->cccaps & CC_CAP_PMU)) + return; + + switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) { + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): + str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1; + str_mask = 0x30000000; + str_shift = 28; + break; + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): + str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): + str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3; + str_mask = 0x00003800; + str_shift = 11; + break; + default: + DHD_ERROR(("No SDIO Drive strength init" + "done for chip %s rev %d pmurev %d\n", + bcm_chipname(bus->ci->chip, chn, 8), + bus->ci->chiprev, bus->ci->pmurev)); + break; + } + + if (str_tab != NULL) { + u32 drivestrength_sel = 0; + u32 cc_data_temp; + int i; + + for (i = 0; str_tab[i].strength != 0; i++) { + if (drivestrength >= str_tab[i].strength) { + drivestrength_sel = str_tab[i].sel; + break; + } + } + + bcmsdh_reg_write(bus->sdh, + CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), + 4, 1); + cc_data_temp = bcmsdh_reg_read(bus->sdh, + CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4); + cc_data_temp &= ~str_mask; + drivestrength_sel <<= str_shift; + cc_data_temp |= drivestrength_sel; + bcmsdh_reg_write(bus->sdh, + CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), + 4, cc_data_temp); + + DHD_INFO(("SDIO: %dmA drive strength selected, set to 0x%08x\n", + drivestrength, cc_data_temp)); + } +}