aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYangbo Lu <yangbo.lu@nxp.com>2018-08-01 06:05:54 -0400
committerDavid S. Miller <davem@davemloft.net>2018-08-05 20:11:49 -0400
commit91305f2812624c0cf7ccbb44133b66d3b24676e4 (patch)
treefb898baeeacc4684606dbaae27a53d0446ff20f8
parenta16b5da54d1f3a06df642b866779358fc64d00e2 (diff)
ptp_qoriq: support automatic configuration for ptp timer
This patch is to support automatic configuration for ptp timer. If required ptp dts properties are not provided, driver could try to calculate a set of default configurations to initialize the ptp timer. This makes the driver work for many boards which don't have the required ptp dts properties in current kernel. Also the users could set dts properties by themselves according to their requirement. Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/ptp/ptp_qoriq.c111
-rw-r--r--include/linux/fsl/ptp_qoriq.h6
2 files changed, 113 insertions, 4 deletions
diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c
index a14c317b5a38..095c18532dc7 100644
--- a/drivers/ptp/ptp_qoriq.c
+++ b/drivers/ptp/ptp_qoriq.c
@@ -29,6 +29,7 @@
29#include <linux/of_platform.h> 29#include <linux/of_platform.h>
30#include <linux/timex.h> 30#include <linux/timex.h>
31#include <linux/slab.h> 31#include <linux/slab.h>
32#include <linux/clk.h>
32 33
33#include <linux/fsl/ptp_qoriq.h> 34#include <linux/fsl/ptp_qoriq.h>
34 35
@@ -317,6 +318,105 @@ static const struct ptp_clock_info ptp_qoriq_caps = {
317 .enable = ptp_qoriq_enable, 318 .enable = ptp_qoriq_enable,
318}; 319};
319 320
321/**
322 * qoriq_ptp_nominal_freq - calculate nominal frequency according to
323 * reference clock frequency
324 *
325 * @clk_src: reference clock frequency
326 *
327 * The nominal frequency is the desired clock frequency.
328 * It should be less than the reference clock frequency.
329 * It should be a factor of 1000MHz.
330 *
331 * Return the nominal frequency
332 */
333static u32 qoriq_ptp_nominal_freq(u32 clk_src)
334{
335 u32 remainder = 0;
336
337 clk_src /= 1000000;
338 remainder = clk_src % 100;
339 if (remainder) {
340 clk_src -= remainder;
341 clk_src += 100;
342 }
343
344 do {
345 clk_src -= 100;
346
347 } while (1000 % clk_src);
348
349 return clk_src * 1000000;
350}
351
352/**
353 * qoriq_ptp_auto_config - calculate a set of default configurations
354 *
355 * @qoriq_ptp: pointer to qoriq_ptp
356 * @node: pointer to device_node
357 *
358 * If below dts properties are not provided, this function will be
359 * called to calculate a set of default configurations for them.
360 * "fsl,tclk-period"
361 * "fsl,tmr-prsc"
362 * "fsl,tmr-add"
363 * "fsl,tmr-fiper1"
364 * "fsl,tmr-fiper2"
365 * "fsl,max-adj"
366 *
367 * Return 0 if success
368 */
369static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
370 struct device_node *node)
371{
372 struct clk *clk;
373 u64 freq_comp;
374 u64 max_adj;
375 u32 nominal_freq;
376 u32 clk_src = 0;
377
378 qoriq_ptp->cksel = DEFAULT_CKSEL;
379
380 clk = of_clk_get(node, 0);
381 if (!IS_ERR(clk)) {
382 clk_src = clk_get_rate(clk);
383 clk_put(clk);
384 }
385
386 if (clk_src <= 100000000UL) {
387 pr_err("error reference clock value, or lower than 100MHz\n");
388 return -EINVAL;
389 }
390
391 nominal_freq = qoriq_ptp_nominal_freq(clk_src);
392 if (!nominal_freq)
393 return -EINVAL;
394
395 qoriq_ptp->tclk_period = 1000000000UL / nominal_freq;
396 qoriq_ptp->tmr_prsc = DEFAULT_TMR_PRSC;
397
398 /* Calculate initial frequency compensation value for TMR_ADD register.
399 * freq_comp = ceil(2^32 / freq_ratio)
400 * freq_ratio = reference_clock_freq / nominal_freq
401 */
402 freq_comp = ((u64)1 << 32) * nominal_freq;
403 if (do_div(freq_comp, clk_src))
404 freq_comp++;
405
406 qoriq_ptp->tmr_add = freq_comp;
407 qoriq_ptp->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - qoriq_ptp->tclk_period;
408 qoriq_ptp->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - qoriq_ptp->tclk_period;
409
410 /* max_adj = 1000000000 * (freq_ratio - 1.0) - 1
411 * freq_ratio = reference_clock_freq / nominal_freq
412 */
413 max_adj = 1000000000ULL * (clk_src - nominal_freq);
414 max_adj = max_adj / nominal_freq - 1;
415 qoriq_ptp->caps.max_adj = max_adj;
416
417 return 0;
418}
419
320static int qoriq_ptp_probe(struct platform_device *dev) 420static int qoriq_ptp_probe(struct platform_device *dev)
321{ 421{
322 struct device_node *node = dev->dev.of_node; 422 struct device_node *node = dev->dev.of_node;
@@ -332,7 +432,7 @@ static int qoriq_ptp_probe(struct platform_device *dev)
332 if (!qoriq_ptp) 432 if (!qoriq_ptp)
333 goto no_memory; 433 goto no_memory;
334 434
335 err = -ENODEV; 435 err = -EINVAL;
336 436
337 qoriq_ptp->caps = ptp_qoriq_caps; 437 qoriq_ptp->caps = ptp_qoriq_caps;
338 438
@@ -351,10 +451,14 @@ static int qoriq_ptp_probe(struct platform_device *dev)
351 "fsl,tmr-fiper2", &qoriq_ptp->tmr_fiper2) || 451 "fsl,tmr-fiper2", &qoriq_ptp->tmr_fiper2) ||
352 of_property_read_u32(node, 452 of_property_read_u32(node,
353 "fsl,max-adj", &qoriq_ptp->caps.max_adj)) { 453 "fsl,max-adj", &qoriq_ptp->caps.max_adj)) {
354 pr_err("device tree node missing required elements\n"); 454 pr_warn("device tree node missing required elements, try automatic configuration\n");
355 goto no_node; 455
456 if (qoriq_ptp_auto_config(qoriq_ptp, node))
457 goto no_config;
356 } 458 }
357 459
460 err = -ENODEV;
461
358 qoriq_ptp->irq = platform_get_irq(dev, 0); 462 qoriq_ptp->irq = platform_get_irq(dev, 0);
359 463
360 if (qoriq_ptp->irq < 0) { 464 if (qoriq_ptp->irq < 0) {
@@ -436,6 +540,7 @@ no_ioremap:
436 release_resource(qoriq_ptp->rsrc); 540 release_resource(qoriq_ptp->rsrc);
437no_resource: 541no_resource:
438 free_irq(qoriq_ptp->irq, qoriq_ptp); 542 free_irq(qoriq_ptp->irq, qoriq_ptp);
543no_config:
439no_node: 544no_node:
440 kfree(qoriq_ptp); 545 kfree(qoriq_ptp);
441no_memory: 546no_memory:
diff --git a/include/linux/fsl/ptp_qoriq.h b/include/linux/fsl/ptp_qoriq.h
index dc3dac40f069..c1f003aadcce 100644
--- a/include/linux/fsl/ptp_qoriq.h
+++ b/include/linux/fsl/ptp_qoriq.h
@@ -127,9 +127,13 @@ struct qoriq_ptp_registers {
127 127
128 128
129#define DRIVER "ptp_qoriq" 129#define DRIVER "ptp_qoriq"
130#define DEFAULT_CKSEL 1
131#define N_EXT_TS 2 130#define N_EXT_TS 2
132 131
132#define DEFAULT_CKSEL 1
133#define DEFAULT_TMR_PRSC 2
134#define DEFAULT_FIPER1_PERIOD 1000000000
135#define DEFAULT_FIPER2_PERIOD 100000
136
133struct qoriq_ptp { 137struct qoriq_ptp {
134 void __iomem *base; 138 void __iomem *base;
135 struct qoriq_ptp_registers regs; 139 struct qoriq_ptp_registers regs;