1c9703146158c0415a60799570397e488bc982af5Michael Buesch/*
2c9703146158c0415a60799570397e488bc982af5Michael Buesch * Sonics Silicon Backplane
3c9703146158c0415a60799570397e488bc982af5Michael Buesch * Broadcom ChipCommon Power Management Unit driver
4c9703146158c0415a60799570397e488bc982af5Michael Buesch *
5eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch * Copyright 2009, Michael Buesch <m@bues.ch>
6c9703146158c0415a60799570397e488bc982af5Michael Buesch * Copyright 2007, Broadcom Corporation
7c9703146158c0415a60799570397e488bc982af5Michael Buesch *
8c9703146158c0415a60799570397e488bc982af5Michael Buesch * Licensed under the GNU/GPL. See COPYING for details.
9c9703146158c0415a60799570397e488bc982af5Michael Buesch */
10c9703146158c0415a60799570397e488bc982af5Michael Buesch
11c9703146158c0415a60799570397e488bc982af5Michael Buesch#include <linux/ssb/ssb.h>
12c9703146158c0415a60799570397e488bc982af5Michael Buesch#include <linux/ssb/ssb_regs.h>
13c9703146158c0415a60799570397e488bc982af5Michael Buesch#include <linux/ssb/ssb_driver_chipcommon.h>
14c9703146158c0415a60799570397e488bc982af5Michael Buesch#include <linux/delay.h>
151014c22e42a6692660d1a77888d07f4811b2914dPaul Gortmaker#include <linux/export.h>
16d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens#ifdef CONFIG_BCM47XX
17d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens#include <asm/mach-bcm47xx/nvram.h>
18d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens#endif
19c9703146158c0415a60799570397e488bc982af5Michael Buesch
20c9703146158c0415a60799570397e488bc982af5Michael Buesch#include "ssb_private.h"
21c9703146158c0415a60799570397e488bc982af5Michael Buesch
22c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic u32 ssb_chipco_pll_read(struct ssb_chipcommon *cc, u32 offset)
23c9703146158c0415a60799570397e488bc982af5Michael Buesch{
24c9703146158c0415a60799570397e488bc982af5Michael Buesch	chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
25c9703146158c0415a60799570397e488bc982af5Michael Buesch	return chipco_read32(cc, SSB_CHIPCO_PLLCTL_DATA);
26c9703146158c0415a60799570397e488bc982af5Michael Buesch}
27c9703146158c0415a60799570397e488bc982af5Michael Buesch
28c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic void ssb_chipco_pll_write(struct ssb_chipcommon *cc,
29c9703146158c0415a60799570397e488bc982af5Michael Buesch				 u32 offset, u32 value)
30c9703146158c0415a60799570397e488bc982af5Michael Buesch{
31c9703146158c0415a60799570397e488bc982af5Michael Buesch	chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
32c9703146158c0415a60799570397e488bc982af5Michael Buesch	chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value);
33c9703146158c0415a60799570397e488bc982af5Michael Buesch}
34c9703146158c0415a60799570397e488bc982af5Michael Buesch
3506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanikstatic void ssb_chipco_regctl_maskset(struct ssb_chipcommon *cc,
3606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik				   u32 offset, u32 mask, u32 set)
3706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik{
3806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	u32 value;
3906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
4006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
4106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	chipco_write32(cc, SSB_CHIPCO_REGCTL_ADDR, offset);
4206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
4306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	value = chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
4406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	value &= mask;
4506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	value |= set;
4606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	chipco_write32(cc, SSB_CHIPCO_REGCTL_DATA, value);
4706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
4806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik}
4906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
50c9703146158c0415a60799570397e488bc982af5Michael Bueschstruct pmu0_plltab_entry {
51c9703146158c0415a60799570397e488bc982af5Michael Buesch	u16 freq;	/* Crystal frequency in kHz.*/
52c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 xf;		/* Crystal frequency value for PMU control */
53c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 wb_int;
54c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 wb_frac;
55c9703146158c0415a60799570397e488bc982af5Michael Buesch};
56c9703146158c0415a60799570397e488bc982af5Michael Buesch
57c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu0_plltab_entry pmu0_plltab[] = {
58c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 12000, .xf =  1, .wb_int = 73, .wb_frac = 349525, },
59c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 13000, .xf =  2, .wb_int = 67, .wb_frac = 725937, },
60c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 14400, .xf =  3, .wb_int = 61, .wb_frac = 116508, },
61c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 15360, .xf =  4, .wb_int = 57, .wb_frac = 305834, },
62c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 16200, .xf =  5, .wb_int = 54, .wb_frac = 336579, },
63c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 16800, .xf =  6, .wb_int = 52, .wb_frac = 399457, },
64c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 19200, .xf =  7, .wb_int = 45, .wb_frac = 873813, },
65c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 19800, .xf =  8, .wb_int = 44, .wb_frac = 466033, },
66c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 20000, .xf =  9, .wb_int = 44, .wb_frac = 0,      },
67c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 25000, .xf = 10, .wb_int = 70, .wb_frac = 419430, },
68c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 26000, .xf = 11, .wb_int = 67, .wb_frac = 725937, },
69c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 30000, .xf = 12, .wb_int = 58, .wb_frac = 699050, },
70c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 38400, .xf = 13, .wb_int = 45, .wb_frac = 873813, },
71c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 40000, .xf = 14, .wb_int = 45, .wb_frac = 0,      },
72c9703146158c0415a60799570397e488bc982af5Michael Buesch};
73c9703146158c0415a60799570397e488bc982af5Michael Buesch#define SSB_PMU0_DEFAULT_XTALFREQ	20000
74c9703146158c0415a60799570397e488bc982af5Michael Buesch
75c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu0_plltab_entry * pmu0_plltab_find_entry(u32 crystalfreq)
76c9703146158c0415a60799570397e488bc982af5Michael Buesch{
77c9703146158c0415a60799570397e488bc982af5Michael Buesch	const struct pmu0_plltab_entry *e;
78c9703146158c0415a60799570397e488bc982af5Michael Buesch	unsigned int i;
79c9703146158c0415a60799570397e488bc982af5Michael Buesch
80c9703146158c0415a60799570397e488bc982af5Michael Buesch	for (i = 0; i < ARRAY_SIZE(pmu0_plltab); i++) {
81c9703146158c0415a60799570397e488bc982af5Michael Buesch		e = &pmu0_plltab[i];
82c9703146158c0415a60799570397e488bc982af5Michael Buesch		if (e->freq == crystalfreq)
83c9703146158c0415a60799570397e488bc982af5Michael Buesch			return e;
84c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
85c9703146158c0415a60799570397e488bc982af5Michael Buesch
86c9703146158c0415a60799570397e488bc982af5Michael Buesch	return NULL;
87c9703146158c0415a60799570397e488bc982af5Michael Buesch}
88c9703146158c0415a60799570397e488bc982af5Michael Buesch
89c9703146158c0415a60799570397e488bc982af5Michael Buesch/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
90c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
91c9703146158c0415a60799570397e488bc982af5Michael Buesch				u32 crystalfreq)
92c9703146158c0415a60799570397e488bc982af5Michael Buesch{
93c9703146158c0415a60799570397e488bc982af5Michael Buesch	struct ssb_bus *bus = cc->dev->bus;
94c9703146158c0415a60799570397e488bc982af5Michael Buesch	const struct pmu0_plltab_entry *e = NULL;
95c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 pmuctl, tmp, pllctl;
96c9703146158c0415a60799570397e488bc982af5Michael Buesch	unsigned int i;
97c9703146158c0415a60799570397e488bc982af5Michael Buesch
98c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (crystalfreq)
99c9703146158c0415a60799570397e488bc982af5Michael Buesch		e = pmu0_plltab_find_entry(crystalfreq);
100c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (!e)
101c9703146158c0415a60799570397e488bc982af5Michael Buesch		e = pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ);
102c9703146158c0415a60799570397e488bc982af5Michael Buesch	BUG_ON(!e);
103c9703146158c0415a60799570397e488bc982af5Michael Buesch	crystalfreq = e->freq;
104c9703146158c0415a60799570397e488bc982af5Michael Buesch	cc->pmu.crystalfreq = e->freq;
105c9703146158c0415a60799570397e488bc982af5Michael Buesch
106c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Check if the PLL already is programmed to this frequency. */
107c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
108c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
109c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* We're already there... */
110c9703146158c0415a60799570397e488bc982af5Michael Buesch		return;
111c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
112c9703146158c0415a60799570397e488bc982af5Michael Buesch
113c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
114c9703146158c0415a60799570397e488bc982af5Michael Buesch		   (crystalfreq / 1000), (crystalfreq % 1000));
115c9703146158c0415a60799570397e488bc982af5Michael Buesch
116c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* First turn the PLL off. */
117c9703146158c0415a60799570397e488bc982af5Michael Buesch	switch (bus->chip_id) {
118c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4328:
119c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
120c9703146158c0415a60799570397e488bc982af5Michael Buesch			      ~(1 << SSB_PMURES_4328_BB_PLL_PU));
121c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
122c9703146158c0415a60799570397e488bc982af5Michael Buesch			      ~(1 << SSB_PMURES_4328_BB_PLL_PU));
123c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
124c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x5354:
125c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
126c9703146158c0415a60799570397e488bc982af5Michael Buesch			      ~(1 << SSB_PMURES_5354_BB_PLL_PU));
127c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
128c9703146158c0415a60799570397e488bc982af5Michael Buesch			      ~(1 << SSB_PMURES_5354_BB_PLL_PU));
129c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
130c9703146158c0415a60799570397e488bc982af5Michael Buesch	default:
131c9703146158c0415a60799570397e488bc982af5Michael Buesch		SSB_WARN_ON(1);
132c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
133c9703146158c0415a60799570397e488bc982af5Michael Buesch	for (i = 1500; i; i--) {
134c9703146158c0415a60799570397e488bc982af5Michael Buesch		tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
135c9703146158c0415a60799570397e488bc982af5Michael Buesch		if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
136c9703146158c0415a60799570397e488bc982af5Michael Buesch			break;
137c9703146158c0415a60799570397e488bc982af5Michael Buesch		udelay(10);
138c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
139c9703146158c0415a60799570397e488bc982af5Michael Buesch	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
140c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
141c9703146158c0415a60799570397e488bc982af5Michael Buesch		ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
142c9703146158c0415a60799570397e488bc982af5Michael Buesch
143c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set PDIV in PLL control 0. */
144c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0);
145c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (crystalfreq >= SSB_PMU0_PLLCTL0_PDIV_FREQ)
146c9703146158c0415a60799570397e488bc982af5Michael Buesch		pllctl |= SSB_PMU0_PLLCTL0_PDIV_MSK;
147c9703146158c0415a60799570397e488bc982af5Michael Buesch	else
148c9703146158c0415a60799570397e488bc982af5Michael Buesch		pllctl &= ~SSB_PMU0_PLLCTL0_PDIV_MSK;
149c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL0, pllctl);
150c9703146158c0415a60799570397e488bc982af5Michael Buesch
151c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set WILD in PLL control 1. */
152c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL1);
153c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl &= ~SSB_PMU0_PLLCTL1_STOPMOD;
154c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl &= ~(SSB_PMU0_PLLCTL1_WILD_IMSK | SSB_PMU0_PLLCTL1_WILD_FMSK);
155c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= ((u32)e->wb_int << SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_IMSK;
156c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= ((u32)e->wb_frac << SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_FMSK;
157c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (e->wb_frac == 0)
158c9703146158c0415a60799570397e488bc982af5Michael Buesch		pllctl |= SSB_PMU0_PLLCTL1_STOPMOD;
159c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL1, pllctl);
160c9703146158c0415a60799570397e488bc982af5Michael Buesch
161c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set WILD in PLL control 2. */
162c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL2);
163c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl &= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI;
164c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= (((u32)e->wb_int >> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT) & SSB_PMU0_PLLCTL2_WILD_IMSKHI;
165c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL2, pllctl);
166c9703146158c0415a60799570397e488bc982af5Michael Buesch
167c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set the crystalfrequency and the divisor. */
168c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
169c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl &= ~SSB_CHIPCO_PMU_CTL_ILP_DIV;
170c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl |= (((crystalfreq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
171c9703146158c0415a60799570397e488bc982af5Michael Buesch			& SSB_CHIPCO_PMU_CTL_ILP_DIV;
172c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl &= ~SSB_CHIPCO_PMU_CTL_XTALFREQ;
173c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
174c9703146158c0415a60799570397e488bc982af5Michael Buesch	chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
175c9703146158c0415a60799570397e488bc982af5Michael Buesch}
176c9703146158c0415a60799570397e488bc982af5Michael Buesch
177c9703146158c0415a60799570397e488bc982af5Michael Bueschstruct pmu1_plltab_entry {
178c9703146158c0415a60799570397e488bc982af5Michael Buesch	u16 freq;	/* Crystal frequency in kHz.*/
179c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 xf;		/* Crystal frequency value for PMU control */
180c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 ndiv_int;
181c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 ndiv_frac;
182c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 p1div;
183c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 p2div;
184c9703146158c0415a60799570397e488bc982af5Michael Buesch};
185c9703146158c0415a60799570397e488bc982af5Michael Buesch
186c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu1_plltab_entry pmu1_plltab[] = {
187c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 12000, .xf =  1, .p1div = 3, .p2div = 22, .ndiv_int =  0x9, .ndiv_frac = 0xFFFFEF, },
188c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 13000, .xf =  2, .p1div = 1, .p2div =  6, .ndiv_int =  0xb, .ndiv_frac = 0x483483, },
189c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 14400, .xf =  3, .p1div = 1, .p2div = 10, .ndiv_int =  0xa, .ndiv_frac = 0x1C71C7, },
190c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 15360, .xf =  4, .p1div = 1, .p2div =  5, .ndiv_int =  0xb, .ndiv_frac = 0x755555, },
191c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 16200, .xf =  5, .p1div = 1, .p2div = 10, .ndiv_int =  0x5, .ndiv_frac = 0x6E9E06, },
192c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 16800, .xf =  6, .p1div = 1, .p2div = 10, .ndiv_int =  0x5, .ndiv_frac = 0x3CF3CF, },
193c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 19200, .xf =  7, .p1div = 1, .p2div =  9, .ndiv_int =  0x5, .ndiv_frac = 0x17B425, },
194c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 19800, .xf =  8, .p1div = 1, .p2div = 11, .ndiv_int =  0x4, .ndiv_frac = 0xA57EB,  },
195c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 20000, .xf =  9, .p1div = 1, .p2div = 11, .ndiv_int =  0x4, .ndiv_frac = 0,        },
196c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 24000, .xf = 10, .p1div = 3, .p2div = 11, .ndiv_int =  0xa, .ndiv_frac = 0,        },
197c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 25000, .xf = 11, .p1div = 5, .p2div = 16, .ndiv_int =  0xb, .ndiv_frac = 0,        },
198c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 26000, .xf = 12, .p1div = 1, .p2div =  2, .ndiv_int = 0x10, .ndiv_frac = 0xEC4EC4, },
199c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 30000, .xf = 13, .p1div = 3, .p2div =  8, .ndiv_int =  0xb, .ndiv_frac = 0,        },
200c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 38400, .xf = 14, .p1div = 1, .p2div =  5, .ndiv_int =  0x4, .ndiv_frac = 0x955555, },
201c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .freq = 40000, .xf = 15, .p1div = 1, .p2div =  2, .ndiv_int =  0xb, .ndiv_frac = 0,        },
202c9703146158c0415a60799570397e488bc982af5Michael Buesch};
203c9703146158c0415a60799570397e488bc982af5Michael Buesch
204c9703146158c0415a60799570397e488bc982af5Michael Buesch#define SSB_PMU1_DEFAULT_XTALFREQ	15360
205c9703146158c0415a60799570397e488bc982af5Michael Buesch
206c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu1_plltab_entry * pmu1_plltab_find_entry(u32 crystalfreq)
207c9703146158c0415a60799570397e488bc982af5Michael Buesch{
208c9703146158c0415a60799570397e488bc982af5Michael Buesch	const struct pmu1_plltab_entry *e;
209c9703146158c0415a60799570397e488bc982af5Michael Buesch	unsigned int i;
210c9703146158c0415a60799570397e488bc982af5Michael Buesch
211c9703146158c0415a60799570397e488bc982af5Michael Buesch	for (i = 0; i < ARRAY_SIZE(pmu1_plltab); i++) {
212c9703146158c0415a60799570397e488bc982af5Michael Buesch		e = &pmu1_plltab[i];
213c9703146158c0415a60799570397e488bc982af5Michael Buesch		if (e->freq == crystalfreq)
214c9703146158c0415a60799570397e488bc982af5Michael Buesch			return e;
215c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
216c9703146158c0415a60799570397e488bc982af5Michael Buesch
217c9703146158c0415a60799570397e488bc982af5Michael Buesch	return NULL;
218c9703146158c0415a60799570397e488bc982af5Michael Buesch}
219c9703146158c0415a60799570397e488bc982af5Michael Buesch
220c9703146158c0415a60799570397e488bc982af5Michael Buesch/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
221c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
222c9703146158c0415a60799570397e488bc982af5Michael Buesch				u32 crystalfreq)
223c9703146158c0415a60799570397e488bc982af5Michael Buesch{
224c9703146158c0415a60799570397e488bc982af5Michael Buesch	struct ssb_bus *bus = cc->dev->bus;
225c9703146158c0415a60799570397e488bc982af5Michael Buesch	const struct pmu1_plltab_entry *e = NULL;
226c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 buffer_strength = 0;
227c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 tmp, pllctl, pmuctl;
228c9703146158c0415a60799570397e488bc982af5Michael Buesch	unsigned int i;
229c9703146158c0415a60799570397e488bc982af5Michael Buesch
230c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (bus->chip_id == 0x4312) {
231c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* We do not touch the BCM4312 PLL and assume
232c9703146158c0415a60799570397e488bc982af5Michael Buesch		 * the default crystal settings work out-of-the-box. */
233c9703146158c0415a60799570397e488bc982af5Michael Buesch		cc->pmu.crystalfreq = 20000;
234c9703146158c0415a60799570397e488bc982af5Michael Buesch		return;
235c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
236c9703146158c0415a60799570397e488bc982af5Michael Buesch
237c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (crystalfreq)
238c9703146158c0415a60799570397e488bc982af5Michael Buesch		e = pmu1_plltab_find_entry(crystalfreq);
239c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (!e)
240c9703146158c0415a60799570397e488bc982af5Michael Buesch		e = pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ);
241c9703146158c0415a60799570397e488bc982af5Michael Buesch	BUG_ON(!e);
242c9703146158c0415a60799570397e488bc982af5Michael Buesch	crystalfreq = e->freq;
243c9703146158c0415a60799570397e488bc982af5Michael Buesch	cc->pmu.crystalfreq = e->freq;
244c9703146158c0415a60799570397e488bc982af5Michael Buesch
245c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Check if the PLL already is programmed to this frequency. */
246c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
247c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
248c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* We're already there... */
249c9703146158c0415a60799570397e488bc982af5Michael Buesch		return;
250c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
251c9703146158c0415a60799570397e488bc982af5Michael Buesch
252c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
253c9703146158c0415a60799570397e488bc982af5Michael Buesch		   (crystalfreq / 1000), (crystalfreq % 1000));
254c9703146158c0415a60799570397e488bc982af5Michael Buesch
255c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* First turn the PLL off. */
256c9703146158c0415a60799570397e488bc982af5Michael Buesch	switch (bus->chip_id) {
257c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4325:
258c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
259c9703146158c0415a60799570397e488bc982af5Michael Buesch			      ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
260c9703146158c0415a60799570397e488bc982af5Michael Buesch				(1 << SSB_PMURES_4325_HT_AVAIL)));
261c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
262c9703146158c0415a60799570397e488bc982af5Michael Buesch			      ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
263c9703146158c0415a60799570397e488bc982af5Michael Buesch				(1 << SSB_PMURES_4325_HT_AVAIL)));
264c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* Adjust the BBPLL to 2 on all channels later. */
265c9703146158c0415a60799570397e488bc982af5Michael Buesch		buffer_strength = 0x222222;
266c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
267c9703146158c0415a60799570397e488bc982af5Michael Buesch	default:
268c9703146158c0415a60799570397e488bc982af5Michael Buesch		SSB_WARN_ON(1);
269c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
270c9703146158c0415a60799570397e488bc982af5Michael Buesch	for (i = 1500; i; i--) {
271c9703146158c0415a60799570397e488bc982af5Michael Buesch		tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
272c9703146158c0415a60799570397e488bc982af5Michael Buesch		if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
273c9703146158c0415a60799570397e488bc982af5Michael Buesch			break;
274c9703146158c0415a60799570397e488bc982af5Michael Buesch		udelay(10);
275c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
276c9703146158c0415a60799570397e488bc982af5Michael Buesch	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
277c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
278c9703146158c0415a60799570397e488bc982af5Michael Buesch		ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
279c9703146158c0415a60799570397e488bc982af5Michael Buesch
280c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set p1div and p2div. */
281c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
282c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl &= ~(SSB_PMU1_PLLCTL0_P1DIV | SSB_PMU1_PLLCTL0_P2DIV);
283c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= ((u32)e->p1div << SSB_PMU1_PLLCTL0_P1DIV_SHIFT) & SSB_PMU1_PLLCTL0_P1DIV;
284c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= ((u32)e->p2div << SSB_PMU1_PLLCTL0_P2DIV_SHIFT) & SSB_PMU1_PLLCTL0_P2DIV;
285c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, pllctl);
286c9703146158c0415a60799570397e488bc982af5Michael Buesch
287c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set ndiv int and ndiv mode */
288c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL2);
289c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl &= ~(SSB_PMU1_PLLCTL2_NDIVINT | SSB_PMU1_PLLCTL2_NDIVMODE);
290c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= ((u32)e->ndiv_int << SSB_PMU1_PLLCTL2_NDIVINT_SHIFT) & SSB_PMU1_PLLCTL2_NDIVINT;
291c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT) & SSB_PMU1_PLLCTL2_NDIVMODE;
292c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, pllctl);
293c9703146158c0415a60799570397e488bc982af5Michael Buesch
294c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set ndiv frac */
295c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL3);
296c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl &= ~SSB_PMU1_PLLCTL3_NDIVFRAC;
297c9703146158c0415a60799570397e488bc982af5Michael Buesch	pllctl |= ((u32)e->ndiv_frac << SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT) & SSB_PMU1_PLLCTL3_NDIVFRAC;
298c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, pllctl);
299c9703146158c0415a60799570397e488bc982af5Michael Buesch
300c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Change the drive strength, if required. */
301c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (buffer_strength) {
302c9703146158c0415a60799570397e488bc982af5Michael Buesch		pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL5);
303c9703146158c0415a60799570397e488bc982af5Michael Buesch		pllctl &= ~SSB_PMU1_PLLCTL5_CLKDRV;
304c9703146158c0415a60799570397e488bc982af5Michael Buesch		pllctl |= (buffer_strength << SSB_PMU1_PLLCTL5_CLKDRV_SHIFT) & SSB_PMU1_PLLCTL5_CLKDRV;
305c9703146158c0415a60799570397e488bc982af5Michael Buesch		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, pllctl);
306c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
307c9703146158c0415a60799570397e488bc982af5Michael Buesch
308c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Tune the crystalfreq and the divisor. */
309c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
310c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl &= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV | SSB_CHIPCO_PMU_CTL_XTALFREQ);
311c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl |= ((((u32)e->freq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
312c9703146158c0415a60799570397e488bc982af5Michael Buesch			& SSB_CHIPCO_PMU_CTL_ILP_DIV;
313c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
314c9703146158c0415a60799570397e488bc982af5Michael Buesch	chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
315c9703146158c0415a60799570397e488bc982af5Michael Buesch}
316c9703146158c0415a60799570397e488bc982af5Michael Buesch
317c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
318c9703146158c0415a60799570397e488bc982af5Michael Buesch{
319c9703146158c0415a60799570397e488bc982af5Michael Buesch	struct ssb_bus *bus = cc->dev->bus;
320c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
321c9703146158c0415a60799570397e488bc982af5Michael Buesch
322c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (bus->bustype == SSB_BUSTYPE_SSB) {
323d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens#ifdef CONFIG_BCM47XX
324d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		char buf[20];
325d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		if (nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
326d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens			crystalfreq = simple_strtoul(buf, NULL, 0);
327d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens#endif
328c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
329c9703146158c0415a60799570397e488bc982af5Michael Buesch
330c9703146158c0415a60799570397e488bc982af5Michael Buesch	switch (bus->chip_id) {
331c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4312:
332c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4325:
333c9703146158c0415a60799570397e488bc982af5Michael Buesch		ssb_pmu1_pllinit_r0(cc, crystalfreq);
334c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
335c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4328:
336d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		ssb_pmu0_pllinit_r0(cc, crystalfreq);
337d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		break;
338c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x5354:
339d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		if (crystalfreq == 0)
340d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens			crystalfreq = 25000;
341c9703146158c0415a60799570397e488bc982af5Michael Buesch		ssb_pmu0_pllinit_r0(cc, crystalfreq);
342c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
343ac5b4e168ebd9046a6cd066d50b3341353f2f309Larry Finger	case 0x4322:
344ac5b4e168ebd9046a6cd066d50b3341353f2f309Larry Finger		if (cc->pmu.rev == 2) {
345ac5b4e168ebd9046a6cd066d50b3341353f2f309Larry Finger			chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, 0x0000000A);
346ac5b4e168ebd9046a6cd066d50b3341353f2f309Larry Finger			chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
347ac5b4e168ebd9046a6cd066d50b3341353f2f309Larry Finger		}
348ac5b4e168ebd9046a6cd066d50b3341353f2f309Larry Finger		break;
349c9703146158c0415a60799570397e488bc982af5Michael Buesch	default:
350c9703146158c0415a60799570397e488bc982af5Michael Buesch		ssb_printk(KERN_ERR PFX
351c9703146158c0415a60799570397e488bc982af5Michael Buesch			   "ERROR: PLL init unknown for device %04X\n",
352c9703146158c0415a60799570397e488bc982af5Michael Buesch			   bus->chip_id);
353c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
354c9703146158c0415a60799570397e488bc982af5Michael Buesch}
355c9703146158c0415a60799570397e488bc982af5Michael Buesch
356c9703146158c0415a60799570397e488bc982af5Michael Bueschstruct pmu_res_updown_tab_entry {
357c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 resource;	/* The resource number */
358c9703146158c0415a60799570397e488bc982af5Michael Buesch	u16 updown;	/* The updown value */
359c9703146158c0415a60799570397e488bc982af5Michael Buesch};
360c9703146158c0415a60799570397e488bc982af5Michael Buesch
361c9703146158c0415a60799570397e488bc982af5Michael Bueschenum pmu_res_depend_tab_task {
362c9703146158c0415a60799570397e488bc982af5Michael Buesch	PMU_RES_DEP_SET = 1,
363c9703146158c0415a60799570397e488bc982af5Michael Buesch	PMU_RES_DEP_ADD,
364c9703146158c0415a60799570397e488bc982af5Michael Buesch	PMU_RES_DEP_REMOVE,
365c9703146158c0415a60799570397e488bc982af5Michael Buesch};
366c9703146158c0415a60799570397e488bc982af5Michael Buesch
367c9703146158c0415a60799570397e488bc982af5Michael Bueschstruct pmu_res_depend_tab_entry {
368c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 resource;	/* The resource number */
369c9703146158c0415a60799570397e488bc982af5Michael Buesch	u8 task;	/* SET | ADD | REMOVE */
370c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 depend;	/* The depend mask */
371c9703146158c0415a60799570397e488bc982af5Michael Buesch};
372c9703146158c0415a60799570397e488bc982af5Michael Buesch
373c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0[] = {
374c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_EXT_SWITCHER_PWM,		.updown = 0x0101, },
375c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_BB_SWITCHER_PWM,		.updown = 0x1F01, },
376c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_BB_SWITCHER_BURST,	.updown = 0x010F, },
377c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_BB_EXT_SWITCHER_BURST,	.updown = 0x0101, },
378c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_ILP_REQUEST,		.updown = 0x0202, },
379c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_RADIO_SWITCHER_PWM,	.updown = 0x0F01, },
380c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_RADIO_SWITCHER_BURST,	.updown = 0x0F01, },
381c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_ROM_SWITCH,		.updown = 0x0101, },
382c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_PA_REF_LDO,		.updown = 0x0F01, },
383c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_RADIO_LDO,		.updown = 0x0F01, },
384c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_AFE_LDO,			.updown = 0x0F01, },
385c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_PLL_LDO,			.updown = 0x0F01, },
386c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_BG_FILTBYP,		.updown = 0x0101, },
387c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_TX_FILTBYP,		.updown = 0x0101, },
388c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_RX_FILTBYP,		.updown = 0x0101, },
389c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_XTAL_PU,			.updown = 0x0101, },
390c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_XTAL_EN,			.updown = 0xA001, },
391c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_BB_PLL_FILTBYP,		.updown = 0x0101, },
392c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_RF_PLL_FILTBYP,		.updown = 0x0101, },
393c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4328_BB_PLL_PU,		.updown = 0x0701, },
394c9703146158c0415a60799570397e488bc982af5Michael Buesch};
395c9703146158c0415a60799570397e488bc982af5Michael Buesch
396c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0[] = {
397c9703146158c0415a60799570397e488bc982af5Michael Buesch	{
398c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */
399c9703146158c0415a60799570397e488bc982af5Michael Buesch		.resource = SSB_PMURES_4328_ILP_REQUEST,
400c9703146158c0415a60799570397e488bc982af5Michael Buesch		.task = PMU_RES_DEP_SET,
401c9703146158c0415a60799570397e488bc982af5Michael Buesch		.depend = ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
402c9703146158c0415a60799570397e488bc982af5Michael Buesch			   (1 << SSB_PMURES_4328_BB_SWITCHER_PWM)),
403c9703146158c0415a60799570397e488bc982af5Michael Buesch	},
404c9703146158c0415a60799570397e488bc982af5Michael Buesch};
405c9703146158c0415a60799570397e488bc982af5Michael Buesch
406c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0[] = {
407c9703146158c0415a60799570397e488bc982af5Michael Buesch	{ .resource = SSB_PMURES_4325_XTAL_PU,			.updown = 0x1501, },
408c9703146158c0415a60799570397e488bc982af5Michael Buesch};
409c9703146158c0415a60799570397e488bc982af5Michael Buesch
410c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0[] = {
411c9703146158c0415a60799570397e488bc982af5Michael Buesch	{
412c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* Adjust HT-Available dependencies. */
413c9703146158c0415a60799570397e488bc982af5Michael Buesch		.resource = SSB_PMURES_4325_HT_AVAIL,
414c9703146158c0415a60799570397e488bc982af5Michael Buesch		.task = PMU_RES_DEP_ADD,
415c9703146158c0415a60799570397e488bc982af5Michael Buesch		.depend = ((1 << SSB_PMURES_4325_RX_PWRSW_PU) |
416c9703146158c0415a60799570397e488bc982af5Michael Buesch			   (1 << SSB_PMURES_4325_TX_PWRSW_PU) |
417c9703146158c0415a60799570397e488bc982af5Michael Buesch			   (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU) |
418c9703146158c0415a60799570397e488bc982af5Michael Buesch			   (1 << SSB_PMURES_4325_AFE_PWRSW_PU)),
419c9703146158c0415a60799570397e488bc982af5Michael Buesch	},
420c9703146158c0415a60799570397e488bc982af5Michael Buesch};
421c9703146158c0415a60799570397e488bc982af5Michael Buesch
422c9703146158c0415a60799570397e488bc982af5Michael Bueschstatic void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
423c9703146158c0415a60799570397e488bc982af5Michael Buesch{
424c9703146158c0415a60799570397e488bc982af5Michael Buesch	struct ssb_bus *bus = cc->dev->bus;
425c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 min_msk = 0, max_msk = 0;
426c9703146158c0415a60799570397e488bc982af5Michael Buesch	unsigned int i;
427c9703146158c0415a60799570397e488bc982af5Michael Buesch	const struct pmu_res_updown_tab_entry *updown_tab = NULL;
428eb40e3e8bb453519ae17d42e7cab6bdd2b4b9fc5Connor Hansen	unsigned int updown_tab_size = 0;
429c9703146158c0415a60799570397e488bc982af5Michael Buesch	const struct pmu_res_depend_tab_entry *depend_tab = NULL;
430eb40e3e8bb453519ae17d42e7cab6bdd2b4b9fc5Connor Hansen	unsigned int depend_tab_size = 0;
431c9703146158c0415a60799570397e488bc982af5Michael Buesch
432c9703146158c0415a60799570397e488bc982af5Michael Buesch	switch (bus->chip_id) {
433c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4312:
4343c35c84a70fc7d76cf7d975481fcb30468c68818Rafał Miłecki		 min_msk = 0xCBB;
4353c35c84a70fc7d76cf7d975481fcb30468c68818Rafał Miłecki		 break;
436ac5b4e168ebd9046a6cd066d50b3341353f2f309Larry Finger	case 0x4322:
437c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* We keep the default settings:
438c9703146158c0415a60799570397e488bc982af5Michael Buesch		 * min_msk = 0xCBB
439c9703146158c0415a60799570397e488bc982af5Michael Buesch		 * max_msk = 0x7FFFF
440c9703146158c0415a60799570397e488bc982af5Michael Buesch		 */
441c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
442c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4325:
443c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* Power OTP down later. */
444c9703146158c0415a60799570397e488bc982af5Michael Buesch		min_msk = (1 << SSB_PMURES_4325_CBUCK_BURST) |
445c9703146158c0415a60799570397e488bc982af5Michael Buesch			  (1 << SSB_PMURES_4325_LNLDO2_PU);
446c9703146158c0415a60799570397e488bc982af5Michael Buesch		if (chipco_read32(cc, SSB_CHIPCO_CHIPSTAT) &
447c9703146158c0415a60799570397e488bc982af5Michael Buesch		    SSB_CHIPCO_CHST_4325_PMUTOP_2B)
448c9703146158c0415a60799570397e488bc982af5Michael Buesch			min_msk |= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST);
449c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* The PLL may turn on, if it decides so. */
450c9703146158c0415a60799570397e488bc982af5Michael Buesch		max_msk = 0xFFFFF;
451c9703146158c0415a60799570397e488bc982af5Michael Buesch		updown_tab = pmu_res_updown_tab_4325a0;
452c9703146158c0415a60799570397e488bc982af5Michael Buesch		updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4325a0);
453c9703146158c0415a60799570397e488bc982af5Michael Buesch		depend_tab = pmu_res_depend_tab_4325a0;
454c9703146158c0415a60799570397e488bc982af5Michael Buesch		depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4325a0);
455c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
456c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x4328:
457c9703146158c0415a60799570397e488bc982af5Michael Buesch		min_msk = (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
458c9703146158c0415a60799570397e488bc982af5Michael Buesch			  (1 << SSB_PMURES_4328_BB_SWITCHER_PWM) |
459c9703146158c0415a60799570397e488bc982af5Michael Buesch			  (1 << SSB_PMURES_4328_XTAL_EN);
460c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* The PLL may turn on, if it decides so. */
461c9703146158c0415a60799570397e488bc982af5Michael Buesch		max_msk = 0xFFFFF;
462c9703146158c0415a60799570397e488bc982af5Michael Buesch		updown_tab = pmu_res_updown_tab_4328a0;
463c9703146158c0415a60799570397e488bc982af5Michael Buesch		updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4328a0);
464c9703146158c0415a60799570397e488bc982af5Michael Buesch		depend_tab = pmu_res_depend_tab_4328a0;
465c9703146158c0415a60799570397e488bc982af5Michael Buesch		depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4328a0);
466c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
467c9703146158c0415a60799570397e488bc982af5Michael Buesch	case 0x5354:
468c9703146158c0415a60799570397e488bc982af5Michael Buesch		/* The PLL may turn on, if it decides so. */
469c9703146158c0415a60799570397e488bc982af5Michael Buesch		max_msk = 0xFFFFF;
470c9703146158c0415a60799570397e488bc982af5Michael Buesch		break;
471c9703146158c0415a60799570397e488bc982af5Michael Buesch	default:
472c9703146158c0415a60799570397e488bc982af5Michael Buesch		ssb_printk(KERN_ERR PFX
473c9703146158c0415a60799570397e488bc982af5Michael Buesch			   "ERROR: PMU resource config unknown for device %04X\n",
474c9703146158c0415a60799570397e488bc982af5Michael Buesch			   bus->chip_id);
475c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
476c9703146158c0415a60799570397e488bc982af5Michael Buesch
477c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (updown_tab) {
478c9703146158c0415a60799570397e488bc982af5Michael Buesch		for (i = 0; i < updown_tab_size; i++) {
479c9703146158c0415a60799570397e488bc982af5Michael Buesch			chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
480c9703146158c0415a60799570397e488bc982af5Michael Buesch				       updown_tab[i].resource);
481c9703146158c0415a60799570397e488bc982af5Michael Buesch			chipco_write32(cc, SSB_CHIPCO_PMU_RES_UPDNTM,
482c9703146158c0415a60799570397e488bc982af5Michael Buesch				       updown_tab[i].updown);
483c9703146158c0415a60799570397e488bc982af5Michael Buesch		}
484c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
485c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (depend_tab) {
486c9703146158c0415a60799570397e488bc982af5Michael Buesch		for (i = 0; i < depend_tab_size; i++) {
487c9703146158c0415a60799570397e488bc982af5Michael Buesch			chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
488c9703146158c0415a60799570397e488bc982af5Michael Buesch				       depend_tab[i].resource);
489c9703146158c0415a60799570397e488bc982af5Michael Buesch			switch (depend_tab[i].task) {
490c9703146158c0415a60799570397e488bc982af5Michael Buesch			case PMU_RES_DEP_SET:
491c9703146158c0415a60799570397e488bc982af5Michael Buesch				chipco_write32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
492c9703146158c0415a60799570397e488bc982af5Michael Buesch					       depend_tab[i].depend);
493c9703146158c0415a60799570397e488bc982af5Michael Buesch				break;
494c9703146158c0415a60799570397e488bc982af5Michael Buesch			case PMU_RES_DEP_ADD:
495c9703146158c0415a60799570397e488bc982af5Michael Buesch				chipco_set32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
496c9703146158c0415a60799570397e488bc982af5Michael Buesch					     depend_tab[i].depend);
497c9703146158c0415a60799570397e488bc982af5Michael Buesch				break;
498c9703146158c0415a60799570397e488bc982af5Michael Buesch			case PMU_RES_DEP_REMOVE:
499c9703146158c0415a60799570397e488bc982af5Michael Buesch				chipco_mask32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
500c9703146158c0415a60799570397e488bc982af5Michael Buesch					      ~(depend_tab[i].depend));
501c9703146158c0415a60799570397e488bc982af5Michael Buesch				break;
502c9703146158c0415a60799570397e488bc982af5Michael Buesch			default:
503c9703146158c0415a60799570397e488bc982af5Michael Buesch				SSB_WARN_ON(1);
504c9703146158c0415a60799570397e488bc982af5Michael Buesch			}
505c9703146158c0415a60799570397e488bc982af5Michael Buesch		}
506c9703146158c0415a60799570397e488bc982af5Michael Buesch	}
507c9703146158c0415a60799570397e488bc982af5Michael Buesch
508c9703146158c0415a60799570397e488bc982af5Michael Buesch	/* Set the resource masks. */
509c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (min_msk)
510c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_write32(cc, SSB_CHIPCO_PMU_MINRES_MSK, min_msk);
511c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (max_msk)
512c9703146158c0415a60799570397e488bc982af5Michael Buesch		chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
513c9703146158c0415a60799570397e488bc982af5Michael Buesch}
514c9703146158c0415a60799570397e488bc982af5Michael Buesch
515c35deb4e70d52ed564c58569fe059dd7ca5f4eecRafał Miłecki/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
516c9703146158c0415a60799570397e488bc982af5Michael Bueschvoid ssb_pmu_init(struct ssb_chipcommon *cc)
517c9703146158c0415a60799570397e488bc982af5Michael Buesch{
518c9703146158c0415a60799570397e488bc982af5Michael Buesch	u32 pmucap;
519c9703146158c0415a60799570397e488bc982af5Michael Buesch
520c9703146158c0415a60799570397e488bc982af5Michael Buesch	if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
521c9703146158c0415a60799570397e488bc982af5Michael Buesch		return;
522c9703146158c0415a60799570397e488bc982af5Michael Buesch
523c9703146158c0415a60799570397e488bc982af5Michael Buesch	pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);
524c9703146158c0415a60799570397e488bc982af5Michael Buesch	cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION);
525c9703146158c0415a60799570397e488bc982af5Michael Buesch
526c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
527c9703146158c0415a60799570397e488bc982af5Michael Buesch		    cc->pmu.rev, pmucap);
528c9703146158c0415a60799570397e488bc982af5Michael Buesch
529c35deb4e70d52ed564c58569fe059dd7ca5f4eecRafał Miłecki	if (cc->pmu.rev == 1)
530c35deb4e70d52ed564c58569fe059dd7ca5f4eecRafał Miłecki		chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
531c35deb4e70d52ed564c58569fe059dd7ca5f4eecRafał Miłecki			      ~SSB_CHIPCO_PMU_CTL_NOILPONW);
532c35deb4e70d52ed564c58569fe059dd7ca5f4eecRafał Miłecki	else
533c35deb4e70d52ed564c58569fe059dd7ca5f4eecRafał Miłecki		chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
534c35deb4e70d52ed564c58569fe059dd7ca5f4eecRafał Miłecki			     SSB_CHIPCO_PMU_CTL_NOILPONW);
535c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_pmu_pll_init(cc);
536c9703146158c0415a60799570397e488bc982af5Michael Buesch	ssb_pmu_resources_init(cc);
537c9703146158c0415a60799570397e488bc982af5Michael Buesch}
53806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
53906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanikvoid ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
54006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			     enum ssb_pmu_ldo_volt_id id, u32 voltage)
54106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik{
54206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	struct ssb_bus *bus = cc->dev->bus;
54306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	u32 addr, shift, mask;
54406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
54506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	switch (bus->chip_id) {
54606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	case 0x4328:
54706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	case 0x5354:
54806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		switch (id) {
54906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		case LDO_VOLT1:
55006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			addr = 2;
55106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			shift = 25;
55206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			mask = 0xF;
55306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			break;
55406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		case LDO_VOLT2:
55506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			addr = 3;
55606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			shift = 1;
55706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			mask = 0xF;
55806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			break;
55906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		case LDO_VOLT3:
56006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			addr = 3;
56106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			shift = 9;
56206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			mask = 0xF;
56306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			break;
56406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		case LDO_PAREF:
56506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			addr = 3;
56606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			shift = 17;
56706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			mask = 0x3F;
56806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			break;
56906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		default:
57006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			SSB_WARN_ON(1);
57106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			return;
57206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		}
57306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		break;
57406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	case 0x4312:
57506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		if (SSB_WARN_ON(id != LDO_PAREF))
57606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik			return;
57706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		addr = 0;
57806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		shift = 21;
57906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		mask = 0x3F;
58006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		break;
58106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	default:
58206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		return;
58306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	}
58406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
58506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	ssb_chipco_regctl_maskset(cc, addr, ~(mask << shift),
58606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik				  (voltage & mask) << shift);
58706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik}
58806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
58906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanikvoid ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on)
59006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik{
59106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	struct ssb_bus *bus = cc->dev->bus;
59206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	int ldo;
59306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
59406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	switch (bus->chip_id) {
59506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	case 0x4312:
59606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		ldo = SSB_PMURES_4312_PA_REF_LDO;
59706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		break;
59806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	case 0x4328:
59906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		ldo = SSB_PMURES_4328_PA_REF_LDO;
60006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		break;
60106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	case 0x5354:
60206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		ldo = SSB_PMURES_5354_PA_REF_LDO;
60306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		break;
60406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	default:
60506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		return;
60606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	}
60706e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
60806e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	if (on)
60906e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		chipco_set32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 1 << ldo);
61006e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	else
61106e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ~(1 << ldo));
61206e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik	chipco_read32(cc, SSB_CHIPCO_PMU_MINRES_MSK); //SPEC FIXME found via mmiotrace - dummy read?
61306e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik}
61406e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor Stefanik
61506e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor StefanikEXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
61606e4da268c0e8f3b8408403d65e47d2885a78ff2Gábor StefanikEXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
617d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens
618d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtensu32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
619d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens{
620d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	struct ssb_bus *bus = cc->dev->bus;
621d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens
622d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	switch (bus->chip_id) {
623d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	case 0x5354:
624d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		/* 5354 chip uses a non programmable PLL of frequency 240MHz */
625d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		return 240000000;
626d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	default:
627d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		ssb_printk(KERN_ERR PFX
628d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens			   "ERROR: PMU cpu clock unknown for device %04X\n",
629d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens			   bus->chip_id);
630d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		return 0;
631d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	}
632d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens}
633d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens
634d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtensu32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
635d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens{
636d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	struct ssb_bus *bus = cc->dev->bus;
637d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens
638d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	switch (bus->chip_id) {
639d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	case 0x5354:
640d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		return 120000000;
641d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	default:
642d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		ssb_printk(KERN_ERR PFX
643d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens			   "ERROR: PMU controlclock unknown for device %04X\n",
644d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens			   bus->chip_id);
645d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		return 0;
646d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	}
647d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens}
648