aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-30 20:07:18 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-30 20:07:18 -0500
commit4bcec913d0a98d991c750034a04675443d1f10b5 (patch)
treece2e960ba26d50f09b6a7bd864b2b4d3c275e69b /drivers/net
parent03c7287dd22c18815964219c9a2e75054cd004df (diff)
parentf878f84373aefda7f041a74b24a83b8b7dec1cf0 (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull more powerpc bits from Ben Herrenschmidt: "Here are a few more powerpc bits for this merge window. The bulk is made of two pull requests from Scott and Anatolij that I had missed previously (they arrived while I was away). Since both their branches are in -next independently, and the content has been around for a little while, they can still go in. The rest is mostly bug and regression fixes, a small series of cleanups to our pseries cpuidle code (including moving it to the right place), and one new cpuidle bakend for the powernv platform. I also wired up the new sched_attr syscalls" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (37 commits) powerpc: Wire up sched_setattr and sched_getattr syscalls powerpc/hugetlb: Replace __get_cpu_var with get_cpu_var powerpc: Make sure "cache" directory is removed when offlining cpu powerpc/mm: Fix mmap errno when MAP_FIXED is set and mapping exceeds the allowed address space powerpc/powernv/cpuidle: Back-end cpuidle driver for powernv platform. powerpc/pseries/cpuidle: smt-snooze-delay cleanup. powerpc/pseries/cpuidle: Remove MAX_IDLE_STATE macro. powerpc/pseries/cpuidle: Make cpuidle-pseries backend driver a non-module. powerpc/pseries/cpuidle: Use cpuidle_register() for initialisation. powerpc/pseries/cpuidle: Move processor_idle.c to drivers/cpuidle. powerpc: Fix 32-bit frames for signals delivered when transactional powerpc/iommu: Fix initialisation of DART iommu table powerpc/numa: Fix decimal permissions powerpc/mm: Fix compile error of pgtable-ppc64.h powerpc: Fix hw breakpoints on !HAVE_HW_BREAKPOINT configurations clk: corenet: Adds the clock binding powerpc/booke64: Guard e6500 tlb handler with CONFIG_PPC_FSL_BOOK3E powerpc/512x: dts: add MPC5125 clock specs powerpc/512x: clk: support MPC5121/5123/5125 SoC variants powerpc/512x: clk: enforce even SDHC divider values ...
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c270
1 files changed, 154 insertions, 116 deletions
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 035e235e3118..44725296f72a 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -108,135 +108,170 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
108#endif /* CONFIG_PPC_MPC52xx */ 108#endif /* CONFIG_PPC_MPC52xx */
109 109
110#ifdef CONFIG_PPC_MPC512x 110#ifdef CONFIG_PPC_MPC512x
111struct mpc512x_clockctl {
112 u32 spmr; /* System PLL Mode Reg */
113 u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */
114 u32 scfr1; /* System Clk Freq Reg 1 */
115 u32 scfr2; /* System Clk Freq Reg 2 */
116 u32 reserved;
117 u32 bcr; /* Bread Crumb Reg */
118 u32 pccr[12]; /* PSC Clk Ctrl Reg 0-11 */
119 u32 spccr; /* SPDIF Clk Ctrl Reg */
120 u32 cccr; /* CFM Clk Ctrl Reg */
121 u32 dccr; /* DIU Clk Cnfg Reg */
122 u32 mccr[4]; /* MSCAN Clk Ctrl Reg 1-3 */
123};
124
125static struct of_device_id mpc512x_clock_ids[] = {
126 { .compatible = "fsl,mpc5121-clock", },
127 {}
128};
129
130static u32 mpc512x_can_get_clock(struct platform_device *ofdev, 111static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
131 const char *clock_name, int *mscan_clksrc) 112 const char *clock_source, int *mscan_clksrc)
132{ 113{
133 struct mpc512x_clockctl __iomem *clockctl; 114 struct device_node *np;
134 struct device_node *np_clock; 115 u32 clockdiv;
135 struct clk *sys_clk, *ref_clk; 116 enum {
136 int plen, clockidx, clocksrc = -1; 117 CLK_FROM_AUTO,
137 u32 sys_freq, val, clockdiv = 1, freq = 0; 118 CLK_FROM_IPS,
138 const u32 *pval; 119 CLK_FROM_SYS,
139 120 CLK_FROM_REF,
140 np_clock = of_find_matching_node(NULL, mpc512x_clock_ids); 121 } clk_from;
141 if (!np_clock) { 122 struct clk *clk_in, *clk_can;
142 dev_err(&ofdev->dev, "couldn't find clock node\n"); 123 unsigned long freq_calc;
143 return 0; 124 struct mscan_priv *priv;
144 } 125 struct clk *clk_ipg;
145 clockctl = of_iomap(np_clock, 0);
146 if (!clockctl) {
147 dev_err(&ofdev->dev, "couldn't map clock registers\n");
148 goto exit_put;
149 }
150 126
151 /* Determine the MSCAN device index from the peripheral's 127 /* the caller passed in the clock source spec that was read from
152 * physical address. Register address offsets against the 128 * the device tree, get the optional clock divider as well
153 * IMMR base are: 0x1300, 0x1380, 0x2300, 0x2380
154 */ 129 */
155 pval = of_get_property(ofdev->dev.of_node, "reg", &plen); 130 np = ofdev->dev.of_node;
156 BUG_ON(!pval || plen < sizeof(*pval)); 131 clockdiv = 1;
157 clockidx = (*pval & 0x80) ? 1 : 0; 132 of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
158 if (*pval & 0x2000) 133 dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
159 clockidx += 2; 134 clock_source ? clock_source : "<NULL>", clockdiv);
135
136 /* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
137 * get set, and the 'ips' clock is the input to the MSCAN
138 * component
139 *
140 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
141 * bit needs to get cleared, an optional clock-divider may have
142 * been specified (the default value is 1), the appropriate
143 * MSCAN related MCLK is the input to the MSCAN component
144 *
145 * in the absence of a clock-source spec, first an optimal clock
146 * gets determined based on the 'sys' clock, if that fails the
147 * 'ref' clock is used
148 */
149 clk_from = CLK_FROM_AUTO;
150 if (clock_source) {
151 /* interpret the device tree's spec for the clock source */
152 if (!strcmp(clock_source, "ip"))
153 clk_from = CLK_FROM_IPS;
154 else if (!strcmp(clock_source, "sys"))
155 clk_from = CLK_FROM_SYS;
156 else if (!strcmp(clock_source, "ref"))
157 clk_from = CLK_FROM_REF;
158 else
159 goto err_invalid;
160 dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
161 }
162 if (clk_from == CLK_FROM_AUTO) {
163 /* no spec so far, try the 'sys' clock; round to the
164 * next MHz and see if we can get a multiple of 16MHz
165 */
166 dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
167 clk_in = devm_clk_get(&ofdev->dev, "sys");
168 if (IS_ERR(clk_in))
169 goto err_notavail;
170 freq_calc = clk_get_rate(clk_in);
171 freq_calc += 499999;
172 freq_calc /= 1000000;
173 freq_calc *= 1000000;
174 if ((freq_calc % 16000000) == 0) {
175 clk_from = CLK_FROM_SYS;
176 clockdiv = freq_calc / 16000000;
177 dev_dbg(&ofdev->dev,
178 "clk fit, sys[%lu] div[%d] freq[%lu]\n",
179 freq_calc, clockdiv, freq_calc / clockdiv);
180 }
181 }
182 if (clk_from == CLK_FROM_AUTO) {
183 /* no spec so far, use the 'ref' clock */
184 dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
185 clk_in = devm_clk_get(&ofdev->dev, "ref");
186 if (IS_ERR(clk_in))
187 goto err_notavail;
188 clk_from = CLK_FROM_REF;
189 freq_calc = clk_get_rate(clk_in);
190 dev_dbg(&ofdev->dev,
191 "clk fit, ref[%lu] (no div) freq[%lu]\n",
192 freq_calc, freq_calc);
193 }
160 194
161 /* 195 /* select IPS or MCLK as the MSCAN input (returned to the caller),
162 * Clock source and divider selection: 3 different clock sources 196 * setup the MCLK mux source and rate if applicable, apply the
163 * can be selected: "ip", "ref" or "sys". For the latter two, a 197 * optionally specified or derived above divider, and determine
164 * clock divider can be defined as well. If the clock source is 198 * the actual resulting clock rate to return to the caller
165 * not specified by the device tree, we first try to find an
166 * optimal CAN source clock based on the system clock. If that
167 * is not posslible, the reference clock will be used.
168 */ 199 */
169 if (clock_name && !strcmp(clock_name, "ip")) { 200 switch (clk_from) {
201 case CLK_FROM_IPS:
202 clk_can = devm_clk_get(&ofdev->dev, "ips");
203 if (IS_ERR(clk_can))
204 goto err_notavail;
205 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
206 priv->clk_can = clk_can;
207 freq_calc = clk_get_rate(clk_can);
170 *mscan_clksrc = MSCAN_CLKSRC_IPS; 208 *mscan_clksrc = MSCAN_CLKSRC_IPS;
171 freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node); 209 dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
172 } else { 210 *mscan_clksrc, freq_calc);
211 break;
212 case CLK_FROM_SYS:
213 case CLK_FROM_REF:
214 clk_can = devm_clk_get(&ofdev->dev, "mclk");
215 if (IS_ERR(clk_can))
216 goto err_notavail;
217 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
218 priv->clk_can = clk_can;
219 if (clk_from == CLK_FROM_SYS)
220 clk_in = devm_clk_get(&ofdev->dev, "sys");
221 if (clk_from == CLK_FROM_REF)
222 clk_in = devm_clk_get(&ofdev->dev, "ref");
223 if (IS_ERR(clk_in))
224 goto err_notavail;
225 clk_set_parent(clk_can, clk_in);
226 freq_calc = clk_get_rate(clk_in);
227 freq_calc /= clockdiv;
228 clk_set_rate(clk_can, freq_calc);
229 freq_calc = clk_get_rate(clk_can);
173 *mscan_clksrc = MSCAN_CLKSRC_BUS; 230 *mscan_clksrc = MSCAN_CLKSRC_BUS;
174 231 dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
175 pval = of_get_property(ofdev->dev.of_node, 232 *mscan_clksrc, freq_calc);
176 "fsl,mscan-clock-divider", &plen); 233 break;
177 if (pval && plen == sizeof(*pval)) 234 default:
178 clockdiv = *pval; 235 goto err_invalid;
179 if (!clockdiv)
180 clockdiv = 1;
181
182 if (!clock_name || !strcmp(clock_name, "sys")) {
183 sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
184 if (IS_ERR(sys_clk)) {
185 dev_err(&ofdev->dev, "couldn't get sys_clk\n");
186 goto exit_unmap;
187 }
188 /* Get and round up/down sys clock rate */
189 sys_freq = 1000000 *
190 ((clk_get_rate(sys_clk) + 499999) / 1000000);
191
192 if (!clock_name) {
193 /* A multiple of 16 MHz would be optimal */
194 if ((sys_freq % 16000000) == 0) {
195 clocksrc = 0;
196 clockdiv = sys_freq / 16000000;
197 freq = sys_freq / clockdiv;
198 }
199 } else {
200 clocksrc = 0;
201 freq = sys_freq / clockdiv;
202 }
203 }
204
205 if (clocksrc < 0) {
206 ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
207 if (IS_ERR(ref_clk)) {
208 dev_err(&ofdev->dev, "couldn't get ref_clk\n");
209 goto exit_unmap;
210 }
211 clocksrc = 1;
212 freq = clk_get_rate(ref_clk) / clockdiv;
213 }
214 } 236 }
215 237
216 /* Disable clock */ 238 /* the above clk_can item is used for the bitrate, access to
217 out_be32(&clockctl->mccr[clockidx], 0x0); 239 * the peripheral's register set needs the clk_ipg item
218 if (clocksrc >= 0) { 240 */
219 /* Set source and divider */ 241 clk_ipg = devm_clk_get(&ofdev->dev, "ipg");
220 val = (clocksrc << 14) | ((clockdiv - 1) << 17); 242 if (IS_ERR(clk_ipg))
221 out_be32(&clockctl->mccr[clockidx], val); 243 goto err_notavail_ipg;
222 /* Enable clock */ 244 if (clk_prepare_enable(clk_ipg))
223 out_be32(&clockctl->mccr[clockidx], val | 0x10000); 245 goto err_notavail_ipg;
224 } 246 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
247 priv->clk_ipg = clk_ipg;
248
249 /* return the determined clock source rate */
250 return freq_calc;
251
252err_invalid:
253 dev_err(&ofdev->dev, "invalid clock source specification\n");
254 /* clock source rate could not get determined */
255 return 0;
225 256
226 /* Enable MSCAN clock domain */ 257err_notavail:
227 val = in_be32(&clockctl->sccr[1]); 258 dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n");
228 if (!(val & (1 << 25))) 259 /* clock source rate could not get determined */
229 out_be32(&clockctl->sccr[1], val | (1 << 25)); 260 return 0;
230 261
231 dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n", 262err_notavail_ipg:
232 *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" : 263 dev_err(&ofdev->dev, "cannot acquire or setup register clock\n");
233 clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv); 264 /* clock source rate could not get determined */
265 return 0;
266}
234 267
235exit_unmap: 268static void mpc512x_can_put_clock(struct platform_device *ofdev)
236 iounmap(clockctl); 269{
237exit_put: 270 struct mscan_priv *priv;
238 of_node_put(np_clock); 271
239 return freq; 272 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
273 if (priv->clk_ipg)
274 clk_disable_unprepare(priv->clk_ipg);
240} 275}
241#else /* !CONFIG_PPC_MPC512x */ 276#else /* !CONFIG_PPC_MPC512x */
242static u32 mpc512x_can_get_clock(struct platform_device *ofdev, 277static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
@@ -244,6 +279,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
244{ 279{
245 return 0; 280 return 0;
246} 281}
282#define mpc512x_can_put_clock NULL
247#endif /* CONFIG_PPC_MPC512x */ 283#endif /* CONFIG_PPC_MPC512x */
248 284
249static const struct of_device_id mpc5xxx_can_table[]; 285static const struct of_device_id mpc5xxx_can_table[];
@@ -385,11 +421,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
385static const struct mpc5xxx_can_data mpc5200_can_data = { 421static const struct mpc5xxx_can_data mpc5200_can_data = {
386 .type = MSCAN_TYPE_MPC5200, 422 .type = MSCAN_TYPE_MPC5200,
387 .get_clock = mpc52xx_can_get_clock, 423 .get_clock = mpc52xx_can_get_clock,
424 /* .put_clock not applicable */
388}; 425};
389 426
390static const struct mpc5xxx_can_data mpc5121_can_data = { 427static const struct mpc5xxx_can_data mpc5121_can_data = {
391 .type = MSCAN_TYPE_MPC5121, 428 .type = MSCAN_TYPE_MPC5121,
392 .get_clock = mpc512x_can_get_clock, 429 .get_clock = mpc512x_can_get_clock,
430 .put_clock = mpc512x_can_put_clock,
393}; 431};
394 432
395static const struct of_device_id mpc5xxx_can_table[] = { 433static const struct of_device_id mpc5xxx_can_table[] = {