~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to drivers/ssb/driver_chipcommon_pmu.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Sonics Silicon Backplane
 
3
 * Broadcom ChipCommon Power Management Unit driver
 
4
 *
 
5
 * Copyright 2009, Michael Buesch <mb@bu3sch.de>
 
6
 * Copyright 2007, Broadcom Corporation
 
7
 *
 
8
 * Licensed under the GNU/GPL. See COPYING for details.
 
9
 */
 
10
 
 
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
 
 
16
#include "ssb_private.h"
 
17
 
 
18
static u32 ssb_chipco_pll_read(struct ssb_chipcommon *cc, u32 offset)
 
19
{
 
20
        chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
 
21
        return chipco_read32(cc, SSB_CHIPCO_PLLCTL_DATA);
 
22
}
 
23
 
 
24
static void ssb_chipco_pll_write(struct ssb_chipcommon *cc,
 
25
                                 u32 offset, u32 value)
 
26
{
 
27
        chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
 
28
        chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value);
 
29
}
 
30
 
 
31
static void ssb_chipco_regctl_maskset(struct ssb_chipcommon *cc,
 
32
                                   u32 offset, u32 mask, u32 set)
 
33
{
 
34
        u32 value;
 
35
 
 
36
        chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
 
37
        chipco_write32(cc, SSB_CHIPCO_REGCTL_ADDR, offset);
 
38
        chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
 
39
        value = chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
 
40
        value &= mask;
 
41
        value |= set;
 
42
        chipco_write32(cc, SSB_CHIPCO_REGCTL_DATA, value);
 
43
        chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
 
44
}
 
45
 
 
46
struct pmu0_plltab_entry {
 
47
        u16 freq;       /* Crystal frequency in kHz.*/
 
48
        u8 xf;          /* Crystal frequency value for PMU control */
 
49
        u8 wb_int;
 
50
        u32 wb_frac;
 
51
};
 
52
 
 
53
static const struct pmu0_plltab_entry pmu0_plltab[] = {
 
54
        { .freq = 12000, .xf =  1, .wb_int = 73, .wb_frac = 349525, },
 
55
        { .freq = 13000, .xf =  2, .wb_int = 67, .wb_frac = 725937, },
 
56
        { .freq = 14400, .xf =  3, .wb_int = 61, .wb_frac = 116508, },
 
57
        { .freq = 15360, .xf =  4, .wb_int = 57, .wb_frac = 305834, },
 
58
        { .freq = 16200, .xf =  5, .wb_int = 54, .wb_frac = 336579, },
 
59
        { .freq = 16800, .xf =  6, .wb_int = 52, .wb_frac = 399457, },
 
60
        { .freq = 19200, .xf =  7, .wb_int = 45, .wb_frac = 873813, },
 
61
        { .freq = 19800, .xf =  8, .wb_int = 44, .wb_frac = 466033, },
 
62
        { .freq = 20000, .xf =  9, .wb_int = 44, .wb_frac = 0,      },
 
63
        { .freq = 25000, .xf = 10, .wb_int = 70, .wb_frac = 419430, },
 
64
        { .freq = 26000, .xf = 11, .wb_int = 67, .wb_frac = 725937, },
 
65
        { .freq = 30000, .xf = 12, .wb_int = 58, .wb_frac = 699050, },
 
66
        { .freq = 38400, .xf = 13, .wb_int = 45, .wb_frac = 873813, },
 
67
        { .freq = 40000, .xf = 14, .wb_int = 45, .wb_frac = 0,      },
 
68
};
 
69
#define SSB_PMU0_DEFAULT_XTALFREQ       20000
 
70
 
 
71
static const struct pmu0_plltab_entry * pmu0_plltab_find_entry(u32 crystalfreq)
 
72
{
 
73
        const struct pmu0_plltab_entry *e;
 
74
        unsigned int i;
 
75
 
 
76
        for (i = 0; i < ARRAY_SIZE(pmu0_plltab); i++) {
 
77
                e = &pmu0_plltab[i];
 
78
                if (e->freq == crystalfreq)
 
79
                        return e;
 
80
        }
 
81
 
 
82
        return NULL;
 
83
}
 
84
 
 
85
/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
 
86
static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
 
