2 * Copyright (C) 2014 Philipp Zabel, Pengutronix
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * PWM (mis)used as clock output
10 #include <linux/clk-provider.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/pwm.h>
19 struct pwm_device
*pwm
;
23 static inline struct clk_pwm
*to_clk_pwm(struct clk_hw
*hw
)
25 return container_of(hw
, struct clk_pwm
, hw
);
28 static int clk_pwm_prepare(struct clk_hw
*hw
)
30 struct clk_pwm
*clk_pwm
= to_clk_pwm(hw
);
32 return pwm_enable(clk_pwm
->pwm
);
35 static void clk_pwm_unprepare(struct clk_hw
*hw
)
37 struct clk_pwm
*clk_pwm
= to_clk_pwm(hw
);
39 pwm_disable(clk_pwm
->pwm
);
42 static unsigned long clk_pwm_recalc_rate(struct clk_hw
*hw
,
43 unsigned long parent_rate
)
45 struct clk_pwm
*clk_pwm
= to_clk_pwm(hw
);
47 return clk_pwm
->fixed_rate
;
50 static const struct clk_ops clk_pwm_ops
= {
51 .prepare
= clk_pwm_prepare
,
52 .unprepare
= clk_pwm_unprepare
,
53 .recalc_rate
= clk_pwm_recalc_rate
,
56 static int clk_pwm_probe(struct platform_device
*pdev
)
58 struct device_node
*node
= pdev
->dev
.of_node
;
59 struct clk_init_data init
;
60 struct clk_pwm
*clk_pwm
;
61 struct pwm_device
*pwm
;
62 struct pwm_args pargs
;
66 clk_pwm
= devm_kzalloc(&pdev
->dev
, sizeof(*clk_pwm
), GFP_KERNEL
);
70 pwm
= devm_pwm_get(&pdev
->dev
, NULL
);
74 pwm_get_args(pwm
, &pargs
);
76 dev_err(&pdev
->dev
, "invalid PWM period\n");
80 if (of_property_read_u32(node
, "clock-frequency", &clk_pwm
->fixed_rate
))
81 clk_pwm
->fixed_rate
= NSEC_PER_SEC
/ pargs
.period
;
83 if (pargs
.period
!= NSEC_PER_SEC
/ clk_pwm
->fixed_rate
&&
84 pargs
.period
!= DIV_ROUND_UP(NSEC_PER_SEC
, clk_pwm
->fixed_rate
)) {
86 "clock-frequency does not match PWM period\n");
91 * FIXME: pwm_apply_args() should be removed when switching to the
95 ret
= pwm_config(pwm
, (pargs
.period
+ 1) >> 1, pargs
.period
);
99 clk_name
= node
->name
;
100 of_property_read_string(node
, "clock-output-names", &clk_name
);
102 init
.name
= clk_name
;
103 init
.ops
= &clk_pwm_ops
;
104 init
.flags
= CLK_IS_BASIC
;
105 init
.num_parents
= 0;
108 clk_pwm
->hw
.init
= &init
;
109 ret
= devm_clk_hw_register(&pdev
->dev
, &clk_pwm
->hw
);
113 return of_clk_add_hw_provider(node
, of_clk_hw_simple_get
, &clk_pwm
->hw
);
116 static int clk_pwm_remove(struct platform_device
*pdev
)
118 of_clk_del_provider(pdev
->dev
.of_node
);
123 static const struct of_device_id clk_pwm_dt_ids
[] = {
124 { .compatible
= "pwm-clock" },
127 MODULE_DEVICE_TABLE(of
, clk_pwm_dt_ids
);
129 static struct platform_driver clk_pwm_driver
= {
130 .probe
= clk_pwm_probe
,
131 .remove
= clk_pwm_remove
,
134 .of_match_table
= of_match_ptr(clk_pwm_dt_ids
),
138 module_platform_driver(clk_pwm_driver
);
140 MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
141 MODULE_DESCRIPTION("PWM clock driver");
142 MODULE_LICENSE("GPL");