[PATCH 6/7] pwm: move existing pwm driver to drivers/pwm
Eric Miao
eric.y.miao at gmail.com
Tue Sep 28 04:02:28 EDT 2010
On Tue, Sep 28, 2010 at 3:40 PM, Arun Murthy <arun.murthy at stericsson.com> wrote:
> As of now only ab8500 and twl6030 are moved.
>
You can use 'git format-patch -M' to reduce the patch size when renaming
is involved.
> Signed-off-by: Arun Murthy <arun.murthy at stericsson.com>
> Acked-by: Linus Walleij <linus.walleij at stericsson.com>
> ---
> drivers/mfd/Kconfig | 9 --
> drivers/mfd/Makefile | 1 -
> drivers/mfd/twl6030-pwm.c | 196 ---------------------------------------------
> drivers/misc/Kconfig | 9 --
> drivers/misc/Makefile | 1 -
> drivers/misc/ab8500-pwm.c | 157 ------------------------------------
> drivers/pwm/Kconfig | 18 ++++
> drivers/pwm/Makefile | 3 +
> drivers/pwm/pwm-ab8500.c | 157 ++++++++++++++++++++++++++++++++++++
> drivers/pwm/pwm-twl6040.c | 196 +++++++++++++++++++++++++++++++++++++++++++++
> 10 files changed, 374 insertions(+), 373 deletions(-)
> delete mode 100644 drivers/mfd/twl6030-pwm.c
> delete mode 100644 drivers/misc/ab8500-pwm.c
> create mode 100644 drivers/pwm/pwm-ab8500.c
> create mode 100644 drivers/pwm/pwm-twl6040.c
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 256fabd..ab1d376 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -186,15 +186,6 @@ config TWL4030_CODEC
> select MFD_CORE
> default n
>
> -config TWL6030_PWM
> - tristate "TWL6030 PWM (Pulse Width Modulator) Support"
> - depends on TWL4030_CORE
> - select HAVE_PWM
> - default n
> - help
> - Say yes here if you want support for TWL6030 PWM.
> - This is used to control charging LED brightness.
> -
> config MFD_STMPE
> bool "Support STMicroelectronics STMPE"
> depends on I2C=y && GENERIC_HARDIRQS
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index d5968cd..1a89dbf 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -37,7 +37,6 @@ obj-$(CONFIG_MENELAUS) += menelaus.o
> obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
> obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
> obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
> -obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
>
> obj-$(CONFIG_MFD_MC13783) += mc13783-core.o
>
> diff --git a/drivers/mfd/twl6030-pwm.c b/drivers/mfd/twl6030-pwm.c
> deleted file mode 100644
> index b78324b..0000000
> --- a/drivers/mfd/twl6030-pwm.c
> +++ /dev/null
> @@ -1,196 +0,0 @@
> -/*
> - * twl6030_pwm.c
> - * Driver for PHOENIX (TWL6030) Pulse Width Modulator
> - *
> - * Copyright (C) 2010 Texas Instruments
> - * Author: Hemanth V <hemanthv at ti.com>
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms of the GNU General Public License version 2 as published by
> - * the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include <linux/module.h>
> -#include <linux/platform_device.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
> -
> -/* Max value for CTRL1 register */
> -#define PWM_CTRL1_MAX 255
> -
> -/* Pull down disable */
> -#define PWM_CTRL2_DIS_PD (1 << 6)
> -
> -/* Current control 2.5 milli Amps */
> -#define PWM_CTRL2_CURR_02 (2 << 4)
> -
> -/* LED supply source */
> -#define PWM_CTRL2_SRC_VAC (1 << 2)
> -
> -/* LED modes */
> -#define PWM_CTRL2_MODE_HW (0 << 0)
> -#define PWM_CTRL2_MODE_SW (1 << 0)
> -#define PWM_CTRL2_MODE_DIS (2 << 0)
> -
> -#define PWM_CTRL2_MODE_MASK 0x3
> -
> -int twl6030_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> -{
> - u8 duty_cycle;
> - int ret = 0;
> -
> - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
> - return -EINVAL;
> -
> - duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
> -
> - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
> -
> - if (ret < 0) {
> - pr_err("%s: Failed to configure PWM, Error %d\n",
> - pwm->label, ret);
> - return ret;
> - }
> - return 0;
> -}
> -
> -int twl6030_pwm_enable(struct pwm_device *pwm)
> -{
> - u8 val;
> - int ret = 0;
> -
> - ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
> - if (ret < 0) {
> - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
> - return ret;
> - }
> -
> - /* Change mode to software control */
> - val &= ~PWM_CTRL2_MODE_MASK;
> - val |= PWM_CTRL2_MODE_SW;
> -
> - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
> - if (ret < 0) {
> - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
> - return ret;
> - }
> -
> - twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
> - return 0;
> -}
> -
> -int twl6030_pwm_disable(struct pwm_device *pwm)
> -{
> - u8 val;
> - 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 ret;
> - }
> -
> - val &= ~PWM_CTRL2_MODE_MASK;
> - val |= PWM_CTRL2_MODE_HW;
> -
> - ret = twl_i2c_write_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 ret;
> -}
> -
> -static int __devinit twl6030_pwm_probe(struct platform_device *pdev)
> -{
> - struct pwm_device *pwm;
> - struct pwm_ops *pops;
> - int ret;
> - u8 val;
> -
> - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> - if (pwm == 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;
> - }
> -
> - 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;
> -
> - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
> - if (ret < 0) {
> - dev_err(&pdev->dev, "Failed to configure PWM, Error %d\n", ret);
> - return ret;
> - }
> - dev_dbg(&pdev->dev, "pwm probe successful\n");
> - return ret;
> -}
> -
> -static int __devexit twl6030_pwm_remove(struct platform_device *pdev)
> -{
> - 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;
> -}
> -
> -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/Kconfig b/drivers/misc/Kconfig
> index ff8ea55..2c38d4e 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -62,15 +62,6 @@ config ATMEL_PWM
> purposes including software controlled power-efficient backlights
> on LCD displays, motor control, and waveform generation.
>
> -config AB8500_PWM
> - bool "AB8500 PWM support"
> - depends on AB8500_CORE
> - select HAVE_PWM
> - help
> - This driver exports functions to enable/disble/config/free Pulse
> - Width Modulation in the Analog Baseband Chip AB8500.
> - It is used by led and backlight driver to control the intensity.
> -
> config ATMEL_TCLIB
> bool "Atmel AT32/AT91 Timer/Counter Library"
> depends on (AVR32 || ARCH_AT91)
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 5da82965..21b4761 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -35,5 +35,4 @@ obj-y += eeprom/
> obj-y += cb710/
> obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o
> obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
> -obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
> obj-$(CONFIG_PCH_PHUB) += pch_phub.o
> diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c
> deleted file mode 100644
> index d2b23b6..0000000
> --- a/drivers/misc/ab8500-pwm.c
> +++ /dev/null
> @@ -1,157 +0,0 @@
> -/*
> - * Copyright (C) ST-Ericsson SA 2010
> - *
> - * Author: Arun R Murthy <arun.murthy at stericsson.com>
> - * License terms: GNU General Public License (GPL) version 2
> - */
> -#include <linux/err.h>
> -#include <linux/platform_device.h>
> -#include <linux/slab.h>
> -#include <linux/pwm.h>
> -#include <linux/mfd/ab8500.h>
> -#include <linux/mfd/abx500.h>
> -
> -/*
> - * PWM Out generators
> - * Bank: 0x10
> - */
> -#define AB8500_PWM_OUT_CTRL1_REG 0x60
> -#define AB8500_PWM_OUT_CTRL2_REG 0x61
> -#define AB8500_PWM_OUT_CTRL7_REG 0x66
> -
> -/* backlight driver constants */
> -#define ENABLE_PWM 1
> -#define DISABLE_PWM 0
> -
> -static LIST_HEAD(pwm_list);
> -
> -int ab8500_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> -{
> - int ret = 0;
> - unsigned int higher_val, lower_val;
> - u8 reg;
> -
> - /*
> - * get the first 8 bits that are be written to
> - * AB8500_PWM_OUT_CTRL1_REG[0:7]
> - */
> - lower_val = duty_ns & 0x00FF;
> - /*
> - * get bits [9:10] that are to be written to
> - * AB8500_PWM_OUT_CTRL2_REG[0:1]
> - */
> - higher_val = ((duty_ns & 0x0300) >> 8);
> -
> - reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2);
> -
> - ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
> - reg, (u8)lower_val);
> - if (ret < 0)
> - return ret;
> - ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
> - (reg + 1), (u8)higher_val);
> -
> - return ret;
> -}
> -
> -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), 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;
> -}
> -
> -int ab8500_pwm_disable(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), DISABLE_PWM);
> - if (ret < 0)
> - dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
> - pwm->label, ret);
> - return ret;
> -}
> -
> -static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
> -{
> - 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
> - */
> - pops = kzalloc(sizeof(struct pwm_ops), GFP_KERNEL);
> - if (pops == NULL) {
> - dev_err(&pdev->dev, "failed to allocate memory\n");
> - return -ENOMEM;
> - }
> - 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_dev = platform_get_drvdata(pdev);
> -
> - pwm_device_unregister(pwm_dev);
> - dev_dbg(&pdev->dev, "pwm driver removed\n");
> - kfree(pwm_dev->pops);
> - kfree(pwm_dev);
> - return 0;
> -}
> -
> -static struct platform_driver ab8500_pwm_driver = {
> - .driver = {
> - .name = "ab8500-pwm",
> - .owner = THIS_MODULE,
> - },
> - .probe = ab8500_pwm_probe,
> - .remove = __devexit_p(ab8500_pwm_remove),
> -};
> -
> -static int __init ab8500_pwm_init(void)
> -{
> - return platform_driver_register(&ab8500_pwm_driver);
> -}
> -
> -static void __exit ab8500_pwm_exit(void)
> -{
> - platform_driver_unregister(&ab8500_pwm_driver);
> -}
> -
> -subsys_initcall(ab8500_pwm_init);
> -module_exit(ab8500_pwm_exit);
> -MODULE_AUTHOR("Arun MURTHY <arun.murthy at stericsson.com>");
> -MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
> -MODULE_ALIAS("AB8500 PWM driver");
> -MODULE_LICENSE("GPL v2");
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index a88640c..e347365 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -14,4 +14,22 @@ menuconfig PWM_DEVICES
>
> if PWM_DEVICES
>
> +config AB8500_PWM
> + bool "AB8500 PWM support"
> + depends on AB8500_CORE
> + select HAVE_PWM
> + help
> + This driver exports functions to enable/disble/config/free Pulse
> + Width Modulation in the Analog Baseband Chip AB8500.
> + It is used by led and backlight driver to control the intensity.
> +
> +config TWL6030_PWM
> + tristate "TWL6030 PWM (Pulse Width Modulator) Support"
> + depends on TWL4030_CORE
> + select HAVE_PWM
> + default n
> + help
> + Say yes here if you want support for TWL6030 PWM.
> + This is used to control charging LED brightness.
> +
> endif # PWM_DEVICES
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 552f969..f35afb4 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -1 +1,4 @@
> obj-$(CONFIG_PWM_DEVICES) += pwm-core.o
> +
> +obj-$(CONFIG_AB8500_PWM) += pwm-ab8500.o
> +obj-$(CONFIG_TWL6030_PWM) += pwm-twl6030.o
> diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c
> new file mode 100644
> index 0000000..d2b23b6
> --- /dev/null
> +++ b/drivers/pwm/pwm-ab8500.c
> @@ -0,0 +1,157 @@
> +/*
> + * Copyright (C) ST-Ericsson SA 2010
> + *
> + * Author: Arun R Murthy <arun.murthy at stericsson.com>
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/pwm.h>
> +#include <linux/mfd/ab8500.h>
> +#include <linux/mfd/abx500.h>
> +
> +/*
> + * PWM Out generators
> + * Bank: 0x10
> + */
> +#define AB8500_PWM_OUT_CTRL1_REG 0x60
> +#define AB8500_PWM_OUT_CTRL2_REG 0x61
> +#define AB8500_PWM_OUT_CTRL7_REG 0x66
> +
> +/* backlight driver constants */
> +#define ENABLE_PWM 1
> +#define DISABLE_PWM 0
> +
> +static LIST_HEAD(pwm_list);
> +
> +int ab8500_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +{
> + int ret = 0;
> + unsigned int higher_val, lower_val;
> + u8 reg;
> +
> + /*
> + * get the first 8 bits that are be written to
> + * AB8500_PWM_OUT_CTRL1_REG[0:7]
> + */
> + lower_val = duty_ns & 0x00FF;
> + /*
> + * get bits [9:10] that are to be written to
> + * AB8500_PWM_OUT_CTRL2_REG[0:1]
> + */
> + higher_val = ((duty_ns & 0x0300) >> 8);
> +
> + reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2);
> +
> + ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
> + reg, (u8)lower_val);
> + if (ret < 0)
> + return ret;
> + ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
> + (reg + 1), (u8)higher_val);
> +
> + return ret;
> +}
> +
> +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), 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;
> +}
> +
> +int ab8500_pwm_disable(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), DISABLE_PWM);
> + if (ret < 0)
> + dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
> + pwm->label, ret);
> + return ret;
> +}
> +
> +static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
> +{
> + 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
> + */
> + pops = kzalloc(sizeof(struct pwm_ops), GFP_KERNEL);
> + if (pops == NULL) {
> + dev_err(&pdev->dev, "failed to allocate memory\n");
> + return -ENOMEM;
> + }
> + 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_dev = platform_get_drvdata(pdev);
> +
> + pwm_device_unregister(pwm_dev);
> + dev_dbg(&pdev->dev, "pwm driver removed\n");
> + kfree(pwm_dev->pops);
> + kfree(pwm_dev);
> + return 0;
> +}
> +
> +static struct platform_driver ab8500_pwm_driver = {
> + .driver = {
> + .name = "ab8500-pwm",
> + .owner = THIS_MODULE,
> + },
> + .probe = ab8500_pwm_probe,
> + .remove = __devexit_p(ab8500_pwm_remove),
> +};
> +
> +static int __init ab8500_pwm_init(void)
> +{
> + return platform_driver_register(&ab8500_pwm_driver);
> +}
> +
> +static void __exit ab8500_pwm_exit(void)
> +{
> + platform_driver_unregister(&ab8500_pwm_driver);
> +}
> +
> +subsys_initcall(ab8500_pwm_init);
> +module_exit(ab8500_pwm_exit);
> +MODULE_AUTHOR("Arun MURTHY <arun.murthy at stericsson.com>");
> +MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
> +MODULE_ALIAS("AB8500 PWM driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/pwm/pwm-twl6040.c b/drivers/pwm/pwm-twl6040.c
> new file mode 100644
> index 0000000..b78324b
> --- /dev/null
> +++ b/drivers/pwm/pwm-twl6040.c
> @@ -0,0 +1,196 @@
> +/*
> + * twl6030_pwm.c
> + * Driver for PHOENIX (TWL6030) Pulse Width Modulator
> + *
> + * Copyright (C) 2010 Texas Instruments
> + * Author: Hemanth V <hemanthv at ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.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
> +
> +/* Max value for CTRL1 register */
> +#define PWM_CTRL1_MAX 255
> +
> +/* Pull down disable */
> +#define PWM_CTRL2_DIS_PD (1 << 6)
> +
> +/* Current control 2.5 milli Amps */
> +#define PWM_CTRL2_CURR_02 (2 << 4)
> +
> +/* LED supply source */
> +#define PWM_CTRL2_SRC_VAC (1 << 2)
> +
> +/* LED modes */
> +#define PWM_CTRL2_MODE_HW (0 << 0)
> +#define PWM_CTRL2_MODE_SW (1 << 0)
> +#define PWM_CTRL2_MODE_DIS (2 << 0)
> +
> +#define PWM_CTRL2_MODE_MASK 0x3
> +
> +int twl6030_pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +{
> + u8 duty_cycle;
> + int ret = 0;
> +
> + if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
> + return -EINVAL;
> +
> + duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
> +
> + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
> +
> + if (ret < 0) {
> + pr_err("%s: Failed to configure PWM, Error %d\n",
> + pwm->label, ret);
> + return ret;
> + }
> + return 0;
> +}
> +
> +int twl6030_pwm_enable(struct pwm_device *pwm)
> +{
> + u8 val;
> + int ret = 0;
> +
> + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
> + if (ret < 0) {
> + pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
> + return ret;
> + }
> +
> + /* Change mode to software control */
> + val &= ~PWM_CTRL2_MODE_MASK;
> + val |= PWM_CTRL2_MODE_SW;
> +
> + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
> + if (ret < 0) {
> + pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
> + return ret;
> + }
> +
> + twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
> + return 0;
> +}
> +
> +int twl6030_pwm_disable(struct pwm_device *pwm)
> +{
> + u8 val;
> + 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 ret;
> + }
> +
> + val &= ~PWM_CTRL2_MODE_MASK;
> + val |= PWM_CTRL2_MODE_HW;
> +
> + ret = twl_i2c_write_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 ret;
> +}
> +
> +static int __devinit twl6030_pwm_probe(struct platform_device *pdev)
> +{
> + struct pwm_device *pwm;
> + struct pwm_ops *pops;
> + int ret;
> + u8 val;
> +
> + pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> + if (pwm == 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;
> + }
> +
> + 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;
> +
> + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "Failed to configure PWM, Error %d\n", ret);
> + return ret;
> + }
> + dev_dbg(&pdev->dev, "pwm probe successful\n");
> + return ret;
> +}
> +
> +static int __devexit twl6030_pwm_remove(struct platform_device *pdev)
> +{
> + 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;
> +}
> +
> +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);
> --
> 1.7.2.dirty
>
>
More information about the linux-arm-kernel
mailing list