87
                                u32 crystalfreq)
 
88
{
 
89
        struct ssb_bus *bus = cc->dev->bus;
 
90
        const struct pmu0_plltab_entry *e = NULL;
 
91
        u32 pmuctl, tmp, pllctl;
 
92
        unsigned int i;
 
93
 
 
94
        if ((bus->chip_id == 0x5354) && !crystalfreq) {
 
95
                /* The 5354 crystal freq is 25MHz */
 
96
                crystalfreq = 25000;
 
97
        }
 
98
        if (crystalfreq)
 
99
                e = pmu0_plltab_find_entry(crystalfreq);
 
100
        if (!e)
 
101
                e = pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ);
 
102
        BUG_ON(!e);
 
103
        crystalfreq = e->freq;
 
104
        cc->pmu.crystalfreq = e->freq;
 
105
 
 
106
        /* Check if the PLL already is programmed to this frequency. */
 
107
        pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
 
108
        if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
 
109
                /* We're already there... */
 
110
                return;
 
111
        }
 
112
 
 
113
        ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
 
114
                   (crystalfreq / 1000), (crystalfreq % 1000));
 
115
 
 
116
        /* First turn the PLL off. */
 
117
        switch (bus->chip_id) {
 
118
        case 0x4328:
 
119
                chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
 
120
                              ~(1 << SSB_PMURES_4328_BB_PLL_PU));
 
121
                chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
 
122
                              ~(1 << SSB_PMURES_4328_BB_PLL_PU));
 
123
                break;
 
124
        case 0x5354:
 
125
                chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
 
126
                              ~(1 << SSB_PMURES_5354_BB_PLL_PU));
 
127
                chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
 
128
                              ~(1 << SSB_PMURES_5354_BB_PLL_PU));
 
129
                break;
 
130
        default:
 
131
                SSB_WARN_ON(1);
 
132
        }
 
133
        for (i = 1500; i; i--) {
 
134
                tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
 
135
                if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
 
136
                        break;
 
137
                udelay(10);
 
138
        }
 
139
        tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
 
140
        if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
 
141
                ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
 
142
 
 
143
        /* Set PDIV in PLL control 0. */
 
144
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0);
 
145
        if (crystalfreq >= SSB_PMU0_PLLCTL0_PDIV_FREQ)
 
146
                pllctl |= SSB_PMU0_PLLCTL0_PDIV_MSK;
 
147
        else
 
148
                pllctl &= ~SSB_PMU0_PLLCTL0_PDIV_MSK;
 
149
        ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL0, pllctl);
 
150
 
 
151
        /* Set WILD in PLL control 1. */
 
152
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL1);
 
153
        pllctl &= ~SSB_PMU0_PLLCTL1_STOPMOD;
 
154
        pllctl &= ~(SSB_PMU0_PLLCTL1_WILD_IMSK | SSB_PMU0_PLLCTL1_WILD_FMSK);
 
155
        pllctl |= ((u32)e->wb_int << SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_IMSK;
 
156
        pllctl |= ((u32)e->wb_frac << SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_FMSK;
 
157
        if (e->wb_frac == 0)
 
158
                pllctl |= SSB_PMU0_PLLCTL1_STOPMOD;
 
159
        ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL1, pllctl);
 
160
 
 
161
        /* Set WILD in PLL control 2. */
 
162
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL2);
 
163
        pllctl &= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI;
 
164
        pllctl |= (((u32)e->wb_int >> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT) & SSB_PMU0_PLLCTL2_WILD_IMSKHI;
 
165
        ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL2, pllctl);
 
166
 
 
167
        /* Set the crystalfrequency and the divisor. */
 
168
        pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
 
169
        pmuctl &= ~SSB_CHIPCO_PMU_CTL_ILP_DIV;
 
