[PATCH 6/7] pwm: move existing pwm driver to drivers/pwm
From: Eric Miao <hidden>
Date: 2010-09-28 08:02:28
On Tue, Sep 28, 2010 at 3:40 PM, Arun Murthy [off-list ref] 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.
quoted hunk
Signed-off-by: Arun Murthy <redacted> Acked-by: Linus Walleij <redacted> --- ?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.cdiff --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_HARDIRQSdiff --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.odiff --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@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.odiff --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@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@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_DEVICESdiff --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.odiff --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@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@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@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