diff options
| -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; |