170
        pmuctl |= (((crystalfreq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
 
171
                        & SSB_CHIPCO_PMU_CTL_ILP_DIV;
 
172
        pmuctl &= ~SSB_CHIPCO_PMU_CTL_XTALFREQ;
 
173
        pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
 
174
        chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
 
175
}
 
176
 
 
177
struct pmu1_plltab_entry {
 
178
        u16 freq;       /* Crystal frequency in kHz.*/
 
179
        u8 xf;          /* Crystal frequency value for PMU control */
 
180
        u8 ndiv_int;
 
181
        u32 ndiv_frac;
 
182
        u8 p1div;
 
183
        u8 p2div;
 
184
};
 
185
 
 
186
static const struct pmu1_plltab_entry pmu1_plltab[] = {
 
187
        { .freq = 12000, .xf =  1, .p1div = 3, .p2div = 22, .ndiv_int =  0x9, .ndiv_frac = 0xFFFFEF, },
 
188
        { .freq = 13000, .xf =  2, .p1div = 1, .p2div =  6, .ndiv_int =  0xb, .ndiv_frac = 0x483483, },
 
189
        { .freq = 14400, .xf =  3, .p1div = 1, .p2div = 10, .ndiv_int =  0xa, .ndiv_frac = 0x1C71C7, },
 
190
        { .freq = 15360, .xf =  4, .p1div = 1, .p2div =  5, .ndiv_int =  0xb, .ndiv_frac = 0x755555, },
 
191
        { .freq = 16200, .xf =  5, .p1div = 1, .p2div = 10, .ndiv_int =  0x5, .ndiv_frac = 0x6E9E06, },
 
192
        { .freq = 16800, .xf =  6, .p1div = 1, .p2div = 10, .ndiv_int =  0x5, .ndiv_frac = 0x3CF3CF, },
 
193
        { .freq = 19200, .xf =  7, .p1div = 1, .p2div =  9, .ndiv_int =  0x5, .ndiv_frac = 0x17B425, },
 
194
        { .freq = 19800, .xf =  8, .p1div = 1, .p2div = 11, .ndiv_int =  0x4, .ndiv_frac = 0xA57EB,  },
 
195
        { .freq = 20000, .xf =  9, .p1div = 1, .p2div = 11, .ndiv_int =  0x4, .ndiv_frac = 0,        },
 
196
        { .freq = 24000, .xf = 10, .p1div = 3, .p2div = 11, .ndiv_int =  0xa, .ndiv_frac = 0,        },
 
197
        { .freq = 25000, .xf = 11, .p1div = 5, .p2div = 16, .ndiv_int =  0xb, .ndiv_frac = 0,        },
 
198
        { .freq = 26000, .xf = 12, .p1div = 1, .p2div =  2, .ndiv_int = 0x10, .ndiv_frac = 0xEC4EC4, },
 
199
        { .freq = 30000, .xf = 13, .p1div = 3, .p2div =  8, .ndiv_int =  0xb, .ndiv_frac = 0,        },
 
200
        { .freq = 38400, .xf = 14, .p1div = 1, .p2div =  5, .ndiv_int =  0x4, .ndiv_frac = 0x955555, },
 
201
        { .freq = 40000, .xf = 15, .p1div = 1, .p2div =  2, .ndiv_int =  0xb, .ndiv_frac = 0,        },
 
202
};
 
203
 
 
204
#define SSB_PMU1_DEFAULT_XTALFREQ       15360
 
205
 
 
206
static const struct pmu1_plltab_entry * pmu1_plltab_find_entry(u32 crystalfreq)
 
207
{
 
208
        const struct pmu1_plltab_entry *e;
 
209
        unsigned int i;
 
210
 
 
211
        for (i = 0; i < ARRAY_SIZE(pmu1_plltab); i++) {
 
212
                e = &pmu1_plltab[i];
 
213
                if (e->freq == crystalfreq)
 
214
                        return e;
 
215
        }
 
216
 
 
217
        return NULL;
 
218
}
 
219
 
 
220
/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
 
221
static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
 
222
                                u32 crystalfreq)
 
223
{
 
224
        struct ssb_bus *bus = cc->dev->bus;
 
225
        const struct pmu1_plltab_entry *e = NULL;
 
226
        u32 buffer_strength = 0;
 
227
        u32 tmp, pllctl, pmuctl;
 
228
        unsigned int i;
 
229
 
 
230
        if (bus->chip_id == 0x4312) {
 
231
                /* We do not touch the BCM4312 PLL and assume
 
232
                 * the default crystal settings work out-of-the-box. */
 
233
                cc->pmu.crystalfreq = 20000;
 
234
                return;
 
235
        }
 
236
 
 
237
        if (crystalfreq)
 
238
                e = pmu1_plltab_find_entry(crystalfreq);
 
239
        if (!e)
 
240
                e = pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ);
 
241
        BUG_ON(!e);
 
242
        crystalfreq = e->freq;
 
243
        cc->pmu.crystalfreq = e->freq;
 
244
 
 
245
        /* Check if the PLL already is programmed to this frequency. */
 
246
        pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
 
247
        if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
 
248
                /* We're already there... */
 
249
                return;
 
250
        }
 
