1 /*
2  * linux/arch/arm/mach-pxa/pwm.c
3  *
4  * simple driver for PWM (Pulse Width Modulator) controller
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 version 2 as
8  * published by the Free Software Foundation.
9  *
10  * 2008-02-13	initial version
11  * 		eric miao <eric.miao@marvell.com>
12  */
13 
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/err.h>
19 #include <linux/clk.h>
20 #include <linux/io.h>
21 #include <linux/pwm.h>
22 
23 #include <asm/div64.h>
24 
25 #define HAS_SECONDARY_PWM	0x10
26 #define PWM_ID_BASE(d)		((d) & 0xf)
27 
28 static const struct platform_device_id pwm_id_table[] = {
29 	/*   PWM    has_secondary_pwm? */
30 	{ "pxa25x-pwm", 0 },
31 	{ "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
32 	{ "pxa168-pwm", 1 },
33 	{ "pxa910-pwm", 1 },
34 	{ },
35 };
36 MODULE_DEVICE_TABLE(platform, pwm_id_table);
37 
38 /* PWM registers and bits definitions */
39 #define PWMCR		(0x00)
40 #define PWMDCR		(0x04)
41 #define PWMPCR		(0x08)
42 
43 #define PWMCR_SD	(1 << 6)
44 #define PWMDCR_FD	(1 << 10)
45 
46 struct pwm_device {
47 	struct list_head	node;
48 	struct pwm_device	*secondary;
49 	struct platform_device	*pdev;
50 
51 	const char	*label;
52 	struct clk	*clk;
53 	int		clk_enabled;
54 	void __iomem	*mmio_base;
55 
56 	unsigned int	use_count;
57 	unsigned int	pwm_id;
58 };
59 
60 /*
61  * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
62  * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
63  */
pwm_config(struct pwm_device * pwm,int duty_ns,int period_ns)64 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
65 {
66 	unsigned long long c;
67 	unsigned long period_cycles, prescale, pv, dc;
68 
69 	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
70 		return -EINVAL;
71 
72 	c = clk_get_rate(pwm->clk);
73 	c = c * period_ns;
74 	do_div(c, 1000000000);
75 	period_cycles = c;
76 
77 	if (period_cycles < 1)
78 		period_cycles = 1;
79 	prescale = (period_cycles - 1) / 1024;
80 	pv = period_cycles / (prescale + 1) - 1;
81 
82 	if (prescale > 63)
83 		return -EINVAL;
84 
85 	if (duty_ns == period_ns)
86 		dc = PWMDCR_FD;
87 	else
88 		dc = (pv + 1) * duty_ns / period_ns;
89 
90 	/* NOTE: the clock to PWM has to be enabled first
91 	 * before writing to the registers
92 	 */
93 	clk_enable(pwm->clk);
94 	__raw_writel(prescale, pwm->mmio_base + PWMCR);
95 	__raw_writel(dc, pwm->mmio_base + PWMDCR);
96 	__raw_writel(pv, pwm->mmio_base + PWMPCR);
97 	clk_disable(pwm->clk);
98 
99 	return 0;
100 }
101 EXPORT_SYMBOL(pwm_config);
102 
pwm_enable(struct pwm_device * pwm)103 int pwm_enable(struct pwm_device *pwm)
104 {
105 	int rc = 0;
106 
107 	if (!pwm->clk_enabled) {
108 		rc = clk_enable(pwm->clk);
109 		if (!rc)
110 			pwm->clk_enabled = 1;
111 	}
112 	return rc;
113 }
114 EXPORT_SYMBOL(pwm_enable);
115 
pwm_disable(struct pwm_device * pwm)116 void pwm_disable(struct pwm_device *pwm)
117 {
118 	if (pwm->clk_enabled) {
119 		clk_disable(pwm->clk);
120 		pwm->clk_enabled = 0;
121 	}
122 }
123 EXPORT_SYMBOL(pwm_disable);
124 
125 static DEFINE_MUTEX(pwm_lock);
126 static LIST_HEAD(pwm_list);
127 
pwm_request(int pwm_id,const char * label)128 struct 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 	}
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 }
154 EXPORT_SYMBOL(pwm_request);
155 
pwm_free(struct pwm_device * pwm)156 void pwm_free(struct pwm_device *pwm)
157 {
158 	mutex_lock(&pwm_lock);
159 
160 	if (pwm->use_count) {
161 		pwm->use_count--;
162 		pwm->label = NULL;
163 	} else
164 		pr_warning("PWM device already freed\n");
165 
166 	mutex_unlock(&pwm_lock);
167 }
168 EXPORT_SYMBOL(pwm_free);
169 
__add_pwm(struct pwm_device * pwm)170 static 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 
pwm_probe(struct platform_device * pdev)177 static int __devinit pwm_probe(struct platform_device *pdev)
178 {
179 	const struct platform_device_id *id = platform_get_device_id(pdev);
180 	struct pwm_device *pwm, *secondary = NULL;
181 	struct resource *r;
182 	int ret = 0;
183 
184 	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
185 	if (pwm == NULL) {
186 		dev_err(&pdev->dev, "failed to allocate memory\n");
187 		return -ENOMEM;
188 	}
189 
190 	pwm->clk = clk_get(&pdev->dev, NULL);
191 	if (IS_ERR(pwm->clk)) {
192 		ret = PTR_ERR(pwm->clk);
193 		goto err_free;
194 	}
195 	pwm->clk_enabled = 0;
196 
197 	pwm->use_count = 0;
198 	pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
199 	pwm->pdev = pdev;
200 
201 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
202 	if (r == NULL) {
203 		dev_err(&pdev->dev, "no memory resource defined\n");
204 		ret = -ENODEV;
205 		goto err_free_clk;
206 	}
207 
208 	r = request_mem_region(r->start, resource_size(r), pdev->name);
209 	if (r == NULL) {
210 		dev_err(&pdev->dev, "failed to request memory resource\n");
211 		ret = -EBUSY;
212 		goto err_free_clk;
213 	}
214 
215 	pwm->mmio_base = ioremap(r->start, resource_size(r));
216 	if (pwm->mmio_base == NULL) {
217 		dev_err(&pdev->dev, "failed to ioremap() registers\n");
218 		ret = -ENODEV;
219 		goto err_free_mem;
220 	}
221 
222 	if (id->driver_data & HAS_SECONDARY_PWM) {
223 		secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
224 		if (secondary == NULL) {
225 			ret = -ENOMEM;
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 	}
236 
237 	__add_pwm(pwm);
238 	if (secondary)
239 		__add_pwm(secondary);
240 
241 	platform_set_drvdata(pdev, pwm);
242 	return 0;
243 
244 err_free_mem:
245 	release_mem_region(r->start, resource_size(r));
246 err_free_clk:
247 	clk_put(pwm->clk);
248 err_free:
249 	kfree(pwm);
250 	return ret;
251 }
252 
pwm_remove(struct platform_device * pdev)253 static int __devexit pwm_remove(struct platform_device *pdev)
254 {
255 	struct pwm_device *pwm;
256 	struct resource *r;
257 
258 	pwm = platform_get_drvdata(pdev);
259 	if (pwm == NULL)
260 		return -ENODEV;
261 
262 	mutex_lock(&pwm_lock);
263 
264 	if (pwm->secondary) {
265 		list_del(&pwm->secondary->node);
266 		kfree(pwm->secondary);
267 	}
268 
269 	list_del(&pwm->node);
270 	mutex_unlock(&pwm_lock);
271 
272 	iounmap(pwm->mmio_base);
273 
274 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
275 	release_mem_region(r->start, resource_size(r));
276 
277 	clk_put(pwm->clk);
278 	kfree(pwm);
279 	return 0;
280 }
281 
282 static struct platform_driver pwm_driver = {
283 	.driver		= {
284 		.name	= "pxa25x-pwm",
285 		.owner	= THIS_MODULE,
286 	},
287 	.probe		= pwm_probe,
288 	.remove		= __devexit_p(pwm_remove),
289 	.id_table	= pwm_id_table,
290 };
291 
pwm_init(void)292 static int __init pwm_init(void)
293 {
294 	return platform_driver_register(&pwm_driver);
295 }
296 arch_initcall(pwm_init);
297 
pwm_exit(void)298 static void __exit pwm_exit(void)
299 {
300 	platform_driver_unregister(&pwm_driver);
301 }
302 module_exit(pwm_exit);
303 
304 MODULE_LICENSE("GPL v2");
305