[PATCH 4/7] pwm: Align existing pwm drivers with pwm-core driver
Lars-Peter Clausen
lars at metafoo.de
Tue Sep 28 04:58:09 EDT 2010
Arun Murthy wrote:
> pwm-core: make the driver visible for ARM only
>
> Align ab8500 pwm with the pwm core driver
> Align twl6030 pwm driver with pwm core driver
> Align Freescale mxc pwm driver with pwm core driver
> Align pxa pwm driver with pwm core driver
> Align samsung(s3c) pwm driver with pwm core driver
>
> mips-jz4740: pwm: Align with new pwm core driver
>
> PWM core driver has been added and has been enabled only for ARM
> platform. The same can be utilised for mips also.
> Please align with the pwm core driver(drivers/pwm-core.c).
Is there any reason for artificially limiting it to ARM?
>
> Signed-off-by: Arun Murthy <arun.murthy at stericsson.com>
> Acked-by: Linus Walleij <linus.walleij at stericsson.com>
> ---
> arch/arm/plat-mxc/pwm.c | 166 +++++++++++++-----------------
> arch/arm/plat-pxa/pwm.c | 210 ++++++++++++++++++--------------------
> arch/arm/plat-samsung/pwm.c | 235 +++++++++++++++++++------------------------
> arch/mips/jz4740/pwm.c | 2 +-
> drivers/mfd/twl-core.c | 13 +++
> drivers/mfd/twl6030-pwm.c | 111 +++++++++++++-------
> drivers/misc/ab8500-pwm.c | 87 +++++++---------
> drivers/pwm/Kconfig | 1 +
> drivers/pwm/pwm-core.c | 9 +--
> include/linux/pwm.h | 21 ++++-
> 10 files changed, 418 insertions(+), 437 deletions(-)
>
> diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
> index c36f263..b259ba9 100644
> --- a/arch/arm/plat-mxc/pwm.c
> +++ b/arch/arm/plat-mxc/pwm.c
> @@ -38,22 +38,16 @@
>
>
>
> -struct pwm_device {
> - struct list_head node;
> - struct platform_device *pdev;
> -
> - const char *label;
> +struct mxc_pwm_device {
> struct clk *clk;
> -
> int clk_enabled;
> void __iomem *mmio_base;
> -
> - unsigned int use_count;
> - unsigned int pwm_id;
> };
>
> -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +static int mxc_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> {
> + struct mxc_pwm_device *mxc_pwm = pwm->data;
> +
> if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
> return -EINVAL;
>
> @@ -62,7 +56,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> unsigned long period_cycles, duty_cycles, prescale;
> u32 cr;
>
> - c = clk_get_rate(pwm->clk);
> + c = clk_get_rate(mxc_pwm->clk);
> c = c * period_ns;
> do_div(c, 1000000000);
> period_cycles = c;
> @@ -74,8 +68,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> do_div(c, period_ns);
> duty_cycles = c;
>
> - writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
> - writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
> + writel(duty_cycles, mxc_pwm->mmio_base + MX3_PWMSAR);
> + writel(period_cycles, mxc_pwm->mmio_base + MX3_PWMPR);
>
> cr = MX3_PWMCR_PRESCALER(prescale) | MX3_PWMCR_EN;
>
> @@ -84,7 +78,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> else
> cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
>
> - writel(cr, pwm->mmio_base + MX3_PWMCR);
> + writel(cr, mxc_pwm->mmio_base + MX3_PWMCR);
> } else if (cpu_is_mx1() || cpu_is_mx21()) {
> /* The PWM subsystem allows for exact frequencies. However,
> * I cannot connect a scope on my device to the PWM line and
> @@ -102,110 +96,76 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> * both the prescaler (/1 .. /128) and then by CLKSEL
> * (/2 .. /16).
> */
> - u32 max = readl(pwm->mmio_base + MX1_PWMP);
> + u32 max = readl(mxc_pwm->mmio_base + MX1_PWMP);
> u32 p = max * duty_ns / period_ns;
> - writel(max - p, pwm->mmio_base + MX1_PWMS);
> + writel(max - p, mxc_pwm->mmio_base + MX1_PWMS);
> } else {
> BUG();
> }
>
> return 0;
> }
> -EXPORT_SYMBOL(pwm_config);
>
> -int pwm_enable(struct pwm_device *pwm)
> +static int mxc_pwm_enable(struct pwm_device *pwm)
> {
> + struct mxc_pwm_device *mxc_pwm = pwm->data;
> int rc = 0;
>
> - if (!pwm->clk_enabled) {
> - rc = clk_enable(pwm->clk);
> + if (!mxc_pwm->clk_enabled) {
> + rc = clk_enable(mxc_pwm->clk);
> if (!rc)
> - pwm->clk_enabled = 1;
> + mxc_pwm->clk_enabled = 1;
> }
> return rc;
> }
> -EXPORT_SYMBOL(pwm_enable);
> -
> -void pwm_disable(struct pwm_device *pwm)
> -{
> - writel(0, pwm->mmio_base + MX3_PWMCR);
> -
> - if (pwm->clk_enabled) {
> - clk_disable(pwm->clk);
> - pwm->clk_enabled = 0;
> - }
> -}
> -EXPORT_SYMBOL(pwm_disable);
> -
> -static DEFINE_MUTEX(pwm_lock);
> -static LIST_HEAD(pwm_list);
>
> -struct pwm_device *pwm_request(int pwm_id, const char *label)
> +static int mxc_pwm_disable(struct pwm_device *pwm)
> {
> - struct pwm_device *pwm;
> - int found = 0;
> + struct mxc_pwm_device *mxc_pwm = pwm->data;
>
> - mutex_lock(&pwm_lock);
> + writel(0, mxc_pwm->mmio_base + MX3_PWMCR);
>
> - list_for_each_entry(pwm, &pwm_list, node) {
> - if (pwm->pwm_id == pwm_id) {
> - found = 1;
> - break;
> - }
> + if (mxc_pwm->clk_enabled) {
> + clk_disable(mxc_pwm->clk);
> + mxc_pwm->clk_enabled = 0;
> }
> -
> - if (found) {
> - if (pwm->use_count == 0) {
> - pwm->use_count++;
> - pwm->label = label;
> - } else
> - pwm = ERR_PTR(-EBUSY);
> - } else
> - pwm = ERR_PTR(-ENOENT);
> -
> - mutex_unlock(&pwm_lock);
> - return pwm;
> -}
> -EXPORT_SYMBOL(pwm_request);
> -
> -void pwm_free(struct pwm_device *pwm)
> -{
> - mutex_lock(&pwm_lock);
> -
> - if (pwm->use_count) {
> - pwm->use_count--;
> - pwm->label = NULL;
> - } else
> - pr_warning("PWM device already freed\n");
> -
> - mutex_unlock(&pwm_lock);
> + return 0;
> }
> -EXPORT_SYMBOL(pwm_free);
>
> static int __devinit mxc_pwm_probe(struct platform_device *pdev)
> {
> + struct mxc_pwm_device *mxc_pwm;
> struct pwm_device *pwm;
> + struct pwm_ops *pops;
> struct resource *r;
> int ret = 0;
>
> + mxc_pwm = kzalloc(sizeof(struct mxc_pwm_device), GFP_KERNEL);
> + if (mxc_pwm == NULL) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + return -ENOMEM;
> + }
> pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> if (pwm == NULL) {
> dev_err(&pdev->dev, "failed to allocate memory\n");
> - return -ENOMEM;
> + ret = -ENOMEM;
> + goto err_free1;
> + }
> + pops = kzalloc(sizeof(struct pwm_ops), GFP_KERNEL);
> + if (pops == NULL) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + ret = -ENOMEM;
> + goto err_free2;
> }
>
> - pwm->clk = clk_get(&pdev->dev, "pwm");
> + mxc_pwm->clk = clk_get(&pdev->dev, "pwm");
>
> - if (IS_ERR(pwm->clk)) {
> - ret = PTR_ERR(pwm->clk);
> - goto err_free;
> + if (IS_ERR(mxc_pwm->clk)) {
> + ret = PTR_ERR(mxc_pwm->clk);
> + goto err_free3;
> }
>
> - pwm->clk_enabled = 0;
> -
> - pwm->use_count = 0;
> - pwm->pwm_id = pdev->id;
> - pwm->pdev = pdev;
> + mxc_pwm->clk_enabled = 0;
>
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (r == NULL) {
> @@ -221,16 +181,27 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev)
> goto err_free_clk;
> }
>
> - pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
> - if (pwm->mmio_base == NULL) {
> + mxc_pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
> + if (mxc_pwm->mmio_base == NULL) {
> dev_err(&pdev->dev, "failed to ioremap() registers\n");
> ret = -ENODEV;
> goto err_free_mem;
> }
>
> - mutex_lock(&pwm_lock);
> - list_add_tail(&pwm->node, &pwm_list);
> - mutex_unlock(&pwm_lock);
> + pops->pwm_config = mxc_pwm_config;
> + pops->pwm_enable = mxc_pwm_enable;
> + pops->pwm_disable = mxc_pwm_disable;
> + pops->name = pdev->name;
> +
> + pwm->pwm_id = pdev->id;
> + pwm->dev = &pdev->dev;
> + pwm->pops = pops;
> + pwm->data = mxc_pwm;
> + ret = pwm_device_register(pwm);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to register pwm device\n");
> + goto err_free_mem;
> + }
>
> platform_set_drvdata(pdev, pwm);
> return 0;
> @@ -238,33 +209,38 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev)
> err_free_mem:
> release_mem_region(r->start, r->end - r->start + 1);
> err_free_clk:
> - clk_put(pwm->clk);
> -err_free:
> + clk_put(mxc_pwm->clk);
> +err_free3:
> + kfree(pops);
> +err_free2:
> kfree(pwm);
> +err_free1:
> + kfree(mxc_pwm);
> return ret;
> }
>
> static int __devexit mxc_pwm_remove(struct platform_device *pdev)
> {
> struct pwm_device *pwm;
> + struct mxc_pwm_device *mxc_pwm;
> struct resource *r;
>
> pwm = platform_get_drvdata(pdev);
> if (pwm == NULL)
> return -ENODEV;
> + mxc_pwm = pwm->data;
>
> - mutex_lock(&pwm_lock);
> - list_del(&pwm->node);
> - mutex_unlock(&pwm_lock);
> -
> - iounmap(pwm->mmio_base);
> + pwm_device_unregister(pwm);
> + iounmap(mxc_pwm->mmio_base);
>
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> release_mem_region(r->start, r->end - r->start + 1);
>
> - clk_put(pwm->clk);
> + clk_put(mxc_pwm->clk);
>
> + kfree(pwm->pops);
> kfree(pwm);
> + kfree(mxc_pwm);
> return 0;
> }
>
> diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c
> index ef32686..1de902a 100644
> --- a/arch/arm/plat-pxa/pwm.c
> +++ b/arch/arm/plat-pxa/pwm.c
> @@ -43,33 +43,27 @@ MODULE_DEVICE_TABLE(platform, pwm_id_table);
> #define PWMCR_SD (1 << 6)
> #define PWMDCR_FD (1 << 10)
>
> -struct pwm_device {
> - struct list_head node;
> - struct pwm_device *secondary;
> - struct platform_device *pdev;
> -
> - const char *label;
> +struct pxa_pwm_device {
> + struct pxa_pwm_device *sec;
> struct clk *clk;
> int clk_enabled;
> void __iomem *mmio_base;
> -
> - unsigned int use_count;
> - unsigned int pwm_id;
> };
>
> /*
> * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
> * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
> */
> -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +int pxa_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> {
> unsigned long long c;
> unsigned long period_cycles, prescale, pv, dc;
> + struct pxa_pwm_device *pxa_pwm = pwm->data;
>
> if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
> return -EINVAL;
>
> - c = clk_get_rate(pwm->clk);
> + c = clk_get_rate(pxa_pwm->clk);
> c = c * period_ns;
> do_div(c, 1000000000);
> period_cycles = c;
> @@ -90,94 +84,45 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> /* NOTE: the clock to PWM has to be enabled first
> * before writing to the registers
> */
> - clk_enable(pwm->clk);
> - __raw_writel(prescale, pwm->mmio_base + PWMCR);
> - __raw_writel(dc, pwm->mmio_base + PWMDCR);
> - __raw_writel(pv, pwm->mmio_base + PWMPCR);
> - clk_disable(pwm->clk);
> + clk_enable(pxa_pwm->clk);
> + __raw_writel(prescale, pxa_pwm->mmio_base + PWMCR);
> + __raw_writel(dc, pxa_pwm->mmio_base + PWMDCR);
> + __raw_writel(pv, pxa_pwm->mmio_base + PWMPCR);
> + clk_disable(pxa_pwm->clk);
>
> return 0;
> }
> -EXPORT_SYMBOL(pwm_config);
>
> -int pwm_enable(struct pwm_device *pwm)
> +int pxa_pwm_enable(struct pwm_device *pwm)
> {
> + struct pxa_pwm_device *pxa_pwm = pwm->data;
> int rc = 0;
>
> - if (!pwm->clk_enabled) {
> - rc = clk_enable(pwm->clk);
> + if (!pxa_pwm->clk_enabled) {
> + rc = clk_enable(pxa_pwm->clk);
> if (!rc)
> - pwm->clk_enabled = 1;
> + pxa_pwm->clk_enabled = 1;
> }
> return rc;
> }
> -EXPORT_SYMBOL(pwm_enable);
>
> -void pwm_disable(struct pwm_device *pwm)
> +int pxa_pwm_disable(struct pwm_device *pwm)
> {
> - if (pwm->clk_enabled) {
> - clk_disable(pwm->clk);
> - pwm->clk_enabled = 0;
> - }
> -}
> -EXPORT_SYMBOL(pwm_disable);
> -
> -static DEFINE_MUTEX(pwm_lock);
> -static LIST_HEAD(pwm_list);
> + struct pxa_pwm_device *pxa_pwm = pwm->data;
>
> -struct pwm_device *pwm_request(int pwm_id, const char *label)
> -{
> - struct pwm_device *pwm;
> - int found = 0;
> -
> - mutex_lock(&pwm_lock);
> -
> - list_for_each_entry(pwm, &pwm_list, node) {
> - if (pwm->pwm_id == pwm_id) {
> - found = 1;
> - break;
> - }
> + if (pxa_pwm->clk_enabled) {
> + clk_disable(pxa_pwm->clk);
> + pxa_pwm->clk_enabled = 0;
> }
> -
> - if (found) {
> - if (pwm->use_count == 0) {
> - pwm->use_count++;
> - pwm->label = label;
> - } else
> - pwm = ERR_PTR(-EBUSY);
> - } else
> - pwm = ERR_PTR(-ENOENT);
> -
> - mutex_unlock(&pwm_lock);
> - return pwm;
> -}
> -EXPORT_SYMBOL(pwm_request);
> -
> -void pwm_free(struct pwm_device *pwm)
> -{
> - mutex_lock(&pwm_lock);
> -
> - if (pwm->use_count) {
> - pwm->use_count--;
> - pwm->label = NULL;
> - } else
> - pr_warning("PWM device already freed\n");
> -
> - mutex_unlock(&pwm_lock);
> -}
> -EXPORT_SYMBOL(pwm_free);
> -
> -static inline void __add_pwm(struct pwm_device *pwm)
> -{
> - mutex_lock(&pwm_lock);
> - list_add_tail(&pwm->node, &pwm_list);
> - mutex_unlock(&pwm_lock);
> + return 0;
> }
>
> static int __devinit pwm_probe(struct platform_device *pdev)
> {
> const struct platform_device_id *id = platform_get_device_id(pdev);
> + struct pxa_pwm_device *pxa_pwm, *pxa_pwm_sec;
> struct pwm_device *pwm, *secondary = NULL;
> + struct pwm_ops *pops;
> struct resource *r;
> int ret = 0;
>
> @@ -186,17 +131,26 @@ static int __devinit pwm_probe(struct platform_device *pdev)
> dev_err(&pdev->dev, "failed to allocate memory\n");
> return -ENOMEM;
> }
> + pops = kzalloc(sizeof(struct pwm_ops), GFP_KERNEL);
> + if (pops == NULL) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + kfree(pwm);
> + return -ENOMEM;
> + }
> + pxa_pwm = kzalloc(sizeof(struct pxa_pwm_device), GFP_KERNEL);
> + if (pxa_pwm == NULL) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + kfree(pops);
> + kfree(pwm);
> + return -ENOMEM;
> + }
>
> - pwm->clk = clk_get(&pdev->dev, NULL);
> - if (IS_ERR(pwm->clk)) {
> - ret = PTR_ERR(pwm->clk);
> + pxa_pwm->clk = clk_get(&pdev->dev, NULL);
> + if (IS_ERR(pxa_pwm->clk)) {
> + ret = PTR_ERR(pxa_pwm->clk);
> goto err_free;
> }
> - pwm->clk_enabled = 0;
> -
> - pwm->use_count = 0;
> - pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
> - pwm->pdev = pdev;
> + pxa_pwm->clk_enabled = 0;
>
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (r == NULL) {
> @@ -212,69 +166,105 @@ static int __devinit pwm_probe(struct platform_device *pdev)
> goto err_free_clk;
> }
>
> - pwm->mmio_base = ioremap(r->start, resource_size(r));
> - if (pwm->mmio_base == NULL) {
> + pxa_pwm->mmio_base = ioremap(r->start, resource_size(r));
> + if (pxa_pwm->mmio_base == NULL) {
> dev_err(&pdev->dev, "failed to ioremap() registers\n");
> ret = -ENODEV;
> goto err_free_mem;
> }
>
> + pops->pwm_config = pxa_pwm_config;
> + pops->pwm_enable = pxa_pwm_enable;
> + pops->pwm_disable = pxa_pwm_disable;
> + pops->name = pdev->name;
> +
> + pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
> + pwm->dev = &pdev->dev;
> + pwm->pops = pops;
> + pwm->data = pxa_pwm;
> +
> + ret = pwm_device_register(pwm);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to register pwm device\n");
> + 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;
> + goto err_pwm;
> + }
> + pxa_pwm_sec = kzalloc(sizeof(struct pxa_pwm_device),
> + GFP_KERNEL);
> + if (pxa_pwm_sec == NULL) {
> + ret = -ENOMEM;
> + goto err_free_mem2;
> }
>
> *secondary = *pwm;
> - pwm->secondary = secondary;
> + *pxa_pwm_sec = *pxa_pwm;
> + pxa_pwm->sec = pxa_pwm_sec;
>
> /* registers for the second PWM has offset of 0x10 */
> - secondary->mmio_base = pwm->mmio_base + 0x10;
> + pxa_pwm_sec->mmio_base = pxa_pwm->mmio_base + 0x10;
> secondary->pwm_id = pdev->id + 2;
> - }
> + secondary->data = pxa_pwm_sec;
>
> - __add_pwm(pwm);
> - if (secondary)
> - __add_pwm(secondary);
> + ret = pwm_device_register(secondary);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to register pwm device\n");
> + goto err_free_mem3;
> + }
> + }
>
> platform_set_drvdata(pdev, pwm);
> return 0;
> -
> +err_free_mem3:
> + kfree(pxa_pwm_sec);
> +err_free_mem2:
> + kfree(secondary);
> +err_pwm:
> + pwm_device_unregister(pwm);
> err_free_mem:
> release_mem_region(r->start, resource_size(r));
> err_free_clk:
> - clk_put(pwm->clk);
> + clk_put(pxa_pwm->clk);
> err_free:
> + kfree(pxa_pwm);
> + kfree(pops);
> kfree(pwm);
> return ret;
> }
>
> static int __devexit pwm_remove(struct platform_device *pdev)
> {
> - struct pwm_device *pwm;
> + struct pwm_device *pwm, *secondary;
> + struct pxa_pwm_device *pxa_pwm, *pxa_pwm_sec;
> struct resource *r;
>
> pwm = platform_get_drvdata(pdev);
> if (pwm == NULL)
> return -ENODEV;
> -
> - mutex_lock(&pwm_lock);
> -
> - if (pwm->secondary) {
> - list_del(&pwm->secondary->node);
> - kfree(pwm->secondary);
> + pxa_pwm = pwm->data;
> + secondary = pwm_request((pdev->id + 2), pdev->name);
> + pxa_pwm_sec = secondary->data;
> +
> + pwm_device_unregister(pwm);
> + iounmap(pxa_pwm->mmio_base);
> + if (secondary) {
> + pwm_device_unregister(secondary);
> + iounmap(pxa_pwm->mmio_base);
> + kfree(pxa_pwm_sec);
> + kfree(secondary);
> }
>
> - list_del(&pwm->node);
> - mutex_unlock(&pwm_lock);
> -
> - iounmap(pwm->mmio_base);
> -
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> release_mem_region(r->start, resource_size(r));
>
> - clk_put(pwm->clk);
> + clk_put(pxa_pwm->clk);
> + kfree(pxa_pwm);
> + kfree(pwm->pops);
> kfree(pwm);
> return 0;
> }
> diff --git a/arch/arm/plat-samsung/pwm.c b/arch/arm/plat-samsung/pwm.c
> index 2eeb49f..63fba01 100644
> --- a/arch/arm/plat-samsung/pwm.c
> +++ b/arch/arm/plat-samsung/pwm.c
> @@ -26,25 +26,19 @@
> #include <plat/devs.h>
> #include <plat/regs-timer.h>
>
> -struct pwm_device {
> - struct list_head list;
> +struct s3c_pwm_device {
> struct platform_device *pdev;
>
> struct clk *clk_div;
> struct clk *clk;
> - const char *label;
>
> unsigned int period_ns;
> unsigned int duty_ns;
>
> unsigned char tcon_base;
> unsigned char running;
> - unsigned char use_count;
> - unsigned char pwm_id;
> };
>
> -#define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg)
> -
> static struct clk *clk_scaler[2];
>
> /* Standard setup for a timer block. */
> @@ -78,108 +72,61 @@ struct platform_device s3c_device_timer[] = {
> [4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
> };
>
> -static inline int pwm_is_tdiv(struct pwm_device *pwm)
> +static inline int pwm_is_tdiv(struct s3c_pwm_device *s3c_pwm)
> {
> - return clk_get_parent(pwm->clk) == pwm->clk_div;
> + return clk_get_parent(s3c_pwm->clk) == s3c_pwm->clk_div;
> }
>
> -static DEFINE_MUTEX(pwm_lock);
> -static LIST_HEAD(pwm_list);
> +#define pwm_tcon_start(s3c_pwm) (1 << (s3c_pwm->tcon_base + 0))
> +#define pwm_tcon_invert(s3c_pwm) (1 << (s3c_pwm->tcon_base + 2))
> +#define pwm_tcon_autoreload(s3c_pwm) (1 << (s3c_pwm->tcon_base + 3))
> +#define pwm_tcon_manulupdate(s3c_pwm) (1 << (s3c_pwm->tcon_base + 1))
>
> -struct pwm_device *pwm_request(int pwm_id, const char *label)
> -{
> - struct pwm_device *pwm;
> - int found = 0;
> -
> - mutex_lock(&pwm_lock);
> -
> - list_for_each_entry(pwm, &pwm_list, list) {
> - if (pwm->pwm_id == pwm_id) {
> - found = 1;
> - break;
> - }
> - }
> -
> - if (found) {
> - if (pwm->use_count == 0) {
> - pwm->use_count = 1;
> - pwm->label = label;
> - } else
> - pwm = ERR_PTR(-EBUSY);
> - } else
> - pwm = ERR_PTR(-ENOENT);
> -
> - mutex_unlock(&pwm_lock);
> - return pwm;
> -}
> -
> -EXPORT_SYMBOL(pwm_request);
> -
> -
> -void pwm_free(struct pwm_device *pwm)
> -{
> - mutex_lock(&pwm_lock);
> -
> - if (pwm->use_count) {
> - pwm->use_count--;
> - pwm->label = NULL;
> - } else
> - printk(KERN_ERR "PWM%d device already freed\n", pwm->pwm_id);
> -
> - mutex_unlock(&pwm_lock);
> -}
> -
> -EXPORT_SYMBOL(pwm_free);
> -
> -#define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0))
> -#define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2))
> -#define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3))
> -#define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1))
> -
> -int pwm_enable(struct pwm_device *pwm)
> +int s3c_pwm_enable(struct pwm_device *pwm)
> {
> unsigned long flags;
> unsigned long tcon;
> + struct s3c_pwm_device *s3c_pwm = pwm->data;
>
> local_irq_save(flags);
>
> tcon = __raw_readl(S3C2410_TCON);
> - tcon |= pwm_tcon_start(pwm);
> + tcon |= pwm_tcon_start(s3c_pwm);
> __raw_writel(tcon, S3C2410_TCON);
>
> local_irq_restore(flags);
>
> - pwm->running = 1;
> + s3c_pwm->running = 1;
> return 0;
> }
>
> -EXPORT_SYMBOL(pwm_enable);
> -
> -void pwm_disable(struct pwm_device *pwm)
> +int s3c_pwm_disable(struct pwm_device *pwm)
> {
> unsigned long flags;
> unsigned long tcon;
> + struct s3c_pwm_device *s3c_pwm = pwm->data;
>
> local_irq_save(flags);
>
> tcon = __raw_readl(S3C2410_TCON);
> - tcon &= ~pwm_tcon_start(pwm);
> + tcon &= ~pwm_tcon_start(s3c_pwm);
> __raw_writel(tcon, S3C2410_TCON);
>
> local_irq_restore(flags);
>
> - pwm->running = 0;
> + s3c_pwm->running = 0;
> + return 0;
> }
>
> -EXPORT_SYMBOL(pwm_disable);
> -
> -static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq)
> +static unsigned long pwm_calc_tin(struct pwm_device *pwm,
> + unsigned long freq)
> {
> unsigned long tin_parent_rate;
> unsigned int div;
> + struct s3c_pwm_device *s3c_pwm = pwm->data;
>
> - tin_parent_rate = clk_get_rate(clk_get_parent(pwm->clk_div));
> - pwm_dbg(pwm, "tin parent at %lu\n", tin_parent_rate);
> + tin_parent_rate = clk_get_rate(clk_get_parent(s3c_pwm->clk_div));
> + dev_dbg(pwm->dev, "tin parent at %lu\n", tin_parent_rate);
>
> for (div = 2; div <= 16; div *= 2) {
> if ((tin_parent_rate / (div << 16)) < freq)
> @@ -191,7 +138,7 @@ static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq)
>
> #define NS_IN_HZ (1000000000UL)
>
> -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +int s3c_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> {
> unsigned long tin_rate;
> unsigned long tin_ns;
> @@ -200,6 +147,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> unsigned long tcon;
> unsigned long tcnt;
> long tcmp;
> + struct s3c_pwm_device *s3c_pwm = pwm->data;
>
> /* We currently avoid using 64bit arithmetic by using the
> * fact that anything faster than 1Hz is easily representable
> @@ -211,8 +159,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> if (duty_ns > period_ns)
> return -EINVAL;
>
> - if (period_ns == pwm->period_ns &&
> - duty_ns == pwm->duty_ns)
> + if (period_ns == s3c_pwm->period_ns &&
> + duty_ns == s3c_pwm->duty_ns)
> return 0;
>
> /* The TCMP and TCNT can be read without a lock, they're not
> @@ -223,26 +171,26 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
>
> period = NS_IN_HZ / period_ns;
>
> - pwm_dbg(pwm, "duty_ns=%d, period_ns=%d (%lu)\n",
> + dev_dbg(pwm->dev, "duty_ns=%d, period_ns=%d (%lu)\n",
> duty_ns, period_ns, period);
>
> /* Check to see if we are changing the clock rate of the PWM */
>
> - if (pwm->period_ns != period_ns) {
> - if (pwm_is_tdiv(pwm)) {
> + if (s3c_pwm->period_ns != period_ns) {
> + if (pwm_is_tdiv(s3c_pwm)) {
> tin_rate = pwm_calc_tin(pwm, period);
> - clk_set_rate(pwm->clk_div, tin_rate);
> + clk_set_rate(s3c_pwm->clk_div, tin_rate);
> } else
> - tin_rate = clk_get_rate(pwm->clk);
> + tin_rate = clk_get_rate(s3c_pwm->clk);
>
> - pwm->period_ns = period_ns;
> + s3c_pwm->period_ns = period_ns;
>
> - pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate);
> + dev_dbg(pwm->dev, "tin_rate=%lu\n", tin_rate);
>
> tin_ns = NS_IN_HZ / tin_rate;
> tcnt = period_ns / tin_ns;
> } else
> - tin_ns = NS_IN_HZ / clk_get_rate(pwm->clk);
> + tin_ns = NS_IN_HZ / clk_get_rate(s3c_pwm->clk);
>
> /* Note, counters count down */
>
> @@ -253,7 +201,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> if (tcmp == tcnt)
> tcmp--;
>
> - pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
> + dev_dbg(pwm->dev, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
>
> if (tcmp < 0)
> tcmp = 0;
> @@ -266,11 +214,11 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> __raw_writel(tcnt, S3C2410_TCNTB(pwm->pwm_id));
>
> tcon = __raw_readl(S3C2410_TCON);
> - tcon |= pwm_tcon_manulupdate(pwm);
> - tcon |= pwm_tcon_autoreload(pwm);
> + tcon |= pwm_tcon_manulupdate(s3c_pwm);
> + tcon |= pwm_tcon_autoreload(s3c_pwm);
> __raw_writel(tcon, S3C2410_TCON);
>
> - tcon &= ~pwm_tcon_manulupdate(pwm);
> + tcon &= ~pwm_tcon_manulupdate(s3c_pwm);
> __raw_writel(tcon, S3C2410_TCON);
>
> local_irq_restore(flags);
> @@ -278,103 +226,122 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> return 0;
> }
>
> -EXPORT_SYMBOL(pwm_config);
> -
> -static int pwm_register(struct pwm_device *pwm)
> -{
> - pwm->duty_ns = -1;
> - pwm->period_ns = -1;
> -
> - mutex_lock(&pwm_lock);
> - list_add_tail(&pwm->list, &pwm_list);
> - mutex_unlock(&pwm_lock);
> -
> - return 0;
> -}
> -
> static int s3c_pwm_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> + struct s3c_pwm_device *s3c_pwm;
> struct pwm_device *pwm;
> + struct pwm_ops *pops;
> unsigned long flags;
> unsigned long tcon;
> unsigned int id = pdev->id;
> - int ret;
> + int ret = 0;
>
> if (id == 4) {
> dev_err(dev, "TIMER4 is currently not supported\n");
> return -ENXIO;
> }
>
> + s3c_pwm = kzalloc(sizeof(struct s3c_pwm_device), GFP_KERNEL);
> + if (s3c_pwm == NULL) {
> + dev_err(dev, "failed to allocate pwm_device\n");
> + return -ENOMEM;
> + }
> + s3c_pwm->pdev = pdev;
> pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> if (pwm == NULL) {
> dev_err(dev, "failed to allocate pwm_device\n");
> - return -ENOMEM;
> + goto err_alloc;
> + ret = -ENOMEM;
> + }
> + pops = kzalloc(sizeof(struct pwm_ops), GFP_KERNEL);
> + if (pops == NULL) {
> + dev_err(dev, "failed to allocate memory\n");
> + goto err_alloc1;
> + ret = -ENOMEM;
> }
> -
> - pwm->pdev = pdev;
> - pwm->pwm_id = id;
>
> /* calculate base of control bits in TCON */
> - pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;
> + s3c_pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;
>
> - pwm->clk = clk_get(dev, "pwm-tin");
> - if (IS_ERR(pwm->clk)) {
> + s3c_pwm->clk = clk_get(dev, "pwm-tin");
> + if (IS_ERR(s3c_pwm->clk)) {
> dev_err(dev, "failed to get pwm tin clk\n");
> - ret = PTR_ERR(pwm->clk);
> - goto err_alloc;
> + ret = PTR_ERR(s3c_pwm->clk);
> + goto err_alloc2;
> }
>
> - pwm->clk_div = clk_get(dev, "pwm-tdiv");
> - if (IS_ERR(pwm->clk_div)) {
> + s3c_pwm->clk_div = clk_get(dev, "pwm-tdiv");
> + if (IS_ERR(s3c_pwm->clk_div)) {
> dev_err(dev, "failed to get pwm tdiv clk\n");
> - ret = PTR_ERR(pwm->clk_div);
> + ret = PTR_ERR(s3c_pwm->clk_div);
> goto err_clk_tin;
> }
>
> local_irq_save(flags);
>
> tcon = __raw_readl(S3C2410_TCON);
> - tcon |= pwm_tcon_invert(pwm);
> + tcon |= pwm_tcon_invert(s3c_pwm);
> __raw_writel(tcon, S3C2410_TCON);
>
> local_irq_restore(flags);
>
> + pops->pwm_config = s3c_pwm_config;
> + pops->pwm_enable = s3c_pwm_enable;
> + pops->pwm_disable = s3c_pwm_disable;
> + pops->name = pdev->name;
> +
> + pwm->dev = dev;
> + pwm->pwm_id = id;
> + pwm->pops = pops;
> + pwm->data = s3c_pwm;
>
> - ret = pwm_register(pwm);
> + s3c_pwm->duty_ns = -1;
> + s3c_pwm->period_ns = -1;
> + ret = pwm_device_register(pwm);
> if (ret) {
> dev_err(dev, "failed to register pwm\n");
> goto err_clk_tdiv;
> }
>
> - pwm_dbg(pwm, "config bits %02x\n",
> - (__raw_readl(S3C2410_TCON) >> pwm->tcon_base) & 0x0f);
> + dev_dbg(dev, "config bits %02x\n",
> + (__raw_readl(S3C2410_TCON) >> s3c_pwm->tcon_base) & 0x0f);
>
> dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n",
> - clk_get_rate(pwm->clk),
> - clk_get_rate(pwm->clk_div),
> - pwm_is_tdiv(pwm) ? "div" : "ext", pwm->tcon_base);
> + clk_get_rate(s3c_pwm->clk),
> + clk_get_rate(s3c_pwm->clk_div),
> + pwm_is_tdiv(s3c_pwm) ? "div" : "ext", s3c_pwm->tcon_base);
>
> platform_set_drvdata(pdev, pwm);
> return 0;
>
> - err_clk_tdiv:
> - clk_put(pwm->clk_div);
> +err_clk_tdiv:
> + clk_put(s3c_pwm->clk_div);
>
> - err_clk_tin:
> - clk_put(pwm->clk);
> +err_clk_tin:
> + clk_put(s3c_pwm->clk);
>
> - err_alloc:
> +err_alloc2:
> + kfree(pops);
> +
> +err_alloc1:
> kfree(pwm);
> +
> +err_alloc:
> + kfree(s3c_pwm);
> return ret;
> }
>
> static int __devexit s3c_pwm_remove(struct platform_device *pdev)
> {
> struct pwm_device *pwm = platform_get_drvdata(pdev);
> + struct s3c_pwm_device *s3c_pwm = pwm->data;
>
> - clk_put(pwm->clk_div);
> - clk_put(pwm->clk);
> + pwm_device_unregister(pwm);
> + clk_put(s3c_pwm->clk_div);
> + clk_put(s3c_pwm->clk);
> + kfree(s3c_pwm);
> + kfree(pwm->pops);
> kfree(pwm);
>
> return 0;
> @@ -384,13 +351,14 @@ static int __devexit s3c_pwm_remove(struct platform_device *pdev)
> static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state)
> {
> struct pwm_device *pwm = platform_get_drvdata(pdev);
> + struct s3c_pwm_device *s3c_pwm = pwm->data;
>
> /* No one preserve these values during suspend so reset them
> * Otherwise driver leaves PWM unconfigured if same values
> * passed to pwm_config
> */
> - pwm->period_ns = 0;
> - pwm->duty_ns = 0;
> + s3c_pwm->period_ns = 0;
> + s3c_pwm->duty_ns = 0;
>
> return 0;
> }
> @@ -398,11 +366,12 @@ static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state)
> static int s3c_pwm_resume(struct platform_device *pdev)
> {
> struct pwm_device *pwm = platform_get_drvdata(pdev);
> + struct s3c_pwm_device *s3c_pwm = pwm->data;
> unsigned long tcon;
>
> /* Restore invertion */
> tcon = __raw_readl(S3C2410_TCON);
> - tcon |= pwm_tcon_invert(pwm);
> + tcon |= pwm_tcon_invert(s3c_pwm);
> __raw_writel(tcon, S3C2410_TCON);
>
> return 0;
> diff --git a/arch/mips/jz4740/pwm.c b/arch/mips/jz4740/pwm.c
> index a26a6fa..9f46767 100644
> --- a/arch/mips/jz4740/pwm.c
> +++ b/arch/mips/jz4740/pwm.c
> @@ -152,7 +152,7 @@ int pwm_enable(struct pwm_device *pwm)
> return 0;
> }
>
> -void pwm_disable(struct pwm_device *pwm)
> +int pwm_disable(struct pwm_device *pwm)
> {
> uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
>
> diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
> index b0f2c00..6a6ea41 100644
> --- a/drivers/mfd/twl-core.c
> +++ b/drivers/mfd/twl-core.c
> @@ -129,6 +129,12 @@
> #define twl_has_pwrbutton() false
> #endif
>
> +#if defined CONFIG_TWL6030_PWM
> +#define twl_has_pwm() true
> +#else
> +#define twl_has_pwm() false
> +#endif
> +
> #define SUB_CHIP_ID0 0
> #define SUB_CHIP_ID1 1
> #define SUB_CHIP_ID2 2
> @@ -825,6 +831,13 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
> if (IS_ERR(child))
> return PTR_ERR(child);
> }
> + if (twl_has_pwm()) {
> + child = add_child(SUB_CHIP_ID2, "twl6030_pwm",
> + NULL, 0,
> + false, 0, 0);
> + if (IS_ERR(child))
> + return PTR_ERR(child);
> + }
>
> return 0;
> }
> diff --git a/drivers/mfd/twl6030-pwm.c b/drivers/mfd/twl6030-pwm.c
> index 5d25bdc..b78324b 100644
> --- a/drivers/mfd/twl6030-pwm.c
> +++ b/drivers/mfd/twl6030-pwm.c
> @@ -20,8 +20,10 @@
>
> #include <linux/module.h>
> #include <linux/platform_device.h>
> -#include <linux/i2c/twl.h>
> #include <linux/slab.h>
> +#include <linux/pwm.h>
> +#include <linux/err.h>
> +#include <linux/i2c/twl.h>
>
> #define LED_PWM_CTRL1 0xF4
> #define LED_PWM_CTRL2 0xF5
> @@ -45,15 +47,10 @@
>
> #define PWM_CTRL2_MODE_MASK 0x3
>
> -struct pwm_device {
> - const char *label;
> - unsigned int pwm_id;
> -};
> -
> -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +int twl6030_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> {
> u8 duty_cycle;
> - int ret;
> + int ret = 0;
>
> if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
> return -EINVAL;
> @@ -69,12 +66,11 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> }
> return 0;
> }
> -EXPORT_SYMBOL(pwm_config);
>
> -int pwm_enable(struct pwm_device *pwm)
> +int twl6030_pwm_enable(struct pwm_device *pwm)
> {
> u8 val;
> - int ret;
> + int ret = 0;
>
> ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
> if (ret < 0) {
> @@ -95,18 +91,17 @@ int pwm_enable(struct pwm_device *pwm)
> twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
> return 0;
> }
> -EXPORT_SYMBOL(pwm_enable);
>
> -void pwm_disable(struct pwm_device *pwm)
> +int twl6030_pwm_disable(struct pwm_device *pwm)
> {
> u8 val;
> - int ret;
> + int ret = 0;
>
> ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
> if (ret < 0) {
> pr_err("%s: Failed to disable PWM, Error %d\n",
> pwm->label, ret);
> - return;
> + return ret;
> }
>
> val &= ~PWM_CTRL2_MODE_MASK;
> @@ -116,48 +111,86 @@ void pwm_disable(struct pwm_device *pwm)
> if (ret < 0) {
> pr_err("%s: Failed to disable PWM, Error %d\n",
> pwm->label, ret);
> - return;
> }
> - return;
> + return ret;
> }
> -EXPORT_SYMBOL(pwm_disable);
>
> -struct pwm_device *pwm_request(int pwm_id, const char *label)
> +static int __devinit twl6030_pwm_probe(struct platform_device *pdev)
> {
> - u8 val;
> - int ret;
> struct pwm_device *pwm;
> + struct pwm_ops *pops;
> + int ret;
> + u8 val;
>
> pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> if (pwm == NULL) {
> - pr_err("%s: failed to allocate memory\n", label);
> - return NULL;
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + return -ENOMEM;
> + }
> + pops = kzalloc(sizeof(struct pwm_ops), GFP_KERNEL);
> + if (pops == NULL) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + kfree(pwm);
> + return -ENOMEM;
> }
>
> - pwm->label = label;
> - pwm->pwm_id = pwm_id;
> -
> + pops->pwm_config = twl6030_pwm_config;
> + pops->pwm_enable = twl6030_pwm_enable;
> + pops->pwm_disable = twl6030_pwm_disable;
> + pops->name = &pdev->name;
> + pwm->dev = &pdev->dev;
> + pwm->pwm_id = pdev->id;
> + pwm->pops = pops;
> + ret = pwm_device_register(pwm);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to register pwm device\n");
> + kfree(pwm);
> + kfree(pops);
> + return ret;
> + }
> + platform_set_drvdata(pdev, pwm);
> /* Configure PWM */
> val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
> - PWM_CTRL2_MODE_HW;
> + PWM_CTRL2_MODE_HW;
>
> ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
> -
> if (ret < 0) {
> - pr_err("%s: Failed to configure PWM, Error %d\n",
> - pwm->label, ret);
> -
> - kfree(pwm);
> - return NULL;
> + dev_err(&pdev->dev, "Failed to configure PWM, Error %d\n", ret);
> + return ret;
> }
> -
> - return pwm;
> + dev_dbg(&pdev->dev, "pwm probe successful\n");
> + return ret;
> }
> -EXPORT_SYMBOL(pwm_request);
>
> -void pwm_free(struct pwm_device *pwm)
> +static int __devexit twl6030_pwm_remove(struct platform_device *pdev)
> {
> - pwm_disable(pwm);
> + struct pwm_device *pwm = platform_get_drvdata(pdev);
> +
> + pwm_device_unregister(pwm);
> + kfree(pwm->pops);
> kfree(pwm);
> + dev_dbg(&pdev->dev, "pwm driver removed\n");
> + return 0;
> }
> -EXPORT_SYMBOL(pwm_free);
> +
> +static struct platform_driver twl6030_pwm_driver = {
> + .driver = {
> + .name = "twl6030_pwm",
> + .owner = THIS_MODULE,
> + },
> + .probe = twl6030_pwm_probe,
> + .remove = __devexit_p(twl6030_pwm_remove),
> +};
> +
> +static int __init twl6030_pwm_init(void)
> +{
> + return platform_driver_register(&twl6030_pwm_driver);
> +}
> +
> +static void __exit twl6030_pwm_deinit(void)
> +{
> + platform_driver_unregister(&twl6030_pwm_driver);
> +}
> +
> +subsys_initcall(twl6030_pwm_init);
> +module_exit(twl6030_pwm_deinit);
> diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c
> index 54e3d05..d2b23b6 100644
> --- a/drivers/misc/ab8500-pwm.c
> +++ b/drivers/misc/ab8500-pwm.c
> @@ -23,16 +23,9 @@
> #define ENABLE_PWM 1
> #define DISABLE_PWM 0
>
> -struct pwm_device {
> - struct device *dev;
> - struct list_head node;
> - const char *label;
> - unsigned int pwm_id;
> -};
> -
> static LIST_HEAD(pwm_list);
>
> -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +int ab8500_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> {
> int ret = 0;
> unsigned int higher_val, lower_val;
> @@ -60,23 +53,21 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
>
> return ret;
> }
> -EXPORT_SYMBOL(pwm_config);
>
> -int pwm_enable(struct pwm_device *pwm)
> +int ab8500_pwm_enable(struct pwm_device *pwm)
> {
> int ret;
>
> ret = abx500_mask_and_set_register_interruptible(pwm->dev,
> AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
> - 1 << (pwm->pwm_id-1), ENABLE_PWM);
> + 1 << (pwm->pwm_id-1), 1 << (pwm->pwm_id-1));
> if (ret < 0)
> dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
> pwm->label, ret);
> return ret;
> }
> -EXPORT_SYMBOL(pwm_enable);
>
> -void pwm_disable(struct pwm_device *pwm)
> +int ab8500_pwm_disable(struct pwm_device *pwm)
> {
> int ret;
>
> @@ -86,58 +77,56 @@ void pwm_disable(struct pwm_device *pwm)
> if (ret < 0)
> dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
> pwm->label, ret);
> - return;
> -}
> -EXPORT_SYMBOL(pwm_disable);
> -
> -struct pwm_device *pwm_request(int pwm_id, const char *label)
> -{
> - struct pwm_device *pwm;
> -
> - list_for_each_entry(pwm, &pwm_list, node) {
> - if (pwm->pwm_id == pwm_id) {
> - pwm->label = label;
> - pwm->pwm_id = pwm_id;
> - return pwm;
> - }
> - }
> -
> - return ERR_PTR(-ENOENT);
> -}
> -EXPORT_SYMBOL(pwm_request);
> -
> -void pwm_free(struct pwm_device *pwm)
> -{
> - pwm_disable(pwm);
> + return ret;
> }
> -EXPORT_SYMBOL(pwm_free);
>
> static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
> {
> - struct pwm_device *pwm;
> + int ret = 0;
> + struct pwm_ops *pops;
> + struct pwm_device *pwm_dev;
> /*
> * Nothing to be done in probe, this is required to get the
> * device which is required for ab8500 read and write
> */
> - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> - if (pwm == NULL) {
> + pops = kzalloc(sizeof(struct pwm_ops), GFP_KERNEL);
> + if (pops == NULL) {
> dev_err(&pdev->dev, "failed to allocate memory\n");
> return -ENOMEM;
> }
> - pwm->dev = &pdev->dev;
> - pwm->pwm_id = pdev->id;
> - list_add_tail(&pwm->node, &pwm_list);
> - platform_set_drvdata(pdev, pwm);
> - dev_dbg(pwm->dev, "pwm probe successful\n");
> - return 0;
> + pwm_dev = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> + if (pwm_dev == NULL) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + kfree(pops);
> + return -ENOMEM;
> + }
> + pops->pwm_config = ab8500_pwm_config;
> + pops->pwm_enable = ab8500_pwm_enable;
> + pops->pwm_disable = ab8500_pwm_disable;
> + pops->name = "ab8500";
> + pwm_dev->dev = &pdev->dev;
> + pwm_dev->pwm_id = pdev->id;
> + pwm_dev->pops = pops;
> + ret = pwm_device_register(pwm_dev);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to register pwm device\n");
> + kfree(pwm_dev);
> + kfree(pops);
> + return ret;
> + }
> + platform_set_drvdata(pdev, pwm_dev);
> + dev_dbg(&pdev->dev, "pwm probe successful\n");
> + return ret;
> }
>
> static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
> {
> - struct pwm_device *pwm = platform_get_drvdata(pdev);
> - list_del(&pwm->node);
> + struct pwm_device *pwm_dev = platform_get_drvdata(pdev);
> +
> + pwm_device_unregister(pwm_dev);
> dev_dbg(&pdev->dev, "pwm driver removed\n");
> - kfree(pwm);
> + kfree(pwm_dev->pops);
> + kfree(pwm_dev);
> return 0;
> }
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 5d10106..a88640c 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -4,6 +4,7 @@
>
> menuconfig PWM_DEVICES
> bool "PWM devices"
> + depends on ARM
> default y
> ---help---
> Say Y here to get to see options for device drivers from various
> diff --git a/drivers/pwm/pwm-core.c b/drivers/pwm/pwm-core.c
> index b84027a..3a0d426 100644
Why can't these changes be in the initial patch which adds pwm-core?
> --- a/drivers/pwm/pwm-core.c
> +++ b/drivers/pwm/pwm-core.c
> @@ -11,11 +11,6 @@
> #include <linux/err.h>
> #include <linux/pwm.h>
>
> -struct pwm_device {
> - struct pwm_ops *pops;
> - int pwm_id;
> -};
> -
> struct pwm_dev_info {
> struct pwm_device *pwm_dev;
> struct list_head list;
> @@ -40,9 +35,9 @@ int pwm_enable(struct pwm_device *pwm)
> }
> EXPORT_SYMBOL(pwm_enable);
>
> -void pwm_disable(struct pwm_device *pwm)
> +int pwm_disable(struct pwm_device *pwm)
> {
> - pwm->pops->pwm_disable(pwm);
> + return pwm->pops->pwm_disable(pwm);
> }
> EXPORT_SYMBOL(pwm_disable);
>
> diff --git a/include/linux/pwm.h b/include/linux/pwm.h
> index 6e7da1f..4344c0b 100644
> --- a/include/linux/pwm.h
> +++ b/include/linux/pwm.h
> @@ -1,14 +1,29 @@
> #ifndef __LINUX_PWM_H
> #define __LINUX_PWM_H
>
> -struct pwm_device;
> +/*
> + * TODO: #if defined CONFIG_PWM_CORE has to be removed after mips jz4740
> + * pwm driver aligning with pwm-core.c driver.
> + */
> +#if defined CONFIG_PWM_CORE
> +struct pwm_device {
> + struct pwm_ops *pops;
> + struct device *dev;
> + struct list_head node;
> + const char *label;
> + unsigned int pwm_id;
> + void *data;
> +};
>
> struct pwm_ops {
> int (*pwm_config)(struct pwm_device *pwm, int duty_ns, int period_ns);
> int (*pwm_enable)(struct pwm_device *pwm);
> int (*pwm_disable)(struct pwm_device *pwm);
> - char *name;
> + const char *name;
> };
> +#else
> +struct pwm_device;
> +#endif
>
> /*
> * pwm_request - request a PWM device
> @@ -33,7 +48,7 @@ int pwm_enable(struct pwm_device *pwm);
> /*
> * pwm_disable - stop a PWM output toggling
> */
> -void pwm_disable(struct pwm_device *pwm);
> +int pwm_disable(struct pwm_device *pwm);
>
> int pwm_device_register(struct pwm_device *pwm_dev);
> int pwm_device_unregister(struct pwm_device *pwm_dev);
More information about the linux-arm-kernel
mailing list