251
 
 
252
        ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
 
253
                   (crystalfreq / 1000), (crystalfreq % 1000));
 
254
 
 
255
        /* First turn the PLL off. */
 
256
        switch (bus->chip_id) {
 
257
        case 0x4325:
 
258
                chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
 
259
                              ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
 
260
                                (1 << SSB_PMURES_4325_HT_AVAIL)));
 
261
                chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
 
262
                              ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
 
263
                                (1 << SSB_PMURES_4325_HT_AVAIL)));
 
264
                /* Adjust the BBPLL to 2 on all channels later. */
 
265
                buffer_strength = 0x222222;
 
266
                break;
 
267
        default:
 
268
                SSB_WARN_ON(1);
 
269
        }
 
270
        for (i = 1500; i; i--) {
 
271
                tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
 
272
                if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
 
273
                        break;
 
274
                udelay(10);
 
275
        }
 
276
        tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
 
277
        if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
 
278
                ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
 
279
 
 
280
        /* Set p1div and p2div. */
 
281
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
 
282
        pllctl &= ~(SSB_PMU1_PLLCTL0_P1DIV | SSB_PMU1_PLLCTL0_P2DIV);
 
283
        pllctl |= ((u32)e->p1div << SSB_PMU1_PLLCTL0_P1DIV_SHIFT) & SSB_PMU1_PLLCTL0_P1DIV;
 
284
        pllctl |= ((u32)e->p2div << SSB_PMU1_PLLCTL0_P2DIV_SHIFT) & SSB_PMU1_PLLCTL0_P2DIV;
 
285
        ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, pllctl);
 
286
 
 
287
        /* Set ndiv int and ndiv mode */
 
288
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL2);
 
289
        pllctl &= ~(SSB_PMU1_PLLCTL2_NDIVINT | SSB_PMU1_PLLCTL2_NDIVMODE);
 
290
        pllctl |= ((u32)e->ndiv_int << SSB_PMU1_PLLCTL2_NDIVINT_SHIFT) & SSB_PMU1_PLLCTL2_NDIVINT;
 
291
        pllctl |= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT) & SSB_PMU1_PLLCTL2_NDIVMODE;
 
292
        ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, pllctl);
 
293
 
 
294
        /* Set ndiv frac */
 
295
        pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL3);
 
296
        pllctl &= ~SSB_PMU1_PLLCTL3_NDIVFRAC;
 
297
        pllctl |= ((u32)e->ndiv_frac << SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT) & SSB_PMU1_PLLCTL3_NDIVFRAC;
 
298
        ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, pllctl);
 
299
 
 
300
        /* Change the drive strength, if required. */
 
301
        if (buffer_strength) {
 
302
                pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL5);
 
303
                pllctl &= ~SSB_PMU1_PLLCTL5_CLKDRV;
 
304
                pllctl |= (buffer_strength << SSB_PMU1_PLLCTL5_CLKDRV_SHIFT) & SSB_PMU1_PLLCTL5_CLKDRV;
 
305
                ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, pllctl);
 
306
        }
 
307
 
 
308
        /* Tune the crystalfreq and the divisor. */
 
309
        pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
 
310
        pmuctl &= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV | SSB_CHIPCO_PMU_CTL_XTALFREQ);
 
