diff options
Diffstat (limited to 'drivers/pwm/pwm-pxa.c')
| -rw-r--r-- | drivers/pwm/pwm-pxa.c | 103 |
1 files changed, 63 insertions, 40 deletions
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index f32fc4e66e0..0b312ec420b 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -8,7 +8,7 @@ * published by the Free Software Foundation. * * 2008-02-13 initial version - * eric miao <eric.miao@marvell.com> + * eric miao <eric.miao@marvell.com> */ #include <linux/module.h> @@ -19,18 +19,18 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/pwm.h> +#include <linux/of_device.h> #include <asm/div64.h> #define HAS_SECONDARY_PWM 0x10 -#define PWM_ID_BASE(d) ((d) & 0xf) static const struct platform_device_id pwm_id_table[] = { /* PWM has_secondary_pwm? */ { "pxa25x-pwm", 0 }, - { "pxa27x-pwm", 0 | HAS_SECONDARY_PWM }, - { "pxa168-pwm", 1 }, - { "pxa910-pwm", 1 }, + { "pxa27x-pwm", HAS_SECONDARY_PWM }, + { "pxa168-pwm", 0 }, + { "pxa910-pwm", 0 }, { }, }; MODULE_DEVICE_TABLE(platform, pwm_id_table); @@ -48,7 +48,6 @@ struct pxa_pwm_chip { struct device *dev; struct clk *clk; - int clk_enabled; void __iomem *mmio_base; }; @@ -108,24 +107,15 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); - int rc = 0; - if (!pc->clk_enabled) { - rc = clk_prepare_enable(pc->clk); - if (!rc) - pc->clk_enabled++; - } - return rc; + return clk_prepare_enable(pc->clk); } static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); - if (pc->clk_enabled) { - clk_disable_unprepare(pc->clk); - pc->clk_enabled--; - } + clk_disable_unprepare(pc->clk); } static struct pwm_ops pxa_pwm_ops = { @@ -135,6 +125,46 @@ static struct pwm_ops pxa_pwm_ops = { .owner = THIS_MODULE, }; +#ifdef CONFIG_OF +/* + * Device tree users must create one device instance for each PWM channel. + * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver + * code that this is a single channel pxa25x-pwm. Currently all devices are + * supported identically. + */ +static const struct of_device_id pwm_of_match[] = { + { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]}, + { } +}; +MODULE_DEVICE_TABLE(of, pwm_of_match); +#else +#define pwm_of_match NULL +#endif + +static const struct platform_device_id *pxa_pwm_get_id_dt(struct device *dev) +{ + const struct of_device_id *id = of_match_device(pwm_of_match, dev); + + return id ? id->data : NULL; +} + +static struct pwm_device * +pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) +{ + struct pwm_device *pwm; + + pwm = pwm_request_from_chip(pc, 0, NULL); + if (IS_ERR(pwm)) + return pwm; + + pwm_set_period(pwm, args->args[0]); + + return pwm; +} + static int pwm_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -142,32 +172,34 @@ static int pwm_probe(struct platform_device *pdev) struct resource *r; int ret = 0; + if (IS_ENABLED(CONFIG_OF) && id == NULL) + id = pxa_pwm_get_id_dt(&pdev->dev); + + if (id == NULL) + return -EINVAL; + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (pwm == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (pwm == NULL) return -ENOMEM; - } pwm->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pwm->clk)) return PTR_ERR(pwm->clk); - pwm->clk_enabled = 0; - pwm->chip.dev = &pdev->dev; pwm->chip.ops = &pxa_pwm_ops; pwm->chip.base = -1; pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no memory resource defined\n"); - return -ENODEV; + if (IS_ENABLED(CONFIG_OF)) { + pwm->chip.of_xlate = pxa_pwm_of_xlate; + pwm->chip.of_pwm_n_cells = 1; } - pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r); - if (pwm->mmio_base == NULL) - return -EADDRNOTAVAIL; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(pwm->mmio_base)) + return PTR_ERR(pwm->mmio_base); ret = pwmchip_add(&pwm->chip); if (ret < 0) { @@ -194,22 +226,13 @@ static struct platform_driver pwm_driver = { .driver = { .name = "pxa25x-pwm", .owner = THIS_MODULE, + .of_match_table = pwm_of_match, }, .probe = pwm_probe, .remove = pwm_remove, .id_table = pwm_id_table, }; -static int __init pwm_init(void) -{ - return platform_driver_register(&pwm_driver); -} -arch_initcall(pwm_init); - -static void __exit pwm_exit(void) -{ - platform_driver_unregister(&pwm_driver); -} -module_exit(pwm_exit); +module_platform_driver(pwm_driver); MODULE_LICENSE("GPL v2"); |
