diff options
Diffstat (limited to 'drivers/pwm')
-rw-r--r-- | drivers/pwm/pwm-fsl-ftm.c | 83 |
1 files changed, 44 insertions, 39 deletions
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 96982da52d86..0f2cc7ef7784 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/pwm.h> | 20 | #include <linux/pwm.h> |
21 | #include <linux/regmap.h> | ||
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | 23 | ||
23 | #define FTM_SC 0x00 | 24 | #define FTM_SC 0x00 |
@@ -82,7 +83,7 @@ struct fsl_pwm_chip { | |||
82 | unsigned int cnt_select; | 83 | unsigned int cnt_select; |
83 | unsigned int clk_ps; | 84 | unsigned int clk_ps; |
84 | 85 | ||
85 | void __iomem *base; | 86 | struct regmap *regmap; |
86 | 87 | ||
87 | int period_ns; | 88 | int period_ns; |
88 | 89 | ||
@@ -218,10 +219,11 @@ static unsigned long fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc, | |||
218 | unsigned long period_ns, | 219 | unsigned long period_ns, |
219 | unsigned long duty_ns) | 220 | unsigned long duty_ns) |
220 | { | 221 | { |
221 | unsigned long long val, duty; | 222 | unsigned long long duty; |
223 | u32 val; | ||
222 | 224 | ||
223 | val = readl(fpc->base + FTM_MOD); | 225 | regmap_read(fpc->regmap, FTM_MOD, &val); |
224 | duty = duty_ns * (val + 1); | 226 | duty = (unsigned long long)duty_ns * (val + 1); |
225 | do_div(duty, period_ns); | 227 | do_div(duty, period_ns); |
226 | 228 | ||
227 | return (unsigned long)duty; | 229 | return (unsigned long)duty; |
@@ -231,7 +233,7 @@ static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
231 | int duty_ns, int period_ns) | 233 | int duty_ns, int period_ns) |
232 | { | 234 | { |
233 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); | 235 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); |
234 | u32 val, period, duty; | 236 | u32 period, duty; |
235 | 237 | ||
236 | mutex_lock(&fpc->lock); | 238 | mutex_lock(&fpc->lock); |
237 | 239 | ||
@@ -256,11 +258,9 @@ static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
256 | return -EINVAL; | 258 | return -EINVAL; |
257 | } | 259 | } |
258 | 260 | ||
259 | val = readl(fpc->base + FTM_SC); | 261 | regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK, |
260 | val &= ~FTM_SC_PS_MASK; | 262 | fpc->clk_ps); |
261 | val |= fpc->clk_ps; | 263 | regmap_write(fpc->regmap, FTM_MOD, period - 1); |
262 | writel(val, fpc->base + FTM_SC); | ||
263 | writel(period - 1, fpc->base + FTM_MOD); | ||
264 | 264 | ||
265 | fpc->period_ns = period_ns; | 265 | fpc->period_ns = period_ns; |
266 | } | 266 | } |
@@ -269,8 +269,9 @@ static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
269 | 269 | ||
270 | duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns); | 270 | duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns); |
271 | 271 | ||
272 | writel(FTM_CSC_MSB | FTM_CSC_ELSB, fpc->base + FTM_CSC(pwm->hwpwm)); | 272 | regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm), |
273 | writel(duty, fpc->base + FTM_CV(pwm->hwpwm)); | 273 | FTM_CSC_MSB | FTM_CSC_ELSB); |
274 | regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty); | ||
274 | 275 | ||
275 | return 0; | 276 | return 0; |
276 | } | 277 | } |
@@ -282,31 +283,28 @@ static int fsl_pwm_set_polarity(struct pwm_chip *chip, | |||
282 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); | 283 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); |
283 | u32 val; | 284 | u32 val; |
284 | 285 | ||
285 | val = readl(fpc->base + FTM_POL); | 286 | regmap_read(fpc->regmap, FTM_POL, &val); |
286 | 287 | ||
287 | if (polarity == PWM_POLARITY_INVERSED) | 288 | if (polarity == PWM_POLARITY_INVERSED) |
288 | val |= BIT(pwm->hwpwm); | 289 | val |= BIT(pwm->hwpwm); |
289 | else | 290 | else |
290 | val &= ~BIT(pwm->hwpwm); | 291 | val &= ~BIT(pwm->hwpwm); |
291 | 292 | ||
292 | writel(val, fpc->base + FTM_POL); | 293 | regmap_write(fpc->regmap, FTM_POL, val); |
293 | 294 | ||
294 | return 0; | 295 | return 0; |
295 | } | 296 | } |
296 | 297 | ||
297 | static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) | 298 | static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) |
298 | { | 299 | { |
299 | u32 val; | ||
300 | int ret; | 300 | int ret; |
301 | 301 | ||
302 | if (fpc->use_count != 0) | 302 | if (fpc->use_count != 0) |
303 | return 0; | 303 | return 0; |
304 | 304 | ||
305 | /* select counter clock source */ | 305 | /* select counter clock source */ |
306 | val = readl(fpc->base + FTM_SC); | 306 | regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, |
307 | val &= ~FTM_SC_CLK_MASK; | 307 | FTM_SC_CLK(fpc->cnt_select)); |
308 | val |= FTM_SC_CLK(fpc->cnt_select); | ||
309 | writel(val, fpc->base + FTM_SC); | ||
310 | 308 | ||
311 | ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]); | 309 | ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]); |
312 | if (ret) | 310 | if (ret) |
@@ -326,13 +324,10 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) | |||
326 | static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 324 | static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
327 | { | 325 | { |
328 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); | 326 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); |
329 | u32 val; | ||
330 | int ret; | 327 | int ret; |
331 | 328 | ||
332 | mutex_lock(&fpc->lock); | 329 | mutex_lock(&fpc->lock); |
333 | val = readl(fpc->base + FTM_OUTMASK); | 330 | regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), 0); |
334 | val &= ~BIT(pwm->hwpwm); | ||
335 | writel(val, fpc->base + FTM_OUTMASK); | ||
336 | 331 | ||
337 | ret = fsl_counter_clock_enable(fpc); | 332 | ret = fsl_counter_clock_enable(fpc); |
338 | mutex_unlock(&fpc->lock); | 333 | mutex_unlock(&fpc->lock); |
@@ -342,8 +337,6 @@ static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
342 | 337 | ||
343 | static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) | 338 | static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) |
344 | { | 339 | { |
345 | u32 val; | ||
346 | |||
347 | /* | 340 | /* |
348 | * already disabled, do nothing | 341 | * already disabled, do nothing |
349 | */ | 342 | */ |
@@ -355,9 +348,7 @@ static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) | |||
355 | return; | 348 | return; |
356 | 349 | ||
357 | /* no users left, disable PWM counter clock */ | 350 | /* no users left, disable PWM counter clock */ |
358 | val = readl(fpc->base + FTM_SC); | 351 | regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 0); |
359 | val &= ~FTM_SC_CLK_MASK; | ||
360 | writel(val, fpc->base + FTM_SC); | ||
361 | 352 | ||
362 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); | 353 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); |
363 | clk_disable_unprepare(fpc->clk[fpc->cnt_select]); | 354 | clk_disable_unprepare(fpc->clk[fpc->cnt_select]); |
@@ -369,14 +360,12 @@ static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
369 | u32 val; | 360 | u32 val; |
370 | 361 | ||
371 | mutex_lock(&fpc->lock); | 362 | mutex_lock(&fpc->lock); |
372 | val = readl(fpc->base + FTM_OUTMASK); | 363 | regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), |
373 | val |= BIT(pwm->hwpwm); | 364 | BIT(pwm->hwpwm)); |
374 | writel(val, fpc->base + FTM_OUTMASK); | ||
375 | 365 | ||
376 | fsl_counter_clock_disable(fpc); | 366 | fsl_counter_clock_disable(fpc); |
377 | 367 | ||
378 | val = readl(fpc->base + FTM_OUTMASK); | 368 | regmap_read(fpc->regmap, FTM_OUTMASK, &val); |
379 | |||
380 | if ((val & 0xFF) == 0xFF) | 369 | if ((val & 0xFF) == 0xFF) |
381 | fpc->period_ns = 0; | 370 | fpc->period_ns = 0; |
382 | 371 | ||
@@ -401,19 +390,28 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) | |||
401 | if (ret) | 390 | if (ret) |
402 | return ret; | 391 | return ret; |
403 | 392 | ||
404 | writel(0x00, fpc->base + FTM_CNTIN); | 393 | regmap_write(fpc->regmap, FTM_CNTIN, 0x00); |
405 | writel(0x00, fpc->base + FTM_OUTINIT); | 394 | regmap_write(fpc->regmap, FTM_OUTINIT, 0x00); |
406 | writel(0xFF, fpc->base + FTM_OUTMASK); | 395 | regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF); |
407 | 396 | ||
408 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); | 397 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); |
409 | 398 | ||
410 | return 0; | 399 | return 0; |
411 | } | 400 | } |
412 | 401 | ||
402 | static const struct regmap_config fsl_pwm_regmap_config = { | ||
403 | .reg_bits = 32, | ||
404 | .reg_stride = 4, | ||
405 | .val_bits = 32, | ||
406 | |||
407 | .max_register = FTM_PWMLOAD, | ||
408 | }; | ||
409 | |||
413 | static int fsl_pwm_probe(struct platform_device *pdev) | 410 | static int fsl_pwm_probe(struct platform_device *pdev) |
414 | { | 411 | { |
415 | struct fsl_pwm_chip *fpc; | 412 | struct fsl_pwm_chip *fpc; |
416 | struct resource *res; | 413 | struct resource *res; |
414 | void __iomem *base; | ||
417 | int ret; | 415 | int ret; |
418 | 416 | ||
419 | fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL); | 417 | fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL); |
@@ -425,9 +423,16 @@ static int fsl_pwm_probe(struct platform_device *pdev) | |||
425 | fpc->chip.dev = &pdev->dev; | 423 | fpc->chip.dev = &pdev->dev; |
426 | 424 | ||
427 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 425 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
428 | fpc->base = devm_ioremap_resource(&pdev->dev, res); | 426 | base = devm_ioremap_resource(&pdev->dev, res); |
429 | if (IS_ERR(fpc->base)) | 427 | if (IS_ERR(base)) |
430 | return PTR_ERR(fpc->base); | 428 | return PTR_ERR(base); |
429 | |||
430 | fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, | ||
431 | &fsl_pwm_regmap_config); | ||
432 | if (IS_ERR(fpc->regmap)) { | ||
433 | dev_err(&pdev->dev, "regmap init failed\n"); | ||
434 | return PTR_ERR(fpc->regmap); | ||
435 | } | ||
431 | 436 | ||
432 | fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys"); | 437 | fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys"); |
433 | if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) { | 438 | if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) { |