diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/hndpmu.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/hndpmu.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c new file mode 100644 index 00000000000..b9586e40d0c --- /dev/null +++ b/drivers/net/wireless/bcmdhd/hndpmu.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * Misc utility routines for accessing PMU corerev specific features | ||
3 | * of the SiliconBackplane-based Broadcom chips. | ||
4 | * | ||
5 | * Copyright (C) 1999-2011, Broadcom Corporation | ||
6 | * | ||
7 | * Unless you and Broadcom execute a separate written software license | ||
8 | * agreement governing use of this software, this software is licensed to you | ||
9 | * under the terms of the GNU General Public License version 2 (the "GPL"), | ||
10 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the | ||
11 | * following added to such license: | ||
12 | * | ||
13 | * As a special exception, the copyright holders of this software give you | ||
14 | * permission to link this software with independent modules, and to copy and | ||
15 | * distribute the resulting executable under terms of your choice, provided that | ||
16 | * you also meet, for each linked independent module, the terms and conditions of | ||
17 | * the license of that module. An independent module is a module which is not | ||
18 | * derived from this software. The special exception does not apply to any | ||
19 | * modifications of the software. | ||
20 | * | ||
21 | * Notwithstanding the above, under no circumstances may you combine this | ||
22 | * software in any way with any other Broadcom software provided under a license | ||
23 | * other than the GPL, without Broadcom's express prior written consent. | ||
24 | * | ||
25 | * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 Exp $ | ||
26 | */ | ||
27 | |||
28 | #include <typedefs.h> | ||
29 | #include <bcmdefs.h> | ||
30 | #include <osl.h> | ||
31 | #include <bcmutils.h> | ||
32 | #include <siutils.h> | ||
33 | #include <bcmdevs.h> | ||
34 | #include <hndsoc.h> | ||
35 | #include <sbchipc.h> | ||
36 | #include <hndpmu.h> | ||
37 | |||
38 | #define PMU_ERROR(args) | ||
39 | |||
40 | #define PMU_MSG(args) | ||
41 | |||
42 | /* To check in verbose debugging messages not intended | ||
43 | * to be on except on private builds. | ||
44 | */ | ||
45 | #define PMU_NONE(args) | ||
46 | |||
47 | |||
48 | /* SDIO Pad drive strength to select value mappings. | ||
49 | * The last strength value in each table must be 0 (the tri-state value). | ||
50 | */ | ||
51 | typedef struct { | ||
52 | uint8 strength; /* Pad Drive Strength in mA */ | ||
53 | uint8 sel; /* Chip-specific select value */ | ||
54 | } sdiod_drive_str_t; | ||
55 | |||
56 | /* SDIO Drive Strength to sel value table for PMU Rev 1 */ | ||
57 | static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = { | ||
58 | {4, 0x2}, | ||
59 | {2, 0x3}, | ||
60 | {1, 0x0}, | ||
61 | {0, 0x0} }; | ||
62 | |||
63 | /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ | ||
64 | static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = { | ||
65 | {12, 0x7}, | ||
66 | {10, 0x6}, | ||
67 | {8, 0x5}, | ||
68 | {6, 0x4}, | ||
69 | {4, 0x2}, | ||
70 | {2, 0x1}, | ||
71 | {0, 0x0} }; | ||
72 | |||
73 | /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ | ||
74 | static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { | ||
75 | {32, 0x7}, | ||
76 | {26, 0x6}, | ||
77 | {22, 0x5}, | ||
78 | {16, 0x4}, | ||
79 | {12, 0x3}, | ||
80 | {8, 0x2}, | ||
81 | {4, 0x1}, | ||
82 | {0, 0x0} }; | ||
83 | |||
84 | /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ | ||
85 | static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { | ||
86 | {32, 0x6}, | ||
87 | {26, 0x7}, | ||
88 | {22, 0x4}, | ||
89 | {16, 0x5}, | ||
90 | {12, 0x2}, | ||
91 | {8, 0x3}, | ||
92 | {4, 0x0}, | ||
93 | {0, 0x1} }; | ||
94 | |||
95 | /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ | ||
96 | static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v2[] = { | ||
97 | {16, 0x3}, | ||
98 | {13, 0x2}, | ||
99 | {11, 0x1}, | ||
100 | {8, 0x0}, | ||
101 | {6, 0x7}, | ||
102 | {4, 0x6}, | ||
103 | {2, 0x5}, | ||
104 | {0, 0x4} }; | ||
105 | |||
106 | /* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ | ||
107 | static const sdiod_drive_str_t sdiod_drive_strength_tab4_2v5[] = { | ||
108 | {80, 0x5}, | ||
109 | {65, 0x4}, | ||
110 | {55, 0x7}, | ||
111 | {40, 0x6}, | ||
112 | {30, 0x1}, | ||
113 | {20, 0x0}, | ||
114 | {10, 0x3}, | ||
115 | {0, 0x2} }; | ||
116 | |||
117 | /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ | ||
118 | static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { | ||
119 | {6, 0x7}, | ||
120 | {5, 0x6}, | ||
121 | {4, 0x5}, | ||
122 | {3, 0x4}, | ||
123 | {2, 0x2}, | ||
124 | {1, 0x1}, | ||
125 | {0, 0x0} }; | ||
126 | |||
127 | /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ | ||
128 | static const sdiod_drive_str_t sdiod_drive_strength_tab5_3v3[] = { | ||
129 | {12, 0x7}, | ||
130 | {10, 0x6}, | ||
131 | {8, 0x5}, | ||
132 | {6, 0x4}, | ||
133 | {4, 0x2}, | ||
134 | {2, 0x1}, | ||
135 | {0, 0x0} }; | ||
136 | |||
137 | |||
138 | #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) | ||
139 | |||
140 | void | ||
141 | si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) | ||
142 | { | ||
143 | chipcregs_t *cc; | ||
144 | uint origidx, intr_val = 0; | ||
145 | sdiod_drive_str_t *str_tab = NULL; | ||
146 | uint32 str_mask = 0; | ||
147 | uint32 str_shift = 0; | ||
148 | |||
149 | if (!(sih->cccaps & CC_CAP_PMU)) { | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | /* Remember original core before switch to chipc */ | ||
154 | cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); | ||
155 | |||
156 | switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { | ||
157 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): | ||
158 | str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; | ||
159 | str_mask = 0x30000000; | ||
160 | str_shift = 28; | ||
161 | break; | ||
162 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): | ||
163 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): | ||
164 | case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): | ||
165 | str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; | ||
166 | str_mask = 0x00003800; | ||
167 | str_shift = 11; | ||
168 | break; | ||
169 | case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): | ||
170 | case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): | ||
171 | if (sih->pmurev == 8) { | ||
172 | str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; | ||
173 | } | ||
174 | else if (sih->pmurev == 11) { | ||
175 | str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; | ||
176 | } | ||
177 | str_mask = 0x00003800; | ||
178 | str_shift = 11; | ||
179 | break; | ||
180 | case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): | ||
181 | str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; | ||
182 | str_mask = 0x00003800; | ||
183 | str_shift = 11; | ||
184 | break; | ||
185 | case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): | ||
186 | str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; | ||
187 | str_mask = 0x00003800; | ||
188 | str_shift = 11; | ||
189 | break; | ||
190 | default: | ||
191 | PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", | ||
192 | bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); | ||
193 | |||
194 | break; | ||
195 | } | ||
196 | |||
197 | if (str_tab != NULL) { | ||
198 | uint32 cc_data_temp; | ||
199 | int i; | ||
200 | |||
201 | /* Pick the lowest available drive strength equal or greater than the | ||
202 | * requested strength. Drive strength of 0 requests tri-state. | ||
203 | */ | ||
204 | for (i = 0; drivestrength < str_tab[i].strength; i++) | ||
205 | ; | ||
206 | |||
207 | if (i > 0 && drivestrength > str_tab[i].strength) | ||
208 | i--; | ||
209 | |||
210 | W_REG(osh, &cc->chipcontrol_addr, 1); | ||
211 | cc_data_temp = R_REG(osh, &cc->chipcontrol_data); | ||
212 | cc_data_temp &= ~str_mask; | ||
213 | cc_data_temp |= str_tab[i].sel << str_shift; | ||
214 | W_REG(osh, &cc->chipcontrol_data, cc_data_temp); | ||
215 | |||
216 | PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", | ||
217 | drivestrength, str_tab[i].strength)); | ||
218 | } | ||
219 | |||
220 | /* Return to original core */ | ||
221 | si_restore_core(sih, origidx, intr_val); | ||
222 | } | ||