PWM: ecap: Clean the access method for PWMSS config space.
[sitara-epos/sitara-epos-kernel.git] / drivers / pwm / ecap.c
index 351d88dc812b59455d6f65bac06e16549f0295b2..fb876f1e394de4fe67264e95e4be1a5880f7c78c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 
 #include <plat/clock.h>
+#include <plat/config_pwm.h>
 
 #define TIMER_CTR_REG                  0x0
 #define CAPTURE_2_REG                  0x0c
@@ -41,8 +42,9 @@ struct ecap_pwm {
        struct pwm_device_ops ops;
        spinlock_t      lock;
        struct clk      *clk;
-       int     clk_enabled;
        void __iomem    *mmio_base;
+       u8 version;
+       void __iomem *config_mem_base;
 };
 
 static inline struct ecap_pwm *to_ecap_pwm(const struct pwm_device *p)
@@ -52,21 +54,21 @@ static inline struct ecap_pwm *to_ecap_pwm(const struct pwm_device *p)
 
 static int ecap_pwm_stop(struct pwm_device *p)
 {
-       unsigned long flags;
+       unsigned long flags, v;
        struct ecap_pwm *ep = to_ecap_pwm(p);
 
-       clk_enable(ep->clk);
+       /* Trying to stop a non-running PWM, not allowed */
+       if (!pwm_is_running(p))
+               return -EPERM;
 
        spin_lock_irqsave(&ep->lock, flags);
-       __raw_writew(__raw_readw(ep->mmio_base + CAPTURE_CTRL2_REG) &
-               ~BIT(4), ep->mmio_base + CAPTURE_CTRL2_REG);
+       v = readw(ep->mmio_base + CAPTURE_CTRL2_REG);
+       v &= ~BIT(4);
+       writew(v, ep->mmio_base + CAPTURE_CTRL2_REG);
        spin_unlock_irqrestore(&ep->lock, flags);
 
+       /* For PWM clock should be disabled on stop */
        clk_disable(ep->clk);
-       if (ep->clk_enabled) {
-               clk_disable(ep->clk);
-               ep->clk_enabled = 0;
-       }
        clear_bit(FLAG_RUNNING, &p->flags);
 
        return 0;
@@ -75,22 +77,21 @@ static int ecap_pwm_stop(struct pwm_device *p)
 static int ecap_pwm_start(struct pwm_device *p)
 {
        int ret = 0;
-       unsigned long flags;
+       unsigned long flags, v;
        struct ecap_pwm *ep = to_ecap_pwm(p);
 
+       /* Trying to start a running PWM, not allowed */
+       if (pwm_is_running(p))
+               return -EPERM;
+
+       /* For PWM clock should be enabled on start */
        clk_enable(ep->clk);
+
        spin_lock_irqsave(&ep->lock, flags);
-       __raw_writew(__raw_readw(ep->mmio_base + CAPTURE_CTRL2_REG) |
-               BIT(4), ep->mmio_base + CAPTURE_CTRL2_REG);
+       v = readw(ep->mmio_base + CAPTURE_CTRL2_REG);
+       v |= BIT(4);
+       writew(v, ep->mmio_base + CAPTURE_CTRL2_REG);
        spin_unlock_irqrestore(&ep->lock, flags);
-
-       clk_disable(ep->clk);
-       if (!ep->clk_enabled) {
-               ret = clk_enable(ep->clk);
-               if (ret)
-                       return ret;
-               ep->clk_enabled = 1;
-       }
        set_bit(FLAG_RUNNING, &p->flags);
 
        return ret;
@@ -98,14 +99,16 @@ static int ecap_pwm_start(struct pwm_device *p)
 
 static int ecap_pwm_set_polarity(struct pwm_device *p, char pol)
 {
-       unsigned long flags;
+       unsigned long flags, v;
        struct ecap_pwm *ep = to_ecap_pwm(p);
 
        clk_enable(ep->clk);
 
        spin_lock_irqsave(&ep->lock, flags);
-        __raw_writew((__raw_readw(ep->mmio_base + CAPTURE_CTRL2_REG) &
-                ~BIT(10)) | (!pol << 10), ep->mmio_base + CAPTURE_CTRL2_REG);
+       v = readw(ep->mmio_base + CAPTURE_CTRL2_REG);
+       v &= ~BIT(10);
+       v |= (!pol << 10);
+       writew(v, ep->mmio_base + CAPTURE_CTRL2_REG);
        spin_unlock_irqrestore(&ep->lock, flags);
 
        clk_disable(ep->clk);
@@ -120,9 +123,9 @@ static int ecap_pwm_config_period(struct pwm_device *p)
         clk_enable(ep->clk);
 
        spin_lock_irqsave(&ep->lock, flags);
-       __raw_writel((p->period_ticks) - 1, ep->mmio_base + CAPTURE_3_REG);
-       __raw_writew(ECTRL2_MDSL_ECAP | ECTRL2_SYNCOSEL_MASK |
-                ECTRL2_CTRSTP_FREERUN, ep->mmio_base + CAPTURE_CTRL2_REG);
+       writel((p->period_ticks) - 1, ep->mmio_base + CAPTURE_3_REG);
+       writew(ECTRL2_MDSL_ECAP | ECTRL2_SYNCOSEL_MASK | ECTRL2_CTRSTP_FREERUN,
+                       ep->mmio_base + CAPTURE_CTRL2_REG);
        spin_unlock_irqrestore(&ep->lock, flags);
 
        clk_disable(ep->clk);
@@ -137,13 +140,13 @@ static int ecap_pwm_config_duty(struct pwm_device *p)
        clk_enable(ep->clk);
 
        spin_lock_irqsave(&ep->lock, flags);
-       __raw_writew(ECTRL2_MDSL_ECAP | ECTRL2_SYNCOSEL_MASK |
-        ECTRL2_CTRSTP_FREERUN, ep->mmio_base + CAPTURE_CTRL2_REG);
+       writew(ECTRL2_MDSL_ECAP | ECTRL2_SYNCOSEL_MASK | ECTRL2_CTRSTP_FREERUN,
+                       ep->mmio_base + CAPTURE_CTRL2_REG);
        if (p->duty_ticks > 0) {
-               __raw_writel(p->duty_ticks, ep->mmio_base + CAPTURE_4_REG);
+               writel(p->duty_ticks, ep->mmio_base + CAPTURE_4_REG);
        } else {
-       __raw_writel(p->duty_ticks, ep->mmio_base + CAPTURE_2_REG);
-       __raw_writel(0, ep->mmio_base + TIMER_CTR_REG);
+               writel(p->duty_ticks, ep->mmio_base + CAPTURE_2_REG);
+               writel(0, ep->mmio_base + TIMER_CTR_REG);
        }
        spin_unlock_irqrestore(&ep->lock, flags);
 
@@ -194,9 +197,13 @@ static int ecap_pwm_request(struct pwm_device *p)
 static int ecap_frequency_transition_cb(struct pwm_device *p)
 {
        struct ecap_pwm *ep = to_ecap_pwm(p);
-       unsigned long duty_ns;
+       unsigned long duty_ns, rate;
+
+       rate = clk_get_rate(ep->clk);
+       if (rate == p->tick_hz)
+               return 0;
+       p->tick_hz = rate;
 
-       p->tick_hz = clk_get_rate(ep->clk);
        duty_ns = p->duty_ns;
        if (pwm_is_running(p)) {
                pwm_stop(p);
@@ -212,48 +219,88 @@ static int ecap_frequency_transition_cb(struct pwm_device *p)
                return 0;
 }
 
-static int __init ecap_probe(struct platform_device *pdev)
+static int ecap_probe(struct platform_device *pdev)
 {
        struct ecap_pwm *ep = NULL;
        struct resource *r;
        int ret = 0;
+       int val;
+       char con_id[PWM_CON_ID_STRING_LENGTH] = "epwmss";
+       struct pwmss_platform_data *pdata = (&pdev->dev)->platform_data;
 
        ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+
        if (!ep) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
-               ret = -ENOMEM;
-               goto err_ecap_pwm_alloc;
+               return -ENOMEM;
        }
 
-       ep->clk = clk_get(&pdev->dev, "ecap");
+       ep->version = pdata->version;
+
+       if (ep->version == PWM_VERSION_1) {
+               sprintf(con_id, "%s%d_%s", con_id, pdev->id, "fck");
+               ep->clk = clk_get(&pdev->dev, con_id);
+       } else
+               ep->clk = clk_get(&pdev->dev, "ecap");
+
        if (IS_ERR(ep->clk)) {
                ret = PTR_ERR(ep->clk);
-               goto err_free;
+               goto err_clk_get;
+       }
+
+       if (ep->version == PWM_VERSION_1) {
+               r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+               if (!r) {
+                       dev_err(&pdev->dev, "no memory resource defined\n");
+                       ret = -ENOMEM;
+                       goto err_get_resource;
+               }
+
+               ep->config_mem_base = ioremap(r->start, resource_size(r));
+
+               if (!ep->config_mem_base) {
+
+                       dev_err(&pdev->dev, "failed to ioremap() registers\n");
+                       ret = -ENOMEM;
+                       goto err_get_resource;
+               }
+
+               clk_enable(ep->clk);
+               val = readw(ep->config_mem_base + PWMSS_CLKCONFIG);
+               val |= BIT(ECAP_CLK_EN);
+               writew(val, ep->config_mem_base + PWMSS_CLKCONFIG);
+               clk_disable(ep->clk);
        }
 
        spin_lock_init(&ep->lock);
        ep->ops.config = ecap_pwm_config;
        ep->ops.request = ecap_pwm_request;
        ep->ops.freq_transition_notifier_cb = ecap_frequency_transition_cb;
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (ep->version == PWM_VERSION_1)
+               r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       else
+               r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
        if (!r) {
                dev_err(&pdev->dev, "no memory resource defined\n");
                ret = -ENODEV;
-               goto err_free_clk;
+               goto err_request_mem;
        }
 
        r = request_mem_region(r->start, resource_size(r), pdev->name);
        if (!r) {
                dev_err(&pdev->dev, "failed to request memory resource\n");
                ret = -EBUSY;
-               goto err_free_clk;
+               goto err_request_mem;
        }
 
        ep->mmio_base = ioremap(r->start, resource_size(r));
        if (!ep->mmio_base) {
                dev_err(&pdev->dev, "failed to ioremap() registers\n");
                ret = -ENODEV;
-               goto err_free_mem;
+               goto err_ioremap;
        }
 
        ep->pwm.ops = &ep->ops;
@@ -262,13 +309,17 @@ static int __init ecap_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ep);
        return 0;
 
-err_free_mem:
+err_ioremap:
        release_mem_region(r->start, resource_size(r));
-err_free_clk:
+err_request_mem:
+       if (ep->version == PWM_VERSION_1) {
+               iounmap(ep->config_mem_base);
+               ep->config_mem_base = NULL;
+       }
+err_get_resource:
        clk_put(ep->clk);
-err_free:
+err_clk_get:
        kfree(ep);
-err_ecap_pwm_alloc:
        return ret;
 }
 
@@ -301,10 +352,25 @@ static int __devexit ecap_remove(struct platform_device *pdev)
 {
        struct ecap_pwm *ep = platform_get_drvdata(pdev);
        struct resource *r;
+       struct pwmss_platform_data *pdata;
+       int val;
+
+       if (ep->version == PWM_VERSION_1) {
+               pdata = (&pdev->dev)->platform_data;
+               val = readw(ep->config_mem_base + PWMSS_CLKCONFIG);
+               val &= ~BIT(ECAP_CLK_EN);
+               writew(val, ep->config_mem_base + PWMSS_CLKCONFIG);
+               iounmap(ep->config_mem_base);
+               ep->config_mem_base = NULL;
+       }
 
        pwm_unregister(&ep->pwm);
        iounmap(ep->mmio_base);
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (ep->version == PWM_VERSION_1)
+               r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       else
+               r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(r->start, resource_size(r));
        platform_set_drvdata(pdev, NULL);
        clk_put(ep->clk);