16
16
#include <linux/mfd/syscon.h>
17
17
#include <linux/module.h>
18
18
#include <linux/of.h>
19
+ #include <linux/of_device.h>
19
20
#include <linux/platform_device.h>
20
21
#include <linux/pwm.h>
21
22
#include <linux/regmap.h>
38
39
#define PERIP_PWM_PDM_CONTROL_CH_MASK 0x1
39
40
#define PERIP_PWM_PDM_CONTROL_CH_SHIFT (ch ) ((ch) * 4)
40
41
41
- #define MAX_TMBASE_STEPS 65536
42
+ /*
43
+ * PWM period is specified with a timebase register,
44
+ * in number of step periods. The PWM duty cycle is also
45
+ * specified in step periods, in the [0, $timebase] range.
46
+ * In other words, the timebase imposes the duty cycle
47
+ * resolution. Therefore, let's constraint the timebase to
48
+ * a minimum value to allow a sane range of duty cycle values.
49
+ * Imposing a minimum timebase, will impose a maximum PWM frequency.
50
+ *
51
+ * The value chosen is completely arbitrary.
52
+ */
53
+ #define MIN_TMBASE_STEPS 16
54
+
55
+ struct img_pwm_soc_data {
56
+ u32 max_timebase ;
57
+ };
42
58
43
59
struct img_pwm_chip {
44
60
struct device * dev ;
@@ -47,6 +63,9 @@ struct img_pwm_chip {
47
63
struct clk * sys_clk ;
48
64
void __iomem * base ;
49
65
struct regmap * periph_regs ;
66
+ int max_period_ns ;
67
+ int min_period_ns ;
68
+ const struct img_pwm_soc_data * data ;
50
69
};
51
70
52
71
static inline struct img_pwm_chip * to_img_pwm_chip (struct pwm_chip * chip )
@@ -72,24 +91,31 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
72
91
u32 val , div , duty , timebase ;
73
92
unsigned long mul , output_clk_hz , input_clk_hz ;
74
93
struct img_pwm_chip * pwm_chip = to_img_pwm_chip (chip );
94
+ unsigned int max_timebase = pwm_chip -> data -> max_timebase ;
95
+
96
+ if (period_ns < pwm_chip -> min_period_ns ||
97
+ period_ns > pwm_chip -> max_period_ns ) {
98
+ dev_err (chip -> dev , "configured period not in range\n" );
99
+ return - ERANGE ;
100
+ }
75
101
76
102
input_clk_hz = clk_get_rate (pwm_chip -> pwm_clk );
77
103
output_clk_hz = DIV_ROUND_UP (NSEC_PER_SEC , period_ns );
78
104
79
105
mul = DIV_ROUND_UP (input_clk_hz , output_clk_hz );
80
- if (mul <= MAX_TMBASE_STEPS ) {
106
+ if (mul <= max_timebase ) {
81
107
div = PWM_CTRL_CFG_NO_SUB_DIV ;
82
108
timebase = DIV_ROUND_UP (mul , 1 );
83
- } else if (mul <= MAX_TMBASE_STEPS * 8 ) {
109
+ } else if (mul <= max_timebase * 8 ) {
84
110
div = PWM_CTRL_CFG_SUB_DIV0 ;
85
111
timebase = DIV_ROUND_UP (mul , 8 );
86
- } else if (mul <= MAX_TMBASE_STEPS * 64 ) {
112
+ } else if (mul <= max_timebase * 64 ) {
87
113
div = PWM_CTRL_CFG_SUB_DIV1 ;
88
114
timebase = DIV_ROUND_UP (mul , 64 );
89
- } else if (mul <= MAX_TMBASE_STEPS * 512 ) {
115
+ } else if (mul <= max_timebase * 512 ) {
90
116
div = PWM_CTRL_CFG_SUB_DIV0_DIV1 ;
91
117
timebase = DIV_ROUND_UP (mul , 512 );
92
- } else if (mul > MAX_TMBASE_STEPS * 512 ) {
118
+ } else if (mul > max_timebase * 512 ) {
93
119
dev_err (chip -> dev ,
94
120
"failed to configure timebase steps/divider value\n" );
95
121
return - EINVAL ;
@@ -143,11 +169,27 @@ static const struct pwm_ops img_pwm_ops = {
143
169
.owner = THIS_MODULE ,
144
170
};
145
171
172
+ static const struct img_pwm_soc_data pistachio_pwm = {
173
+ .max_timebase = 255 ,
174
+ };
175
+
176
+ static const struct of_device_id img_pwm_of_match [] = {
177
+ {
178
+ .compatible = "img,pistachio-pwm" ,
179
+ .data = & pistachio_pwm ,
180
+ },
181
+ { }
182
+ };
183
+ MODULE_DEVICE_TABLE (of , img_pwm_of_match );
184
+
146
185
static int img_pwm_probe (struct platform_device * pdev )
147
186
{
148
187
int ret ;
188
+ u64 val ;
189
+ unsigned long clk_rate ;
149
190
struct resource * res ;
150
191
struct img_pwm_chip * pwm ;
192
+ const struct of_device_id * of_dev_id ;
151
193
152
194
pwm = devm_kzalloc (& pdev -> dev , sizeof (* pwm ), GFP_KERNEL );
153
195
if (!pwm )
@@ -160,6 +202,11 @@ static int img_pwm_probe(struct platform_device *pdev)
160
202
if (IS_ERR (pwm -> base ))
161
203
return PTR_ERR (pwm -> base );
162
204
205
+ of_dev_id = of_match_device (img_pwm_of_match , & pdev -> dev );
206
+ if (!of_dev_id )
207
+ return - ENODEV ;
208
+ pwm -> data = of_dev_id -> data ;
209
+
163
210
pwm -> periph_regs = syscon_regmap_lookup_by_phandle (pdev -> dev .of_node ,
164
211
"img,cr-periph" );
165
212
if (IS_ERR (pwm -> periph_regs ))
@@ -189,6 +236,17 @@ static int img_pwm_probe(struct platform_device *pdev)
189
236
goto disable_sysclk ;
190
237
}
191
238
239
+ clk_rate = clk_get_rate (pwm -> pwm_clk );
240
+
241
+ /* The maximum input clock divider is 512 */
242
+ val = (u64 )NSEC_PER_SEC * 512 * pwm -> data -> max_timebase ;
243
+ do_div (val , clk_rate );
244
+ pwm -> max_period_ns = val ;
245
+
246
+ val = (u64 )NSEC_PER_SEC * MIN_TMBASE_STEPS ;
247
+ do_div (val , clk_rate );
248
+ pwm -> min_period_ns = val ;
249
+
192
250
pwm -> chip .dev = & pdev -> dev ;
193
251
pwm -> chip .ops = & img_pwm_ops ;
194
252
pwm -> chip .base = -1 ;
@@ -228,12 +286,6 @@ static int img_pwm_remove(struct platform_device *pdev)
228
286
return pwmchip_remove (& pwm_chip -> chip );
229
287
}
230
288
231
- static const struct of_device_id img_pwm_of_match [] = {
232
- { .compatible = "img,pistachio-pwm" , },
233
- { }
234
- };
235
- MODULE_DEVICE_TABLE (of , img_pwm_of_match );
236
-
237
289
static struct platform_driver img_pwm_driver = {
238
290
.driver = {
239
291
.name = "img-pwm" ,
0 commit comments