[ARM] pxa: allow PWM ID base number to be specified in pwm_id_table
[pandora-kernel.git] / arch / arm / mach-pxa / pwm.c
index fcdd374..5513c51 100644 (file)
 
 #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 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, pwm_id_table);
+
 /* PWM registers and bits definitions */
 #define PWMCR          (0x00)
 #define PWMDCR         (0x04)
@@ -31,7 +42,8 @@
 
 struct pwm_device {
        struct list_head        node;
-       struct platform_device *pdev;
+       struct pwm_device       *secondary;
+       struct platform_device  *pdev;
 
        const char      *label;
        struct clk      *clk;
@@ -159,17 +171,17 @@ static inline void __add_pwm(struct pwm_device *pwm)
        mutex_unlock(&pwm_lock);
 }
 
-static struct pwm_device *pwm_probe(struct platform_device *pdev,
-               unsigned int pwm_id, struct pwm_device *parent_pwm)
+static int __devinit pwm_probe(struct platform_device *pdev)
 {
-       struct pwm_device *pwm;
+       struct platform_device_id *id = platform_get_device_id(pdev);
+       struct pwm_device *pwm, *secondary = NULL;
        struct resource *r;
        int ret = 0;
 
        pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
        if (pwm == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
        }
 
        pwm->clk = clk_get(&pdev->dev, NULL);
@@ -180,16 +192,9 @@ static struct pwm_device *pwm_probe(struct platform_device *pdev,
        pwm->clk_enabled = 0;
 
        pwm->use_count = 0;
-       pwm->pwm_id = pwm_id;
+       pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
        pwm->pdev = pdev;
 
-       if (parent_pwm != NULL) {
-               /* registers for the second PWM has offset of 0x10 */
-               pwm->mmio_base = parent_pwm->mmio_base + 0x10;
-               __add_pwm(pwm);
-               return pwm;
-       }
-
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&pdev->dev, "no memory resource defined\n");
@@ -211,9 +216,27 @@ static struct pwm_device *pwm_probe(struct platform_device *pdev,
                goto err_free_mem;
        }
 
+       if (id->driver_data & HAS_SECONDARY_PWM) {
+               secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+               if (secondary == NULL) {
+                       ret = -ENOMEM;
+                       goto err_free_mem;
+               }
+
+               *secondary = *pwm;
+               pwm->secondary = secondary;
+
+               /* registers for the second PWM has offset of 0x10 */
+               secondary->mmio_base = pwm->mmio_base + 0x10;
+               secondary->pwm_id = pdev->id + 2;
+       }
+
        __add_pwm(pwm);
+       if (secondary)
+               __add_pwm(secondary);
+
        platform_set_drvdata(pdev, pwm);
-       return pwm;
+       return 0;
 
 err_free_mem:
        release_mem_region(r->start, r->end - r->start + 1);
@@ -221,32 +244,7 @@ err_free_clk:
        clk_put(pwm->clk);
 err_free:
        kfree(pwm);
-       return ERR_PTR(ret);
-}
-
-static int __devinit pxa25x_pwm_probe(struct platform_device *pdev)
-{
-       struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
-
-       if (IS_ERR(pwm))
-               return PTR_ERR(pwm);
-
-       return 0;
-}
-
-static int __devinit pxa27x_pwm_probe(struct platform_device *pdev)
-{
-       struct pwm_device *pwm;
-
-       pwm = pwm_probe(pdev, pdev->id, NULL);
-       if (IS_ERR(pwm))
-               return PTR_ERR(pwm);
-
-       pwm = pwm_probe(pdev, pdev->id + 2, pwm);
-       if (IS_ERR(pwm))
-               return PTR_ERR(pwm);
-
-       return 0;
+       return ret;
 }
 
 static int __devexit pwm_remove(struct platform_device *pdev)
@@ -259,6 +257,12 @@ static int __devexit pwm_remove(struct platform_device *pdev)
                return -ENODEV;
 
        mutex_lock(&pwm_lock);
+
+       if (pwm->secondary) {
+               list_del(&pwm->secondary->node);
+               kfree(pwm->secondary);
+       }
+
        list_del(&pwm->node);
        mutex_unlock(&pwm_lock);
 
@@ -272,46 +276,25 @@ static int __devexit pwm_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver pxa25x_pwm_driver = {
+static struct platform_driver pwm_driver = {
        .driver         = {
                .name   = "pxa25x-pwm",
+               .owner  = THIS_MODULE,
        },
-       .probe          = pxa25x_pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
-};
-
-static struct platform_driver pxa27x_pwm_driver = {
-       .driver         = {
-               .name   = "pxa27x-pwm",
-       },
-       .probe          = pxa27x_pwm_probe,
+       .probe          = pwm_probe,
        .remove         = __devexit_p(pwm_remove),
+       .id_table       = pwm_id_table,
 };
 
 static int __init pwm_init(void)
 {
-       int ret = 0;
-
-       ret = platform_driver_register(&pxa25x_pwm_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register pxa25x_pwm_driver\n");
-               return ret;
-       }
-
-       ret = platform_driver_register(&pxa27x_pwm_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register pxa27x_pwm_driver\n");
-               return ret;
-       }
-
-       return ret;
+       return platform_driver_register(&pwm_driver);
 }
 arch_initcall(pwm_init);
 
 static void __exit pwm_exit(void)
 {
-       platform_driver_unregister(&pxa25x_pwm_driver);
-       platform_driver_unregister(&pxa27x_pwm_driver);
+       platform_driver_unregister(&pwm_driver);
 }
 module_exit(pwm_exit);