311
        pmuctl |= ((((u32)e->freq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
 
312
                        & SSB_CHIPCO_PMU_CTL_ILP_DIV;
 
313
        pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
 
314
        chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
 
315
}
 
316
 
 
317
static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
 
318
{
 
319
        struct ssb_bus *bus = cc->dev->bus;
 
320
        u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
 
321
 
 
322
        if (bus->bustype == SSB_BUSTYPE_SSB) {
 
323
                /* TODO: The user may override the crystal frequency. */
 
324
        }
 
325
 
 
326
        switch (bus->chip_id) {
 
327
        case 0x4312:
 
328
        case 0x4325:
 
329
                ssb_pmu1_pllinit_r0(cc, crystalfreq);
 
330
                break;
 
331
        case 0x4328:
 
332
        case 0x5354:
 
333
                ssb_pmu0_pllinit_r0(cc, crystalfreq);
 
334
                break;
 
335
        default:
 
336
                ssb_printk(KERN_ERR PFX
 
337
                           "ERROR: PLL init unknown for device %04X\n",
 
338
                           bus->chip_id);
 
339
        }
 
340
}
 
341
 
 
342
struct pmu_res_updown_tab_entry {
 
343
        u8 resource;    /* The resource number */
 
344
        u16 updown;     /* The updown value */
 
345
};
 
346
 
 
347
enum pmu_res_depend_tab_task {
 
348
        PMU_RES_DEP_SET = 1,
 
349
        PMU_RES_DEP_ADD,
 
350
        PMU_RES_DEP_REMOVE,
 
351
};
 
352
 
 
353
struct pmu_res_depend_tab_entry {
 
354
        u8 resource;    /* The resource number */
 
355
        u8 task;        /* SET | ADD | REMOVE */
 
356
        u32 depend;     /* The depend mask */
 
357
};
 
358
 
 
359
static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0[] = {
 
360
        { .resource = SSB_PMURES_4328_EXT_SWITCHER_PWM,         .updown = 0x0101, },
 
361
        { .resource = SSB_PMURES_4328_BB_SWITCHER_PWM,          .updown = 0x1F01, },
 
362
        { .resource = SSB_PMURES_4328_BB_SWITCHER_BURST,        .updown = 0x010F, },
 
363
        { .resource = SSB_PMURES_4328_BB_EXT_SWITCHER_BURST,    .updown = 0x0101, },
 
364
        { .resource = SSB_PMURES_4328_ILP_REQUEST,              .updown = 0x0202, },
 
365
        { .resource = SSB_PMURES_4328_RADIO_SWITCHER_PWM,       .updown = 0x0F01, },
 
366
        { .resource = SSB_PMURES_4328_RADIO_SWITCHER_BURST,     .updown = 0x0F01, },
 
367
        { .resource = SSB_PMURES_4328_ROM_SWITCH,               .updown = 0x0101, },
 
368
        { .resource = SSB_PMURES_4328_PA_REF_LDO,               .updown = 0x0F01, },
 
369
        { .resource = SSB_PMURES_4328_RADIO_LDO,                .updown = 0x0F01, },
 
370
        { .resource = SSB_PMURES_4328_AFE_LDO,                  .updown = 0x0F01, },
 
371
        { .resource = SSB_PMURES_4328_PLL_LDO,                  .updown = 0x0F01, },
 
372
        { .resource = SSB_PMURES_4328_BG_FILTBYP,               .updown = 0x0101, },
 
373
        { .resource = SSB_PMURES_4328_TX_FILTBYP,               .updown = 0x0101, },
 
374
        { .resource = SSB_PMURES_4328_RX_FILTBYP,               .updown = 0x0101, },
 
375
        { .resource = SSB_PMURES_4328_XTAL_PU,                  .updown = 0x0101, },
 
376
        { .resource = SSB_PMURES_4328_XTAL_EN,                  .updown = 0xA001, },
 
377
        { .resource = SSB_PMURES_4328_BB_PLL_FILTBYP,           .updown = 0x0101, },
 
378
        { .resource = SSB_PMURES_4328_RF_PLL_FILTBYP,           .updown = 0x0101, },
 
379
        { .resource = SSB_PMURES_4328_BB_PLL_PU,                .updown = 0x0701, },
 
380
};
 
381
 
 
382
static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0[] = {
 
383
        {
 
384
                /* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */
 
385
                .resource = SSB_PMURES_4328_ILP_REQUEST,
 
386
                .task = PMU_RES_DEP_SET,
 
387
                .depend = ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
 
388
                           (1 << SSB_PMURES_4328_BB_SWITCHER_PWM)),
 
389
        },
 
390
};
 
391
 
 
392
static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0[] = {
 
393
        { .resource = SSB_PMURES_4325_XTAL_PU,                  .updown = 0x1501, },
 
394
};
 
395
 
 
396
static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0[] = {
 
397
        {
 
398
                /* Adjust HT-Available dependencies. */
 
399
                .resource = SSB_PMURES_4325_HT_AVAIL,
 
400
                .task = PMU_RES_DEP_ADD,
 
401
                .depend = ((1 << SSB_PMURES_4325_RX_PWRSW_PU) |
 
402
                           (1 << SSB_PMURES_4325_TX_PWRSW_PU) |
 
403
                           (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU) |
 
404
                           (1 << SSB_PMURES_4325_AFE_PWRSW_PU)),
 
405
        },
 
406
};
 
407
 
 
408
static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
 
409
{
 
410
        struct ssb_bus *bus = cc->dev->bus;
 
411
        u32 min_msk = 0, max_msk = 0;
 
412
        unsigned int i;
 
413
        const struct pmu_res_updown_tab_entry *updown_tab = NULL;
 
414
        unsigned int updown_tab_size;
 
415
        const struct pmu_res_depend_tab_entry *depend_tab = NULL;
 
416
        unsigned int depend_tab_size;
 
417
 
 
418
        switch (bus->chip_id) {
 
419
        case 0x4312:
 
420
                /* We keep the default settings:
 
421
                 * min_msk = 0xCBB
 
422
                 * max_msk = 0x7FFFF
 
423
                 */
 
424
                break;
 
425
        case 0x4325:
 
426
                /* Power OTP down later. */
 
427
                min_msk = (1 << SSB_PMURES_4325_CBUCK_BURST) |
 
428
                          (1 << SSB_PMURES_4325_LNLDO2_PU);
 
429
                if (chipco_read32(cc, SSB_CHIPCO_CHIPSTAT) &
 
430
                    SSB_CHIPCO_CHST_4325_PMUTOP_2B)
 
431
                        min_msk |= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST);
 
432
                /* The PLL may turn on, if it decides so. */
 
433
                max_msk = 0xFFFFF;
 
434
                updown_tab = pmu_res_updown_tab_4325a0;
 
435
                updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4325a0);
 
436
                depend_tab = pmu_res_depend_tab_4325a0;
 
437
                depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4325a0);
 
