* [PATCHv2 0/1] u8500: led and backlight driver @ 2010-09-06 6:04 Arun Murthy 2010-09-06 6:04 ` [PATCHv2 1/1] u8500: ab8500-pwm: Add pwm driver Arun Murthy 0 siblings, 1 reply; 3+ messages in thread From: Arun Murthy @ 2010-09-06 6:04 UTC (permalink / raw) To: sameo, riku.voipio, mike Cc: linux-kernel, STEricsson_nomadik_linux, arun.murthy Implement a generic pwm driver that makes use of the existing generic led and backlight driver based on pwm(drivers/leds/leds-pwm.c and drivers/video/backlight/pwm_bl.c ). Implemented comments from Mike Rapoport. Arun Murthy (1): u8500: ab8500-pwm: Add pwm driver drivers/mfd/ab8500-core.c | 13 +++- drivers/misc/Kconfig | 9 +++ drivers/misc/Makefile | 1 + drivers/misc/ab8500-pwm.c | 174 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 1 deletions(-) create mode 100644 drivers/misc/ab8500-pwm.c -- 1.7.2.dirty ^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCHv2 1/1] u8500: ab8500-pwm: Add pwm driver 2010-09-06 6:04 [PATCHv2 0/1] u8500: led and backlight driver Arun Murthy @ 2010-09-06 6:04 ` Arun Murthy 2010-09-06 6:17 ` Mike Rapoport 0 siblings, 1 reply; 3+ messages in thread From: Arun Murthy @ 2010-09-06 6:04 UTC (permalink / raw) To: sameo, riku.voipio, mike Cc: linux-kernel, STEricsson_nomadik_linux, arun.murthy This patch adds a Pulse Width Modulation driver for Analog Baseband Chip AB8500. Signed-off-by: Arun Murthy <arun.murthy@stericsson.com> Acked-by: Linus Walleij <linus.walleij@stericsson.com> --- drivers/mfd/ab8500-core.c | 13 +++- drivers/misc/Kconfig | 9 +++ drivers/misc/Makefile | 1 + drivers/misc/ab8500-pwm.c | 174 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 1 deletions(-) create mode 100644 drivers/misc/ab8500-pwm.c diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6548f50..67d7361 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -397,7 +397,18 @@ static struct mfd_cell ab8500_devs[] = { { .name = "ab8500-charger", }, { .name = "ab8500-audio", }, { .name = "ab8500-usb", }, - { .name = "ab8500-pwm", }, + { + .name = "ab8500-pwm", + .id = 1, + }, + { + .name = "ab8500-pwm", + .id = 2, + }, + { + .name = "ab8500-pwm", + .id = 3, + }, { .name = "ab8500-regulator", }, }; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 9df5b75..fcf2e7f 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -62,6 +62,15 @@ 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 Ananlog 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 255a80d..33bc441 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -35,3 +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 diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c new file mode 100644 index 0000000..e25c575 --- /dev/null +++ b/drivers/misc/ab8500-pwm.c @@ -0,0 +1,174 @@ +/* + * 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 + +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 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; +} +EXPORT_SYMBOL(pwm_config); + +int 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); + 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 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; +} +EXPORT_SYMBOL(pwm_disable); + +struct pwm_device *pwm_request(int pwm_id, const char *label) +{ + struct pwm_device *pwm; + int found = 0; + + list_for_each_entry(pwm, &pwm_list, node) { + if (pwm->pwm_id == pwm_id) { + found = 1; + break; + } + } + + if (found) { + pwm->label = label; + pwm->pwm_id = pwm_id; + } else + pwm = ERR_PTR(-ENOENT); + + return pwm; +} +EXPORT_SYMBOL(pwm_request); + +void pwm_free(struct pwm_device *pwm) +{ + pwm_disable(pwm); +} +EXPORT_SYMBOL(pwm_free); + +static int __devinit ab8500_pwm_probe(struct platform_device *pdev) +{ + struct pwm_device *pwm; + /* + * 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) { + 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; +} + +static int __devexit ab8500_pwm_remove(struct platform_device *pdev) +{ + struct pwm_device *pwm = platform_get_drvdata(pdev); + list_del(&pwm->node); + dev_dbg(&pdev->dev, "pwm driver removed\n"); + kfree(pwm); + 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"); -- 1.7.2.dirty ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCHv2 1/1] u8500: ab8500-pwm: Add pwm driver 2010-09-06 6:04 ` [PATCHv2 1/1] u8500: ab8500-pwm: Add pwm driver Arun Murthy @ 2010-09-06 6:17 ` Mike Rapoport 0 siblings, 0 replies; 3+ messages in thread From: Mike Rapoport @ 2010-09-06 6:17 UTC (permalink / raw) To: Arun Murthy Cc: sameo, riku.voipio, linux-kernel, STEricsson_nomadik_linux, Mike Rapoport Arun Murthy wrote: > This patch adds a Pulse Width Modulation driver for Analog Baseband > Chip AB8500. > > Signed-off-by: Arun Murthy <arun.murthy@stericsson.com> > Acked-by: Linus Walleij <linus.walleij@stericsson.com> Overall looks good to me. Just some nitpicking comments below. > --- > drivers/mfd/ab8500-core.c | 13 +++- > drivers/misc/Kconfig | 9 +++ > drivers/misc/Makefile | 1 + > drivers/misc/ab8500-pwm.c | 174 +++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 196 insertions(+), 1 deletions(-) > create mode 100644 drivers/misc/ab8500-pwm.c > > diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c > index 6548f50..67d7361 100644 > --- a/drivers/mfd/ab8500-core.c > +++ b/drivers/mfd/ab8500-core.c > @@ -397,7 +397,18 @@ static struct mfd_cell ab8500_devs[] = { > { .name = "ab8500-charger", }, > { .name = "ab8500-audio", }, > { .name = "ab8500-usb", }, > - { .name = "ab8500-pwm", }, > + { > + .name = "ab8500-pwm", > + .id = 1, > + }, > + { > + .name = "ab8500-pwm", > + .id = 2, > + }, > + { > + .name = "ab8500-pwm", > + .id = 3, > + }, > { .name = "ab8500-regulator", }, I'd move pwm cells after the regulator to make the code nicer. Feel free, though, to discard this comment. > }; > > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig > index 9df5b75..fcf2e7f 100644 > --- a/drivers/misc/Kconfig > +++ b/drivers/misc/Kconfig > @@ -62,6 +62,15 @@ 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 Ananlog 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 255a80d..33bc441 100644 > --- a/drivers/misc/Makefile > +++ b/drivers/misc/Makefile > @@ -35,3 +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 > diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c > new file mode 100644 > index 0000000..e25c575 > --- /dev/null > +++ b/drivers/misc/ab8500-pwm.c > @@ -0,0 +1,174 @@ > +/* > + * 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 > + > +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 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; > +} > +EXPORT_SYMBOL(pwm_config); > + > +int 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); > + 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 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; > +} > +EXPORT_SYMBOL(pwm_disable); > + > +struct pwm_device *pwm_request(int pwm_id, const char *label) > +{ > + struct pwm_device *pwm; > + int found = 0; > + > + list_for_each_entry(pwm, &pwm_list, node) { > + if (pwm->pwm_id == pwm_id) { > + found = 1; > + break; > + } > + } > + > + if (found) { > + pwm->label = label; > + pwm->pwm_id = pwm_id; > + } else > + pwm = ERR_PTR(-ENOENT); > + Braces are required for else clause (see CodingStyle). Besides, if you move pwm fields initialization into the for_each loop you can just abandon the 'if (found)' statement. > + return pwm; > +} > +EXPORT_SYMBOL(pwm_request); > + > +void pwm_free(struct pwm_device *pwm) > +{ > + pwm_disable(pwm); > +} > +EXPORT_SYMBOL(pwm_free); > + > +static int __devinit ab8500_pwm_probe(struct platform_device *pdev) > +{ > + struct pwm_device *pwm; > + /* > + * 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) { > + 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; > +} > + > +static int __devexit ab8500_pwm_remove(struct platform_device *pdev) > +{ > + struct pwm_device *pwm = platform_get_drvdata(pdev); > + list_del(&pwm->node); > + dev_dbg(&pdev->dev, "pwm driver removed\n"); > + kfree(pwm); > + 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"); -- Sincerely yours, Mike. ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2010-09-06 6:18 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-09-06 6:04 [PATCHv2 0/1] u8500: led and backlight driver Arun Murthy 2010-09-06 6:04 ` [PATCHv2 1/1] u8500: ab8500-pwm: Add pwm driver Arun Murthy 2010-09-06 6:17 ` Mike Rapoport
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox