diff options
author | Thierry Reding <thierry.reding@avionic-design.de> | 2012-01-02 15:22:38 -0500 |
---|---|---|
committer | Thierry Reding <thierry.reding@avionic-design.de> | 2012-07-02 15:39:00 -0400 |
commit | 17b2b4780f879a559b8dc96c170dd6df98fe9ab3 (patch) | |
tree | a7e7915adf0a94828811a72b8ab35e83fcdbabfd | |
parent | a4315e3c11f97ea0fa602184fa310161309657df (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/Makefile | 1 | ||||
-rw-r--r-- | drivers/pwm/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 1 | ||||
-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 | |||
8 | obj-$(CONFIG_PXA95x) += mfp.o | 8 | obj-$(CONFIG_PXA95x) += mfp.o |
9 | obj-$(CONFIG_ARCH_MMP) += mfp.o | 9 | obj-$(CONFIG_ARCH_MMP) += mfp.o |
10 | 10 | ||
11 | obj-$(CONFIG_HAVE_PWM) += pwm.o | ||
12 | obj-$(CONFIG_PXA_SSP) += ssp.o | 11 | obj-$(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 | ||
21 | config 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 | |||
21 | config PWM_TEGRA | 30 | config 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 @@ | |||
1 | obj-$(CONFIG_PWM) += core.o | 1 | obj-$(CONFIG_PWM) += core.o |
2 | obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o | 2 | obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o |
3 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o | ||
3 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o | 4 | obj-$(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 | ||
46 | struct pwm_device { | 46 | struct 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 | ||
55 | static 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 | */ |
64 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | 64 | static 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 | } |
101 | EXPORT_SYMBOL(pwm_config); | ||
102 | 110 | ||
103 | int pwm_enable(struct pwm_device *pwm) | 111 | static 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 | } |
114 | EXPORT_SYMBOL(pwm_enable); | ||
115 | 123 | ||
116 | void pwm_disable(struct pwm_device *pwm) | 124 | static 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 | } | ||
123 | EXPORT_SYMBOL(pwm_disable); | ||
124 | 127 | ||
125 | static DEFINE_MUTEX(pwm_lock); | 128 | if (pc->clk_enabled) { |
126 | static LIST_HEAD(pwm_list); | 129 | clk_disable_unprepare(pc->clk); |
127 | 130 | pc->clk_enabled--; | |
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 | } | 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 | } |
154 | EXPORT_SYMBOL(pwm_request); | ||
155 | |||
156 | void pwm_free(struct pwm_device *pwm) | ||
157 | { | ||
158 | mutex_lock(&pwm_lock); | ||
159 | 133 | ||
160 | if (pwm->use_count) { | 134 | static 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 | } | ||
168 | EXPORT_SYMBOL(pwm_free); | ||
169 | |||
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 | 140 | ||
177 | static int __devinit pwm_probe(struct platform_device *pdev) | 141 | static 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 | ||
253 | static int __devexit pwm_remove(struct platform_device *pdev) | 205 | static 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 | ||