438
                break;
 
439
        case 0x4328:
 
440
                min_msk = (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
 
441
                          (1 << SSB_PMURES_4328_BB_SWITCHER_PWM) |
 
442
                          (1 << SSB_PMURES_4328_XTAL_EN);
 
443
                /* The PLL may turn on, if it decides so. */
 
444
                max_msk = 0xFFFFF;
 
445
                updown_tab = pmu_res_updown_tab_4328a0;
 
446
                updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4328a0);
 
447
                depend_tab = pmu_res_depend_tab_4328a0;
 
448
                depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4328a0);
 
449
                break;
 
450
        case 0x5354:
 
451
                /* The PLL may turn on, if it decides so. */
 
452
                max_msk = 0xFFFFF;
 
453
                break;
 
454
        default:
 
455
                ssb_printk(KERN_ERR PFX
 
456
                           "ERROR: PMU resource config unknown for device %04X\n",
 
457
                           bus->chip_id);
 
458
        }
 
459
 
 
460
        if (updown_tab) {
 
461
                for (i = 0; i < updown_tab_size; i++) {
 
462
                        chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
 
463
                                       updown_tab[i].resource);
 
464
                        chipco_write32(cc, SSB_CHIPCO_PMU_RES_UPDNTM,
 
465
                                       updown_tab[i].updown);
 
466
                }
 
467
        }
 
468
        if (depend_tab) {
 
469
                for (i = 0; i < depend_tab_size; i++) {
 
470
                        chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
 
471
                                       depend_tab[i].resource);
 
472
                        switch (depend_tab[i].task) {
 
473
                        case PMU_RES_DEP_SET:
 
474
                                chipco_write32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
 
475
                                               depend_tab[i].depend);
 
476
                                break;
 
477
                        case PMU_RES_DEP_ADD:
 
478
                                chipco_set32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
 
479
                                             depend_tab[i].depend);
 
480
                                break;
 
