aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <thierry.reding@avionic-design.de>2012-01-02 15:22:38 -0500
committerThierry Reding <thierry.reding@avionic-design.de>2012-07-02 15:39:00 -0400
commit17b2b4780f879a559b8dc96c170dd6df98fe9ab3 (patch)
treea7e7915adf0a94828811a72b8ab35e83fcdbabfd
parenta4315e3c11f97ea0fa602184fa310161309657df (diff)
pwm: Move PXA PWM driver to PWM framework
This commit moves the PXA PWM driver to the drivers/pwm subdirectory and converts it to use the new PWM framework. Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r--arch/arm/plat-pxa/Makefile1
-rw-r--r--drivers/pwm/Kconfig9
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/pwm-pxa.c (renamed from arch/arm/plat-pxa/pwm.c)172
4 files changed, 68 insertions, 115 deletions
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index f302d048392d..af8e484001e5 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -8,5 +8,4 @@ obj-$(CONFIG_PXA3xx) += mfp.o
8obj-$(CONFIG_PXA95x) += mfp.o 8obj-$(CONFIG_PXA95x) += mfp.o
9obj-$(CONFIG_ARCH_MMP) += mfp.o 9obj-$(CONFIG_ARCH_MMP) += mfp.o
10 10
11obj-$(CONFIG_HAVE_PWM) += pwm.o
12obj-$(CONFIG_PXA_SSP) += ssp.o 11obj-$(CONFIG_PXA_SSP) += ssp.o
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index eb5404268135..0ef4f3037c4a 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -18,6 +18,15 @@ config PWM_BFIN
18 To compile this driver as a module, choose M here: the module 18 To compile this driver as a module, choose M here: the module
19 will be called pwm-bfin. 19 will be called pwm-bfin.
20 20
21config PWM_PXA
22 tristate "PXA PWM support"
23 depends on ARCH_PXA
24 help
25 Generic PWM framework driver for PXA.
26
27 To compile this driver as a module, choose M here: the module
28 will be called pwm-pxa.
29
21config PWM_TEGRA 30config PWM_TEGRA
22 tristate "NVIDIA Tegra PWM support" 31 tristate "NVIDIA Tegra PWM support"
23 depends on ARCH_TEGRA 32 depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 251b8d22435f..e859c513add8 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_PWM) += core.o 1obj-$(CONFIG_PWM) += core.o
2obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 2obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
3obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
3obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o 4obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/arch/arm/plat-pxa/pwm.c b/drivers/pwm/pwm-pxa.c
index ef32686feef9..d5c6ce513e29 100644
--- a/arch/arm/plat-pxa/pwm.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -43,33 +43,39 @@ MODULE_DEVICE_TABLE(platform, pwm_id_table);
43#define PWMCR_SD (1 << 6) 43#define PWMCR_SD (1 << 6)
44#define PWMDCR_FD (1 << 10) 44#define PWMDCR_FD (1 << 10)
45 45
46struct pwm_device { 46struct pxa_pwm_chip {
47 struct list_head node; 47 struct pwm_chip chip;
48 struct pwm_device *secondary; 48 struct device *dev;
49 struct platform_device *pdev;
50 49
51 const char *label;
52 struct clk *clk; 50 struct clk *clk;
53 int clk_enabled; 51 int clk_enabled;
54 void __iomem *mmio_base; 52 void __iomem *mmio_base;
55
56 unsigned int use_count;
57 unsigned int pwm_id;
58}; 53};
59 54
55static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip)
56{
57 return container_of(chip, struct pxa_pwm_chip, chip);
58}
59
60/* 60/*
61 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE 61 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
62 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE 62 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
63 */ 63 */
64int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) 64static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
65 int duty_ns, int period_ns)
65{ 66{
67 struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
66 unsigned long long c; 68 unsigned long long c;
67 unsigned long period_cycles, prescale, pv, dc; 69 unsigned long period_cycles, prescale, pv, dc;
70 unsigned long offset;
71 int rc;
68 72
69 if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) 73 if (period_ns == 0 || duty_ns > period_ns)
70 return -EINVAL; 74 return -EINVAL;
71 75
72 c = clk_get_rate(pwm->clk); 76 offset = pwm->hwpwm ? 0x10 : 0;
77
78 c = clk_get_rate(pc->clk);
73 c = c * period_ns; 79 c = c * period_ns;
74 do_div(c, 1000000000); 80 do_div(c, 1000000000);
75 period_cycles = c; 81 period_cycles = c;
@@ -90,98 +96,56 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
90 /* NOTE: the clock to PWM has to be enabled first 96 /* NOTE: the clock to PWM has to be enabled first
91 * before writing to the registers 97 * before writing to the registers
92 */ 98 */
93 clk_enable(pwm->clk); 99 rc = clk_prepare_enable(pc->clk);
94 __raw_writel(prescale, pwm->mmio_base + PWMCR); 100 if (rc < 0)
95 __raw_writel(dc, pwm->mmio_base + PWMDCR); 101 return rc;
96 __raw_writel(pv, pwm->mmio_base + PWMPCR); 102
97 clk_disable(pwm->clk); 103 writel(prescale, pc->mmio_base + offset + PWMCR);
104 writel(dc, pc->mmio_base + offset + PWMDCR);
105 writel(pv, pc->mmio_base + offset + PWMPCR);
98 106
107 clk_disable_unprepare(pc->clk);
99 return 0; 108 return 0;
100} 109}
101EXPORT_SYMBOL(pwm_config);
102 110
103int pwm_enable(struct pwm_device *pwm) 111static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
104{ 112{
113 struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
105 int rc = 0; 114 int rc = 0;
106 115
107 if (!pwm->clk_enabled) { 116 if (!pc->clk_enabled) {
108 rc = clk_enable(pwm->clk); 117 rc = clk_prepare_enable(pc->clk);
109 if (!rc) 118 if (!rc)
110 pwm->clk_enabled = 1; 119 pc->clk_enabled++;
111 } 120 }
112 return rc; 121 return rc;
113} 122}
114EXPORT_SYMBOL(pwm_enable);
115 123
116void pwm_disable(struct pwm_device *pwm) 124static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
117{ 125{
118 if (pwm->clk_enabled) { 126 struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
119 clk_disable(pwm->clk);
120 pwm->clk_enabled = 0;
121 }
122}
123EXPORT_SYMBOL(pwm_disable);
124 127
125static DEFINE_MUTEX(pwm_lock); 128 if (pc->clk_enabled) {
126static LIST_HEAD(pwm_list); 129 clk_disable_unprepare(pc->clk);
127 130 pc->clk_enabled--;
128struct pwm_device *pwm_request(int pwm_id, const char *label)
129{
130 struct pwm_device *pwm;
131 int found = 0;
132
133 mutex_lock(&pwm_lock);
134
135 list_for_each_entry(pwm, &pwm_list, node) {
136 if (pwm->pwm_id == pwm_id) {
137 found = 1;
138 break;
139 }
140 } 131 }
141
142 if (found) {
143 if (pwm->use_count == 0) {
144 pwm->use_count++;
145 pwm->label = label;
146 } else
147 pwm = ERR_PTR(-EBUSY);
148 } else
149 pwm = ERR_PTR(-ENOENT);
150
151 mutex_unlock(&pwm_lock);
152 return pwm;
153} 132}
154EXPORT_SYMBOL(pwm_request);
155
156void pwm_free(struct pwm_device *pwm)
157{
158 mutex_lock(&pwm_lock);
159 133
160 if (pwm->use_count) { 134static struct pwm_ops pxa_pwm_ops = {
161 pwm->use_count--; 135 .config = pxa_pwm_config,
162 pwm->label = NULL; 136 .enable = pxa_pwm_enable,
163 } else 137 .disable = pxa_pwm_disable,
164 pr_warning("PWM device already freed\n"); 138 .owner = THIS_MODULE,
165 139};
166 mutex_unlock(&pwm_lock);
167}
168EXPORT_SYMBOL(pwm_free);
169
170static inline void __add_pwm(struct pwm_device *pwm)
171{
172 mutex_lock(&pwm_lock);
173 list_add_tail(&pwm->node, &pwm_list);
174 mutex_unlock(&pwm_lock);
175}
176 140
177static int __devinit pwm_probe(struct platform_device *pdev) 141static int __devinit pwm_probe(struct platform_device *pdev)
178{ 142{
179 const struct platform_device_id *id = platform_get_device_id(pdev); 143 const struct platform_device_id *id = platform_get_device_id(pdev);
180 struct pwm_device *pwm, *secondary = NULL; 144 struct pxa_pwm_chip *pwm;
181 struct resource *r; 145 struct resource *r;
182 int ret = 0; 146 int ret = 0;
183 147
184 pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); 148 pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
185 if (pwm == NULL) { 149 if (pwm == NULL) {
186 dev_err(&pdev->dev, "failed to allocate memory\n"); 150 dev_err(&pdev->dev, "failed to allocate memory\n");
187 return -ENOMEM; 151 return -ENOMEM;
@@ -194,9 +158,10 @@ static int __devinit pwm_probe(struct platform_device *pdev)
194 } 158 }
195 pwm->clk_enabled = 0; 159 pwm->clk_enabled = 0;
196 160
197 pwm->use_count = 0; 161 pwm->chip.dev = &pdev->dev;
198 pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id; 162 pwm->chip.ops = &pxa_pwm_ops;
199 pwm->pdev = pdev; 163 pwm->chip.base = -1;
164 pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
200 165
201 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 166 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
202 if (r == NULL) { 167 if (r == NULL) {
@@ -219,25 +184,12 @@ static int __devinit pwm_probe(struct platform_device *pdev)
219 goto err_free_mem; 184 goto err_free_mem;
220 } 185 }
221 186
222 if (id->driver_data & HAS_SECONDARY_PWM) { 187 ret = pwmchip_add(&pwm->chip);
223 secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); 188 if (ret < 0) {
224 if (secondary == NULL) { 189 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
225 ret = -ENOMEM; 190 return ret;
226 goto err_free_mem;
227 }
228
229 *secondary = *pwm;
230 pwm->secondary = secondary;
231
232 /* registers for the second PWM has offset of 0x10 */
233 secondary->mmio_base = pwm->mmio_base + 0x10;
234 secondary->pwm_id = pdev->id + 2;
235 } 191 }
236 192
237 __add_pwm(pwm);
238 if (secondary)
239 __add_pwm(secondary);
240
241 platform_set_drvdata(pdev, pwm); 193 platform_set_drvdata(pdev, pwm);
242 return 0; 194 return 0;
243 195
@@ -252,30 +204,22 @@ err_free:
252 204
253static int __devexit pwm_remove(struct platform_device *pdev) 205static int __devexit pwm_remove(struct platform_device *pdev)
254{ 206{
255 struct pwm_device *pwm; 207 struct pxa_pwm_chip *chip;
256 struct resource *r; 208 struct resource *r;
257 209
258 pwm = platform_get_drvdata(pdev); 210 chip = platform_get_drvdata(pdev);
259 if (pwm == NULL) 211 if (chip == NULL)
260 return -ENODEV; 212 return -ENODEV;
261 213
262 mutex_lock(&pwm_lock); 214 pwmchip_remove(&chip->chip);
263
264 if (pwm->secondary) {
265 list_del(&pwm->secondary->node);
266 kfree(pwm->secondary);
267 }
268 215
269 list_del(&pwm->node); 216 iounmap(chip->mmio_base);
270 mutex_unlock(&pwm_lock);
271
272 iounmap(pwm->mmio_base);
273 217
274 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 218 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
275 release_mem_region(r->start, resource_size(r)); 219 release_mem_region(r->start, resource_size(r));
276 220
277 clk_put(pwm->clk); 221 clk_put(chip->clk);
278 kfree(pwm); 222 kfree(chip);
279 return 0; 223 return 0;
280} 224}
281 225