HTC Vision (and others) have a Broadcom BCM4329 chip-set for WiFi/Bluetooth/FM-rx...
[bootloader-ap.git] / drivers / net / wireless / bcm4329 / hndpmu.c
diff --git a/drivers/net/wireless/bcm4329/hndpmu.c b/drivers/net/wireless/bcm4329/hndpmu.c
new file mode 100644 (file)
index 0000000..25712ac
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Misc utility routines for accessing PMU corerev specific features
+ * of the SiliconBackplane-based Broadcom chips.
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: hndpmu.c,v 1.95.2.17.4.11.2.50 2009/10/26 14:45:51 Exp $
+ */
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <bcmdevs.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <hndpmu.h>
+
+/* debug/trace */
+#define        PMU_ERROR(args)
+
+#define        PMU_MSG(args)
+
+
+/* SDIO Pad drive strength to select value mappings */
+typedef struct {
+       uint8 strength;                 /* Pad Drive Strength in mA */
+       uint8 sel;                      /* Chip-specific select value */
+} sdiod_drive_str_t;
+
+/* SDIO Drive Strength to sel value table for PMU Rev 1 */
+static const sdiod_drive_str_t 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 sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
+       {12, 0x7},
+       {10, 0x6},
+       {8, 0x5},
+       {6, 0x4},
+       {4, 0x2},
+       {2, 0x1},
+       {0, 0x0} };
+
+#define SDIOD_DRVSTR_KEY(chip, pmu)    (((chip) << 16) | (pmu))
+
+void
+si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
+{
+       chipcregs_t *cc;
+       uint origidx, intr_val = 0;
+       sdiod_drive_str_t *str_tab = NULL;
+       uint32 str_mask = 0;
+       uint32 str_shift = 0;
+
+       if (!(sih->cccaps & CC_CAP_PMU)) {
+               return;
+       }
+
+       /* Remember original core before switch to chipc */
+       cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
+
+       switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) {
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+               str_tab = (sdiod_drive_str_t *)&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):
+       case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
+               str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
+
+       default:
+               PMU_MSG(("No SDIO Drive strength init done for chip %x rev %d pmurev %d\n",
+                        sih->chip, sih->chiprev, sih->pmurev));
+
+               break;
+       }
+
+       if (str_tab != NULL) {
+               uint32 drivestrength_sel = 0;
+               uint32 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;
+                       }
+               }
+
+               W_REG(osh, &cc->chipcontrol_addr, 1);
+               cc_data_temp = R_REG(osh, &cc->chipcontrol_data);
+               cc_data_temp &= ~str_mask;
+               drivestrength_sel <<= str_shift;
+               cc_data_temp |= drivestrength_sel;
+               W_REG(osh, &cc->chipcontrol_data, cc_data_temp);
+
+               PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n",
+                        drivestrength, cc_data_temp));
+       }
+
+       /* Return to original core */
+       si_restore_core(sih, origidx, intr_val);
+}