481
                        case PMU_RES_DEP_REMOVE:
 
482
                                chipco_mask32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
 
483
                                              ~(depend_tab[i].depend));
 
484
                                break;
 
485
                        default:
 
486
                                SSB_WARN_ON(1);
 
487
                        }
 
488
                }
 
489
        }
 
490
 
 
491
        /* Set the resource masks. */
 
492
        if (min_msk)
 
493
                chipco_write32(cc, SSB_CHIPCO_PMU_MINRES_MSK, min_msk);
 
494
        if (max_msk)
 
495
                chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
 
496
}
 
497
 
 
498
void ssb_pmu_init(struct ssb_chipcommon *cc)
 
499
{
 
500
        struct ssb_bus *bus = cc->dev->bus;
 
501
        u32 pmucap;
 
502
 
 
503
        if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
 
504
                return;
 
505
 
 
506
        pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);
 
507
        cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION);
 
508
 
 
509
        ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
 
510
                    cc->pmu.rev, pmucap);
 
511
 
 
512
        if (cc->pmu.rev >= 1) {
 
513
                if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
 
514
                        chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
 
515
                                      ~SSB_CHIPCO_PMU_CTL_NOILPONW);
 
516
                } else {
 
517
                        chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
 
518
                                     SSB_CHIPCO_PMU_CTL_NOILPONW);
 
519
                }
 
520
        }
 
521
        ssb_pmu_pll_init(cc);
 
522
        ssb_pmu_resources_init(cc);
 
523
}
 
524
 
 
525
void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
 
526
                             enum ssb_pmu_ldo_volt_id id, u32 voltage)
 
527
{
 
528
        struct ssb_bus *bus = cc->dev->bus;
 
529
        u32 addr, shift, mask;
 
530
 
 
531
        switch (bus->chip_id) {
 
532
        case 0x4328:
 
533
        case 0x5354:
 
534
                switch (id) {
 
535
                case LDO_VOLT1:
 
536
                        addr = 2;
 
537
                        shift = 25;
 
538
                        mask = 0xF;
 
539
                        break;
 
540
                case LDO_VOLT2:
 
541
                        addr = 3;
 
542
                        shift = 1;
 
543
                        mask = 0xF;
 
544
                        break;
 
545
                case LDO_VOLT3:
 
546
                        addr = 3;
 
547
                        shift = 9;
 
548
                        mask = 0xF;
 
549
                        break;
 
550
                case LDO_PAREF:
 
551
                        addr = 3;
 
552
                        shift = 17;
 
553
                        mask = 0x3F;
 
554
                        break;
 
555
                default:
 
556
                        SSB_WARN_ON(1);
 
557
                        return;
 
558
                }
 
559
                break;
 
560
        case 0x4312:
 
561
                if (SSB_WARN_ON(id != LDO_PAREF))
 
562
                        return;
 
563
                addr = 0;
 
564
                shift = 21;
 
565
                mask = 0x3F;
 
566
                break;
 
567
        default:
 
568
                return;
 
569
        }
 
570
 
 
571
        ssb_chipco_regctl_maskset(cc, addr, ~(mask << shift),
 
572
                                  (voltage & mask) << shift);
 
573
}
 
574
 
 
575
void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on)
 
576
{
 
577
        struct ssb_bus *bus = cc->dev->bus;
 
578
        int ldo;
 
579
 
 
580
        switch (bus->chip_id) {
 
581
        case 0x4312:
 
582
                ldo = SSB_PMURES_4312_PA_REF_LDO;
 
583
                break;
 
584
        case 0x4328:
 
585
                ldo = SSB_PMURES_4328_PA_REF_LDO;
 
586
                break;
 
587
        case 0x5354:
 
588
                ldo = SSB_PMURES_5354_PA_REF_LDO;
 
589
                break;
 
590
        default:
 
591
                return;
 
592
        }
 
593
 
 
594
        if (on)
 
595
                chipco_set32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 1 << ldo);
 
596
        else
 
597
                chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ~(1 << ldo));
 
598
        chipco_read32(cc, SSB_CHIPCO_PMU_MINRES_MSK); //SPEC FIXME found via mmiotrace - dummy read?
 
599
}
 
600
 
 
601
EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
 
602
EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);