diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-23 02:09:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-23 02:09:18 -0500 |
commit | 5a787756b809888e8925d722862167f1229b58f7 (patch) | |
tree | 4137c992106b20d2a8cca3cba103ed8fca01f4b5 | |
parent | 1b8c5cd890e274781a8ef61585ae03614be9ccd8 (diff) | |
parent | f83e2ae2606b3754a5b9dfe9dd792c453698df6c (diff) |
Merge tag 'pwm/for-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding:
"The changes for this release include power management improvements for
the pwm-img driver, support for the backup mode on pwm-atmel-tcb as
well as support for more hardware with the R-Car and Mediatek drivers.
To round things off there's a bit of cleanup for sunxi and stm32-lp"
* tag 'pwm/for-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
pwm: stm32-lp: Remove pwm_is_enabled() check before calling pwm_disable()
pwm: mediatek: Add MT2712/MT7622 support
pwm: sunxi: Use of_device_get_match_data()
pwm: atmel-tcb: Support backup mode
dt-bindings: pwm: Add R-Car D3 device tree bindings
pwm: img: Add runtime PM
pwm: img: Add suspend / resume handling
-rw-r--r-- | Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt | 1 | ||||
-rw-r--r-- | drivers/pwm/pwm-atmel-tcb.c | 63 | ||||
-rw-r--r-- | drivers/pwm/pwm-img.c | 160 | ||||
-rw-r--r-- | drivers/pwm/pwm-mediatek.c | 53 | ||||
-rw-r--r-- | drivers/pwm/pwm-stm32-lp.c | 3 | ||||
-rw-r--r-- | drivers/pwm/pwm-sun4i.c | 8 |
6 files changed, 252 insertions, 36 deletions
diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt index 7e94b802395d..74c118015980 100644 --- a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt +++ b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt | |||
@@ -9,6 +9,7 @@ Required Properties: | |||
9 | - "renesas,pwm-r8a7794": for R-Car E2 | 9 | - "renesas,pwm-r8a7794": for R-Car E2 |
10 | - "renesas,pwm-r8a7795": for R-Car H3 | 10 | - "renesas,pwm-r8a7795": for R-Car H3 |
11 | - "renesas,pwm-r8a7796": for R-Car M3-W | 11 | - "renesas,pwm-r8a7796": for R-Car M3-W |
12 | - "renesas,pwm-r8a77995": for R-Car D3 | ||
12 | - reg: base address and length of the registers block for the PWM. | 13 | - reg: base address and length of the registers block for the PWM. |
13 | - #pwm-cells: should be 2. See pwm.txt in this directory for a description of | 14 | - #pwm-cells: should be 2. See pwm.txt in this directory for a description of |
14 | the cells format. | 15 | the cells format. |
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 75db585a2a94..acd3ce8ecf3f 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c | |||
@@ -37,11 +37,20 @@ struct atmel_tcb_pwm_device { | |||
37 | unsigned period; /* PWM period expressed in clk cycles */ | 37 | unsigned period; /* PWM period expressed in clk cycles */ |
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct atmel_tcb_channel { | ||
41 | u32 enabled; | ||
42 | u32 cmr; | ||
43 | u32 ra; | ||
44 | u32 rb; | ||
45 | u32 rc; | ||
46 | }; | ||
47 | |||
40 | struct atmel_tcb_pwm_chip { | 48 | struct atmel_tcb_pwm_chip { |
41 | struct pwm_chip chip; | 49 | struct pwm_chip chip; |
42 | spinlock_t lock; | 50 | spinlock_t lock; |
43 | struct atmel_tc *tc; | 51 | struct atmel_tc *tc; |
44 | struct atmel_tcb_pwm_device *pwms[NPWM]; | 52 | struct atmel_tcb_pwm_device *pwms[NPWM]; |
53 | struct atmel_tcb_channel bkup[NPWM / 2]; | ||
45 | }; | 54 | }; |
46 | 55 | ||
47 | static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip) | 56 | static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip) |
@@ -175,12 +184,15 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
175 | * Use software trigger to apply the new setting. | 184 | * Use software trigger to apply the new setting. |
176 | * If both PWM devices in this group are disabled we stop the clock. | 185 | * If both PWM devices in this group are disabled we stop the clock. |
177 | */ | 186 | */ |
178 | if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC))) | 187 | if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC))) { |
179 | __raw_writel(ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS, | 188 | __raw_writel(ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS, |
180 | regs + ATMEL_TC_REG(group, CCR)); | 189 | regs + ATMEL_TC_REG(group, CCR)); |
181 | else | 190 | tcbpwmc->bkup[group].enabled = 1; |
191 | } else { | ||
182 | __raw_writel(ATMEL_TC_SWTRG, regs + | 192 | __raw_writel(ATMEL_TC_SWTRG, regs + |
183 | ATMEL_TC_REG(group, CCR)); | 193 | ATMEL_TC_REG(group, CCR)); |
194 | tcbpwmc->bkup[group].enabled = 0; | ||
195 | } | ||
184 | 196 | ||
185 | spin_unlock(&tcbpwmc->lock); | 197 | spin_unlock(&tcbpwmc->lock); |
186 | } | 198 | } |
@@ -263,6 +275,7 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
263 | /* Use software trigger to apply the new setting */ | 275 | /* Use software trigger to apply the new setting */ |
264 | __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, | 276 | __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, |
265 | regs + ATMEL_TC_REG(group, CCR)); | 277 | regs + ATMEL_TC_REG(group, CCR)); |
278 | tcbpwmc->bkup[group].enabled = 1; | ||
266 | spin_unlock(&tcbpwmc->lock); | 279 | spin_unlock(&tcbpwmc->lock); |
267 | return 0; | 280 | return 0; |
268 | } | 281 | } |
@@ -445,10 +458,56 @@ static const struct of_device_id atmel_tcb_pwm_dt_ids[] = { | |||
445 | }; | 458 | }; |
446 | MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids); | 459 | MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids); |
447 | 460 | ||
461 | #ifdef CONFIG_PM_SLEEP | ||
462 | static int atmel_tcb_pwm_suspend(struct device *dev) | ||
463 | { | ||
464 | struct platform_device *pdev = to_platform_device(dev); | ||
465 | struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); | ||
466 | void __iomem *base = tcbpwm->tc->regs; | ||
467 | int i; | ||
468 | |||
469 | for (i = 0; i < (NPWM / 2); i++) { | ||
470 | struct atmel_tcb_channel *chan = &tcbpwm->bkup[i]; | ||
471 | |||
472 | chan->cmr = readl(base + ATMEL_TC_REG(i, CMR)); | ||
473 | chan->ra = readl(base + ATMEL_TC_REG(i, RA)); | ||
474 | chan->rb = readl(base + ATMEL_TC_REG(i, RB)); | ||
475 | chan->rc = readl(base + ATMEL_TC_REG(i, RC)); | ||
476 | } | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static int atmel_tcb_pwm_resume(struct device *dev) | ||
481 | { | ||
482 | struct platform_device *pdev = to_platform_device(dev); | ||
483 | struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); | ||
484 | void __iomem *base = tcbpwm->tc->regs; | ||
485 | int i; | ||
486 | |||
487 | for (i = 0; i < (NPWM / 2); i++) { | ||
488 | struct atmel_tcb_channel *chan = &tcbpwm->bkup[i]; | ||
489 | |||
490 | writel(chan->cmr, base + ATMEL_TC_REG(i, CMR)); | ||
491 | writel(chan->ra, base + ATMEL_TC_REG(i, RA)); | ||
492 | writel(chan->rb, base + ATMEL_TC_REG(i, RB)); | ||
493 | writel(chan->rc, base + ATMEL_TC_REG(i, RC)); | ||
494 | if (chan->enabled) { | ||
495 | writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, | ||
496 | base + ATMEL_TC_REG(i, CCR)); | ||
497 | } | ||
498 | } | ||
499 | return 0; | ||
500 | } | ||
501 | #endif | ||
502 | |||
503 | static SIMPLE_DEV_PM_OPS(atmel_tcb_pwm_pm_ops, atmel_tcb_pwm_suspend, | ||
504 | atmel_tcb_pwm_resume); | ||
505 | |||
448 | static struct platform_driver atmel_tcb_pwm_driver = { | 506 | static struct platform_driver atmel_tcb_pwm_driver = { |
449 | .driver = { | 507 | .driver = { |
450 | .name = "atmel-tcb-pwm", | 508 | .name = "atmel-tcb-pwm", |
451 | .of_match_table = atmel_tcb_pwm_dt_ids, | 509 | .of_match_table = atmel_tcb_pwm_dt_ids, |
510 | .pm = &atmel_tcb_pwm_pm_ops, | ||
452 | }, | 511 | }, |
453 | .probe = atmel_tcb_pwm_probe, | 512 | .probe = atmel_tcb_pwm_probe, |
454 | .remove = atmel_tcb_pwm_remove, | 513 | .remove = atmel_tcb_pwm_remove, |
diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index 2fb30deee345..815f5333bb8f 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
19 | #include <linux/of_device.h> | 19 | #include <linux/of_device.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/pm_runtime.h> | ||
21 | #include <linux/pwm.h> | 22 | #include <linux/pwm.h> |
22 | #include <linux/regmap.h> | 23 | #include <linux/regmap.h> |
23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -39,6 +40,8 @@ | |||
39 | #define PERIP_PWM_PDM_CONTROL_CH_MASK 0x1 | 40 | #define PERIP_PWM_PDM_CONTROL_CH_MASK 0x1 |
40 | #define PERIP_PWM_PDM_CONTROL_CH_SHIFT(ch) ((ch) * 4) | 41 | #define PERIP_PWM_PDM_CONTROL_CH_SHIFT(ch) ((ch) * 4) |
41 | 42 | ||
43 | #define IMG_PWM_PM_TIMEOUT 1000 /* ms */ | ||
44 | |||
42 | /* | 45 | /* |
43 | * PWM period is specified with a timebase register, | 46 | * PWM period is specified with a timebase register, |
44 | * in number of step periods. The PWM duty cycle is also | 47 | * in number of step periods. The PWM duty cycle is also |
@@ -52,6 +55,8 @@ | |||
52 | */ | 55 | */ |
53 | #define MIN_TMBASE_STEPS 16 | 56 | #define MIN_TMBASE_STEPS 16 |
54 | 57 | ||
58 | #define IMG_PWM_NPWM 4 | ||
59 | |||
55 | struct img_pwm_soc_data { | 60 | struct img_pwm_soc_data { |
56 | u32 max_timebase; | 61 | u32 max_timebase; |
57 | }; | 62 | }; |
@@ -66,6 +71,8 @@ struct img_pwm_chip { | |||
66 | int max_period_ns; | 71 | int max_period_ns; |
67 | int min_period_ns; | 72 | int min_period_ns; |
68 | const struct img_pwm_soc_data *data; | 73 | const struct img_pwm_soc_data *data; |
74 | u32 suspend_ctrl_cfg; | ||
75 | u32 suspend_ch_cfg[IMG_PWM_NPWM]; | ||
69 | }; | 76 | }; |
70 | 77 | ||
71 | static inline struct img_pwm_chip *to_img_pwm_chip(struct pwm_chip *chip) | 78 | static inline struct img_pwm_chip *to_img_pwm_chip(struct pwm_chip *chip) |
@@ -92,6 +99,7 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
92 | unsigned long mul, output_clk_hz, input_clk_hz; | 99 | unsigned long mul, output_clk_hz, input_clk_hz; |
93 | struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); | 100 | struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); |
94 | unsigned int max_timebase = pwm_chip->data->max_timebase; | 101 | unsigned int max_timebase = pwm_chip->data->max_timebase; |
102 | int ret; | ||
95 | 103 | ||
96 | if (period_ns < pwm_chip->min_period_ns || | 104 | if (period_ns < pwm_chip->min_period_ns || |
97 | period_ns > pwm_chip->max_period_ns) { | 105 | period_ns > pwm_chip->max_period_ns) { |
@@ -123,6 +131,10 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
123 | 131 | ||
124 | duty = DIV_ROUND_UP(timebase * duty_ns, period_ns); | 132 | duty = DIV_ROUND_UP(timebase * duty_ns, period_ns); |
125 | 133 | ||
134 | ret = pm_runtime_get_sync(chip->dev); | ||
135 | if (ret < 0) | ||
136 | return ret; | ||
137 | |||
126 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); | 138 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); |
127 | val &= ~(PWM_CTRL_CFG_DIV_MASK << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm)); | 139 | val &= ~(PWM_CTRL_CFG_DIV_MASK << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm)); |
128 | val |= (div & PWM_CTRL_CFG_DIV_MASK) << | 140 | val |= (div & PWM_CTRL_CFG_DIV_MASK) << |
@@ -133,6 +145,9 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
133 | (timebase << PWM_CH_CFG_TMBASE_SHIFT); | 145 | (timebase << PWM_CH_CFG_TMBASE_SHIFT); |
134 | img_pwm_writel(pwm_chip, PWM_CH_CFG(pwm->hwpwm), val); | 146 | img_pwm_writel(pwm_chip, PWM_CH_CFG(pwm->hwpwm), val); |
135 | 147 | ||
148 | pm_runtime_mark_last_busy(chip->dev); | ||
149 | pm_runtime_put_autosuspend(chip->dev); | ||
150 | |||
136 | return 0; | 151 | return 0; |
137 | } | 152 | } |
138 | 153 | ||
@@ -140,6 +155,11 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
140 | { | 155 | { |
141 | u32 val; | 156 | u32 val; |
142 | struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); | 157 | struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); |
158 | int ret; | ||
159 | |||
160 | ret = pm_runtime_get_sync(chip->dev); | ||
161 | if (ret < 0) | ||
162 | return ret; | ||
143 | 163 | ||
144 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); | 164 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); |
145 | val |= BIT(pwm->hwpwm); | 165 | val |= BIT(pwm->hwpwm); |
@@ -160,6 +180,9 @@ static void img_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
160 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); | 180 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); |
161 | val &= ~BIT(pwm->hwpwm); | 181 | val &= ~BIT(pwm->hwpwm); |
162 | img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val); | 182 | img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val); |
183 | |||
184 | pm_runtime_mark_last_busy(chip->dev); | ||
185 | pm_runtime_put_autosuspend(chip->dev); | ||
163 | } | 186 | } |
164 | 187 | ||
165 | static const struct pwm_ops img_pwm_ops = { | 188 | static const struct pwm_ops img_pwm_ops = { |
@@ -182,6 +205,37 @@ static const struct of_device_id img_pwm_of_match[] = { | |||
182 | }; | 205 | }; |
183 | MODULE_DEVICE_TABLE(of, img_pwm_of_match); | 206 | MODULE_DEVICE_TABLE(of, img_pwm_of_match); |
184 | 207 | ||
208 | static int img_pwm_runtime_suspend(struct device *dev) | ||
209 | { | ||
210 | struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); | ||
211 | |||
212 | clk_disable_unprepare(pwm_chip->pwm_clk); | ||
213 | clk_disable_unprepare(pwm_chip->sys_clk); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int img_pwm_runtime_resume(struct device *dev) | ||
219 | { | ||
220 | struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); | ||
221 | int ret; | ||
222 | |||
223 | ret = clk_prepare_enable(pwm_chip->sys_clk); | ||
224 | if (ret < 0) { | ||
225 | dev_err(dev, "could not prepare or enable sys clock\n"); | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | ret = clk_prepare_enable(pwm_chip->pwm_clk); | ||
230 | if (ret < 0) { | ||
231 | dev_err(dev, "could not prepare or enable pwm clock\n"); | ||
232 | clk_disable_unprepare(pwm_chip->sys_clk); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
185 | static int img_pwm_probe(struct platform_device *pdev) | 239 | static int img_pwm_probe(struct platform_device *pdev) |
186 | { | 240 | { |
187 | int ret; | 241 | int ret; |
@@ -224,23 +278,20 @@ static int img_pwm_probe(struct platform_device *pdev) | |||
224 | return PTR_ERR(pwm->pwm_clk); | 278 | return PTR_ERR(pwm->pwm_clk); |
225 | } | 279 | } |
226 | 280 | ||
227 | ret = clk_prepare_enable(pwm->sys_clk); | 281 | pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_PWM_PM_TIMEOUT); |
228 | if (ret < 0) { | 282 | pm_runtime_use_autosuspend(&pdev->dev); |
229 | dev_err(&pdev->dev, "could not prepare or enable sys clock\n"); | 283 | pm_runtime_enable(&pdev->dev); |
230 | return ret; | 284 | if (!pm_runtime_enabled(&pdev->dev)) { |
231 | } | 285 | ret = img_pwm_runtime_resume(&pdev->dev); |
232 | 286 | if (ret) | |
233 | ret = clk_prepare_enable(pwm->pwm_clk); | 287 | goto err_pm_disable; |
234 | if (ret < 0) { | ||
235 | dev_err(&pdev->dev, "could not prepare or enable pwm clock\n"); | ||
236 | goto disable_sysclk; | ||
237 | } | 288 | } |
238 | 289 | ||
239 | clk_rate = clk_get_rate(pwm->pwm_clk); | 290 | clk_rate = clk_get_rate(pwm->pwm_clk); |
240 | if (!clk_rate) { | 291 | if (!clk_rate) { |
241 | dev_err(&pdev->dev, "pwm clock has no frequency\n"); | 292 | dev_err(&pdev->dev, "pwm clock has no frequency\n"); |
242 | ret = -EINVAL; | 293 | ret = -EINVAL; |
243 | goto disable_pwmclk; | 294 | goto err_suspend; |
244 | } | 295 | } |
245 | 296 | ||
246 | /* The maximum input clock divider is 512 */ | 297 | /* The maximum input clock divider is 512 */ |
@@ -255,21 +306,23 @@ static int img_pwm_probe(struct platform_device *pdev) | |||
255 | pwm->chip.dev = &pdev->dev; | 306 | pwm->chip.dev = &pdev->dev; |
256 | pwm->chip.ops = &img_pwm_ops; | 307 | pwm->chip.ops = &img_pwm_ops; |
257 | pwm->chip.base = -1; | 308 | pwm->chip.base = -1; |
258 | pwm->chip.npwm = 4; | 309 | pwm->chip.npwm = IMG_PWM_NPWM; |
259 | 310 | ||
260 | ret = pwmchip_add(&pwm->chip); | 311 | ret = pwmchip_add(&pwm->chip); |
261 | if (ret < 0) { | 312 | if (ret < 0) { |
262 | dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); | 313 | dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); |
263 | goto disable_pwmclk; | 314 | goto err_suspend; |
264 | } | 315 | } |
265 | 316 | ||
266 | platform_set_drvdata(pdev, pwm); | 317 | platform_set_drvdata(pdev, pwm); |
267 | return 0; | 318 | return 0; |
268 | 319 | ||
269 | disable_pwmclk: | 320 | err_suspend: |
270 | clk_disable_unprepare(pwm->pwm_clk); | 321 | if (!pm_runtime_enabled(&pdev->dev)) |
271 | disable_sysclk: | 322 | img_pwm_runtime_suspend(&pdev->dev); |
272 | clk_disable_unprepare(pwm->sys_clk); | 323 | err_pm_disable: |
324 | pm_runtime_disable(&pdev->dev); | ||
325 | pm_runtime_dont_use_autosuspend(&pdev->dev); | ||
273 | return ret; | 326 | return ret; |
274 | } | 327 | } |
275 | 328 | ||
@@ -278,6 +331,11 @@ static int img_pwm_remove(struct platform_device *pdev) | |||
278 | struct img_pwm_chip *pwm_chip = platform_get_drvdata(pdev); | 331 | struct img_pwm_chip *pwm_chip = platform_get_drvdata(pdev); |
279 | u32 val; | 332 | u32 val; |
280 | unsigned int i; | 333 | unsigned int i; |
334 | int ret; | ||
335 | |||
336 | ret = pm_runtime_get_sync(&pdev->dev); | ||
337 | if (ret < 0) | ||
338 | return ret; | ||
281 | 339 | ||
282 | for (i = 0; i < pwm_chip->chip.npwm; i++) { | 340 | for (i = 0; i < pwm_chip->chip.npwm; i++) { |
283 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); | 341 | val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); |
@@ -285,15 +343,79 @@ static int img_pwm_remove(struct platform_device *pdev) | |||
285 | img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val); | 343 | img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val); |
286 | } | 344 | } |
287 | 345 | ||
288 | clk_disable_unprepare(pwm_chip->pwm_clk); | 346 | pm_runtime_put(&pdev->dev); |
289 | clk_disable_unprepare(pwm_chip->sys_clk); | 347 | pm_runtime_disable(&pdev->dev); |
348 | if (!pm_runtime_status_suspended(&pdev->dev)) | ||
349 | img_pwm_runtime_suspend(&pdev->dev); | ||
290 | 350 | ||
291 | return pwmchip_remove(&pwm_chip->chip); | 351 | return pwmchip_remove(&pwm_chip->chip); |
292 | } | 352 | } |
293 | 353 | ||
354 | #ifdef CONFIG_PM_SLEEP | ||
355 | static int img_pwm_suspend(struct device *dev) | ||
356 | { | ||
357 | struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); | ||
358 | int i, ret; | ||
359 | |||
360 | if (pm_runtime_status_suspended(dev)) { | ||
361 | ret = img_pwm_runtime_resume(dev); | ||
362 | if (ret) | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | for (i = 0; i < pwm_chip->chip.npwm; i++) | ||
367 | pwm_chip->suspend_ch_cfg[i] = img_pwm_readl(pwm_chip, | ||
368 | PWM_CH_CFG(i)); | ||
369 | |||
370 | pwm_chip->suspend_ctrl_cfg = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); | ||
371 | |||
372 | img_pwm_runtime_suspend(dev); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int img_pwm_resume(struct device *dev) | ||
378 | { | ||
379 | struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); | ||
380 | int ret; | ||
381 | int i; | ||
382 | |||
383 | ret = img_pwm_runtime_resume(dev); | ||
384 | if (ret) | ||
385 | return ret; | ||
386 | |||
387 | for (i = 0; i < pwm_chip->chip.npwm; i++) | ||
388 | img_pwm_writel(pwm_chip, PWM_CH_CFG(i), | ||
389 | pwm_chip->suspend_ch_cfg[i]); | ||
390 | |||
391 | img_pwm_writel(pwm_chip, PWM_CTRL_CFG, pwm_chip->suspend_ctrl_cfg); | ||
392 | |||
393 | for (i = 0; i < pwm_chip->chip.npwm; i++) | ||
394 | if (pwm_chip->suspend_ctrl_cfg & BIT(i)) | ||
395 | regmap_update_bits(pwm_chip->periph_regs, | ||
396 | PERIP_PWM_PDM_CONTROL, | ||
397 | PERIP_PWM_PDM_CONTROL_CH_MASK << | ||
398 | PERIP_PWM_PDM_CONTROL_CH_SHIFT(i), | ||
399 | 0); | ||
400 | |||
401 | if (pm_runtime_status_suspended(dev)) | ||
402 | img_pwm_runtime_suspend(dev); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | #endif /* CONFIG_PM */ | ||
407 | |||
408 | static const struct dev_pm_ops img_pwm_pm_ops = { | ||
409 | SET_RUNTIME_PM_OPS(img_pwm_runtime_suspend, | ||
410 | img_pwm_runtime_resume, | ||
411 | NULL) | ||
412 | SET_SYSTEM_SLEEP_PM_OPS(img_pwm_suspend, img_pwm_resume) | ||
413 | }; | ||
414 | |||
294 | static struct platform_driver img_pwm_driver = { | 415 | static struct platform_driver img_pwm_driver = { |
295 | .driver = { | 416 | .driver = { |
296 | .name = "img-pwm", | 417 | .name = "img-pwm", |
418 | .pm = &img_pwm_pm_ops, | ||
297 | .of_match_table = img_pwm_of_match, | 419 | .of_match_table = img_pwm_of_match, |
298 | }, | 420 | }, |
299 | .probe = img_pwm_probe, | 421 | .probe = img_pwm_probe, |
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index b52f3afb2ba1..f5d97e0ad52b 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
19 | #include <linux/of_device.h> | ||
19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
20 | #include <linux/pwm.h> | 21 | #include <linux/pwm.h> |
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
@@ -40,11 +41,19 @@ enum { | |||
40 | MTK_CLK_PWM3, | 41 | MTK_CLK_PWM3, |
41 | MTK_CLK_PWM4, | 42 | MTK_CLK_PWM4, |
42 | MTK_CLK_PWM5, | 43 | MTK_CLK_PWM5, |
44 | MTK_CLK_PWM6, | ||
45 | MTK_CLK_PWM7, | ||
46 | MTK_CLK_PWM8, | ||
43 | MTK_CLK_MAX, | 47 | MTK_CLK_MAX, |
44 | }; | 48 | }; |
45 | 49 | ||
46 | static const char * const mtk_pwm_clk_name[] = { | 50 | static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = { |
47 | "main", "top", "pwm1", "pwm2", "pwm3", "pwm4", "pwm5" | 51 | "main", "top", "pwm1", "pwm2", "pwm3", "pwm4", "pwm5", "pwm6", "pwm7", |
52 | "pwm8" | ||
53 | }; | ||
54 | |||
55 | struct mtk_pwm_platform_data { | ||
56 | unsigned int num_pwms; | ||
48 | }; | 57 | }; |
49 | 58 | ||
50 | /** | 59 | /** |
@@ -59,6 +68,10 @@ struct mtk_pwm_chip { | |||
59 | struct clk *clks[MTK_CLK_MAX]; | 68 | struct clk *clks[MTK_CLK_MAX]; |
60 | }; | 69 | }; |
61 | 70 | ||
71 | static const unsigned int mtk_pwm_reg_offset[] = { | ||
72 | 0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220 | ||
73 | }; | ||
74 | |||
62 | static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) | 75 | static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) |
63 | { | 76 | { |
64 | return container_of(chip, struct mtk_pwm_chip, chip); | 77 | return container_of(chip, struct mtk_pwm_chip, chip); |
@@ -103,14 +116,14 @@ static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
103 | static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, | 116 | static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, |
104 | unsigned int offset) | 117 | unsigned int offset) |
105 | { | 118 | { |
106 | return readl(chip->regs + 0x10 + (num * 0x40) + offset); | 119 | return readl(chip->regs + mtk_pwm_reg_offset[num] + offset); |
107 | } | 120 | } |
108 | 121 | ||
109 | static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, | 122 | static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, |
110 | unsigned int num, unsigned int offset, | 123 | unsigned int num, unsigned int offset, |
111 | u32 value) | 124 | u32 value) |
112 | { | 125 | { |
113 | writel(value, chip->regs + 0x10 + (num * 0x40) + offset); | 126 | writel(value, chip->regs + mtk_pwm_reg_offset[num] + offset); |
114 | } | 127 | } |
115 | 128 | ||
116 | static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | 129 | static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
@@ -185,6 +198,7 @@ static const struct pwm_ops mtk_pwm_ops = { | |||
185 | 198 | ||
186 | static int mtk_pwm_probe(struct platform_device *pdev) | 199 | static int mtk_pwm_probe(struct platform_device *pdev) |
187 | { | 200 | { |
201 | const struct mtk_pwm_platform_data *data; | ||
188 | struct mtk_pwm_chip *pc; | 202 | struct mtk_pwm_chip *pc; |
189 | struct resource *res; | 203 | struct resource *res; |
190 | unsigned int i; | 204 | unsigned int i; |
@@ -194,15 +208,22 @@ static int mtk_pwm_probe(struct platform_device *pdev) | |||
194 | if (!pc) | 208 | if (!pc) |
195 | return -ENOMEM; | 209 | return -ENOMEM; |
196 | 210 | ||
211 | data = of_device_get_match_data(&pdev->dev); | ||
212 | if (data == NULL) | ||
213 | return -EINVAL; | ||
214 | |||
197 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 215 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
198 | pc->regs = devm_ioremap_resource(&pdev->dev, res); | 216 | pc->regs = devm_ioremap_resource(&pdev->dev, res); |
199 | if (IS_ERR(pc->regs)) | 217 | if (IS_ERR(pc->regs)) |
200 | return PTR_ERR(pc->regs); | 218 | return PTR_ERR(pc->regs); |
201 | 219 | ||
202 | for (i = 0; i < MTK_CLK_MAX; i++) { | 220 | for (i = 0; i < data->num_pwms + 2; i++) { |
203 | pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); | 221 | pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); |
204 | if (IS_ERR(pc->clks[i])) | 222 | if (IS_ERR(pc->clks[i])) { |
223 | dev_err(&pdev->dev, "clock: %s fail: %ld\n", | ||
224 | mtk_pwm_clk_name[i], PTR_ERR(pc->clks[i])); | ||
205 | return PTR_ERR(pc->clks[i]); | 225 | return PTR_ERR(pc->clks[i]); |
226 | } | ||
206 | } | 227 | } |
207 | 228 | ||
208 | platform_set_drvdata(pdev, pc); | 229 | platform_set_drvdata(pdev, pc); |
@@ -210,7 +231,7 @@ static int mtk_pwm_probe(struct platform_device *pdev) | |||
210 | pc->chip.dev = &pdev->dev; | 231 | pc->chip.dev = &pdev->dev; |
211 | pc->chip.ops = &mtk_pwm_ops; | 232 | pc->chip.ops = &mtk_pwm_ops; |
212 | pc->chip.base = -1; | 233 | pc->chip.base = -1; |
213 | pc->chip.npwm = 5; | 234 | pc->chip.npwm = data->num_pwms; |
214 | 235 | ||
215 | ret = pwmchip_add(&pc->chip); | 236 | ret = pwmchip_add(&pc->chip); |
216 | if (ret < 0) { | 237 | if (ret < 0) { |
@@ -228,9 +249,23 @@ static int mtk_pwm_remove(struct platform_device *pdev) | |||
228 | return pwmchip_remove(&pc->chip); | 249 | return pwmchip_remove(&pc->chip); |
229 | } | 250 | } |
230 | 251 | ||
252 | static const struct mtk_pwm_platform_data mt2712_pwm_data = { | ||
253 | .num_pwms = 8, | ||
254 | }; | ||
255 | |||
256 | static const struct mtk_pwm_platform_data mt7622_pwm_data = { | ||
257 | .num_pwms = 6, | ||
258 | }; | ||
259 | |||
260 | static const struct mtk_pwm_platform_data mt7623_pwm_data = { | ||
261 | .num_pwms = 5, | ||
262 | }; | ||
263 | |||
231 | static const struct of_device_id mtk_pwm_of_match[] = { | 264 | static const struct of_device_id mtk_pwm_of_match[] = { |
232 | { .compatible = "mediatek,mt7623-pwm" }, | 265 | { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, |
233 | { } | 266 | { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, |
267 | { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, | ||
268 | { }, | ||
234 | }; | 269 | }; |
235 | MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); | 270 | MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); |
236 | 271 | ||
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 9793b296108f..1ac9e4384142 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c | |||
@@ -219,8 +219,7 @@ static int stm32_pwm_lp_remove(struct platform_device *pdev) | |||
219 | unsigned int i; | 219 | unsigned int i; |
220 | 220 | ||
221 | for (i = 0; i < priv->chip.npwm; i++) | 221 | for (i = 0; i < priv->chip.npwm; i++) |
222 | if (pwm_is_enabled(&priv->chip.pwms[i])) | 222 | pwm_disable(&priv->chip.pwms[i]); |
223 | pwm_disable(&priv->chip.pwms[i]); | ||
224 | 223 | ||
225 | return pwmchip_remove(&priv->chip); | 224 | return pwmchip_remove(&priv->chip); |
226 | } | 225 | } |
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 6d23f1d1c9b7..334199c58f1d 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c | |||
@@ -368,14 +368,15 @@ static int sun4i_pwm_probe(struct platform_device *pdev) | |||
368 | struct sun4i_pwm_chip *pwm; | 368 | struct sun4i_pwm_chip *pwm; |
369 | struct resource *res; | 369 | struct resource *res; |
370 | int ret; | 370 | int ret; |
371 | const struct of_device_id *match; | ||
372 | |||
373 | match = of_match_device(sun4i_pwm_dt_ids, &pdev->dev); | ||
374 | 371 | ||
375 | pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); | 372 | pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); |
376 | if (!pwm) | 373 | if (!pwm) |
377 | return -ENOMEM; | 374 | return -ENOMEM; |
378 | 375 | ||
376 | pwm->data = of_device_get_match_data(&pdev->dev); | ||
377 | if (!pwm->data) | ||
378 | return -ENODEV; | ||
379 | |||
379 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 380 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
380 | pwm->base = devm_ioremap_resource(&pdev->dev, res); | 381 | pwm->base = devm_ioremap_resource(&pdev->dev, res); |
381 | if (IS_ERR(pwm->base)) | 382 | if (IS_ERR(pwm->base)) |
@@ -385,7 +386,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev) | |||
385 | if (IS_ERR(pwm->clk)) | 386 | if (IS_ERR(pwm->clk)) |
386 | return PTR_ERR(pwm->clk); | 387 | return PTR_ERR(pwm->clk); |
387 | 388 | ||
388 | pwm->data = match->data; | ||
389 | pwm->chip.dev = &pdev->dev; | 389 | pwm->chip.dev = &pdev->dev; |
390 | pwm->chip.ops = &sun4i_pwm_ops; | 390 | pwm->chip.ops = &sun4i_pwm_ops; |
391 | pwm->chip.base = -1; | 391 | pwm->chip.base = -1; |