aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-13 18:46:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-13 18:46:21 -0400
commitdaf3ef6e965d1d51d6ec604a8fc9919b75d5ec3c (patch)
tree643eeb6adc04a5e0a038d1a1dcbb2f6c8169c47e /drivers/pwm
parent41531f58a6513b86f8f379117eca82502022b4a9 (diff)
parent6873842235d678a245a378669f35e145df2441b9 (diff)
Merge tag 'pwm/for-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding: "This set of changes adds support for more generations of the RCar controller as well as runtime PM support. The JZ4740 driver gains support for device tree and can now be used on all Ingenic SoCs. Rounding things off is a random assortment of fixes and cleanups all across the board" * tag 'pwm/for-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (29 commits) pwm: rcar: Add suspend/resume support pwm: rcar: Use PM Runtime to control module clock dt-bindings: pwm: rcar: Add bindings for R-Car M3N support pwm: rcar: Fix a condition to prevent mismatch value setting to duty pwm: sysfs: Use put_device() instead of kfree() dt-bindings: pwm: sunxi: Add new compatible strings pwm: sun4i: Simplify controller mapping pwm: sun4i: Drop unused .has_rdy member pwm: sun4i: Properly check current state pwm: Remove depends on AVR32 pwm: stm32: LPTimer: Use 3 cells ->of_xlate() dt-bindings: pwm-stm32-lp: Add #pwm-cells pwm: stm32: Protect common prescaler for all channels pwm: stm32: Remove unused struct device pwm: mediatek: Improve precision in rate calculation pwm: mediatek: Remove redundant MODULE_ALIAS entries pwm: mediatek: Fix up PWM4 and PWM5 malfunction on MT7623 pwm: jz4740: Enable for all Ingenic SoCs pwm: jz4740: Add support for devicetree pwm: jz4740: Implement ->set_polarity() ...
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/Kconfig6
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c1
-rw-r--r--drivers/pwm/pwm-imx.c3
-rw-r--r--drivers/pwm/pwm-jz4740.c41
-rw-r--r--drivers/pwm/pwm-mediatek.c36
-rw-r--r--drivers/pwm/pwm-puv3.c4
-rw-r--r--drivers/pwm/pwm-rcar.c58
-rw-r--r--drivers/pwm/pwm-stm32-lp.c5
-rw-r--r--drivers/pwm/pwm-stm32.c22
-rw-r--r--drivers/pwm/pwm-sun4i.c38
-rw-r--r--drivers/pwm/sysfs.c3
11 files changed, 161 insertions, 56 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 38d49dbbf9b7..4635cb35008c 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -200,10 +200,10 @@ config PWM_IMX
200 will be called pwm-imx. 200 will be called pwm-imx.
201 201
202config PWM_JZ4740 202config PWM_JZ4740
203 tristate "Ingenic JZ4740 PWM support" 203 tristate "Ingenic JZ47xx PWM support"
204 depends on MACH_JZ4740 204 depends on MACH_INGENIC
205 help 205 help
206 Generic PWM framework driver for Ingenic JZ4740 based 206 Generic PWM framework driver for Ingenic JZ47xx based
207 machines. 207 machines.
208 208
209 To compile this driver as a module, choose M here: the module 209 To compile this driver as a module, choose M here: the module
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index acd3ce8ecf3f..4fb1be246c44 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -401,7 +401,6 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
401 tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); 401 tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL);
402 if (tcbpwm == NULL) { 402 if (tcbpwm == NULL) {
403 err = -ENOMEM; 403 err = -ENOMEM;
404 dev_err(&pdev->dev, "failed to allocate memory\n");
405 goto err_free_tc; 404 goto err_free_tc;
406 } 405 }
407 406
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 2ba5c3a398ff..08cbe8120588 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -35,6 +35,7 @@
35#define MX3_PWMSAR 0x0C /* PWM Sample Register */ 35#define MX3_PWMSAR 0x0C /* PWM Sample Register */
36#define MX3_PWMPR 0x10 /* PWM Period Register */ 36#define MX3_PWMPR 0x10 /* PWM Period Register */
37#define MX3_PWMCR_PRESCALER(x) ((((x) - 1) & 0xFFF) << 4) 37#define MX3_PWMCR_PRESCALER(x) ((((x) - 1) & 0xFFF) << 4)
38#define MX3_PWMCR_STOPEN (1 << 25)
38#define MX3_PWMCR_DOZEEN (1 << 24) 39#define MX3_PWMCR_DOZEEN (1 << 24)
39#define MX3_PWMCR_WAITEN (1 << 23) 40#define MX3_PWMCR_WAITEN (1 << 23)
40#define MX3_PWMCR_DBGEN (1 << 22) 41#define MX3_PWMCR_DBGEN (1 << 22)
@@ -210,7 +211,7 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm,
210 writel(period_cycles, imx->mmio_base + MX3_PWMPR); 211 writel(period_cycles, imx->mmio_base + MX3_PWMPR);
211 212
212 cr = MX3_PWMCR_PRESCALER(prescale) | 213 cr = MX3_PWMCR_PRESCALER(prescale) |
213 MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | 214 MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
214 MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH | 215 MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH |
215 MX3_PWMCR_EN; 216 MX3_PWMCR_EN;
216 217
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index a75ff3622450..a7b134af5e04 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -18,6 +18,7 @@
18#include <linux/gpio.h> 18#include <linux/gpio.h>
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/of_device.h>
21#include <linux/platform_device.h> 22#include <linux/platform_device.h>
22#include <linux/pwm.h> 23#include <linux/pwm.h>
23 24
@@ -71,9 +72,15 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
71{ 72{
72 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm); 73 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
73 74
75 /* Disable PWM output.
76 * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the
77 * counter is stopped, while in TCU1 mode the order does not matter.
78 */
74 ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE; 79 ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
75 jz4740_timer_disable(pwm->hwpwm);
76 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); 80 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
81
82 /* Stop counter */
83 jz4740_timer_disable(pwm->hwpwm);
77} 84}
78 85
79static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 86static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -124,10 +131,29 @@ static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
124 return 0; 131 return 0;
125} 132}
126 133
134static int jz4740_pwm_set_polarity(struct pwm_chip *chip,
135 struct pwm_device *pwm, enum pwm_polarity polarity)
136{
137 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
138
139 switch (polarity) {
140 case PWM_POLARITY_NORMAL:
141 ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
142 break;
143 case PWM_POLARITY_INVERSED:
144 ctrl |= JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
145 break;
146 }
147
148 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
149 return 0;
150}
151
127static const struct pwm_ops jz4740_pwm_ops = { 152static const struct pwm_ops jz4740_pwm_ops = {
128 .request = jz4740_pwm_request, 153 .request = jz4740_pwm_request,
129 .free = jz4740_pwm_free, 154 .free = jz4740_pwm_free,
130 .config = jz4740_pwm_config, 155 .config = jz4740_pwm_config,
156 .set_polarity = jz4740_pwm_set_polarity,
131 .enable = jz4740_pwm_enable, 157 .enable = jz4740_pwm_enable,
132 .disable = jz4740_pwm_disable, 158 .disable = jz4740_pwm_disable,
133 .owner = THIS_MODULE, 159 .owner = THIS_MODULE,
@@ -149,6 +175,8 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
149 jz4740->chip.ops = &jz4740_pwm_ops; 175 jz4740->chip.ops = &jz4740_pwm_ops;
150 jz4740->chip.npwm = NUM_PWM; 176 jz4740->chip.npwm = NUM_PWM;
151 jz4740->chip.base = -1; 177 jz4740->chip.base = -1;
178 jz4740->chip.of_xlate = of_pwm_xlate_with_flags;
179 jz4740->chip.of_pwm_n_cells = 3;
152 180
153 platform_set_drvdata(pdev, jz4740); 181 platform_set_drvdata(pdev, jz4740);
154 182
@@ -162,9 +190,20 @@ static int jz4740_pwm_remove(struct platform_device *pdev)
162 return pwmchip_remove(&jz4740->chip); 190 return pwmchip_remove(&jz4740->chip);
163} 191}
164 192
193#ifdef CONFIG_OF
194static const struct of_device_id jz4740_pwm_dt_ids[] = {
195 { .compatible = "ingenic,jz4740-pwm", },
196 { .compatible = "ingenic,jz4770-pwm", },
197 { .compatible = "ingenic,jz4780-pwm", },
198 {},
199};
200MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids);
201#endif
202
165static struct platform_driver jz4740_pwm_driver = { 203static struct platform_driver jz4740_pwm_driver = {
166 .driver = { 204 .driver = {
167 .name = "jz4740-pwm", 205 .name = "jz4740-pwm",
206 .of_match_table = of_match_ptr(jz4740_pwm_dt_ids),
168 }, 207 },
169 .probe = jz4740_pwm_probe, 208 .probe = jz4740_pwm_probe,
170 .remove = jz4740_pwm_remove, 209 .remove = jz4740_pwm_remove,
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index f5d97e0ad52b..328c124773b2 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -29,7 +29,9 @@
29#define PWMGDUR 0x0c 29#define PWMGDUR 0x0c
30#define PWMWAVENUM 0x28 30#define PWMWAVENUM 0x28
31#define PWMDWIDTH 0x2c 31#define PWMDWIDTH 0x2c
32#define PWM45DWIDTH_FIXUP 0x30
32#define PWMTHRES 0x30 33#define PWMTHRES 0x30
34#define PWM45THRES_FIXUP 0x34
33 35
34#define PWM_CLK_DIV_MAX 7 36#define PWM_CLK_DIV_MAX 7
35 37
@@ -54,6 +56,7 @@ static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = {
54 56
55struct mtk_pwm_platform_data { 57struct mtk_pwm_platform_data {
56 unsigned int num_pwms; 58 unsigned int num_pwms;
59 bool pwm45_fixup;
57}; 60};
58 61
59/** 62/**
@@ -66,6 +69,7 @@ struct mtk_pwm_chip {
66 struct pwm_chip chip; 69 struct pwm_chip chip;
67 void __iomem *regs; 70 void __iomem *regs;
68 struct clk *clks[MTK_CLK_MAX]; 71 struct clk *clks[MTK_CLK_MAX];
72 const struct mtk_pwm_platform_data *soc;
69}; 73};
70 74
71static const unsigned int mtk_pwm_reg_offset[] = { 75static const unsigned int mtk_pwm_reg_offset[] = {
@@ -131,18 +135,25 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
131{ 135{
132 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 136 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
133 struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]; 137 struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm];
134 u32 resolution, clkdiv = 0; 138 u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH,
139 reg_thres = PWMTHRES;
140 u64 resolution;
135 int ret; 141 int ret;
136 142
137 ret = mtk_pwm_clk_enable(chip, pwm); 143 ret = mtk_pwm_clk_enable(chip, pwm);
138 if (ret < 0) 144 if (ret < 0)
139 return ret; 145 return ret;
140 146
141 resolution = NSEC_PER_SEC / clk_get_rate(clk); 147 /* Using resolution in picosecond gets accuracy higher */
148 resolution = (u64)NSEC_PER_SEC * 1000;
149 do_div(resolution, clk_get_rate(clk));
142 150
143 while (period_ns / resolution > 8191) { 151 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution);
152 while (cnt_period > 8191) {
144 resolution *= 2; 153 resolution *= 2;
145 clkdiv++; 154 clkdiv++;
155 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000,
156 resolution);
146 } 157 }
147 158
148 if (clkdiv > PWM_CLK_DIV_MAX) { 159 if (clkdiv > PWM_CLK_DIV_MAX) {
@@ -151,9 +162,19 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
151 return -EINVAL; 162 return -EINVAL;
152 } 163 }
153 164
165 if (pc->soc->pwm45_fixup && pwm->hwpwm > 2) {
166 /*
167 * PWM[4,5] has distinct offset for PWMDWIDTH and PWMTHRES
168 * from the other PWMs on MT7623.
169 */
170 reg_width = PWM45DWIDTH_FIXUP;
171 reg_thres = PWM45THRES_FIXUP;
172 }
173
174 cnt_duty = DIV_ROUND_CLOSEST_ULL((u64)duty_ns * 1000, resolution);
154 mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); 175 mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv);
155 mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); 176 mtk_pwm_writel(pc, pwm->hwpwm, reg_width, cnt_period);
156 mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); 177 mtk_pwm_writel(pc, pwm->hwpwm, reg_thres, cnt_duty);
157 178
158 mtk_pwm_clk_disable(chip, pwm); 179 mtk_pwm_clk_disable(chip, pwm);
159 180
@@ -211,6 +232,7 @@ static int mtk_pwm_probe(struct platform_device *pdev)
211 data = of_device_get_match_data(&pdev->dev); 232 data = of_device_get_match_data(&pdev->dev);
212 if (data == NULL) 233 if (data == NULL)
213 return -EINVAL; 234 return -EINVAL;
235 pc->soc = data;
214 236
215 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 237 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
216 pc->regs = devm_ioremap_resource(&pdev->dev, res); 238 pc->regs = devm_ioremap_resource(&pdev->dev, res);
@@ -251,14 +273,17 @@ static int mtk_pwm_remove(struct platform_device *pdev)
251 273
252static const struct mtk_pwm_platform_data mt2712_pwm_data = { 274static const struct mtk_pwm_platform_data mt2712_pwm_data = {
253 .num_pwms = 8, 275 .num_pwms = 8,
276 .pwm45_fixup = false,
254}; 277};
255 278
256static const struct mtk_pwm_platform_data mt7622_pwm_data = { 279static const struct mtk_pwm_platform_data mt7622_pwm_data = {
257 .num_pwms = 6, 280 .num_pwms = 6,
281 .pwm45_fixup = false,
258}; 282};
259 283
260static const struct mtk_pwm_platform_data mt7623_pwm_data = { 284static const struct mtk_pwm_platform_data mt7623_pwm_data = {
261 .num_pwms = 5, 285 .num_pwms = 5,
286 .pwm45_fixup = true,
262}; 287};
263 288
264static const struct of_device_id mtk_pwm_of_match[] = { 289static const struct of_device_id mtk_pwm_of_match[] = {
@@ -280,5 +305,4 @@ static struct platform_driver mtk_pwm_driver = {
280module_platform_driver(mtk_pwm_driver); 305module_platform_driver(mtk_pwm_driver);
281 306
282MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); 307MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
283MODULE_ALIAS("platform:mtk-pwm");
284MODULE_LICENSE("GPL"); 308MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
index ed6007b27585..754fd9a98f6b 100644
--- a/drivers/pwm/pwm-puv3.c
+++ b/drivers/pwm/pwm-puv3.c
@@ -107,10 +107,8 @@ static int pwm_probe(struct platform_device *pdev)
107 int ret; 107 int ret;
108 108
109 puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL); 109 puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL);
110 if (puv3 == NULL) { 110 if (!puv3)
111 dev_err(&pdev->dev, "failed to allocate memory\n");
112 return -ENOMEM; 111 return -ENOMEM;
113 }
114 112
115 puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK"); 113 puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK");
116 if (IS_ERR(puv3->clk)) 114 if (IS_ERR(puv3->clk))
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 1c85ecc9e7ac..91d11f2e2fef 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -134,16 +134,12 @@ static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns,
134 134
135static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 135static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
136{ 136{
137 struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); 137 return pm_runtime_get_sync(chip->dev);
138
139 return clk_prepare_enable(rp->clk);
140} 138}
141 139
142static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 140static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
143{ 141{
144 struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); 142 pm_runtime_put(chip->dev);
145
146 clk_disable_unprepare(rp->clk);
147} 143}
148 144
149static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 145static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -156,8 +152,12 @@ static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
156 if (div < 0) 152 if (div < 0)
157 return div; 153 return div;
158 154
159 /* Let the core driver set pwm->period if disabled and duty_ns == 0 */ 155 /*
160 if (!pwm_is_enabled(pwm) && !duty_ns) 156 * Let the core driver set pwm->period if disabled and duty_ns == 0.
157 * But, this driver should prevent to set the new duty_ns if current
158 * duty_cycle is not set
159 */
160 if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle)
161 return 0; 161 return 0;
162 162
163 rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR); 163 rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
@@ -258,11 +258,53 @@ static const struct of_device_id rcar_pwm_of_table[] = {
258}; 258};
259MODULE_DEVICE_TABLE(of, rcar_pwm_of_table); 259MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
260 260
261#ifdef CONFIG_PM_SLEEP
262static struct pwm_device *rcar_pwm_dev_to_pwm_dev(struct device *dev)
263{
264 struct platform_device *pdev = to_platform_device(dev);
265 struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
266 struct pwm_chip *chip = &rcar_pwm->chip;
267
268 return &chip->pwms[0];
269}
270
271static int rcar_pwm_suspend(struct device *dev)
272{
273 struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev);
274
275 if (!test_bit(PWMF_REQUESTED, &pwm->flags))
276 return 0;
277
278 pm_runtime_put(dev);
279
280 return 0;
281}
282
283static int rcar_pwm_resume(struct device *dev)
284{
285 struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev);
286
287 if (!test_bit(PWMF_REQUESTED, &pwm->flags))
288 return 0;
289
290 pm_runtime_get_sync(dev);
291
292 rcar_pwm_config(pwm->chip, pwm, pwm->state.duty_cycle,
293 pwm->state.period);
294 if (pwm_is_enabled(pwm))
295 rcar_pwm_enable(pwm->chip, pwm);
296
297 return 0;
298}
299#endif /* CONFIG_PM_SLEEP */
300static SIMPLE_DEV_PM_OPS(rcar_pwm_pm_ops, rcar_pwm_suspend, rcar_pwm_resume);
301
261static struct platform_driver rcar_pwm_driver = { 302static struct platform_driver rcar_pwm_driver = {
262 .probe = rcar_pwm_probe, 303 .probe = rcar_pwm_probe,
263 .remove = rcar_pwm_remove, 304 .remove = rcar_pwm_remove,
264 .driver = { 305 .driver = {
265 .name = "pwm-rcar", 306 .name = "pwm-rcar",
307 .pm = &rcar_pwm_pm_ops,
266 .of_match_table = of_match_ptr(rcar_pwm_of_table), 308 .of_match_table = of_match_ptr(rcar_pwm_of_table),
267 } 309 }
268}; 310};
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index 1ac9e4384142..7c13e2505080 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -1,3 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * STM32 Low-Power Timer PWM driver 3 * STM32 Low-Power Timer PWM driver
3 * 4 *
@@ -5,8 +6,6 @@
5 * 6 *
6 * Author: Gerald Baeza <gerald.baeza@st.com> 7 * Author: Gerald Baeza <gerald.baeza@st.com>
7 * 8 *
8 * License terms: GNU General Public License (GPL), version 2
9 *
10 * Inspired by Gerald Baeza's pwm-stm32 driver 9 * Inspired by Gerald Baeza's pwm-stm32 driver
11 */ 10 */
12 11
@@ -203,6 +202,8 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
203 priv->chip.dev = &pdev->dev; 202 priv->chip.dev = &pdev->dev;
204 priv->chip.ops = &stm32_pwm_lp_ops; 203 priv->chip.ops = &stm32_pwm_lp_ops;
205 priv->chip.npwm = 1; 204 priv->chip.npwm = 1;
205 priv->chip.of_xlate = of_pwm_xlate_with_flags;
206 priv->chip.of_pwm_n_cells = 3;
206 207
207 ret = pwmchip_add(&priv->chip); 208 ret = pwmchip_add(&priv->chip);
208 if (ret < 0) 209 if (ret < 0)
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 6139512aab7b..2708212933f7 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -1,10 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics 2016 3 * Copyright (C) STMicroelectronics 2016
3 * 4 *
4 * Author: Gerald Baeza <gerald.baeza@st.com> 5 * Author: Gerald Baeza <gerald.baeza@st.com>
5 * 6 *
6 * License terms: GNU General Public License (GPL), version 2
7 *
8 * Inspired by timer-stm32.c from Maxime Coquelin 7 * Inspired by timer-stm32.c from Maxime Coquelin
9 * pwm-atmel.c from Bo Shen 8 * pwm-atmel.c from Bo Shen
10 */ 9 */
@@ -21,7 +20,7 @@
21 20
22struct stm32_pwm { 21struct stm32_pwm {
23 struct pwm_chip chip; 22 struct pwm_chip chip;
24 struct device *dev; 23 struct mutex lock; /* protect pwm config/enable */
25 struct clk *clk; 24 struct clk *clk;
26 struct regmap *regmap; 25 struct regmap *regmap;
27 u32 max_arr; 26 u32 max_arr;
@@ -214,9 +213,23 @@ static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
214 return ret; 213 return ret;
215} 214}
216 215
216static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm,
217 struct pwm_state *state)
218{
219 struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
220 int ret;
221
222 /* protect common prescaler for all active channels */
223 mutex_lock(&priv->lock);
224 ret = stm32_pwm_apply(chip, pwm, state);
225 mutex_unlock(&priv->lock);
226
227 return ret;
228}
229
217static const struct pwm_ops stm32pwm_ops = { 230static const struct pwm_ops stm32pwm_ops = {
218 .owner = THIS_MODULE, 231 .owner = THIS_MODULE,
219 .apply = stm32_pwm_apply, 232 .apply = stm32_pwm_apply_locked,
220}; 233};
221 234
222static int stm32_pwm_set_breakinput(struct stm32_pwm *priv, 235static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
@@ -336,6 +349,7 @@ static int stm32_pwm_probe(struct platform_device *pdev)
336 if (!priv) 349 if (!priv)
337 return -ENOMEM; 350 return -ENOMEM;
338 351
352 mutex_init(&priv->lock);
339 priv->regmap = ddata->regmap; 353 priv->regmap = ddata->regmap;
340 priv->clk = ddata->clk; 354 priv->clk = ddata->clk;
341 priv->max_arr = ddata->max_arr; 355 priv->max_arr = ddata->max_arr;
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index 334199c58f1d..470d4f71e7eb 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -73,7 +73,6 @@ static const u32 prescaler_table[] = {
73 73
74struct sun4i_pwm_data { 74struct sun4i_pwm_data {
75 bool has_prescaler_bypass; 75 bool has_prescaler_bypass;
76 bool has_rdy;
77 unsigned int npwm; 76 unsigned int npwm;
78}; 77};
79 78
@@ -117,7 +116,8 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip,
117 116
118 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); 117 val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
119 118
120 if ((val == PWM_PRESCAL_MASK) && sun4i_pwm->data->has_prescaler_bypass) 119 if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) &&
120 sun4i_pwm->data->has_prescaler_bypass)
121 prescaler = 1; 121 prescaler = 1;
122 else 122 else
123 prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)]; 123 prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)];
@@ -130,7 +130,8 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip,
130 else 130 else
131 state->polarity = PWM_POLARITY_INVERSED; 131 state->polarity = PWM_POLARITY_INVERSED;
132 132
133 if (val & BIT_CH(PWM_CLK_GATING | PWM_EN, pwm->hwpwm)) 133 if ((val & BIT_CH(PWM_CLK_GATING | PWM_EN, pwm->hwpwm)) ==
134 BIT_CH(PWM_CLK_GATING | PWM_EN, pwm->hwpwm))
134 state->enabled = true; 135 state->enabled = true;
135 else 136 else
136 state->enabled = false; 137 state->enabled = false;
@@ -311,52 +312,37 @@ static const struct pwm_ops sun4i_pwm_ops = {
311 .owner = THIS_MODULE, 312 .owner = THIS_MODULE,
312}; 313};
313 314
314static const struct sun4i_pwm_data sun4i_pwm_data_a10 = { 315static const struct sun4i_pwm_data sun4i_pwm_dual_nobypass = {
315 .has_prescaler_bypass = false, 316 .has_prescaler_bypass = false,
316 .has_rdy = false,
317 .npwm = 2, 317 .npwm = 2,
318}; 318};
319 319
320static const struct sun4i_pwm_data sun4i_pwm_data_a10s = { 320static const struct sun4i_pwm_data sun4i_pwm_dual_bypass = {
321 .has_prescaler_bypass = true, 321 .has_prescaler_bypass = true,
322 .has_rdy = true,
323 .npwm = 2, 322 .npwm = 2,
324}; 323};
325 324
326static const struct sun4i_pwm_data sun4i_pwm_data_a13 = { 325static const struct sun4i_pwm_data sun4i_pwm_single_bypass = {
327 .has_prescaler_bypass = true, 326 .has_prescaler_bypass = true,
328 .has_rdy = true,
329 .npwm = 1,
330};
331
332static const struct sun4i_pwm_data sun4i_pwm_data_a20 = {
333 .has_prescaler_bypass = true,
334 .has_rdy = true,
335 .npwm = 2,
336};
337
338static const struct sun4i_pwm_data sun4i_pwm_data_h3 = {
339 .has_prescaler_bypass = true,
340 .has_rdy = true,
341 .npwm = 1, 327 .npwm = 1,
342}; 328};
343 329
344static const struct of_device_id sun4i_pwm_dt_ids[] = { 330static const struct of_device_id sun4i_pwm_dt_ids[] = {
345 { 331 {
346 .compatible = "allwinner,sun4i-a10-pwm", 332 .compatible = "allwinner,sun4i-a10-pwm",
347 .data = &sun4i_pwm_data_a10, 333 .data = &sun4i_pwm_dual_nobypass,
348 }, { 334 }, {
349 .compatible = "allwinner,sun5i-a10s-pwm", 335 .compatible = "allwinner,sun5i-a10s-pwm",
350 .data = &sun4i_pwm_data_a10s, 336 .data = &sun4i_pwm_dual_bypass,
351 }, { 337 }, {
352 .compatible = "allwinner,sun5i-a13-pwm", 338 .compatible = "allwinner,sun5i-a13-pwm",
353 .data = &sun4i_pwm_data_a13, 339 .data = &sun4i_pwm_single_bypass,
354 }, { 340 }, {
355 .compatible = "allwinner,sun7i-a20-pwm", 341 .compatible = "allwinner,sun7i-a20-pwm",
356 .data = &sun4i_pwm_data_a20, 342 .data = &sun4i_pwm_dual_bypass,
357 }, { 343 }, {
358 .compatible = "allwinner,sun8i-h3-pwm", 344 .compatible = "allwinner,sun8i-h3-pwm",
359 .data = &sun4i_pwm_data_h3, 345 .data = &sun4i_pwm_single_bypass,
360 }, { 346 }, {
361 /* sentinel */ 347 /* sentinel */
362 }, 348 },
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 83f2b0b15712..7c71cdb8a9d8 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -273,7 +273,8 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
273 ret = device_register(&export->child); 273 ret = device_register(&export->child);
274 if (ret) { 274 if (ret) {
275 clear_bit(PWMF_EXPORTED, &pwm->flags); 275 clear_bit(PWMF_EXPORTED, &pwm->flags);
276 kfree(export); 276 put_device(&export->child);
277 export = NULL;
277 return ret; 278 return ret;
278 } 279 }
279 280