aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-05 21:32:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-05 21:32:31 -0400
commit9712d3c377a9868355ea9a611aca3c54f88dc576 (patch)
tree67f1e0dcc9a8fee4acf7d39622a998333464bafe /drivers/pwm
parent2bf73dd61a84cdf27e49f48e08739af6ba70ace1 (diff)
parent2ae69a460413615c82381b240df3800a909100d3 (diff)
Merge tag 'pwm/for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm changes from Thierry Reding: "The legacy HAVE_PWM Kconfig symbol is finally being retired. Thanks a lot to Sascha Hauer for doing that. Three new drivers are added: Freescale FTM, Cirrus Logic CLPS711X and Intel Low Power Subsystem. An assortment of fixes and cleanups rounds things off for this release cycle" * tag 'pwm/for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: pwm: pxa: Constify OF match table pwm: pxa: Fix typo "pwm" -> "PWM" Revert "pwm: pxa: Use of_match_ptr()" pwm: add support for Intel Low Power Subsystem PWM pwm: Add CLPS711X PWM support pwm: atmel: correct CDTY calculation pwm: atmel: Fix polarity handling Documentation: Add device tree bindings for Freescale FTM PWM. pwm: Add Freescale FTM PWM driver support pwm: pxa: Use of_match_ptr() pwm: samsung: Use SIMPLE_DEV_PM_OPS macro pwm: renesas-tpu: Add dependency on HAS_IOMEM pwm: Remove obsolete HAVE_PWM Kconfig symbol
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/Kconfig30
-rw-r--r--drivers/pwm/Makefile3
-rw-r--r--drivers/pwm/pwm-atmel.c9
-rw-r--r--drivers/pwm/pwm-clps711x.c176
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c495
-rw-r--r--drivers/pwm/pwm-lpss.c183
-rw-r--r--drivers/pwm/pwm-pxa.c4
-rw-r--r--drivers/pwm/pwm-samsung.c5
8 files changed, 898 insertions, 7 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 22f2f2857b82..5b34ff29ea38 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -71,6 +71,15 @@ config PWM_BFIN
71 To compile this driver as a module, choose M here: the module 71 To compile this driver as a module, choose M here: the module
72 will be called pwm-bfin. 72 will be called pwm-bfin.
73 73
74config PWM_CLPS711X
75 tristate "CLPS711X PWM support"
76 depends on ARCH_CLPS711X || COMPILE_TEST
77 help
78 Generic PWM framework driver for Cirrus Logic CLPS711X.
79
80 To compile this driver as a module, choose M here: the module
81 will be called pwm-clps711x.
82
74config PWM_EP93XX 83config PWM_EP93XX
75 tristate "Cirrus Logic EP93xx PWM support" 84 tristate "Cirrus Logic EP93xx PWM support"
76 depends on ARCH_EP93XX 85 depends on ARCH_EP93XX
@@ -80,6 +89,16 @@ config PWM_EP93XX
80 To compile this driver as a module, choose M here: the module 89 To compile this driver as a module, choose M here: the module
81 will be called pwm-ep93xx. 90 will be called pwm-ep93xx.
82 91
92config PWM_FSL_FTM
93 tristate "Freescale FlexTimer Module (FTM) PWM support"
94 depends on OF
95 help
96 Generic FTM PWM framework driver for Freescale VF610 and
97 Layerscape LS-1 SoCs.
98
99 To compile this driver as a module, choose M here: the module
100 will be called pwm-fsl-ftm.
101
83config PWM_IMX 102config PWM_IMX
84 tristate "i.MX PWM support" 103 tristate "i.MX PWM support"
85 depends on ARCH_MXC 104 depends on ARCH_MXC
@@ -119,6 +138,16 @@ config PWM_LPC32XX
119 To compile this driver as a module, choose M here: the module 138 To compile this driver as a module, choose M here: the module
120 will be called pwm-lpc32xx. 139 will be called pwm-lpc32xx.
121 140
141config PWM_LPSS
142 tristate "Intel LPSS PWM support"
143 depends on ACPI
144 help
145 Generic PWM framework driver for Intel Low Power Subsystem PWM
146 controller.
147
148 To compile this driver as a module, choose M here: the module
149 will be called pwm-lpss.
150
122config PWM_MXS 151config PWM_MXS
123 tristate "Freescale MXS PWM support" 152 tristate "Freescale MXS PWM support"
124 depends on ARCH_MXS && OF 153 depends on ARCH_MXS && OF
@@ -160,6 +189,7 @@ config PWM_PXA
160config PWM_RENESAS_TPU 189config PWM_RENESAS_TPU
161 tristate "Renesas TPU PWM support" 190 tristate "Renesas TPU PWM support"
162 depends on ARCH_SHMOBILE || COMPILE_TEST 191 depends on ARCH_SHMOBILE || COMPILE_TEST
192 depends on HAS_IOMEM
163 help 193 help
164 This driver exposes the Timer Pulse Unit (TPU) PWM controller found 194 This driver exposes the Timer Pulse Unit (TPU) PWM controller found
165 in Renesas chips through the PWM API. 195 in Renesas chips through the PWM API.
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index d8906ec69976..e57d2c38a794 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -4,11 +4,14 @@ obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
4obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o 4obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
5obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o 5obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
6obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 6obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
7obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
7obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o 8obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
9obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
8obj-$(CONFIG_PWM_IMX) += pwm-imx.o 10obj-$(CONFIG_PWM_IMX) += pwm-imx.o
9obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o 11obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
10obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o 12obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o
11obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o 13obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
14obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
12obj-$(CONFIG_PWM_MXS) += pwm-mxs.o 15obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
13obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o 16obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
14obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o 17obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index bf4144a14661..0adc952cc4ef 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -32,6 +32,7 @@
32/* Bit field in CMR */ 32/* Bit field in CMR */
33#define PWM_CMR_CPOL (1 << 9) 33#define PWM_CMR_CPOL (1 << 9)
34#define PWM_CMR_UPD_CDTY (1 << 10) 34#define PWM_CMR_UPD_CDTY (1 << 10)
35#define PWM_CMR_CPRE_MSK 0xF
35 36
36/* The following registers for PWM v1 */ 37/* The following registers for PWM v1 */
37#define PWMV1_CDTY 0x04 38#define PWMV1_CDTY 0x04
@@ -104,6 +105,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
104 unsigned long clk_rate, prd, dty; 105 unsigned long clk_rate, prd, dty;
105 unsigned long long div; 106 unsigned long long div;
106 unsigned int pres = 0; 107 unsigned int pres = 0;
108 u32 val;
107 int ret; 109 int ret;
108 110
109 if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) { 111 if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) {
@@ -131,7 +133,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
131 prd = div; 133 prd = div;
132 div *= duty_ns; 134 div *= duty_ns;
133 do_div(div, period_ns); 135 do_div(div, period_ns);
134 dty = div; 136 dty = prd - div;
135 137
136 ret = clk_enable(atmel_pwm->clk); 138 ret = clk_enable(atmel_pwm->clk);
137 if (ret) { 139 if (ret) {
@@ -139,7 +141,10 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
139 return ret; 141 return ret;
140 } 142 }
141 143
142 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, pres); 144 /* It is necessary to preserve CPOL, inside CMR */
145 val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
146 val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK);
147 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
143 atmel_pwm->config(chip, pwm, dty, prd); 148 atmel_pwm->config(chip, pwm, dty, prd);
144 149
145 clk_disable(atmel_pwm->clk); 150 clk_disable(atmel_pwm->clk);
diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
new file mode 100644
index 000000000000..fafb6a0111b0
--- /dev/null
+++ b/drivers/pwm/pwm-clps711x.c
@@ -0,0 +1,176 @@
1/*
2 * Cirrus Logic CLPS711X PWM driver
3 *
4 * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/clk.h>
13#include <linux/io.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/platform_device.h>
17#include <linux/pwm.h>
18
19struct clps711x_chip {
20 struct pwm_chip chip;
21 void __iomem *pmpcon;
22 struct clk *clk;
23 spinlock_t lock;
24};
25
26static inline struct clps711x_chip *to_clps711x_chip(struct pwm_chip *chip)
27{
28 return container_of(chip, struct clps711x_chip, chip);
29}
30
31static void clps711x_pwm_update_val(struct clps711x_chip *priv, u32 n, u32 v)
32{
33 /* PWM0 - bits 4..7, PWM1 - bits 8..11 */
34 u32 shift = (n + 1) * 4;
35 unsigned long flags;
36 u32 tmp;
37
38 spin_lock_irqsave(&priv->lock, flags);
39
40 tmp = readl(priv->pmpcon);
41 tmp &= ~(0xf << shift);
42 tmp |= v << shift;
43 writel(tmp, priv->pmpcon);
44
45 spin_unlock_irqrestore(&priv->lock, flags);
46}
47
48static unsigned int clps711x_get_duty(struct pwm_device *pwm, unsigned int v)
49{
50 /* Duty cycle 0..15 max */
51 return DIV_ROUND_CLOSEST(v * 0xf, pwm_get_period(pwm));
52}
53
54static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
55{
56 struct clps711x_chip *priv = to_clps711x_chip(chip);
57 unsigned int freq = clk_get_rate(priv->clk);
58
59 if (!freq)
60 return -EINVAL;
61
62 /* Store constant period value */
63 pwm_set_period(pwm, DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq));
64
65 return 0;
66}
67
68static int clps711x_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
69 int duty_ns, int period_ns)
70{
71 struct clps711x_chip *priv = to_clps711x_chip(chip);
72 unsigned int duty;
73
74 if (period_ns != pwm_get_period(pwm))
75 return -EINVAL;
76
77 duty = clps711x_get_duty(pwm, duty_ns);
78 clps711x_pwm_update_val(priv, pwm->hwpwm, duty);
79
80 return 0;
81}
82
83static int clps711x_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
84{
85 struct clps711x_chip *priv = to_clps711x_chip(chip);
86 unsigned int duty;
87
88 duty = clps711x_get_duty(pwm, pwm_get_duty_cycle(pwm));
89 clps711x_pwm_update_val(priv, pwm->hwpwm, duty);
90
91 return 0;
92}
93
94static void clps711x_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
95{
96 struct clps711x_chip *priv = to_clps711x_chip(chip);
97
98 clps711x_pwm_update_val(priv, pwm->hwpwm, 0);
99}
100
101static const struct pwm_ops clps711x_pwm_ops = {
102 .request = clps711x_pwm_request,
103 .config = clps711x_pwm_config,
104 .enable = clps711x_pwm_enable,
105 .disable = clps711x_pwm_disable,
106 .owner = THIS_MODULE,
107};
108
109static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip,
110 const struct of_phandle_args *args)
111{
112 if (args->args[0] >= chip->npwm)
113 return ERR_PTR(-EINVAL);
114
115 return pwm_request_from_chip(chip, args->args[0], NULL);
116}
117
118static int clps711x_pwm_probe(struct platform_device *pdev)
119{
120 struct clps711x_chip *priv;
121 struct resource *res;
122
123 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
124 if (!priv)
125 return -ENOMEM;
126
127 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
128 priv->pmpcon = devm_ioremap_resource(&pdev->dev, res);
129 if (IS_ERR(priv->pmpcon))
130 return PTR_ERR(priv->pmpcon);
131
132 priv->clk = devm_clk_get(&pdev->dev, NULL);
133 if (IS_ERR(priv->clk))
134 return PTR_ERR(priv->clk);
135
136 priv->chip.ops = &clps711x_pwm_ops;
137 priv->chip.dev = &pdev->dev;
138 priv->chip.base = -1;
139 priv->chip.npwm = 2;
140 priv->chip.of_xlate = clps711x_pwm_xlate;
141 priv->chip.of_pwm_n_cells = 1;
142
143 spin_lock_init(&priv->lock);
144
145 platform_set_drvdata(pdev, priv);
146
147 return pwmchip_add(&priv->chip);
148}
149
150static int clps711x_pwm_remove(struct platform_device *pdev)
151{
152 struct clps711x_chip *priv = platform_get_drvdata(pdev);
153
154 return pwmchip_remove(&priv->chip);
155}
156
157static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
158 { .compatible = "cirrus,clps711x-pwm", },
159 { }
160};
161MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids);
162
163static struct platform_driver clps711x_pwm_driver = {
164 .driver = {
165 .name = "clps711x-pwm",
166 .owner = THIS_MODULE,
167 .of_match_table = of_match_ptr(clps711x_pwm_dt_ids),
168 },
169 .probe = clps711x_pwm_probe,
170 .remove = clps711x_pwm_remove,
171};
172module_platform_driver(clps711x_pwm_driver);
173
174MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
175MODULE_DESCRIPTION("Cirrus Logic CLPS711X PWM driver");
176MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
new file mode 100644
index 000000000000..420169e96b5f
--- /dev/null
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -0,0 +1,495 @@
1/*
2 * Freescale FlexTimer Module (FTM) PWM Driver
3 *
4 * Copyright 2012-2013 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/clk.h>
13#include <linux/err.h>
14#include <linux/io.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/mutex.h>
18#include <linux/of_address.h>
19#include <linux/platform_device.h>
20#include <linux/pwm.h>
21#include <linux/slab.h>
22
23#define FTM_SC 0x00
24#define FTM_SC_CLK_MASK 0x3
25#define FTM_SC_CLK_SHIFT 3
26#define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_SHIFT)
27#define FTM_SC_PS_MASK 0x7
28#define FTM_SC_PS_SHIFT 0
29
30#define FTM_CNT 0x04
31#define FTM_MOD 0x08
32
33#define FTM_CSC_BASE 0x0C
34#define FTM_CSC_MSB BIT(5)
35#define FTM_CSC_MSA BIT(4)
36#define FTM_CSC_ELSB BIT(3)
37#define FTM_CSC_ELSA BIT(2)
38#define FTM_CSC(_channel) (FTM_CSC_BASE + ((_channel) * 8))
39
40#define FTM_CV_BASE 0x10
41#define FTM_CV(_channel) (FTM_CV_BASE + ((_channel) * 8))
42
43#define FTM_CNTIN 0x4C
44#define FTM_STATUS 0x50
45
46#define FTM_MODE 0x54
47#define FTM_MODE_FTMEN BIT(0)
48#define FTM_MODE_INIT BIT(2)
49#define FTM_MODE_PWMSYNC BIT(3)
50
51#define FTM_SYNC 0x58
52#define FTM_OUTINIT 0x5C
53#define FTM_OUTMASK 0x60
54#define FTM_COMBINE 0x64
55#define FTM_DEADTIME 0x68
56#define FTM_EXTTRIG 0x6C
57#define FTM_POL 0x70
58#define FTM_FMS 0x74
59#define FTM_FILTER 0x78
60#define FTM_FLTCTRL 0x7C
61#define FTM_QDCTRL 0x80
62#define FTM_CONF 0x84
63#define FTM_FLTPOL 0x88
64#define FTM_SYNCONF 0x8C
65#define FTM_INVCTRL 0x90
66#define FTM_SWOCTRL 0x94
67#define FTM_PWMLOAD 0x98
68
69enum fsl_pwm_clk {
70 FSL_PWM_CLK_SYS,
71 FSL_PWM_CLK_FIX,
72 FSL_PWM_CLK_EXT,
73 FSL_PWM_CLK_CNTEN,
74 FSL_PWM_CLK_MAX
75};
76
77struct fsl_pwm_chip {
78 struct pwm_chip chip;
79
80 struct mutex lock;
81
82 unsigned int use_count;
83 unsigned int cnt_select;
84 unsigned int clk_ps;
85
86 void __iomem *base;
87
88 int period_ns;
89
90 struct clk *clk[FSL_PWM_CLK_MAX];
91};
92
93static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
94{
95 return container_of(chip, struct fsl_pwm_chip, chip);
96}
97
98static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
99{
100 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
101
102 return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
103}
104
105static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
106{
107 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
108
109 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
110}
111
112static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc,
113 enum fsl_pwm_clk index)
114{
115 unsigned long sys_rate, cnt_rate;
116 unsigned long long ratio;
117
118 sys_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_SYS]);
119 if (!sys_rate)
120 return -EINVAL;
121
122 cnt_rate = clk_get_rate(fpc->clk[fpc->cnt_select]);
123 if (!cnt_rate)
124 return -EINVAL;
125
126 switch (index) {
127 case FSL_PWM_CLK_SYS:
128 fpc->clk_ps = 1;
129 break;
130 case FSL_PWM_CLK_FIX:
131 ratio = 2 * cnt_rate - 1;
132 do_div(ratio, sys_rate);
133 fpc->clk_ps = ratio;
134 break;
135 case FSL_PWM_CLK_EXT:
136 ratio = 4 * cnt_rate - 1;
137 do_div(ratio, sys_rate);
138 fpc->clk_ps = ratio;
139 break;
140 default:
141 return -EINVAL;
142 }
143
144 return 0;
145}
146
147static unsigned long fsl_pwm_calculate_cycles(struct fsl_pwm_chip *fpc,
148 unsigned long period_ns)
149{
150 unsigned long long c, c0;
151
152 c = clk_get_rate(fpc->clk[fpc->cnt_select]);
153 c = c * period_ns;
154 do_div(c, 1000000000UL);
155
156 do {
157 c0 = c;
158 do_div(c0, (1 << fpc->clk_ps));
159 if (c0 <= 0xFFFF)
160 return (unsigned long)c0;
161 } while (++fpc->clk_ps < 8);
162
163 return 0;
164}
165
166static unsigned long fsl_pwm_calculate_period_cycles(struct fsl_pwm_chip *fpc,
167 unsigned long period_ns,
168 enum fsl_pwm_clk index)
169{
170 int ret;
171
172 ret = fsl_pwm_calculate_default_ps(fpc, index);
173 if (ret) {
174 dev_err(fpc->chip.dev,
175 "failed to calculate default prescaler: %d\n",
176 ret);
177 return 0;
178 }
179
180 return fsl_pwm_calculate_cycles(fpc, period_ns);
181}
182
183static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
184 unsigned long period_ns)
185{
186 enum fsl_pwm_clk m0, m1;
187 unsigned long fix_rate, ext_rate, cycles;
188
189 cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns,
190 FSL_PWM_CLK_SYS);
191 if (cycles) {
192 fpc->cnt_select = FSL_PWM_CLK_SYS;
193 return cycles;
194 }
195
196 fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]);
197 ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]);
198
199 if (fix_rate > ext_rate) {
200 m0 = FSL_PWM_CLK_FIX;
201 m1 = FSL_PWM_CLK_EXT;
202 } else {
203 m0 = FSL_PWM_CLK_EXT;
204 m1 = FSL_PWM_CLK_FIX;
205 }
206
207 cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns, m0);
208 if (cycles) {
209 fpc->cnt_select = m0;
210 return cycles;
211 }
212
213 fpc->cnt_select = m1;
214
215 return fsl_pwm_calculate_period_cycles(fpc, period_ns, m1);
216}
217
218static unsigned long fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,
219 unsigned long period_ns,
220 unsigned long duty_ns)
221{
222 unsigned long long val, duty;
223
224 val = readl(fpc->base + FTM_MOD);
225 duty = duty_ns * (val + 1);
226 do_div(duty, period_ns);
227
228 return (unsigned long)duty;
229}
230
231static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
232 int duty_ns, int period_ns)
233{
234 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
235 u32 val, period, duty;
236
237 mutex_lock(&fpc->lock);
238
239 /*
240 * The Freescale FTM controller supports only a single period for
241 * all PWM channels, therefore incompatible changes need to be
242 * refused.
243 */
244 if (fpc->period_ns && fpc->period_ns != period_ns) {
245 dev_err(fpc->chip.dev,
246 "conflicting period requested for PWM %u\n",
247 pwm->hwpwm);
248 mutex_unlock(&fpc->lock);
249 return -EBUSY;
250 }
251
252 if (!fpc->period_ns && duty_ns) {
253 period = fsl_pwm_calculate_period(fpc, period_ns);
254 if (!period) {
255 dev_err(fpc->chip.dev, "failed to calculate period\n");
256 mutex_unlock(&fpc->lock);
257 return -EINVAL;
258 }
259
260 val = readl(fpc->base + FTM_SC);
261 val &= ~(FTM_SC_PS_MASK << FTM_SC_PS_SHIFT);
262 val |= fpc->clk_ps;
263 writel(val, fpc->base + FTM_SC);
264 writel(period - 1, fpc->base + FTM_MOD);
265
266 fpc->period_ns = period_ns;
267 }
268
269 mutex_unlock(&fpc->lock);
270
271 duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns);
272
273 writel(FTM_CSC_MSB | FTM_CSC_ELSB, fpc->base + FTM_CSC(pwm->hwpwm));
274 writel(duty, fpc->base + FTM_CV(pwm->hwpwm));
275
276 return 0;
277}
278
279static int fsl_pwm_set_polarity(struct pwm_chip *chip,
280 struct pwm_device *pwm,
281 enum pwm_polarity polarity)
282{
283 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
284 u32 val;
285
286 val = readl(fpc->base + FTM_POL);
287
288 if (polarity == PWM_POLARITY_INVERSED)
289 val |= BIT(pwm->hwpwm);
290 else
291 val &= ~BIT(pwm->hwpwm);
292
293 writel(val, fpc->base + FTM_POL);
294
295 return 0;
296}
297
298static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
299{
300 u32 val;
301 int ret;
302
303 if (fpc->use_count != 0)
304 return 0;
305
306 /* select counter clock source */
307 val = readl(fpc->base + FTM_SC);
308 val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT);
309 val |= FTM_SC_CLK(fpc->cnt_select);
310 writel(val, fpc->base + FTM_SC);
311
312 ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]);
313 if (ret)
314 return ret;
315
316 ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
317 if (ret) {
318 clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
319 return ret;
320 }
321
322 fpc->use_count++;
323
324 return 0;
325}
326
327static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
328{
329 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
330 u32 val;
331 int ret;
332
333 mutex_lock(&fpc->lock);
334 val = readl(fpc->base + FTM_OUTMASK);
335 val &= ~BIT(pwm->hwpwm);
336 writel(val, fpc->base + FTM_OUTMASK);
337
338 ret = fsl_counter_clock_enable(fpc);
339 mutex_unlock(&fpc->lock);
340
341 return ret;
342}
343
344static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc)
345{
346 u32 val;
347
348 /*
349 * already disabled, do nothing
350 */
351 if (fpc->use_count == 0)
352 return;
353
354 /* there are still users, so can't disable yet */
355 if (--fpc->use_count > 0)
356 return;
357
358 /* no users left, disable PWM counter clock */
359 val = readl(fpc->base + FTM_SC);
360 val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT);
361 writel(val, fpc->base + FTM_SC);
362
363 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
364 clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
365}
366
367static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
368{
369 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
370 u32 val;
371
372 mutex_lock(&fpc->lock);
373 val = readl(fpc->base + FTM_OUTMASK);
374 val |= BIT(pwm->hwpwm);
375 writel(val, fpc->base + FTM_OUTMASK);
376
377 fsl_counter_clock_disable(fpc);
378
379 val = readl(fpc->base + FTM_OUTMASK);
380
381 if ((val & 0xFF) == 0xFF)
382 fpc->period_ns = 0;
383
384 mutex_unlock(&fpc->lock);
385}
386
387static const struct pwm_ops fsl_pwm_ops = {
388 .request = fsl_pwm_request,
389 .free = fsl_pwm_free,
390 .config = fsl_pwm_config,
391 .set_polarity = fsl_pwm_set_polarity,
392 .enable = fsl_pwm_enable,
393 .disable = fsl_pwm_disable,
394 .owner = THIS_MODULE,
395};
396
397static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
398{
399 int ret;
400
401 ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
402 if (ret)
403 return ret;
404
405 writel(0x00, fpc->base + FTM_CNTIN);
406 writel(0x00, fpc->base + FTM_OUTINIT);
407 writel(0xFF, fpc->base + FTM_OUTMASK);
408
409 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
410
411 return 0;
412}
413
414static int fsl_pwm_probe(struct platform_device *pdev)
415{
416 struct fsl_pwm_chip *fpc;
417 struct resource *res;
418 int ret;
419
420 fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL);
421 if (!fpc)
422 return -ENOMEM;
423
424 mutex_init(&fpc->lock);
425
426 fpc->chip.dev = &pdev->dev;
427
428 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
429 fpc->base = devm_ioremap_resource(&pdev->dev, res);
430 if (IS_ERR(fpc->base))
431 return PTR_ERR(fpc->base);
432
433 fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys");
434 if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) {
435 dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n");
436 return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);
437 }
438
439 fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(fpc->chip.dev, "ftm_fix");
440 if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX]))
441 return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]);
442
443 fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(fpc->chip.dev, "ftm_ext");
444 if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT]))
445 return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]);
446
447 fpc->clk[FSL_PWM_CLK_CNTEN] =
448 devm_clk_get(fpc->chip.dev, "ftm_cnt_clk_en");
449 if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))
450 return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);
451
452 fpc->chip.ops = &fsl_pwm_ops;
453 fpc->chip.of_xlate = of_pwm_xlate_with_flags;
454 fpc->chip.of_pwm_n_cells = 3;
455 fpc->chip.base = -1;
456 fpc->chip.npwm = 8;
457
458 ret = pwmchip_add(&fpc->chip);
459 if (ret < 0) {
460 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
461 return ret;
462 }
463
464 platform_set_drvdata(pdev, fpc);
465
466 return fsl_pwm_init(fpc);
467}
468
469static int fsl_pwm_remove(struct platform_device *pdev)
470{
471 struct fsl_pwm_chip *fpc = platform_get_drvdata(pdev);
472
473 return pwmchip_remove(&fpc->chip);
474}
475
476static const struct of_device_id fsl_pwm_dt_ids[] = {
477 { .compatible = "fsl,vf610-ftm-pwm", },
478 { /* sentinel */ }
479};
480MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids);
481
482static struct platform_driver fsl_pwm_driver = {
483 .driver = {
484 .name = "fsl-ftm-pwm",
485 .of_match_table = fsl_pwm_dt_ids,
486 },
487 .probe = fsl_pwm_probe,
488 .remove = fsl_pwm_remove,
489};
490module_platform_driver(fsl_pwm_driver);
491
492MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver");
493MODULE_AUTHOR("Xiubo Li <Li.Xiubo@freescale.com>");
494MODULE_ALIAS("platform:fsl-ftm-pwm");
495MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
new file mode 100644
index 000000000000..449e372050a0
--- /dev/null
+++ b/drivers/pwm/pwm-lpss.c
@@ -0,0 +1,183 @@
1/*
2 * Intel Low Power Subsystem PWM controller driver
3 *
4 * Copyright (C) 2014, Intel Corporation
5 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
6 * Author: Chew Kean Ho <kean.ho.chew@intel.com>
7 * Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
8 * Author: Chew Chiau Ee <chiau.ee.chew@intel.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/acpi.h>
16#include <linux/clk.h>
17#include <linux/device.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/pwm.h>
21#include <linux/platform_device.h>
22
23#define PWM 0x00000000
24#define PWM_ENABLE BIT(31)
25#define PWM_SW_UPDATE BIT(30)
26#define PWM_BASE_UNIT_SHIFT 8
27#define PWM_BASE_UNIT_MASK 0x00ffff00
28#define PWM_ON_TIME_DIV_MASK 0x000000ff
29#define PWM_DIVISION_CORRECTION 0x2
30#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION)
31#define NSECS_PER_SEC 1000000000UL
32
33struct pwm_lpss_chip {
34 struct pwm_chip chip;
35 void __iomem *regs;
36 struct clk *clk;
37};
38
39static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
40{
41 return container_of(chip, struct pwm_lpss_chip, chip);
42}
43
44static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
45 int duty_ns, int period_ns)
46{
47 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
48 u8 on_time_div;
49 unsigned long c;
50 unsigned long long base_unit, freq = NSECS_PER_SEC;
51 u32 ctrl;
52
53 do_div(freq, period_ns);
54
55 /* The equation is: base_unit = ((freq / c) * 65536) + correction */
56 base_unit = freq * 65536;
57
58 c = clk_get_rate(lpwm->clk);
59 if (!c)
60 return -EINVAL;
61
62 do_div(base_unit, c);
63 base_unit += PWM_DIVISION_CORRECTION;
64 if (base_unit > PWM_LIMIT)
65 return -EINVAL;
66
67 if (duty_ns <= 0)
68 duty_ns = 1;
69 on_time_div = 255 - (255 * duty_ns / period_ns);
70
71 ctrl = readl(lpwm->regs + PWM);
72 ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK);
73 ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT;
74 ctrl |= on_time_div;
75 /* request PWM to update on next cycle */
76 ctrl |= PWM_SW_UPDATE;
77 writel(ctrl, lpwm->regs + PWM);
78
79 return 0;
80}
81
82static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
83{
84 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
85 u32 ctrl;
86 int ret;
87
88 ret = clk_prepare_enable(lpwm->clk);
89 if (ret)
90 return ret;
91
92 ctrl = readl(lpwm->regs + PWM);
93 writel(ctrl | PWM_ENABLE, lpwm->regs + PWM);
94
95 return 0;
96}
97
98static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
99{
100 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
101 u32 ctrl;
102
103 ctrl = readl(lpwm->regs + PWM);
104 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
105
106 clk_disable_unprepare(lpwm->clk);
107}
108
109static const struct pwm_ops pwm_lpss_ops = {
110 .config = pwm_lpss_config,
111 .enable = pwm_lpss_enable,
112 .disable = pwm_lpss_disable,
113 .owner = THIS_MODULE,
114};
115
116static const struct acpi_device_id pwm_lpss_acpi_match[] = {
117 { "80860F09", 0 },
118 { },
119};
120MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
121
122static int pwm_lpss_probe(struct platform_device *pdev)
123{
124 struct pwm_lpss_chip *lpwm;
125 struct resource *r;
126 int ret;
127
128 lpwm = devm_kzalloc(&pdev->dev, sizeof(*lpwm), GFP_KERNEL);
129 if (!lpwm)
130 return -ENOMEM;
131
132 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
133
134 lpwm->regs = devm_ioremap_resource(&pdev->dev, r);
135 if (IS_ERR(lpwm->regs))
136 return PTR_ERR(lpwm->regs);
137
138 lpwm->clk = devm_clk_get(&pdev->dev, NULL);
139 if (IS_ERR(lpwm->clk)) {
140 dev_err(&pdev->dev, "failed to get PWM clock\n");
141 return PTR_ERR(lpwm->clk);
142 }
143
144 lpwm->chip.dev = &pdev->dev;
145 lpwm->chip.ops = &pwm_lpss_ops;
146 lpwm->chip.base = -1;
147 lpwm->chip.npwm = 1;
148
149 ret = pwmchip_add(&lpwm->chip);
150 if (ret) {
151 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
152 return ret;
153 }
154
155 platform_set_drvdata(pdev, lpwm);
156 return 0;
157}
158
159static int pwm_lpss_remove(struct platform_device *pdev)
160{
161 struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
162 u32 ctrl;
163
164 ctrl = readl(lpwm->regs + PWM);
165 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
166
167 return pwmchip_remove(&lpwm->chip);
168}
169
170static struct platform_driver pwm_lpss_driver = {
171 .driver = {
172 .name = "pwm-lpss",
173 .acpi_match_table = pwm_lpss_acpi_match,
174 },
175 .probe = pwm_lpss_probe,
176 .remove = pwm_lpss_remove,
177};
178module_platform_driver(pwm_lpss_driver);
179
180MODULE_DESCRIPTION("PWM driver for Intel LPSS");
181MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
182MODULE_LICENSE("GPL v2");
183MODULE_ALIAS("platform:pwm-lpss");
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index 8d995731cef8..cd356d870244 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -127,12 +127,12 @@ static struct pwm_ops pxa_pwm_ops = {
127 127
128#ifdef CONFIG_OF 128#ifdef CONFIG_OF
129/* 129/*
130 * Device tree users must create one device instance for each pwm channel. 130 * Device tree users must create one device instance for each PWM channel.
131 * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver 131 * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver
132 * code that this is a single channel pxa25x-pwm. Currently all devices are 132 * code that this is a single channel pxa25x-pwm. Currently all devices are
133 * supported identically. 133 * supported identically.
134 */ 134 */
135static struct of_device_id pwm_of_match[] = { 135static const struct of_device_id pwm_of_match[] = {
136 { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]}, 136 { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]},
137 { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]}, 137 { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]},
138 { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]}, 138 { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]},
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index b59639e0c029..d66529a995a1 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -598,9 +598,8 @@ static int pwm_samsung_resume(struct device *dev)
598} 598}
599#endif 599#endif
600 600
601static const struct dev_pm_ops pwm_samsung_pm_ops = { 601static SIMPLE_DEV_PM_OPS(pwm_samsung_pm_ops, pwm_samsung_suspend,
602 SET_SYSTEM_SLEEP_PM_OPS(pwm_samsung_suspend, pwm_samsung_resume) 602 pwm_samsung_resume);
603};
604 603
605static struct platform_driver pwm_samsung_driver = { 604static struct platform_driver pwm_samsung_driver = {
606 .driver = { 605 .driver = {