2 * Sonics Silicon Backplane
3 * Broadcom ChipCommon Power Management Unit driver
5 * Copyright 2009, Michael Buesch <m@bues.ch>
6 * Copyright 2007, Broadcom Corporation
8 * Licensed under the GNU/GPL. See COPYING for details.
11 #include <linux/ssb/ssb.h>
12 #include <linux/ssb/ssb_regs.h>
13 #include <linux/ssb/ssb_driver_chipcommon.h>
14 #include <linux/delay.h>
15 #include <linux/export.h>
17 #include "ssb_private.h"
19 static u32
ssb_chipco_pll_read(struct ssb_chipcommon
*cc
, u32 offset
)
21 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, offset
);
22 return chipco_read32(cc
, SSB_CHIPCO_PLLCTL_DATA
);
25 static void ssb_chipco_pll_write(struct ssb_chipcommon
*cc
,
26 u32 offset
, u32 value
)
28 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, offset
);
29 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_DATA
, value
);
32 static void ssb_chipco_regctl_maskset(struct ssb_chipcommon
*cc
,
33 u32 offset
, u32 mask
, u32 set
)
37 chipco_read32(cc
, SSB_CHIPCO_REGCTL_ADDR
);
38 chipco_write32(cc
, SSB_CHIPCO_REGCTL_ADDR
, offset
);
39 chipco_read32(cc
, SSB_CHIPCO_REGCTL_ADDR
);
40 value
= chipco_read32(cc
, SSB_CHIPCO_REGCTL_DATA
);
43 chipco_write32(cc
, SSB_CHIPCO_REGCTL_DATA
, value
);
44 chipco_read32(cc
, SSB_CHIPCO_REGCTL_DATA
);
47 struct pmu0_plltab_entry
{
48 u16 freq
; /* Crystal frequency in kHz.*/
49 u8 xf
; /* Crystal frequency value for PMU control */
54 static const struct pmu0_plltab_entry pmu0_plltab
[] = {
55 { .freq
= 12000, .xf
= 1, .wb_int
= 73, .wb_frac
= 349525, },
56 { .freq
= 13000, .xf
= 2, .wb_int
= 67, .wb_frac
= 725937, },
57 { .freq
= 14400, .xf
= 3, .wb_int
= 61, .wb_frac
= 116508, },
58 { .freq
= 15360, .xf
= 4, .wb_int
= 57, .wb_frac
= 305834, },
59 { .freq
= 16200, .xf
= 5, .wb_int
= 54, .wb_frac
= 336579, },
60 { .freq
= 16800, .xf
= 6, .wb_int
= 52, .wb_frac
= 399457, },
61 { .freq
= 19200, .xf
= 7, .wb_int
= 45, .wb_frac
= 873813, },
62 { .freq
= 19800, .xf
= 8, .wb_int
= 44, .wb_frac
= 466033, },
63 { .freq
= 20000, .xf
= 9, .wb_int
= 44, .wb_frac
= 0, },
64 { .freq
= 25000, .xf
= 10, .wb_int
= 70, .wb_frac
= 419430, },
65 { .freq
= 26000, .xf
= 11, .wb_int
= 67, .wb_frac
= 725937, },
66 { .freq
= 30000, .xf
= 12, .wb_int
= 58, .wb_frac
= 699050, },
67 { .freq
= 38400, .xf
= 13, .wb_int
= 45, .wb_frac
= 873813, },
68 { .freq
= 40000, .xf
= 14, .wb_int
= 45, .wb_frac
= 0, },
70 #define SSB_PMU0_DEFAULT_XTALFREQ 20000
72 static const struct pmu0_plltab_entry
* pmu0_plltab_find_entry(u32 crystalfreq
)
74 const struct pmu0_plltab_entry
*e
;
77 for (i
= 0; i
< ARRAY_SIZE(pmu0_plltab
); i
++) {
79 if (e
->freq
== crystalfreq
)
86 /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
87 static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon
*cc
,
90 struct ssb_bus
*bus
= cc
->dev
->bus
;
91 const struct pmu0_plltab_entry
*e
= NULL
;
92 u32 pmuctl
, tmp
, pllctl
;
95 if ((bus
->chip_id
== 0x5354) && !crystalfreq
) {
96 /* The 5354 crystal freq is 25MHz */
100 e
= pmu0_plltab_find_entry(crystalfreq
);
102 e
= pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ
);
104 crystalfreq
= e
->freq
;
105 cc
->pmu
.crystalfreq
= e
->freq
;
107 /* Check if the PLL already is programmed to this frequency. */
108 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
109 if (((pmuctl
& SSB_CHIPCO_PMU_CTL_XTALFREQ
) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) == e
->xf
) {
110 /* We're already there... */
114 ssb_printk(KERN_INFO PFX
"Programming PLL to %u.%03u MHz\n",
115 (crystalfreq
/ 1000), (crystalfreq
% 1000));
117 /* First turn the PLL off. */
118 switch (bus
->chip_id
) {
120 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
121 ~(1 << SSB_PMURES_4328_BB_PLL_PU
));
122 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
123 ~(1 << SSB_PMURES_4328_BB_PLL_PU
));
126 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
127 ~(1 << SSB_PMURES_5354_BB_PLL_PU
));
128 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
129 ~(1 << SSB_PMURES_5354_BB_PLL_PU
));
134 for (i
= 1500; i
; i
--) {
135 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
136 if (!(tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
))
140 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
141 if (tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
)
142 ssb_printk(KERN_EMERG PFX
"Failed to turn the PLL off!\n");
144 /* Set PDIV in PLL control 0. */
145 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL0
);
146 if (crystalfreq
>= SSB_PMU0_PLLCTL0_PDIV_FREQ
)
147 pllctl
|= SSB_PMU0_PLLCTL0_PDIV_MSK
;
149 pllctl
&= ~SSB_PMU0_PLLCTL0_PDIV_MSK
;
150 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL0
, pllctl
);
152 /* Set WILD in PLL control 1. */
153 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL1
);
154 pllctl
&= ~SSB_PMU0_PLLCTL1_STOPMOD
;
155 pllctl
&= ~(SSB_PMU0_PLLCTL1_WILD_IMSK
| SSB_PMU0_PLLCTL1_WILD_FMSK
);
156 pllctl
|= ((u32
)e
->wb_int
<< SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT
) & SSB_PMU0_PLLCTL1_WILD_IMSK
;
157 pllctl
|= ((u32
)e
->wb_frac
<< SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT
) & SSB_PMU0_PLLCTL1_WILD_FMSK
;
159 pllctl
|= SSB_PMU0_PLLCTL1_STOPMOD
;
160 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL1
, pllctl
);
162 /* Set WILD in PLL control 2. */
163 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU0_PLLCTL2
);
164 pllctl
&= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI
;
165 pllctl
|= (((u32
)e
->wb_int
>> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT
) & SSB_PMU0_PLLCTL2_WILD_IMSKHI
;
166 ssb_chipco_pll_write(cc
, SSB_PMU0_PLLCTL2
, pllctl
);
168 /* Set the crystalfrequency and the divisor. */
169 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
170 pmuctl
&= ~SSB_CHIPCO_PMU_CTL_ILP_DIV
;
171 pmuctl
|= (((crystalfreq
+ 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT
)
172 & SSB_CHIPCO_PMU_CTL_ILP_DIV
;
173 pmuctl
&= ~SSB_CHIPCO_PMU_CTL_XTALFREQ
;
174 pmuctl
|= ((u32
)e
->xf
<< SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) & SSB_CHIPCO_PMU_CTL_XTALFREQ
;
175 chipco_write32(cc
, SSB_CHIPCO_PMU_CTL
, pmuctl
);
178 struct pmu1_plltab_entry
{
179 u16 freq
; /* Crystal frequency in kHz.*/
180 u8 xf
; /* Crystal frequency value for PMU control */
187 static const struct pmu1_plltab_entry pmu1_plltab
[] = {
188 { .freq
= 12000, .xf
= 1, .p1div
= 3, .p2div
= 22, .ndiv_int
= 0x9, .ndiv_frac
= 0xFFFFEF, },
189 { .freq
= 13000, .xf
= 2, .p1div
= 1, .p2div
= 6, .ndiv_int
= 0xb, .ndiv_frac
= 0x483483, },
190 { .freq
= 14400, .xf
= 3, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0xa, .ndiv_frac
= 0x1C71C7, },
191 { .freq
= 15360, .xf
= 4, .p1div
= 1, .p2div
= 5, .ndiv_int
= 0xb, .ndiv_frac
= 0x755555, },
192 { .freq
= 16200, .xf
= 5, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0x5, .ndiv_frac
= 0x6E9E06, },
193 { .freq
= 16800, .xf
= 6, .p1div
= 1, .p2div
= 10, .ndiv_int
= 0x5, .ndiv_frac
= 0x3CF3CF, },
194 { .freq
= 19200, .xf
= 7, .p1div
= 1, .p2div
= 9, .ndiv_int
= 0x5, .ndiv_frac
= 0x17B425, },
195 { .freq
= 19800, .xf
= 8, .p1div
= 1, .p2div
= 11, .ndiv_int
= 0x4, .ndiv_frac
= 0xA57EB, },
196 { .freq
= 20000, .xf
= 9, .p1div
= 1, .p2div
= 11, .ndiv_int
= 0x4, .ndiv_frac
= 0, },
197 { .freq
= 24000, .xf
= 10, .p1div
= 3, .p2div
= 11, .ndiv_int
= 0xa, .ndiv_frac
= 0, },
198 { .freq
= 25000, .xf
= 11, .p1div
= 5, .p2div
= 16, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
199 { .freq
= 26000, .xf
= 12, .p1div
= 1, .p2div
= 2, .ndiv_int
= 0x10, .ndiv_frac
= 0xEC4EC4, },
200 { .freq
= 30000, .xf
= 13, .p1div
= 3, .p2div
= 8, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
201 { .freq
= 38400, .xf
= 14, .p1div
= 1, .p2div
= 5, .ndiv_int
= 0x4, .ndiv_frac
= 0x955555, },
202 { .freq
= 40000, .xf
= 15, .p1div
= 1, .p2div
= 2, .ndiv_int
= 0xb, .ndiv_frac
= 0, },
205 #define SSB_PMU1_DEFAULT_XTALFREQ 15360
207 static const struct pmu1_plltab_entry
* pmu1_plltab_find_entry(u32 crystalfreq
)
209 const struct pmu1_plltab_entry
*e
;
212 for (i
= 0; i
< ARRAY_SIZE(pmu1_plltab
); i
++) {
214 if (e
->freq
== crystalfreq
)
221 /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
222 static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon
*cc
,
225 struct ssb_bus
*bus
= cc
->dev
->bus
;
226 const struct pmu1_plltab_entry
*e
= NULL
;
227 u32 buffer_strength
= 0;
228 u32 tmp
, pllctl
, pmuctl
;
231 if (bus
->chip_id
== 0x4312) {
232 /* We do not touch the BCM4312 PLL and assume
233 * the default crystal settings work out-of-the-box. */
234 cc
->pmu
.crystalfreq
= 20000;
239 e
= pmu1_plltab_find_entry(crystalfreq
);
241 e
= pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ
);
243 crystalfreq
= e
->freq
;
244 cc
->pmu
.crystalfreq
= e
->freq
;
246 /* Check if the PLL already is programmed to this frequency. */
247 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
248 if (((pmuctl
& SSB_CHIPCO_PMU_CTL_XTALFREQ
) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) == e
->xf
) {
249 /* We're already there... */
253 ssb_printk(KERN_INFO PFX
"Programming PLL to %u.%03u MHz\n",
254 (crystalfreq
/ 1000), (crystalfreq
% 1000));
256 /* First turn the PLL off. */
257 switch (bus
->chip_id
) {
259 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
,
260 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU
) |
261 (1 << SSB_PMURES_4325_HT_AVAIL
)));
262 chipco_mask32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
,
263 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU
) |
264 (1 << SSB_PMURES_4325_HT_AVAIL
)));
265 /* Adjust the BBPLL to 2 on all channels later. */
266 buffer_strength
= 0x222222;
271 for (i
= 1500; i
; i
--) {
272 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
273 if (!(tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
))
277 tmp
= chipco_read32(cc
, SSB_CHIPCO_CLKCTLST
);
278 if (tmp
& SSB_CHIPCO_CLKCTLST_HAVEHT
)
279 ssb_printk(KERN_EMERG PFX
"Failed to turn the PLL off!\n");
281 /* Set p1div and p2div. */
282 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL0
);
283 pllctl
&= ~(SSB_PMU1_PLLCTL0_P1DIV
| SSB_PMU1_PLLCTL0_P2DIV
);
284 pllctl
|= ((u32
)e
->p1div
<< SSB_PMU1_PLLCTL0_P1DIV_SHIFT
) & SSB_PMU1_PLLCTL0_P1DIV
;
285 pllctl
|= ((u32
)e
->p2div
<< SSB_PMU1_PLLCTL0_P2DIV_SHIFT
) & SSB_PMU1_PLLCTL0_P2DIV
;
286 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL0
, pllctl
);
288 /* Set ndiv int and ndiv mode */
289 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL2
);
290 pllctl
&= ~(SSB_PMU1_PLLCTL2_NDIVINT
| SSB_PMU1_PLLCTL2_NDIVMODE
);
291 pllctl
|= ((u32
)e
->ndiv_int
<< SSB_PMU1_PLLCTL2_NDIVINT_SHIFT
) & SSB_PMU1_PLLCTL2_NDIVINT
;
292 pllctl
|= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT
) & SSB_PMU1_PLLCTL2_NDIVMODE
;
293 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL2
, pllctl
);
296 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL3
);
297 pllctl
&= ~SSB_PMU1_PLLCTL3_NDIVFRAC
;
298 pllctl
|= ((u32
)e
->ndiv_frac
<< SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT
) & SSB_PMU1_PLLCTL3_NDIVFRAC
;
299 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL3
, pllctl
);
301 /* Change the drive strength, if required. */
302 if (buffer_strength
) {
303 pllctl
= ssb_chipco_pll_read(cc
, SSB_PMU1_PLLCTL5
);
304 pllctl
&= ~SSB_PMU1_PLLCTL5_CLKDRV
;
305 pllctl
|= (buffer_strength
<< SSB_PMU1_PLLCTL5_CLKDRV_SHIFT
) & SSB_PMU1_PLLCTL5_CLKDRV
;
306 ssb_chipco_pll_write(cc
, SSB_PMU1_PLLCTL5
, pllctl
);
309 /* Tune the crystalfreq and the divisor. */
310 pmuctl
= chipco_read32(cc
, SSB_CHIPCO_PMU_CTL
);
311 pmuctl
&= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV
| SSB_CHIPCO_PMU_CTL_XTALFREQ
);
312 pmuctl
|= ((((u32
)e
->freq
+ 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT
)
313 & SSB_CHIPCO_PMU_CTL_ILP_DIV
;
314 pmuctl
|= ((u32
)e
->xf
<< SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT
) & SSB_CHIPCO_PMU_CTL_XTALFREQ
;
315 chipco_write32(cc
, SSB_CHIPCO_PMU_CTL
, pmuctl
);
318 static void ssb_pmu_pll_init(struct ssb_chipcommon
*cc
)
320 struct ssb_bus
*bus
= cc
->dev
->bus
;
321 u32 crystalfreq
= 0; /* in kHz. 0 = keep default freq. */
323 if (bus
->bustype
== SSB_BUSTYPE_SSB
) {
324 /* TODO: The user may override the crystal frequency. */
327 switch (bus
->chip_id
) {
330 ssb_pmu1_pllinit_r0(cc
, crystalfreq
);
334 ssb_pmu0_pllinit_r0(cc
, crystalfreq
);
337 if (cc
->pmu
.rev
== 2) {
338 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_ADDR
, 0x0000000A);
339 chipco_write32(cc
, SSB_CHIPCO_PLLCTL_DATA
, 0x380005C0);
343 ssb_printk(KERN_ERR PFX
344 "ERROR: PLL init unknown for device %04X\n",
349 struct pmu_res_updown_tab_entry
{
350 u8 resource
; /* The resource number */
351 u16 updown
; /* The updown value */
354 enum pmu_res_depend_tab_task
{
360 struct pmu_res_depend_tab_entry
{
361 u8 resource
; /* The resource number */
362 u8 task
; /* SET | ADD | REMOVE */
363 u32 depend
; /* The depend mask */
366 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0
[] = {
367 { .resource
= SSB_PMURES_4328_EXT_SWITCHER_PWM
, .updown
= 0x0101, },
368 { .resource
= SSB_PMURES_4328_BB_SWITCHER_PWM
, .updown
= 0x1F01, },
369 { .resource
= SSB_PMURES_4328_BB_SWITCHER_BURST
, .updown
= 0x010F, },
370 { .resource
= SSB_PMURES_4328_BB_EXT_SWITCHER_BURST
, .updown
= 0x0101, },
371 { .resource
= SSB_PMURES_4328_ILP_REQUEST
, .updown
= 0x0202, },
372 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_PWM
, .updown
= 0x0F01, },
373 { .resource
= SSB_PMURES_4328_RADIO_SWITCHER_BURST
, .updown
= 0x0F01, },
374 { .resource
= SSB_PMURES_4328_ROM_SWITCH
, .updown
= 0x0101, },
375 { .resource
= SSB_PMURES_4328_PA_REF_LDO
, .updown
= 0x0F01, },
376 { .resource
= SSB_PMURES_4328_RADIO_LDO
, .updown
= 0x0F01, },
377 { .resource
= SSB_PMURES_4328_AFE_LDO
, .updown
= 0x0F01, },
378 { .resource
= SSB_PMURES_4328_PLL_LDO
, .updown
= 0x0F01, },
379 { .resource
= SSB_PMURES_4328_BG_FILTBYP
, .updown
= 0x0101, },
380 { .resource
= SSB_PMURES_4328_TX_FILTBYP
, .updown
= 0x0101, },
381 { .resource
= SSB_PMURES_4328_RX_FILTBYP
, .updown
= 0x0101, },
382 { .resource
= SSB_PMURES_4328_XTAL_PU
, .updown
= 0x0101, },
383 { .resource
= SSB_PMURES_4328_XTAL_EN
, .updown
= 0xA001, },
384 { .resource
= SSB_PMURES_4328_BB_PLL_FILTBYP
, .updown
= 0x0101, },
385 { .resource
= SSB_PMURES_4328_RF_PLL_FILTBYP
, .updown
= 0x0101, },
386 { .resource
= SSB_PMURES_4328_BB_PLL_PU
, .updown
= 0x0701, },
389 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0
[] = {
391 /* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */
392 .resource
= SSB_PMURES_4328_ILP_REQUEST
,
393 .task
= PMU_RES_DEP_SET
,
394 .depend
= ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
395 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
)),
399 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0
[] = {
400 { .resource
= SSB_PMURES_4325_XTAL_PU
, .updown
= 0x1501, },
403 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0
[] = {
405 /* Adjust HT-Available dependencies. */
406 .resource
= SSB_PMURES_4325_HT_AVAIL
,
407 .task
= PMU_RES_DEP_ADD
,
408 .depend
= ((1 << SSB_PMURES_4325_RX_PWRSW_PU
) |
409 (1 << SSB_PMURES_4325_TX_PWRSW_PU
) |
410 (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU
) |
411 (1 << SSB_PMURES_4325_AFE_PWRSW_PU
)),
415 static void ssb_pmu_resources_init(struct ssb_chipcommon
*cc
)
417 struct ssb_bus
*bus
= cc
->dev
->bus
;
418 u32 min_msk
= 0, max_msk
= 0;
420 const struct pmu_res_updown_tab_entry
*updown_tab
= NULL
;
421 unsigned int updown_tab_size
= 0;
422 const struct pmu_res_depend_tab_entry
*depend_tab
= NULL
;
423 unsigned int depend_tab_size
= 0;
425 switch (bus
->chip_id
) {
430 /* We keep the default settings:
436 /* Power OTP down later. */
437 min_msk
= (1 << SSB_PMURES_4325_CBUCK_BURST
) |
438 (1 << SSB_PMURES_4325_LNLDO2_PU
);
439 if (chipco_read32(cc
, SSB_CHIPCO_CHIPSTAT
) &
440 SSB_CHIPCO_CHST_4325_PMUTOP_2B
)
441 min_msk
|= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST
);
442 /* The PLL may turn on, if it decides so. */
444 updown_tab
= pmu_res_updown_tab_4325a0
;
445 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4325a0
);
446 depend_tab
= pmu_res_depend_tab_4325a0
;
447 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4325a0
);
450 min_msk
= (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM
) |
451 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM
) |
452 (1 << SSB_PMURES_4328_XTAL_EN
);
453 /* The PLL may turn on, if it decides so. */
455 updown_tab
= pmu_res_updown_tab_4328a0
;
456 updown_tab_size
= ARRAY_SIZE(pmu_res_updown_tab_4328a0
);
457 depend_tab
= pmu_res_depend_tab_4328a0
;
458 depend_tab_size
= ARRAY_SIZE(pmu_res_depend_tab_4328a0
);
461 /* The PLL may turn on, if it decides so. */
465 ssb_printk(KERN_ERR PFX
466 "ERROR: PMU resource config unknown for device %04X\n",
471 for (i
= 0; i
< updown_tab_size
; i
++) {
472 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
473 updown_tab
[i
].resource
);
474 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_UPDNTM
,
475 updown_tab
[i
].updown
);
479 for (i
= 0; i
< depend_tab_size
; i
++) {
480 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_TABSEL
,
481 depend_tab
[i
].resource
);
482 switch (depend_tab
[i
].task
) {
483 case PMU_RES_DEP_SET
:
484 chipco_write32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
485 depend_tab
[i
].depend
);
487 case PMU_RES_DEP_ADD
:
488 chipco_set32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
489 depend_tab
[i
].depend
);
491 case PMU_RES_DEP_REMOVE
:
492 chipco_mask32(cc
, SSB_CHIPCO_PMU_RES_DEPMSK
,
493 ~(depend_tab
[i
].depend
));
501 /* Set the resource masks. */
503 chipco_write32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, min_msk
);
505 chipco_write32(cc
, SSB_CHIPCO_PMU_MAXRES_MSK
, max_msk
);
508 /* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
509 void ssb_pmu_init(struct ssb_chipcommon
*cc
)
513 if (!(cc
->capabilities
& SSB_CHIPCO_CAP_PMU
))
516 pmucap
= chipco_read32(cc
, SSB_CHIPCO_PMU_CAP
);
517 cc
->pmu
.rev
= (pmucap
& SSB_CHIPCO_PMU_CAP_REVISION
);
519 ssb_dprintk(KERN_DEBUG PFX
"Found rev %u PMU (capabilities 0x%08X)\n",
520 cc
->pmu
.rev
, pmucap
);
522 if (cc
->pmu
.rev
== 1)
523 chipco_mask32(cc
, SSB_CHIPCO_PMU_CTL
,
524 ~SSB_CHIPCO_PMU_CTL_NOILPONW
);
526 chipco_set32(cc
, SSB_CHIPCO_PMU_CTL
,
527 SSB_CHIPCO_PMU_CTL_NOILPONW
);
528 ssb_pmu_pll_init(cc
);
529 ssb_pmu_resources_init(cc
);
532 void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon
*cc
,
533 enum ssb_pmu_ldo_volt_id id
, u32 voltage
)
535 struct ssb_bus
*bus
= cc
->dev
->bus
;
536 u32 addr
, shift
, mask
;
538 switch (bus
->chip_id
) {
568 if (SSB_WARN_ON(id
!= LDO_PAREF
))
578 ssb_chipco_regctl_maskset(cc
, addr
, ~(mask
<< shift
),
579 (voltage
& mask
) << shift
);
582 void ssb_pmu_set_ldo_paref(struct ssb_chipcommon
*cc
, bool on
)
584 struct ssb_bus
*bus
= cc
->dev
->bus
;
587 switch (bus
->chip_id
) {
589 ldo
= SSB_PMURES_4312_PA_REF_LDO
;
592 ldo
= SSB_PMURES_4328_PA_REF_LDO
;
595 ldo
= SSB_PMURES_5354_PA_REF_LDO
;
602 chipco_set32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, 1 << ldo
);
604 chipco_mask32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
, ~(1 << ldo
));
605 chipco_read32(cc
, SSB_CHIPCO_PMU_MINRES_MSK
); //SPEC FIXME found via mmiotrace - dummy read?
608 EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage
);
609 EXPORT_SYMBOL(ssb_pmu_set_ldo_paref
);