aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2014-04-18 07:17:40 -0400
committerThierry Reding <thierry.reding@gmail.com>2014-04-28 07:47:03 -0400
commit093e00bb3f82f3c67e2d1682e316fc012bcd0d92 (patch)
tree8bd81baf9056af3a4f8e71a985b3d226fdc625d6 /drivers/pwm
parentb9f87404dde26769429b470e1d4854a3c380cf26 (diff)
pwm: lpss: Add support for PCI devices
Not all systems enumerate the PWM devices via ACPI. They can also be exposed via the PCI interface. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Chew, Chiau Ee <chiau.ee.chew@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/pwm-lpss.c161
1 files changed, 130 insertions, 31 deletions
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 449e372050a0..c718ad1df3bb 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -6,6 +6,7 @@
6 * Author: Chew Kean Ho <kean.ho.chew@intel.com> 6 * Author: Chew Kean Ho <kean.ho.chew@intel.com>
7 * Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com> 7 * Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
8 * Author: Chew Chiau Ee <chiau.ee.chew@intel.com> 8 * Author: Chew Chiau Ee <chiau.ee.chew@intel.com>
9 * Author: Alan Cox <alan@linux.intel.com>
9 * 10 *
10 * This program is free software; you can redistribute it and/or modify 11 * 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 * it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,9 @@
19#include <linux/module.h> 20#include <linux/module.h>
20#include <linux/pwm.h> 21#include <linux/pwm.h>
21#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/pci.h>
24
25static int pci_drv, plat_drv; /* So we know which drivers registered */
22 26
23#define PWM 0x00000000 27#define PWM 0x00000000
24#define PWM_ENABLE BIT(31) 28#define PWM_ENABLE BIT(31)
@@ -34,6 +38,16 @@ struct pwm_lpss_chip {
34 struct pwm_chip chip; 38 struct pwm_chip chip;
35 void __iomem *regs; 39 void __iomem *regs;
36 struct clk *clk; 40 struct clk *clk;
41 unsigned long clk_rate;
42};
43
44struct pwm_lpss_boardinfo {
45 unsigned long clk_rate;
46};
47
48/* BayTrail */
49static const struct pwm_lpss_boardinfo byt_info = {
50 25000000
37}; 51};
38 52
39static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) 53static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
@@ -55,7 +69,7 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
55 /* The equation is: base_unit = ((freq / c) * 65536) + correction */ 69 /* The equation is: base_unit = ((freq / c) * 65536) + correction */
56 base_unit = freq * 65536; 70 base_unit = freq * 65536;
57 71
58 c = clk_get_rate(lpwm->clk); 72 c = lpwm->clk_rate;
59 if (!c) 73 if (!c)
60 return -EINVAL; 74 return -EINVAL;
61 75
@@ -113,52 +127,48 @@ static const struct pwm_ops pwm_lpss_ops = {
113 .owner = THIS_MODULE, 127 .owner = THIS_MODULE,
114}; 128};
115 129
116static const struct acpi_device_id pwm_lpss_acpi_match[] = { 130static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev,
117 { "80860F09", 0 }, 131 struct resource *r,
118 { }, 132 struct pwm_lpss_boardinfo *info)
119};
120MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
121
122static int pwm_lpss_probe(struct platform_device *pdev)
123{ 133{
124 struct pwm_lpss_chip *lpwm; 134 struct pwm_lpss_chip *lpwm;
125 struct resource *r;
126 int ret; 135 int ret;
127 136
128 lpwm = devm_kzalloc(&pdev->dev, sizeof(*lpwm), GFP_KERNEL); 137 lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL);
129 if (!lpwm) 138 if (!lpwm)
130 return -ENOMEM; 139 return ERR_PTR(-ENOMEM);
131
132 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
133 140
134 lpwm->regs = devm_ioremap_resource(&pdev->dev, r); 141 lpwm->regs = devm_ioremap_resource(dev, r);
135 if (IS_ERR(lpwm->regs)) 142 if (IS_ERR(lpwm->regs))
136 return PTR_ERR(lpwm->regs); 143 return lpwm->regs;
137 144
138 lpwm->clk = devm_clk_get(&pdev->dev, NULL); 145 if (info) {
139 if (IS_ERR(lpwm->clk)) { 146 lpwm->clk_rate = info->clk_rate;
140 dev_err(&pdev->dev, "failed to get PWM clock\n"); 147 } else {
141 return PTR_ERR(lpwm->clk); 148 lpwm->clk = devm_clk_get(dev, NULL);
149 if (IS_ERR(lpwm->clk)) {
150 dev_err(dev, "failed to get PWM clock\n");
151 return ERR_CAST(lpwm->clk);
152 }
153 lpwm->clk_rate = clk_get_rate(lpwm->clk);
142 } 154 }
143 155
144 lpwm->chip.dev = &pdev->dev; 156 lpwm->chip.dev = dev;
145 lpwm->chip.ops = &pwm_lpss_ops; 157 lpwm->chip.ops = &pwm_lpss_ops;
146 lpwm->chip.base = -1; 158 lpwm->chip.base = -1;
147 lpwm->chip.npwm = 1; 159 lpwm->chip.npwm = 1;
148 160
149 ret = pwmchip_add(&lpwm->chip); 161 ret = pwmchip_add(&lpwm->chip);
150 if (ret) { 162 if (ret) {
151 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); 163 dev_err(dev, "failed to add PWM chip: %d\n", ret);
152 return ret; 164 return ERR_PTR(ret);
153 } 165 }
154 166
155 platform_set_drvdata(pdev, lpwm); 167 return lpwm;
156 return 0;
157} 168}
158 169
159static int pwm_lpss_remove(struct platform_device *pdev) 170static int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
160{ 171{
161 struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
162 u32 ctrl; 172 u32 ctrl;
163 173
164 ctrl = readl(lpwm->regs + PWM); 174 ctrl = readl(lpwm->regs + PWM);
@@ -167,15 +177,104 @@ static int pwm_lpss_remove(struct platform_device *pdev)
167 return pwmchip_remove(&lpwm->chip); 177 return pwmchip_remove(&lpwm->chip);
168} 178}
169 179
170static struct platform_driver pwm_lpss_driver = { 180static int pwm_lpss_probe_pci(struct pci_dev *pdev,
181 const struct pci_device_id *id)
182{
183 const struct pwm_lpss_boardinfo *info;
184 struct pwm_lpss_chip *lpwm;
185 int err;
186
187 err = pci_enable_device(pdev);
188 if (err < 0)
189 return err;
190
191 info = (struct pwm_lpss_boardinfo *)id->driver_data;
192 lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info);
193 if (IS_ERR(lpwm))
194 return PTR_ERR(lpwm);
195
196 pci_set_drvdata(pdev, lpwm);
197 return 0;
198}
199
200static void pwm_lpss_remove_pci(struct pci_dev *pdev)
201{
202 struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
203
204 pwm_lpss_remove(lpwm);
205 pci_disable_device(pdev);
206}
207
208static struct pci_device_id pwm_lpss_pci_ids[] = {
209 { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&byt_info},
210 { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&byt_info},
211 { },
212};
213MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids);
214
215static struct pci_driver pwm_lpss_driver_pci = {
216 .name = "pwm-lpss",
217 .id_table = pwm_lpss_pci_ids,
218 .probe = pwm_lpss_probe_pci,
219 .remove = pwm_lpss_remove_pci,
220};
221
222static int pwm_lpss_probe_platform(struct platform_device *pdev)
223{
224 struct pwm_lpss_chip *lpwm;
225 struct resource *r;
226
227 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
228
229 lpwm = pwm_lpss_probe(&pdev->dev, r, NULL);
230 if (IS_ERR(lpwm))
231 return PTR_ERR(lpwm);
232
233 platform_set_drvdata(pdev, lpwm);
234 return 0;
235}
236
237static int pwm_lpss_remove_platform(struct platform_device *pdev)
238{
239 struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
240
241 return pwm_lpss_remove(lpwm);
242}
243
244static const struct acpi_device_id pwm_lpss_acpi_match[] = {
245 { "80860F09", 0 },
246 { },
247};
248MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
249
250static struct platform_driver pwm_lpss_driver_platform = {
171 .driver = { 251 .driver = {
172 .name = "pwm-lpss", 252 .name = "pwm-lpss",
173 .acpi_match_table = pwm_lpss_acpi_match, 253 .acpi_match_table = pwm_lpss_acpi_match,
174 }, 254 },
175 .probe = pwm_lpss_probe, 255 .probe = pwm_lpss_probe_platform,
176 .remove = pwm_lpss_remove, 256 .remove = pwm_lpss_remove_platform,
177}; 257};
178module_platform_driver(pwm_lpss_driver); 258
259static int __init pwm_init(void)
260{
261 pci_drv = pci_register_driver(&pwm_lpss_driver_pci);
262 plat_drv = platform_driver_register(&pwm_lpss_driver_platform);
263 if (pci_drv && plat_drv)
264 return pci_drv;
265
266 return 0;
267}
268module_init(pwm_init);
269
270static void __exit pwm_exit(void)
271{
272 if (!pci_drv)
273 pci_unregister_driver(&pwm_lpss_driver_pci);
274 if (!plat_drv)
275 platform_driver_unregister(&pwm_lpss_driver_platform);
276}
277module_exit(pwm_exit);
179 278
180MODULE_DESCRIPTION("PWM driver for Intel LPSS"); 279MODULE_DESCRIPTION("PWM driver for Intel LPSS");
181MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 280MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");