2 * arch/arm/mach-tegra/pwm.c
4 * Tegra pulse-width-modulation controller driver
6 * Copyright (c) 2010, NVIDIA Corporation.
7 * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer <s.hauer@pengutronix.de>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <linux/clk.h>
25 #include <linux/err.h>
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/platform_device.h>
30 #include <linux/pwm.h>
31 #include <linux/slab.h>
33 #define PWM_ENABLE (1 << 31)
34 #define PWM_DUTY_WIDTH 8
35 #define PWM_DUTY_SHIFT 16
36 #define PWM_SCALE_WIDTH 13
37 #define PWM_SCALE_SHIFT 0
40 struct list_head node;
41 struct platform_device *pdev;
47 void __iomem *mmio_base;
53 static DEFINE_MUTEX(pwm_lock);
54 static LIST_HEAD(pwm_list);
56 static inline int pwm_writel(struct pwm_device *pwm, unsigned long val)
60 rc = clk_enable(pwm->clk);
63 writel(val, pwm->mmio_base);
64 clk_disable(pwm->clk);
68 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
71 unsigned long rate, hz;
74 /* convert from duty_ns / period_ns to a fixed number of duty
75 * ticks per (1 << PWM_DUTY_WIDTH) cycles. */
76 c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1);
79 val = (u32)c << PWM_DUTY_SHIFT;
81 /* compute the prescaler value for which (1 << PWM_DUTY_WIDTH)
82 * cycles at the PWM clock rate will take period_ns nanoseconds. */
83 rate = clk_get_rate(pwm->clk) >> PWM_DUTY_WIDTH;
84 hz = 1000000000ul / period_ns;
86 rate = (rate + (hz / 2)) / hz;
88 if (rate >> PWM_SCALE_WIDTH)
91 val |= (rate << PWM_SCALE_SHIFT);
93 /* the struct clk may be shared across multiple PWM devices, so
94 * only enable the PWM if this device has been enabled */
98 return pwm_writel(pwm, val);
100 EXPORT_SYMBOL(pwm_config);
102 int pwm_enable(struct pwm_device *pwm)
106 mutex_lock(&pwm_lock);
108 rc = clk_enable(pwm->clk);
110 u32 val = readl(pwm->mmio_base);
111 writel(val | PWM_ENABLE, pwm->mmio_base);
115 mutex_unlock(&pwm_lock);
119 EXPORT_SYMBOL(pwm_enable);
121 void pwm_disable(struct pwm_device *pwm)
123 mutex_lock(&pwm_lock);
125 u32 val = readl(pwm->mmio_base);
126 writel(val & ~PWM_ENABLE, pwm->mmio_base);
127 clk_disable(pwm->clk);
130 dev_warn(&pwm->pdev->dev, "%s called on disabled PWM\n",
132 mutex_unlock(&pwm_lock);
134 EXPORT_SYMBOL(pwm_disable);
136 struct pwm_device *pwm_request(int pwm_id, const char *label)
138 struct pwm_device *pwm;
141 mutex_lock(&pwm_lock);
143 list_for_each_entry(pwm, &pwm_list, node) {
144 if (pwm->id == pwm_id) {
155 pwm = ERR_PTR(-EBUSY);
157 pwm = ERR_PTR(-ENOENT);
159 mutex_unlock(&pwm_lock);
163 EXPORT_SYMBOL(pwm_request);
165 void pwm_free(struct pwm_device *pwm)
167 mutex_lock(&pwm_lock);
172 dev_warn(&pwm->pdev->dev, "PWM device already freed\n");
174 mutex_unlock(&pwm_lock);
176 EXPORT_SYMBOL(pwm_free);
178 static int tegra_pwm_probe(struct platform_device *pdev)
180 struct pwm_device *pwm;
184 pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
186 dev_err(&pdev->dev, "failed to allocate memory\n");
189 pwm->clk = clk_get(&pdev->dev, NULL);
191 if (IS_ERR(pwm->clk)) {
192 ret = PTR_ERR(pwm->clk);
201 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
203 dev_err(&pdev->dev, "no memory resources defined\n");
208 r = request_mem_region(r->start, resource_size(r), pdev->name);
210 dev_err(&pdev->dev, "failed to request memory\n");
215 pwm->mmio_base = ioremap(r->start, resource_size(r));
216 if (!pwm->mmio_base) {
217 dev_err(&pdev->dev, "failed to ioremap() region\n");
222 platform_set_drvdata(pdev, pwm);
224 mutex_lock(&pwm_lock);
225 list_add_tail(&pwm->node, &pwm_list);
226 mutex_unlock(&pwm_lock);
231 release_mem_region(r->start, resource_size(r));
239 static int __devexit tegra_pwm_remove(struct platform_device *pdev)
241 struct pwm_device *pwm = platform_get_drvdata(pdev);
248 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
250 mutex_lock(&pwm_lock);
252 mutex_unlock(&pwm_lock);
255 list_del(&pwm->node);
256 mutex_unlock(&pwm_lock);
258 rc = pwm_writel(pwm, 0);
260 iounmap(pwm->mmio_base);
261 release_mem_region(r->start, resource_size(r));
264 clk_disable(pwm->clk);
272 static struct platform_driver tegra_pwm_driver = {
276 .probe = tegra_pwm_probe,
277 .remove = __devexit_p(tegra_pwm_remove),
280 static int __init tegra_pwm_init(void)
282 return platform_driver_register(&tegra_pwm_driver);
284 subsys_initcall(tegra_pwm_init);
286 static void __exit tegra_pwm_exit(void)
288 platform_driver_unregister(&tegra_pwm_driver);
290 module_exit(tegra_pwm_exit);
292 MODULE_LICENSE("GPL v2");
293 MODULE_AUTHOR("NVIDIA Corporation");