aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-berlin.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-12 14:11:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-12 14:11:05 -0400
commitb67be92feb486f800d80d72c67fd87b47b79b18e (patch)
treefcd22ae553cc094be6fcee8f2d3f99661793d165 /drivers/pwm/pwm-berlin.c
parent2d2474a194652f55c7af51068db3c1b851f16711 (diff)
parentdc8e6e1e8f2d2719dd396708b0f56d8b73c9ea52 (diff)
Merge tag 'pwm/for-4.9-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 contains support for PWM signal capture in the STi driver as well as support for the PWM controller found on Meson SoCs. There's also support added for the MediaTek MT2701 and SunXi H3 to the existing drivers. Other than that there's a fair set of miscellaneous cleanups and fixes across the board" * tag 'pwm/for-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (24 commits) pwm: meson: Handle unknown ID values pwm: sti: Take the opportunity to conduct a little house keeping pwm: sti: It's now valid for number of PWM channels to be zero pwm: sti: Add PWM capture callback pwm: sti: Add support for PWM capture interrupts pwm: sti: Initialise PWM capture device data pwm: sti: Supply PWM Capture clock handling pwm: sti: Supply PWM capture register addresses and bit locations pwm: sti: Only request clock rate when needed pwm: sti: Reorganise register names in preparation for new functionality pwm: sti: Rename channel => device dt-bindings: pwm: sti: Update DT bindings for capture support pwm: lpc-18xx: use pwm_set_chip_data pwm: sunxi: Add H3 support pwm: Add support for Meson PWM Controller dt-bindings: pwm: Add bindings for Meson PWM Controller pwm: samsung: Fix to use lowest div for large enough modulation bits pwm: pwm-tipwmss: Remove all runtime PM gets/puts pwm: cros-ec: Add __packed to prevent padding pwm: Add MediaTek MT2701 display PWM driver support ...
Diffstat (limited to 'drivers/pwm/pwm-berlin.c')
-rw-r--r--drivers/pwm/pwm-berlin.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index 65108129d505..01339c152ab0 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -16,6 +16,7 @@
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/pwm.h> 18#include <linux/pwm.h>
19#include <linux/slab.h>
19 20
20#define BERLIN_PWM_EN 0x0 21#define BERLIN_PWM_EN 0x0
21#define BERLIN_PWM_ENABLE BIT(0) 22#define BERLIN_PWM_ENABLE BIT(0)
@@ -27,6 +28,13 @@
27#define BERLIN_PWM_TCNT 0xc 28#define BERLIN_PWM_TCNT 0xc
28#define BERLIN_PWM_MAX_TCNT 65535 29#define BERLIN_PWM_MAX_TCNT 65535
29 30
31struct berlin_pwm_channel {
32 u32 enable;
33 u32 ctrl;
34 u32 duty;
35 u32 tcnt;
36};
37
30struct berlin_pwm_chip { 38struct berlin_pwm_chip {
31 struct pwm_chip chip; 39 struct pwm_chip chip;
32 struct clk *clk; 40 struct clk *clk;
@@ -55,6 +63,25 @@ static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip,
55 writel_relaxed(value, chip->base + channel * 0x10 + offset); 63 writel_relaxed(value, chip->base + channel * 0x10 + offset);
56} 64}
57 65
66static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
67{
68 struct berlin_pwm_channel *channel;
69
70 channel = kzalloc(sizeof(*channel), GFP_KERNEL);
71 if (!channel)
72 return -ENOMEM;
73
74 return pwm_set_chip_data(pwm, channel);
75}
76
77static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
78{
79 struct berlin_pwm_channel *channel = pwm_get_chip_data(pwm);
80
81 pwm_set_chip_data(pwm, NULL);
82 kfree(channel);
83}
84
58static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, 85static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
59 int duty_ns, int period_ns) 86 int duty_ns, int period_ns)
60{ 87{
@@ -137,6 +164,8 @@ static void berlin_pwm_disable(struct pwm_chip *chip,
137} 164}
138 165
139static const struct pwm_ops berlin_pwm_ops = { 166static const struct pwm_ops berlin_pwm_ops = {
167 .request = berlin_pwm_request,
168 .free = berlin_pwm_free,
140 .config = berlin_pwm_config, 169 .config = berlin_pwm_config,
141 .set_polarity = berlin_pwm_set_polarity, 170 .set_polarity = berlin_pwm_set_polarity,
142 .enable = berlin_pwm_enable, 171 .enable = berlin_pwm_enable,
@@ -204,12 +233,67 @@ static int berlin_pwm_remove(struct platform_device *pdev)
204 return ret; 233 return ret;
205} 234}
206 235
236#ifdef CONFIG_PM_SLEEP
237static int berlin_pwm_suspend(struct device *dev)
238{
239 struct berlin_pwm_chip *pwm = dev_get_drvdata(dev);
240 unsigned int i;
241
242 for (i = 0; i < pwm->chip.npwm; i++) {
243 struct berlin_pwm_channel *channel;
244
245 channel = pwm_get_chip_data(&pwm->chip.pwms[i]);
246 if (!channel)
247 continue;
248
249 channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE);
250 channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL);
251 channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY);
252 channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT);
253 }
254
255 clk_disable_unprepare(pwm->clk);
256
257 return 0;
258}
259
260static int berlin_pwm_resume(struct device *dev)
261{
262 struct berlin_pwm_chip *pwm = dev_get_drvdata(dev);
263 unsigned int i;
264 int ret;
265
266 ret = clk_prepare_enable(pwm->clk);
267 if (ret)
268 return ret;
269
270 for (i = 0; i < pwm->chip.npwm; i++) {
271 struct berlin_pwm_channel *channel;
272
273 channel = pwm_get_chip_data(&pwm->chip.pwms[i]);
274 if (!channel)
275 continue;
276
277 berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL);
278 berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY);
279 berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT);
280 berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE);
281 }
282
283 return 0;
284}
285#endif
286
287static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend,
288 berlin_pwm_resume);
289
207static struct platform_driver berlin_pwm_driver = { 290static struct platform_driver berlin_pwm_driver = {
208 .probe = berlin_pwm_probe, 291 .probe = berlin_pwm_probe,
209 .remove = berlin_pwm_remove, 292 .remove = berlin_pwm_remove,
210 .driver = { 293 .driver = {
211 .name = "berlin-pwm", 294 .name = "berlin-pwm",
212 .of_match_table = berlin_pwm_match, 295 .of_match_table = berlin_pwm_match,
296 .pm = &berlin_pwm_pm_ops,
213 }, 297 },
214}; 298};
215module_platform_driver(berlin_pwm_driver); 299module_platform_driver(berlin_pwm_driver);