Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ssb: Add PMU support

This adds support for the SSB PMU.
A PMU is found on Low-Power devices.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Michael Buesch and committed by
John W. Linville
c9703146 baf62eec

+734 -13
+1
drivers/ssb/Makefile
··· 9 9 10 10 # built-in drivers 11 11 ssb-y += driver_chipcommon.o 12 + ssb-y += driver_chipcommon_pmu.o 12 13 ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o 13 14 ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o 14 15 ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
+1 -13
drivers/ssb/driver_chipcommon.c
··· 26 26 }; 27 27 28 28 29 - static inline u32 chipco_read32(struct ssb_chipcommon *cc, 30 - u16 offset) 31 - { 32 - return ssb_read32(cc->dev, offset); 33 - } 34 - 35 - static inline void chipco_write32(struct ssb_chipcommon *cc, 36 - u16 offset, 37 - u32 value) 38 - { 39 - ssb_write32(cc->dev, offset, value); 40 - } 41 - 42 29 static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, 43 30 u32 mask, u32 value) 44 31 { ··· 233 246 { 234 247 if (!cc->dev) 235 248 return; /* We don't have a ChipCommon */ 249 + ssb_pmu_init(cc); 236 250 chipco_powercontrol_init(cc); 237 251 ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); 238 252 calc_fast_powerup_delay(cc);
+508
drivers/ssb/driver_chipcommon_pmu.c
··· 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 + struct pmu0_plltab_entry { 32 + u16 freq; /* Crystal frequency in kHz.*/ 33 + u8 xf; /* Crystal frequency value for PMU control */ 34 + u8 wb_int; 35 + u32 wb_frac; 36 + }; 37 + 38 + static const struct pmu0_plltab_entry pmu0_plltab[] = { 39 + { .freq = 12000, .xf = 1, .wb_int = 73, .wb_frac = 349525, }, 40 + { .freq = 13000, .xf = 2, .wb_int = 67, .wb_frac = 725937, }, 41 + { .freq = 14400, .xf = 3, .wb_int = 61, .wb_frac = 116508, }, 42 + { .freq = 15360, .xf = 4, .wb_int = 57, .wb_frac = 305834, }, 43 + { .freq = 16200, .xf = 5, .wb_int = 54, .wb_frac = 336579, }, 44 + { .freq = 16800, .xf = 6, .wb_int = 52, .wb_frac = 399457, }, 45 + { .freq = 19200, .xf = 7, .wb_int = 45, .wb_frac = 873813, }, 46 + { .freq = 19800, .xf = 8, .wb_int = 44, .wb_frac = 466033, }, 47 + { .freq = 20000, .xf = 9, .wb_int = 44, .wb_frac = 0, }, 48 + { .freq = 25000, .xf = 10, .wb_int = 70, .wb_frac = 419430, }, 49 + { .freq = 26000, .xf = 11, .wb_int = 67, .wb_frac = 725937, }, 50 + { .freq = 30000, .xf = 12, .wb_int = 58, .wb_frac = 699050, }, 51 + { .freq = 38400, .xf = 13, .wb_int = 45, .wb_frac = 873813, }, 52 + { .freq = 40000, .xf = 14, .wb_int = 45, .wb_frac = 0, }, 53 + }; 54 + #define SSB_PMU0_DEFAULT_XTALFREQ 20000 55 + 56 + static const struct pmu0_plltab_entry * pmu0_plltab_find_entry(u32 crystalfreq) 57 + { 58 + const struct pmu0_plltab_entry *e; 59 + unsigned int i; 60 + 61 + for (i = 0; i < ARRAY_SIZE(pmu0_plltab); i++) { 62 + e = &pmu0_plltab[i]; 63 + if (e->freq == crystalfreq) 64 + return e; 65 + } 66 + 67 + return NULL; 68 + } 69 + 70 + /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */ 71 + static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc, 72 + u32 crystalfreq) 73 + { 74 + struct ssb_bus *bus = cc->dev->bus; 75 + const struct pmu0_plltab_entry *e = NULL; 76 + u32 pmuctl, tmp, pllctl; 77 + unsigned int i; 78 + 79 + if ((bus->chip_id == 0x5354) && !crystalfreq) { 80 + /* The 5354 crystal freq is 25MHz */ 81 + crystalfreq = 25000; 82 + } 83 + if (crystalfreq) 84 + e = pmu0_plltab_find_entry(crystalfreq); 85 + if (!e) 86 + e = pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ); 87 + BUG_ON(!e); 88 + crystalfreq = e->freq; 89 + cc->pmu.crystalfreq = e->freq; 90 + 91 + /* Check if the PLL already is programmed to this frequency. */ 92 + pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL); 93 + if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) { 94 + /* We're already there... */ 95 + return; 96 + } 97 + 98 + ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n", 99 + (crystalfreq / 1000), (crystalfreq % 1000)); 100 + 101 + /* First turn the PLL off. */ 102 + switch (bus->chip_id) { 103 + case 0x4328: 104 + chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 105 + ~(1 << SSB_PMURES_4328_BB_PLL_PU)); 106 + chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, 107 + ~(1 << SSB_PMURES_4328_BB_PLL_PU)); 108 + break; 109 + case 0x5354: 110 + chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 111 + ~(1 << SSB_PMURES_5354_BB_PLL_PU)); 112 + chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, 113 + ~(1 << SSB_PMURES_5354_BB_PLL_PU)); 114 + break; 115 + default: 116 + SSB_WARN_ON(1); 117 + } 118 + for (i = 1500; i; i--) { 119 + tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST); 120 + if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)) 121 + break; 122 + udelay(10); 123 + } 124 + tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST); 125 + if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT) 126 + ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n"); 127 + 128 + /* Set PDIV in PLL control 0. */ 129 + pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0); 130 + if (crystalfreq >= SSB_PMU0_PLLCTL0_PDIV_FREQ) 131 + pllctl |= SSB_PMU0_PLLCTL0_PDIV_MSK; 132 + else 133 + pllctl &= ~SSB_PMU0_PLLCTL0_PDIV_MSK; 134 + ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL0, pllctl); 135 + 136 + /* Set WILD in PLL control 1. */ 137 + pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL1); 138 + pllctl &= ~SSB_PMU0_PLLCTL1_STOPMOD; 139 + pllctl &= ~(SSB_PMU0_PLLCTL1_WILD_IMSK | SSB_PMU0_PLLCTL1_WILD_FMSK); 140 + pllctl |= ((u32)e->wb_int << SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_IMSK; 141 + pllctl |= ((u32)e->wb_frac << SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_FMSK; 142 + if (e->wb_frac == 0) 143 + pllctl |= SSB_PMU0_PLLCTL1_STOPMOD; 144 + ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL1, pllctl); 145 + 146 + /* Set WILD in PLL control 2. */ 147 + pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL2); 148 + pllctl &= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI; 149 + pllctl |= (((u32)e->wb_int >> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT) & SSB_PMU0_PLLCTL2_WILD_IMSKHI; 150 + ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL2, pllctl); 151 + 152 + /* Set the crystalfrequency and the divisor. */ 153 + pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL); 154 + pmuctl &= ~SSB_CHIPCO_PMU_CTL_ILP_DIV; 155 + pmuctl |= (((crystalfreq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT) 156 + & SSB_CHIPCO_PMU_CTL_ILP_DIV; 157 + pmuctl &= ~SSB_CHIPCO_PMU_CTL_XTALFREQ; 158 + pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ; 159 + chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl); 160 + } 161 + 162 + struct pmu1_plltab_entry { 163 + u16 freq; /* Crystal frequency in kHz.*/ 164 + u8 xf; /* Crystal frequency value for PMU control */ 165 + u8 ndiv_int; 166 + u32 ndiv_frac; 167 + u8 p1div; 168 + u8 p2div; 169 + }; 170 + 171 + static const struct pmu1_plltab_entry pmu1_plltab[] = { 172 + { .freq = 12000, .xf = 1, .p1div = 3, .p2div = 22, .ndiv_int = 0x9, .ndiv_frac = 0xFFFFEF, }, 173 + { .freq = 13000, .xf = 2, .p1div = 1, .p2div = 6, .ndiv_int = 0xb, .ndiv_frac = 0x483483, }, 174 + { .freq = 14400, .xf = 3, .p1div = 1, .p2div = 10, .ndiv_int = 0xa, .ndiv_frac = 0x1C71C7, }, 175 + { .freq = 15360, .xf = 4, .p1div = 1, .p2div = 5, .ndiv_int = 0xb, .ndiv_frac = 0x755555, }, 176 + { .freq = 16200, .xf = 5, .p1div = 1, .p2div = 10, .ndiv_int = 0x5, .ndiv_frac = 0x6E9E06, }, 177 + { .freq = 16800, .xf = 6, .p1div = 1, .p2div = 10, .ndiv_int = 0x5, .ndiv_frac = 0x3CF3CF, }, 178 + { .freq = 19200, .xf = 7, .p1div = 1, .p2div = 9, .ndiv_int = 0x5, .ndiv_frac = 0x17B425, }, 179 + { .freq = 19800, .xf = 8, .p1div = 1, .p2div = 11, .ndiv_int = 0x4, .ndiv_frac = 0xA57EB, }, 180 + { .freq = 20000, .xf = 9, .p1div = 1, .p2div = 11, .ndiv_int = 0x4, .ndiv_frac = 0, }, 181 + { .freq = 24000, .xf = 10, .p1div = 3, .p2div = 11, .ndiv_int = 0xa, .ndiv_frac = 0, }, 182 + { .freq = 25000, .xf = 11, .p1div = 5, .p2div = 16, .ndiv_int = 0xb, .ndiv_frac = 0, }, 183 + { .freq = 26000, .xf = 12, .p1div = 1, .p2div = 2, .ndiv_int = 0x10, .ndiv_frac = 0xEC4EC4, }, 184 + { .freq = 30000, .xf = 13, .p1div = 3, .p2div = 8, .ndiv_int = 0xb, .ndiv_frac = 0, }, 185 + { .freq = 38400, .xf = 14, .p1div = 1, .p2div = 5, .ndiv_int = 0x4, .ndiv_frac = 0x955555, }, 186 + { .freq = 40000, .xf = 15, .p1div = 1, .p2div = 2, .ndiv_int = 0xb, .ndiv_frac = 0, }, 187 + }; 188 + 189 + #define SSB_PMU1_DEFAULT_XTALFREQ 15360 190 + 191 + static const struct pmu1_plltab_entry * pmu1_plltab_find_entry(u32 crystalfreq) 192 + { 193 + const struct pmu1_plltab_entry *e; 194 + unsigned int i; 195 + 196 + for (i = 0; i < ARRAY_SIZE(pmu1_plltab); i++) { 197 + e = &pmu1_plltab[i]; 198 + if (e->freq == crystalfreq) 199 + return e; 200 + } 201 + 202 + return NULL; 203 + } 204 + 205 + /* Tune the PLL to the crystal speed. crystalfreq is in kHz. */ 206 + static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc, 207 + u32 crystalfreq) 208 + { 209 + struct ssb_bus *bus = cc->dev->bus; 210 + const struct pmu1_plltab_entry *e = NULL; 211 + u32 buffer_strength = 0; 212 + u32 tmp, pllctl, pmuctl; 213 + unsigned int i; 214 + 215 + if (bus->chip_id == 0x4312) { 216 + /* We do not touch the BCM4312 PLL and assume 217 + * the default crystal settings work out-of-the-box. */ 218 + cc->pmu.crystalfreq = 20000; 219 + return; 220 + } 221 + 222 + if (crystalfreq) 223 + e = pmu1_plltab_find_entry(crystalfreq); 224 + if (!e) 225 + e = pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ); 226 + BUG_ON(!e); 227 + crystalfreq = e->freq; 228 + cc->pmu.crystalfreq = e->freq; 229 + 230 + /* Check if the PLL already is programmed to this frequency. */ 231 + pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL); 232 + if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) { 233 + /* We're already there... */ 234 + return; 235 + } 236 + 237 + ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n", 238 + (crystalfreq / 1000), (crystalfreq % 1000)); 239 + 240 + /* First turn the PLL off. */ 241 + switch (bus->chip_id) { 242 + case 0x4325: 243 + chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 244 + ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) | 245 + (1 << SSB_PMURES_4325_HT_AVAIL))); 246 + chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, 247 + ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) | 248 + (1 << SSB_PMURES_4325_HT_AVAIL))); 249 + /* Adjust the BBPLL to 2 on all channels later. */ 250 + buffer_strength = 0x222222; 251 + break; 252 + default: 253 + SSB_WARN_ON(1); 254 + } 255 + for (i = 1500; i; i--) { 256 + tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST); 257 + if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)) 258 + break; 259 + udelay(10); 260 + } 261 + tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST); 262 + if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT) 263 + ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n"); 264 + 265 + /* Set p1div and p2div. */ 266 + pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0); 267 + pllctl &= ~(SSB_PMU1_PLLCTL0_P1DIV | SSB_PMU1_PLLCTL0_P2DIV); 268 + pllctl |= ((u32)e->p1div << SSB_PMU1_PLLCTL0_P1DIV_SHIFT) & SSB_PMU1_PLLCTL0_P1DIV; 269 + pllctl |= ((u32)e->p2div << SSB_PMU1_PLLCTL0_P2DIV_SHIFT) & SSB_PMU1_PLLCTL0_P2DIV; 270 + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, pllctl); 271 + 272 + /* Set ndiv int and ndiv mode */ 273 + pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL2); 274 + pllctl &= ~(SSB_PMU1_PLLCTL2_NDIVINT | SSB_PMU1_PLLCTL2_NDIVMODE); 275 + pllctl |= ((u32)e->ndiv_int << SSB_PMU1_PLLCTL2_NDIVINT_SHIFT) & SSB_PMU1_PLLCTL2_NDIVINT; 276 + pllctl |= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT) & SSB_PMU1_PLLCTL2_NDIVMODE; 277 + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, pllctl); 278 + 279 + /* Set ndiv frac */ 280 + pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL3); 281 + pllctl &= ~SSB_PMU1_PLLCTL3_NDIVFRAC; 282 + pllctl |= ((u32)e->ndiv_frac << SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT) & SSB_PMU1_PLLCTL3_NDIVFRAC; 283 + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, pllctl); 284 + 285 + /* Change the drive strength, if required. */ 286 + if (buffer_strength) { 287 + pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL5); 288 + pllctl &= ~SSB_PMU1_PLLCTL5_CLKDRV; 289 + pllctl |= (buffer_strength << SSB_PMU1_PLLCTL5_CLKDRV_SHIFT) & SSB_PMU1_PLLCTL5_CLKDRV; 290 + ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, pllctl); 291 + } 292 + 293 + /* Tune the crystalfreq and the divisor. */ 294 + pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL); 295 + pmuctl &= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV | SSB_CHIPCO_PMU_CTL_XTALFREQ); 296 + pmuctl |= ((((u32)e->freq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT) 297 + & SSB_CHIPCO_PMU_CTL_ILP_DIV; 298 + pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ; 299 + chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl); 300 + } 301 + 302 + static void ssb_pmu_pll_init(struct ssb_chipcommon *cc) 303 + { 304 + struct ssb_bus *bus = cc->dev->bus; 305 + u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */ 306 + 307 + if (bus->bustype == SSB_BUSTYPE_SSB) { 308 + /* TODO: The user may override the crystal frequency. */ 309 + } 310 + 311 + switch (bus->chip_id) { 312 + case 0x4312: 313 + case 0x4325: 314 + ssb_pmu1_pllinit_r0(cc, crystalfreq); 315 + break; 316 + case 0x4328: 317 + case 0x5354: 318 + ssb_pmu0_pllinit_r0(cc, crystalfreq); 319 + break; 320 + default: 321 + ssb_printk(KERN_ERR PFX 322 + "ERROR: PLL init unknown for device %04X\n", 323 + bus->chip_id); 324 + } 325 + } 326 + 327 + struct pmu_res_updown_tab_entry { 328 + u8 resource; /* The resource number */ 329 + u16 updown; /* The updown value */ 330 + }; 331 + 332 + enum pmu_res_depend_tab_task { 333 + PMU_RES_DEP_SET = 1, 334 + PMU_RES_DEP_ADD, 335 + PMU_RES_DEP_REMOVE, 336 + }; 337 + 338 + struct pmu_res_depend_tab_entry { 339 + u8 resource; /* The resource number */ 340 + u8 task; /* SET | ADD | REMOVE */ 341 + u32 depend; /* The depend mask */ 342 + }; 343 + 344 + static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0[] = { 345 + { .resource = SSB_PMURES_4328_EXT_SWITCHER_PWM, .updown = 0x0101, }, 346 + { .resource = SSB_PMURES_4328_BB_SWITCHER_PWM, .updown = 0x1F01, }, 347 + { .resource = SSB_PMURES_4328_BB_SWITCHER_BURST, .updown = 0x010F, }, 348 + { .resource = SSB_PMURES_4328_BB_EXT_SWITCHER_BURST, .updown = 0x0101, }, 349 + { .resource = SSB_PMURES_4328_ILP_REQUEST, .updown = 0x0202, }, 350 + { .resource = SSB_PMURES_4328_RADIO_SWITCHER_PWM, .updown = 0x0F01, }, 351 + { .resource = SSB_PMURES_4328_RADIO_SWITCHER_BURST, .updown = 0x0F01, }, 352 + { .resource = SSB_PMURES_4328_ROM_SWITCH, .updown = 0x0101, }, 353 + { .resource = SSB_PMURES_4328_PA_REF_LDO, .updown = 0x0F01, }, 354 + { .resource = SSB_PMURES_4328_RADIO_LDO, .updown = 0x0F01, }, 355 + { .resource = SSB_PMURES_4328_AFE_LDO, .updown = 0x0F01, }, 356 + { .resource = SSB_PMURES_4328_PLL_LDO, .updown = 0x0F01, }, 357 + { .resource = SSB_PMURES_4328_BG_FILTBYP, .updown = 0x0101, }, 358 + { .resource = SSB_PMURES_4328_TX_FILTBYP, .updown = 0x0101, }, 359 + { .resource = SSB_PMURES_4328_RX_FILTBYP, .updown = 0x0101, }, 360 + { .resource = SSB_PMURES_4328_XTAL_PU, .updown = 0x0101, }, 361 + { .resource = SSB_PMURES_4328_XTAL_EN, .updown = 0xA001, }, 362 + { .resource = SSB_PMURES_4328_BB_PLL_FILTBYP, .updown = 0x0101, }, 363 + { .resource = SSB_PMURES_4328_RF_PLL_FILTBYP, .updown = 0x0101, }, 364 + { .resource = SSB_PMURES_4328_BB_PLL_PU, .updown = 0x0701, }, 365 + }; 366 + 367 + static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0[] = { 368 + { 369 + /* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */ 370 + .resource = SSB_PMURES_4328_ILP_REQUEST, 371 + .task = PMU_RES_DEP_SET, 372 + .depend = ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) | 373 + (1 << SSB_PMURES_4328_BB_SWITCHER_PWM)), 374 + }, 375 + }; 376 + 377 + static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0[] = { 378 + { .resource = SSB_PMURES_4325_XTAL_PU, .updown = 0x1501, }, 379 + }; 380 + 381 + static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0[] = { 382 + { 383 + /* Adjust HT-Available dependencies. */ 384 + .resource = SSB_PMURES_4325_HT_AVAIL, 385 + .task = PMU_RES_DEP_ADD, 386 + .depend = ((1 << SSB_PMURES_4325_RX_PWRSW_PU) | 387 + (1 << SSB_PMURES_4325_TX_PWRSW_PU) | 388 + (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU) | 389 + (1 << SSB_PMURES_4325_AFE_PWRSW_PU)), 390 + }, 391 + }; 392 + 393 + static void ssb_pmu_resources_init(struct ssb_chipcommon *cc) 394 + { 395 + struct ssb_bus *bus = cc->dev->bus; 396 + u32 min_msk = 0, max_msk = 0; 397 + unsigned int i; 398 + const struct pmu_res_updown_tab_entry *updown_tab = NULL; 399 + unsigned int updown_tab_size; 400 + const struct pmu_res_depend_tab_entry *depend_tab = NULL; 401 + unsigned int depend_tab_size; 402 + 403 + switch (bus->chip_id) { 404 + case 0x4312: 405 + /* We keep the default settings: 406 + * min_msk = 0xCBB 407 + * max_msk = 0x7FFFF 408 + */ 409 + break; 410 + case 0x4325: 411 + /* Power OTP down later. */ 412 + min_msk = (1 << SSB_PMURES_4325_CBUCK_BURST) | 413 + (1 << SSB_PMURES_4325_LNLDO2_PU); 414 + if (chipco_read32(cc, SSB_CHIPCO_CHIPSTAT) & 415 + SSB_CHIPCO_CHST_4325_PMUTOP_2B) 416 + min_msk |= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST); 417 + /* The PLL may turn on, if it decides so. */ 418 + max_msk = 0xFFFFF; 419 + updown_tab = pmu_res_updown_tab_4325a0; 420 + updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4325a0); 421 + depend_tab = pmu_res_depend_tab_4325a0; 422 + depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4325a0); 423 + break; 424 + case 0x4328: 425 + min_msk = (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) | 426 + (1 << SSB_PMURES_4328_BB_SWITCHER_PWM) | 427 + (1 << SSB_PMURES_4328_XTAL_EN); 428 + /* The PLL may turn on, if it decides so. */ 429 + max_msk = 0xFFFFF; 430 + updown_tab = pmu_res_updown_tab_4328a0; 431 + updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4328a0); 432 + depend_tab = pmu_res_depend_tab_4328a0; 433 + depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4328a0); 434 + break; 435 + case 0x5354: 436 + /* The PLL may turn on, if it decides so. */ 437 + max_msk = 0xFFFFF; 438 + break; 439 + default: 440 + ssb_printk(KERN_ERR PFX 441 + "ERROR: PMU resource config unknown for device %04X\n", 442 + bus->chip_id); 443 + } 444 + 445 + if (updown_tab) { 446 + for (i = 0; i < updown_tab_size; i++) { 447 + chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL, 448 + updown_tab[i].resource); 449 + chipco_write32(cc, SSB_CHIPCO_PMU_RES_UPDNTM, 450 + updown_tab[i].updown); 451 + } 452 + } 453 + if (depend_tab) { 454 + for (i = 0; i < depend_tab_size; i++) { 455 + chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL, 456 + depend_tab[i].resource); 457 + switch (depend_tab[i].task) { 458 + case PMU_RES_DEP_SET: 459 + chipco_write32(cc, SSB_CHIPCO_PMU_RES_DEPMSK, 460 + depend_tab[i].depend); 461 + break; 462 + case PMU_RES_DEP_ADD: 463 + chipco_set32(cc, SSB_CHIPCO_PMU_RES_DEPMSK, 464 + depend_tab[i].depend); 465 + break; 466 + case PMU_RES_DEP_REMOVE: 467 + chipco_mask32(cc, SSB_CHIPCO_PMU_RES_DEPMSK, 468 + ~(depend_tab[i].depend)); 469 + break; 470 + default: 471 + SSB_WARN_ON(1); 472 + } 473 + } 474 + } 475 + 476 + /* Set the resource masks. */ 477 + if (min_msk) 478 + chipco_write32(cc, SSB_CHIPCO_PMU_MINRES_MSK, min_msk); 479 + if (max_msk) 480 + chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk); 481 + } 482 + 483 + void ssb_pmu_init(struct ssb_chipcommon *cc) 484 + { 485 + struct ssb_bus *bus = cc->dev->bus; 486 + u32 pmucap; 487 + 488 + if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU)) 489 + return; 490 + 491 + pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP); 492 + cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION); 493 + 494 + ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n", 495 + cc->pmu.rev, pmucap); 496 + 497 + if (cc->pmu.rev >= 1) { 498 + if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) { 499 + chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, 500 + ~SSB_CHIPCO_PMU_CTL_NOILPONW); 501 + } else { 502 + chipco_set32(cc, SSB_CHIPCO_PMU_CTL, 503 + SSB_CHIPCO_PMU_CTL_NOILPONW); 504 + } 505 + } 506 + ssb_pmu_pll_init(cc); 507 + ssb_pmu_resources_init(cc); 508 + }
+224
include/linux/ssb/ssb_driver_chipcommon.h
··· 181 181 #define SSB_CHIPCO_PROG_WAITCNT 0x0124 182 182 #define SSB_CHIPCO_FLASH_CFG 0x0128 183 183 #define SSB_CHIPCO_FLASH_WAITCNT 0x012C 184 + #define SSB_CHIPCO_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */ 185 + #define SSB_CHIPCO_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */ 186 + #define SSB_CHIPCO_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */ 187 + #define SSB_CHIPCO_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */ 188 + #define SSB_CHIPCO_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ 189 + #define SSB_CHIPCO_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ 190 + #define SSB_CHIPCO_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ 191 + #define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00010000 /* HT available */ 192 + #define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00020000 /* APL available */ 193 + #define SSB_CHIPCO_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ 184 194 #define SSB_CHIPCO_UART0_DATA 0x0300 185 195 #define SSB_CHIPCO_UART0_IMR 0x0304 186 196 #define SSB_CHIPCO_UART0_FCR 0x0308 ··· 207 197 #define SSB_CHIPCO_UART1_LSR 0x0414 208 198 #define SSB_CHIPCO_UART1_MSR 0x0418 209 199 #define SSB_CHIPCO_UART1_SCRATCH 0x041C 200 + /* PMU registers (rev >= 20) */ 201 + #define SSB_CHIPCO_PMU_CTL 0x0600 /* PMU control */ 202 + #define SSB_CHIPCO_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */ 203 + #define SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT 16 204 + #define SSB_CHIPCO_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */ 205 + #define SSB_CHIPCO_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */ 206 + #define SSB_CHIPCO_PMU_CTL_ALPREQEN 0x00000080 /* ALP req enable */ 207 + #define SSB_CHIPCO_PMU_CTL_XTALFREQ 0x0000007C /* Crystal freq */ 208 + #define SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT 2 209 + #define SSB_CHIPCO_PMU_CTL_ILPDIVEN 0x00000002 /* ILP div enable */ 210 + #define SSB_CHIPCO_PMU_CTL_LPOSEL 0x00000001 /* LPO sel */ 211 + #define SSB_CHIPCO_PMU_CAP 0x0604 /* PMU capabilities */ 212 + #define SSB_CHIPCO_PMU_CAP_REVISION 0x000000FF /* Revision mask */ 213 + #define SSB_CHIPCO_PMU_STAT 0x0608 /* PMU status */ 214 + #define SSB_CHIPCO_PMU_STAT_INTPEND 0x00000040 /* Interrupt pending */ 215 + #define SSB_CHIPCO_PMU_STAT_SBCLKST 0x00000030 /* Backplane clock status? */ 216 + #define SSB_CHIPCO_PMU_STAT_HAVEALP 0x00000008 /* ALP available */ 217 + #define SSB_CHIPCO_PMU_STAT_HAVEHT 0x00000004 /* HT available */ 218 + #define SSB_CHIPCO_PMU_STAT_RESINIT 0x00000003 /* Res init */ 219 + #define SSB_CHIPCO_PMU_RES_STAT 0x060C /* PMU res status */ 220 + #define SSB_CHIPCO_PMU_RES_PEND 0x0610 /* PMU res pending */ 221 + #define SSB_CHIPCO_PMU_TIMER 0x0614 /* PMU timer */ 222 + #define SSB_CHIPCO_PMU_MINRES_MSK 0x0618 /* PMU min res mask */ 223 + #define SSB_CHIPCO_PMU_MAXRES_MSK 0x061C /* PMU max res mask */ 224 + #define SSB_CHIPCO_PMU_RES_TABSEL 0x0620 /* PMU res table sel */ 225 + #define SSB_CHIPCO_PMU_RES_DEPMSK 0x0624 /* PMU res dep mask */ 226 + #define SSB_CHIPCO_PMU_RES_UPDNTM 0x0628 /* PMU res updown timer */ 227 + #define SSB_CHIPCO_PMU_RES_TIMER 0x062C /* PMU res timer */ 228 + #define SSB_CHIPCO_PMU_CLKSTRETCH 0x0630 /* PMU clockstretch */ 229 + #define SSB_CHIPCO_PMU_WATCHDOG 0x0634 /* PMU watchdog */ 230 + #define SSB_CHIPCO_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */ 231 + #define SSB_CHIPCO_PMU_RES_REQT 0x0644 /* PMU res req timer */ 232 + #define SSB_CHIPCO_PMU_RES_REQM 0x0648 /* PMU res req mask */ 233 + #define SSB_CHIPCO_CHIPCTL_ADDR 0x0650 234 + #define SSB_CHIPCO_CHIPCTL_DATA 0x0654 235 + #define SSB_CHIPCO_REGCTL_ADDR 0x0658 236 + #define SSB_CHIPCO_REGCTL_DATA 0x065C 237 + #define SSB_CHIPCO_PLLCTL_ADDR 0x0660 238 + #define SSB_CHIPCO_PLLCTL_DATA 0x0664 239 + 240 + 241 + 242 + /** PMU PLL registers */ 243 + 244 + /* PMU rev 0 PLL registers */ 245 + #define SSB_PMU0_PLLCTL0 0 246 + #define SSB_PMU0_PLLCTL0_PDIV_MSK 0x00000001 247 + #define SSB_PMU0_PLLCTL0_PDIV_FREQ 25000 /* kHz */ 248 + #define SSB_PMU0_PLLCTL1 1 249 + #define SSB_PMU0_PLLCTL1_WILD_IMSK 0xF0000000 /* Wild int mask (low nibble) */ 250 + #define SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT 28 251 + #define SSB_PMU0_PLLCTL1_WILD_FMSK 0x0FFFFF00 /* Wild frac mask */ 252 + #define SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT 8 253 + #define SSB_PMU0_PLLCTL1_STOPMOD 0x00000040 /* Stop mod */ 254 + #define SSB_PMU0_PLLCTL2 2 255 + #define SSB_PMU0_PLLCTL2_WILD_IMSKHI 0x0000000F /* Wild int mask (high nibble) */ 256 + #define SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT 0 257 + 258 + /* PMU rev 1 PLL registers */ 259 + #define SSB_PMU1_PLLCTL0 0 260 + #define SSB_PMU1_PLLCTL0_P1DIV 0x00F00000 /* P1 div */ 261 + #define SSB_PMU1_PLLCTL0_P1DIV_SHIFT 20 262 + #define SSB_PMU1_PLLCTL0_P2DIV 0x0F000000 /* P2 div */ 263 + #define SSB_PMU1_PLLCTL0_P2DIV_SHIFT 24 264 + #define SSB_PMU1_PLLCTL1 1 265 + #define SSB_PMU1_PLLCTL1_M1DIV 0x000000FF /* M1 div */ 266 + #define SSB_PMU1_PLLCTL1_M1DIV_SHIFT 0 267 + #define SSB_PMU1_PLLCTL1_M2DIV 0x0000FF00 /* M2 div */ 268 + #define SSB_PMU1_PLLCTL1_M2DIV_SHIFT 8 269 + #define SSB_PMU1_PLLCTL1_M3DIV 0x00FF0000 /* M3 div */ 270 + #define SSB_PMU1_PLLCTL1_M3DIV_SHIFT 16 271 + #define SSB_PMU1_PLLCTL1_M4DIV 0xFF000000 /* M4 div */ 272 + #define SSB_PMU1_PLLCTL1_M4DIV_SHIFT 24 273 + #define SSB_PMU1_PLLCTL2 2 274 + #define SSB_PMU1_PLLCTL2_M5DIV 0x000000FF /* M5 div */ 275 + #define SSB_PMU1_PLLCTL2_M5DIV_SHIFT 0 276 + #define SSB_PMU1_PLLCTL2_M6DIV 0x0000FF00 /* M6 div */ 277 + #define SSB_PMU1_PLLCTL2_M6DIV_SHIFT 8 278 + #define SSB_PMU1_PLLCTL2_NDIVMODE 0x000E0000 /* NDIV mode */ 279 + #define SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT 17 280 + #define SSB_PMU1_PLLCTL2_NDIVINT 0x1FF00000 /* NDIV int */ 281 + #define SSB_PMU1_PLLCTL2_NDIVINT_SHIFT 20 282 + #define SSB_PMU1_PLLCTL3 3 283 + #define SSB_PMU1_PLLCTL3_NDIVFRAC 0x00FFFFFF /* NDIV frac */ 284 + #define SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT 0 285 + #define SSB_PMU1_PLLCTL4 4 286 + #define SSB_PMU1_PLLCTL5 5 287 + #define SSB_PMU1_PLLCTL5_CLKDRV 0xFFFFFF00 /* clk drv */ 288 + #define SSB_PMU1_PLLCTL5_CLKDRV_SHIFT 8 289 + 290 + /* BCM4312 PLL resource numbers. */ 291 + #define SSB_PMURES_4312_SWITCHER_BURST 0 292 + #define SSB_PMURES_4312_SWITCHER_PWM 1 293 + #define SSB_PMURES_4312_PA_REF_LDO 2 294 + #define SSB_PMURES_4312_CORE_LDO_BURST 3 295 + #define SSB_PMURES_4312_CORE_LDO_PWM 4 296 + #define SSB_PMURES_4312_RADIO_LDO 5 297 + #define SSB_PMURES_4312_ILP_REQUEST 6 298 + #define SSB_PMURES_4312_BG_FILTBYP 7 299 + #define SSB_PMURES_4312_TX_FILTBYP 8 300 + #define SSB_PMURES_4312_RX_FILTBYP 9 301 + #define SSB_PMURES_4312_XTAL_PU 10 302 + #define SSB_PMURES_4312_ALP_AVAIL 11 303 + #define SSB_PMURES_4312_BB_PLL_FILTBYP 12 304 + #define SSB_PMURES_4312_RF_PLL_FILTBYP 13 305 + #define SSB_PMURES_4312_HT_AVAIL 14 306 + 307 + /* BCM4325 PLL resource numbers. */ 308 + #define SSB_PMURES_4325_BUCK_BOOST_BURST 0 309 + #define SSB_PMURES_4325_CBUCK_BURST 1 310 + #define SSB_PMURES_4325_CBUCK_PWM 2 311 + #define SSB_PMURES_4325_CLDO_CBUCK_BURST 3 312 + #define SSB_PMURES_4325_CLDO_CBUCK_PWM 4 313 + #define SSB_PMURES_4325_BUCK_BOOST_PWM 5 314 + #define SSB_PMURES_4325_ILP_REQUEST 6 315 + #define SSB_PMURES_4325_ABUCK_BURST 7 316 + #define SSB_PMURES_4325_ABUCK_PWM 8 317 + #define SSB_PMURES_4325_LNLDO1_PU 9 318 + #define SSB_PMURES_4325_LNLDO2_PU 10 319 + #define SSB_PMURES_4325_LNLDO3_PU 11 320 + #define SSB_PMURES_4325_LNLDO4_PU 12 321 + #define SSB_PMURES_4325_XTAL_PU 13 322 + #define SSB_PMURES_4325_ALP_AVAIL 14 323 + #define SSB_PMURES_4325_RX_PWRSW_PU 15 324 + #define SSB_PMURES_4325_TX_PWRSW_PU 16 325 + #define SSB_PMURES_4325_RFPLL_PWRSW_PU 17 326 + #define SSB_PMURES_4325_LOGEN_PWRSW_PU 18 327 + #define SSB_PMURES_4325_AFE_PWRSW_PU 19 328 + #define SSB_PMURES_4325_BBPLL_PWRSW_PU 20 329 + #define SSB_PMURES_4325_HT_AVAIL 21 330 + 331 + /* BCM4328 PLL resource numbers. */ 332 + #define SSB_PMURES_4328_EXT_SWITCHER_PWM 0 333 + #define SSB_PMURES_4328_BB_SWITCHER_PWM 1 334 + #define SSB_PMURES_4328_BB_SWITCHER_BURST 2 335 + #define SSB_PMURES_4328_BB_EXT_SWITCHER_BURST 3 336 + #define SSB_PMURES_4328_ILP_REQUEST 4 337 + #define SSB_PMURES_4328_RADIO_SWITCHER_PWM 5 338 + #define SSB_PMURES_4328_RADIO_SWITCHER_BURST 6 339 + #define SSB_PMURES_4328_ROM_SWITCH 7 340 + #define SSB_PMURES_4328_PA_REF_LDO 8 341 + #define SSB_PMURES_4328_RADIO_LDO 9 342 + #define SSB_PMURES_4328_AFE_LDO 10 343 + #define SSB_PMURES_4328_PLL_LDO 11 344 + #define SSB_PMURES_4328_BG_FILTBYP 12 345 + #define SSB_PMURES_4328_TX_FILTBYP 13 346 + #define SSB_PMURES_4328_RX_FILTBYP 14 347 + #define SSB_PMURES_4328_XTAL_PU 15 348 + #define SSB_PMURES_4328_XTAL_EN 16 349 + #define SSB_PMURES_4328_BB_PLL_FILTBYP 17 350 + #define SSB_PMURES_4328_RF_PLL_FILTBYP 18 351 + #define SSB_PMURES_4328_BB_PLL_PU 19 352 + 353 + /* BCM5354 PLL resource numbers. */ 354 + #define SSB_PMURES_5354_EXT_SWITCHER_PWM 0 355 + #define SSB_PMURES_5354_BB_SWITCHER_PWM 1 356 + #define SSB_PMURES_5354_BB_SWITCHER_BURST 2 357 + #define SSB_PMURES_5354_BB_EXT_SWITCHER_BURST 3 358 + #define SSB_PMURES_5354_ILP_REQUEST 4 359 + #define SSB_PMURES_5354_RADIO_SWITCHER_PWM 5 360 + #define SSB_PMURES_5354_RADIO_SWITCHER_BURST 6 361 + #define SSB_PMURES_5354_ROM_SWITCH 7 362 + #define SSB_PMURES_5354_PA_REF_LDO 8 363 + #define SSB_PMURES_5354_RADIO_LDO 9 364 + #define SSB_PMURES_5354_AFE_LDO 10 365 + #define SSB_PMURES_5354_PLL_LDO 11 366 + #define SSB_PMURES_5354_BG_FILTBYP 12 367 + #define SSB_PMURES_5354_TX_FILTBYP 13 368 + #define SSB_PMURES_5354_RX_FILTBYP 14 369 + #define SSB_PMURES_5354_XTAL_PU 15 370 + #define SSB_PMURES_5354_XTAL_EN 16 371 + #define SSB_PMURES_5354_BB_PLL_FILTBYP 17 372 + #define SSB_PMURES_5354_RF_PLL_FILTBYP 18 373 + #define SSB_PMURES_5354_BB_PLL_PU 19 374 + 375 + 376 + 377 + /** Chip specific Chip-Status register contents. */ 378 + #define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003 379 + #define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ 380 + #define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ 381 + #define SSB_CHIPCO_CHST_4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ 382 + #define SSB_CHIPCO_CHST_4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ 383 + #define SSB_CHIPCO_CHST_4325_SDIO_USB_MODE 0x00000004 384 + #define SSB_CHIPCO_CHST_4325_SDIO_USB_MODE_SHIFT 2 385 + #define SSB_CHIPCO_CHST_4325_RCAL_VALID 0x00000008 386 + #define SSB_CHIPCO_CHST_4325_RCAL_VALID_SHIFT 3 387 + #define SSB_CHIPCO_CHST_4325_RCAL_VALUE 0x000001F0 388 + #define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4 389 + #define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */ 210 390 211 391 212 392 ··· 553 353 struct ssb_device; 554 354 struct ssb_serial_port; 555 355 356 + /* Data for the PMU, if available. 357 + * Check availability with ((struct ssb_chipcommon)->capabilities & SSB_CHIPCO_CAP_PMU) 358 + */ 359 + struct ssb_chipcommon_pmu { 360 + u8 rev; /* PMU revision */ 361 + u32 crystalfreq; /* The active crystal frequency (in kHz) */ 362 + }; 363 + 556 364 struct ssb_chipcommon { 557 365 struct ssb_device *dev; 558 366 u32 capabilities; 559 367 /* Fast Powerup Delay constant */ 560 368 u16 fast_pwrup_delay; 369 + struct ssb_chipcommon_pmu pmu; 561 370 }; 562 371 563 372 static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) 564 373 { 565 374 return (cc->dev != NULL); 566 375 } 376 + 377 + /* Register access */ 378 + #define chipco_read32(cc, offset) ssb_read32((cc)->dev, offset) 379 + #define chipco_write32(cc, offset, val) ssb_write32((cc)->dev, offset, val) 380 + 381 + #define chipco_mask32(cc, offset, mask) \ 382 + chipco_write32(cc, offset, chipco_read32(cc, offset) & (mask)) 383 + #define chipco_set32(cc, offset, set) \ 384 + chipco_write32(cc, offset, chipco_read32(cc, offset) | (set)) 385 + #define chipco_maskset32(cc, offset, mask, set) \ 386 + chipco_write32(cc, offset, (chipco_read32(cc, offset) & (mask)) | (set)) 567 387 568 388 extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); 569 389 ··· 625 405 extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, 626 406 struct ssb_serial_port *ports); 627 407 #endif /* CONFIG_SSB_SERIAL */ 408 + 409 + /* PMU support */ 410 + extern void ssb_pmu_init(struct ssb_chipcommon *cc); 411 + 628 412 629 413 #endif /* LINUX_SSB_CHIPCO_H_ */