aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/can
diff options
context:
space:
mode:
authorGerhard Sittig <gsi@denx.de>2013-11-30 17:51:34 -0500
committerAnatolij Gustschin <agust@denx.de>2014-01-12 12:53:05 -0500
commit5ac22504f928db34a3a75ab67bf1eef82b91ef0b (patch)
tree05d4709c53108065711ee4ee93b5e63b0c03c067 /drivers/net/can
parent17552189088d261a7bbc8fe7b974061fae938d26 (diff)
net: can: mscan: adjust to common clock support for mpc512x
implement a .get_clock() callback for the MPC512x platform which uses the common clock infrastructure (eliminating direct access to the clock control registers from within the CAN network driver), and provide the corresponding .put_clock() callback to release resources after use acquire both the clock items for register access ("ipg") as well as for wire communication ("can") keep the previous implementation of MPC512x support in place during migration, this results in a readable diff of the change this change is neutral to the MPC5200 platform Cc: Wolfgang Grandegger <wg@grandegger.com> Cc: Marc Kleine-Budde <mkl@pengutronix.de> Cc: linux-can@vger.kernel.org Signed-off-by: Gerhard Sittig <gsi@denx.de> Signed-off-by: Anatolij Gustschin <agust@denx.de>
Diffstat (limited to 'drivers/net/can')
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index e59b3a392af6..f48f1297ff30 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -109,6 +109,177 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
109#endif /* CONFIG_PPC_MPC52xx */ 109#endif /* CONFIG_PPC_MPC52xx */
110 110
111#ifdef CONFIG_PPC_MPC512x 111#ifdef CONFIG_PPC_MPC512x
112
113#if IS_ENABLED(CONFIG_COMMON_CLK)
114
115static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
116 const char *clock_source, int *mscan_clksrc)
117{
118 struct device_node *np;
119 u32 clockdiv;
120 enum {
121 CLK_FROM_AUTO,
122 CLK_FROM_IPS,
123 CLK_FROM_SYS,
124 CLK_FROM_REF,
125 } clk_from;
126 struct clk *clk_in, *clk_can;
127 unsigned long freq_calc;
128 struct mscan_priv *priv;
129 struct clk *clk_ipg;
130
131 /* the caller passed in the clock source spec that was read from
132 * the device tree, get the optional clock divider as well
133 */
134 np = ofdev->dev.of_node;
135 clockdiv = 1;
136 of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
137 dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
138 clock_source ? clock_source : "<NULL>", clockdiv);
139
140 /* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
141 * get set, and the 'ips' clock is the input to the MSCAN
142 * component
143 *
144 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
145 * bit needs to get cleared, an optional clock-divider may have
146 * been specified (the default value is 1), the appropriate
147 * MSCAN related MCLK is the input to the MSCAN component
148 *
149 * in the absence of a clock-source spec, first an optimal clock
150 * gets determined based on the 'sys' clock, if that fails the
151 * 'ref' clock is used
152 */
153 clk_from = CLK_FROM_AUTO;
154 if (clock_source) {
155 /* interpret the device tree's spec for the clock source */
156 if (!strcmp(clock_source, "ip"))
157 clk_from = CLK_FROM_IPS;
158 else if (!strcmp(clock_source, "sys"))
159 clk_from = CLK_FROM_SYS;
160 else if (!strcmp(clock_source, "ref"))
161 clk_from = CLK_FROM_REF;
162 else
163 goto err_invalid;
164 dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
165 }
166 if (clk_from == CLK_FROM_AUTO) {
167 /* no spec so far, try the 'sys' clock; round to the
168 * next MHz and see if we can get a multiple of 16MHz
169 */
170 dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
171 clk_in = devm_clk_get(&ofdev->dev, "sys");
172 if (IS_ERR(clk_in))
173 goto err_notavail;
174 freq_calc = clk_get_rate(clk_in);
175 freq_calc += 499999;
176 freq_calc /= 1000000;
177 freq_calc *= 1000000;
178 if ((freq_calc % 16000000) == 0) {
179 clk_from = CLK_FROM_SYS;
180 clockdiv = freq_calc / 16000000;
181 dev_dbg(&ofdev->dev,
182 "clk fit, sys[%lu] div[%d] freq[%lu]\n",
183 freq_calc, clockdiv, freq_calc / clockdiv);
184 }
185 }
186 if (clk_from == CLK_FROM_AUTO) {
187 /* no spec so far, use the 'ref' clock */
188 dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
189 clk_in = devm_clk_get(&ofdev->dev, "ref");
190 if (IS_ERR(clk_in))
191 goto err_notavail;
192 clk_from = CLK_FROM_REF;
193 freq_calc = clk_get_rate(clk_in);
194 dev_dbg(&ofdev->dev,
195 "clk fit, ref[%lu] (no div) freq[%lu]\n",
196 freq_calc, freq_calc);
197 }
198
199 /* select IPS or MCLK as the MSCAN input (returned to the caller),
200 * setup the MCLK mux source and rate if applicable, apply the
201 * optionally specified or derived above divider, and determine
202 * the actual resulting clock rate to return to the caller
203 */
204 switch (clk_from) {
205 case CLK_FROM_IPS:
206 clk_can = devm_clk_get(&ofdev->dev, "ips");
207 if (IS_ERR(clk_can))
208 goto err_notavail;
209 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
210 priv->clk_can = clk_can;
211 freq_calc = clk_get_rate(clk_can);
212 *mscan_clksrc = MSCAN_CLKSRC_IPS;
213 dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
214 *mscan_clksrc, freq_calc);
215 break;
216 case CLK_FROM_SYS:
217 case CLK_FROM_REF:
218 clk_can = devm_clk_get(&ofdev->dev, "mclk");
219 if (IS_ERR(clk_can))
220 goto err_notavail;
221 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
222 priv->clk_can = clk_can;
223 if (clk_from == CLK_FROM_SYS)
224 clk_in = devm_clk_get(&ofdev->dev, "sys");
225 if (clk_from == CLK_FROM_REF)
226 clk_in = devm_clk_get(&ofdev->dev, "ref");
227 if (IS_ERR(clk_in))
228 goto err_notavail;
229 clk_set_parent(clk_can, clk_in);
230 freq_calc = clk_get_rate(clk_in);
231 freq_calc /= clockdiv;
232 clk_set_rate(clk_can, freq_calc);
233 freq_calc = clk_get_rate(clk_can);
234 *mscan_clksrc = MSCAN_CLKSRC_BUS;
235 dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
236 *mscan_clksrc, freq_calc);
237 break;
238 default:
239 goto err_invalid;
240 }
241
242 /* the above clk_can item is used for the bitrate, access to
243 * the peripheral's register set needs the clk_ipg item
244 */
245 clk_ipg = devm_clk_get(&ofdev->dev, "ipg");
246 if (IS_ERR(clk_ipg))
247 goto err_notavail_ipg;
248 if (clk_prepare_enable(clk_ipg))
249 goto err_notavail_ipg;
250 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
251 priv->clk_ipg = clk_ipg;
252
253 /* return the determined clock source rate */
254 return freq_calc;
255
256err_invalid:
257 dev_err(&ofdev->dev, "invalid clock source specification\n");
258 /* clock source rate could not get determined */
259 return 0;
260
261err_notavail:
262 dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n");
263 /* clock source rate could not get determined */
264 return 0;
265
266err_notavail_ipg:
267 dev_err(&ofdev->dev, "cannot acquire or setup register clock\n");
268 /* clock source rate could not get determined */
269 return 0;
270}
271
272static void mpc512x_can_put_clock(struct platform_device *ofdev)
273{
274 struct mscan_priv *priv;
275
276 priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
277 if (priv->clk_ipg)
278 clk_disable_unprepare(priv->clk_ipg);
279}
280
281#else /* COMMON_CLK */
282
112struct mpc512x_clockctl { 283struct mpc512x_clockctl {
113 u32 spmr; /* System PLL Mode Reg */ 284 u32 spmr; /* System PLL Mode Reg */
114 u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ 285 u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */
@@ -239,12 +410,18 @@ exit_put:
239 of_node_put(np_clock); 410 of_node_put(np_clock);
240 return freq; 411 return freq;
241} 412}
413
414#define mpc512x_can_put_clock NULL
415
416#endif /* COMMON_CLK */
417
242#else /* !CONFIG_PPC_MPC512x */ 418#else /* !CONFIG_PPC_MPC512x */
243static u32 mpc512x_can_get_clock(struct platform_device *ofdev, 419static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
244 const char *clock_name, int *mscan_clksrc) 420 const char *clock_name, int *mscan_clksrc)
245{ 421{
246 return 0; 422 return 0;
247} 423}
424#define mpc512x_can_put_clock NULL
248#endif /* CONFIG_PPC_MPC512x */ 425#endif /* CONFIG_PPC_MPC512x */
249 426
250static const struct of_device_id mpc5xxx_can_table[]; 427static const struct of_device_id mpc5xxx_can_table[];
@@ -386,11 +563,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
386static const struct mpc5xxx_can_data mpc5200_can_data = { 563static const struct mpc5xxx_can_data mpc5200_can_data = {
387 .type = MSCAN_TYPE_MPC5200, 564 .type = MSCAN_TYPE_MPC5200,
388 .get_clock = mpc52xx_can_get_clock, 565 .get_clock = mpc52xx_can_get_clock,
566 /* .put_clock not applicable */
389}; 567};
390 568
391static const struct mpc5xxx_can_data mpc5121_can_data = { 569static const struct mpc5xxx_can_data mpc5121_can_data = {
392 .type = MSCAN_TYPE_MPC5121, 570 .type = MSCAN_TYPE_MPC5121,
393 .get_clock = mpc512x_can_get_clock, 571 .get_clock = mpc512x_can_get_clock,
572 .put_clock = mpc512x_can_put_clock,
394}; 573};
395 574
396static const struct of_device_id mpc5xxx_can_table[] = { 575static const struct of_device_id mpc5xxx_can_table[] = {