* [PATCH 2/7] backlight:pwm: add an element 'name' to platform data
  2010-09-28  7:40 [PATCHv2 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
@ 2010-09-28  7:40 ` Arun Murthy
  2010-09-28 17:47   ` Mark Brown
  0 siblings, 1 reply; 15+ messages in thread
From: Arun Murthy @ 2010-09-28  7:40 UTC (permalink / raw)
  To: linux-arm-kernel
A new element 'name' is added to pwm backlight platform data structure.
This is required to identify the pwm device.
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 drivers/video/backlight/pwm_bl.c |    4 +++-
 include/linux/pwm_backlight.h    |    1 +
 2 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 5504435..b0978a8 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -94,7 +94,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	pb->notify = data->notify;
 	pb->dev = &pdev->dev;
 
-	pb->pwm = pwm_request(data->pwm_id, "backlight");
+	if (!data->name)
+		data->name = "backlight";
+	pb->pwm = pwm_request(data->pwm_id, data->name);
 	if (IS_ERR(pb->pwm)) {
 		dev_err(&pdev->dev, "unable to request PWM for backlight\n");
 		ret = PTR_ERR(pb->pwm);
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 01b3d75..c2ce8f8 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -6,6 +6,7 @@
 
 struct platform_pwm_backlight_data {
 	int pwm_id;
+	char *name;
 	unsigned int max_brightness;
 	unsigned int dft_brightness;
 	unsigned int pwm_period_ns;
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 0/7] PWM core driver for pwm based led and backlight driver
@ 2010-09-28 10:35 Arun Murthy
  2010-09-28 10:35 ` [PATCH 1/7] pwm: Add pwm core driver Arun Murthy
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
The series of patch add a new pwm core driver.
Align the existing pwm drivers to make use of the pwm core driver.
Arun Murthy (7):
  pwm: Add pwm core driver
  backlight:pwm: add an element 'name' to platform data
  leds: pwm: add a new element 'name' to platform data
  pwm: Align existing pwm drivers with pwm-core driver
  platform: Update the pwm based led and backlight platform data
  pwm: move existing pwm driver to drivers/pwm
  pwm: Modify backlight and led Kconfig aligning to pwm core
 arch/arm/mach-pxa/cm-x300.c               |    1 +
 arch/arm/mach-pxa/colibri-pxa270-income.c |    1 +
 arch/arm/mach-pxa/ezx.c                   |    1 +
 arch/arm/mach-pxa/hx4700.c                |    1 +
 arch/arm/mach-pxa/lpd270.c                |    1 +
 arch/arm/mach-pxa/magician.c              |    1 +
 arch/arm/mach-pxa/mainstone.c             |    1 +
 arch/arm/mach-pxa/mioa701.c               |    1 +
 arch/arm/mach-pxa/palm27x.c               |    1 +
 arch/arm/mach-pxa/palmtc.c                |    1 +
 arch/arm/mach-pxa/palmte2.c               |    1 +
 arch/arm/mach-pxa/pcm990-baseboard.c      |    1 +
 arch/arm/mach-pxa/raumfeld.c              |    1 +
 arch/arm/mach-pxa/tavorevb.c              |    2 +
 arch/arm/mach-pxa/viper.c                 |    1 +
 arch/arm/mach-pxa/z2.c                    |    2 +
 arch/arm/mach-pxa/zylonite.c              |    1 +
 arch/arm/mach-s3c2410/mach-h1940.c        |    1 +
 arch/arm/mach-s3c2440/mach-rx1950.c       |    1 +
 arch/arm/mach-s3c64xx/mach-hmt.c          |    1 +
 arch/arm/mach-s3c64xx/mach-smartq.c       |    1 +
 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/Kconfig                           |    2 +
 drivers/Makefile                          |    1 +
 drivers/leds/Kconfig                      |    2 +-
 drivers/leds/leds-pwm.c                   |    4 +-
 drivers/mfd/Kconfig                       |    9 -
 drivers/mfd/Makefile                      |    1 -
 drivers/mfd/twl-core.c                    |   13 ++
 drivers/mfd/twl6030-pwm.c                 |  163 --------------------
 drivers/misc/Kconfig                      |    9 -
 drivers/misc/Makefile                     |    1 -
 drivers/misc/ab8500-pwm.c                 |  168 --------------------
 drivers/pwm/Kconfig                       |   33 ++++
 drivers/pwm/Makefile                      |    4 +
 drivers/pwm/pwm-ab8500.c                  |  157 +++++++++++++++++++
 drivers/pwm/pwm-core.c                    |  124 +++++++++++++++
 drivers/pwm/pwm-twl6040.c                 |  196 ++++++++++++++++++++++++
 drivers/video/backlight/Kconfig           |    2 +-
 drivers/video/backlight/pwm_bl.c          |    4 +-
 include/linux/leds_pwm.h                  |    1 +
 include/linux/pwm.h                       |   29 ++++-
 include/linux/pwm_backlight.h             |    1 +
 46 files changed, 864 insertions(+), 696 deletions(-)
 delete mode 100644 drivers/mfd/twl6030-pwm.c
 delete mode 100644 drivers/misc/ab8500-pwm.c
 create mode 100644 drivers/pwm/Kconfig
 create mode 100644 drivers/pwm/Makefile
 create mode 100644 drivers/pwm/pwm-ab8500.c
 create mode 100644 drivers/pwm/pwm-core.c
 create mode 100644 drivers/pwm/pwm-twl6040.c
-- 
1.7.2.dirty
^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH 1/7] pwm: Add pwm core driver
  2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
@ 2010-09-28 10:35 ` Arun Murthy
  2010-09-28 12:53   ` Hemanth V
  2010-09-28 10:35 ` [PATCH 2/7] backlight:pwm: add an element 'name' to platform data Arun Murthy
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
The existing pwm based led and backlight driver makes use of the
pwm(include/linux/pwm.h). So all the board specific pwm drivers will
be exposing the same set of function name as in include/linux/pwm.h.
As a result build fails in case of multi soc environments where each soc
has a pwm device in it.
In order to overcome this issue all the pwm drivers must register to
some core pwm driver with function pointers for pwm operations (i.e
pwm_config, pwm_enable, pwm_disable).
The clients of pwm device will have to call pwm_request, wherein
they will get the pointer to struct pwm_ops. This structure include
function pointers for pwm_config, pwm_enable and pwm_disable.
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 drivers/Kconfig        |    2 +
 drivers/Makefile       |    1 +
 drivers/pwm/Kconfig    |   16 ++++++
 drivers/pwm/Makefile   |    1 +
 drivers/pwm/pwm-core.c |  129 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pwm.h    |   12 ++++-
 6 files changed, 160 insertions(+), 1 deletions(-)
 create mode 100644 drivers/pwm/Kconfig
 create mode 100644 drivers/pwm/Makefile
 create mode 100644 drivers/pwm/pwm-core.c
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a2b902f..e042f27 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -111,4 +111,6 @@ source "drivers/xen/Kconfig"
 source "drivers/staging/Kconfig"
 
 source "drivers/platform/Kconfig"
+
+source "drivers/pwm/Kconfig"
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 4ca727d..0061ec4 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -116,3 +116,4 @@ obj-$(CONFIG_STAGING)		+= staging/
 obj-y				+= platform/
 obj-y				+= ieee802154/
 obj-y				+= vbus/
+obj-$(CONFIG_PWM_DEVICES)	+= pwm/
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
new file mode 100644
index 0000000..5d10106
--- /dev/null
+++ b/drivers/pwm/Kconfig
@@ -0,0 +1,16 @@
+#
+# PWM devices
+#
+
+menuconfig PWM_DEVICES
+	bool "PWM devices"
+	default y
+	---help---
+	  Say Y here to get to see options for device drivers from various
+	  different categories. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
+
+if PWM_DEVICES
+
+endif # PWM_DEVICES
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
new file mode 100644
index 0000000..552f969
--- /dev/null
+++ b/drivers/pwm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PWM_DEVICES)	+= pwm-core.o
diff --git a/drivers/pwm/pwm-core.c b/drivers/pwm/pwm-core.c
new file mode 100644
index 0000000..b84027a
--- /dev/null
+++ b/drivers/pwm/pwm-core.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ */
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/rwsem.h>
+#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;
+};
+static struct pwm_dev_info *di;
+
+DECLARE_RWSEM(pwm_list_lock);
+
+void __deprecated pwm_free(struct pwm_device *pwm)
+{
+}
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	return pwm->pops->pwm_config(pwm, duty_ns, period_ns);
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+	return pwm->pops->pwm_enable(pwm);
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+	pwm->pops->pwm_disable(pwm);
+}
+EXPORT_SYMBOL(pwm_disable);
+
+int pwm_device_register(struct pwm_device *pwm_dev)
+{
+	struct pwm_dev_info *pwm;
+
+	down_write(&pwm_list_lock);
+	pwm = kzalloc(sizeof(struct pwm_dev_info), GFP_KERNEL);
+	if (!pwm) {
+		up_write(&pwm_list_lock);
+		return -ENOMEM;
+	}
+	pwm->pwm_dev = pwm_dev;
+	list_add_tail(&pwm->list, &di->list);
+	up_write(&pwm_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pwm_device_register);
+
+int pwm_device_unregister(struct pwm_device *pwm_dev)
+{
+	struct pwm_dev_info *tmp;
+	struct list_head *pos, *tmp_lst;
+
+	down_write(&pwm_list_lock);
+	list_for_each_safe(pos, tmp_lst, &di->list) {
+		tmp = list_entry(pos, struct pwm_dev_info, list);
+		if (tmp->pwm_dev == pwm_dev) {
+			list_del(pos);
+			kfree(tmp);
+			up_write(&pwm_list_lock);
+			return 0;
+		}
+	}
+	up_write(&pwm_list_lock);
+	return -ENOENT;
+}
+EXPORT_SYMBOL(pwm_device_unregister);
+
+struct pwm_device *pwm_request(int pwm_id, const char *name)
+{
+	struct pwm_dev_info *pwm;
+	struct list_head *pos;
+
+	down_read(&pwm_list_lock);
+	list_for_each(pos, &di->list) {
+		pwm = list_entry(pos, struct pwm_dev_info, list);
+		if ((!strcmp(pwm->pwm_dev->pops->name, name)) &&
+				(pwm->pwm_dev->pwm_id == pwm_id)) {
+			up_read(&pwm_list_lock);
+			return pwm->pwm_dev;
+		}
+	}
+	up_read(&pwm_list_lock);
+	return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(pwm_request);
+
+static int __init pwm_init(void)
+{
+	struct pwm_dev_info *pwm;
+
+	pwm = kzalloc(sizeof(struct pwm_dev_info), GFP_KERNEL);
+	if (!pwm)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&pwm->list);
+	di = pwm;
+	return 0;
+}
+
+static void __exit pwm_exit(void)
+{
+	kfree(di);
+}
+
+subsys_initcall(pwm_init);
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Arun R Murthy");
+MODULE_ALIAS("core:pwm");
+MODULE_DESCRIPTION("Core pwm driver");
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 7c77575..6e7da1f 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -3,6 +3,13 @@
 
 struct pwm_device;
 
+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;
+};
+
 /*
  * pwm_request - request a PWM device
  */
@@ -11,7 +18,7 @@ struct pwm_device *pwm_request(int pwm_id, const char *label);
 /*
  * pwm_free - free a PWM device
  */
-void pwm_free(struct pwm_device *pwm);
+void __deprecated pwm_free(struct pwm_device *pwm);
 
 /*
  * pwm_config - change a PWM device configuration
@@ -28,4 +35,7 @@ int pwm_enable(struct pwm_device *pwm);
  */
 void pwm_disable(struct pwm_device *pwm);
 
+int pwm_device_register(struct pwm_device *pwm_dev);
+int pwm_device_unregister(struct pwm_device *pwm_dev);
+
 #endif /* __LINUX_PWM_H */
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 2/7] backlight:pwm: add an element 'name' to platform data
  2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
  2010-09-28 10:35 ` [PATCH 1/7] pwm: Add pwm core driver Arun Murthy
@ 2010-09-28 10:35 ` Arun Murthy
  2010-09-28 10:35 ` [PATCH 3/7] leds: pwm: add a new " Arun Murthy
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
A new element 'name' is added to pwm backlight platform data structure.
This is required to identify the pwm device.
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 drivers/video/backlight/pwm_bl.c |    4 +++-
 include/linux/pwm_backlight.h    |    1 +
 2 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 5504435..b0978a8 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -94,7 +94,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	pb->notify = data->notify;
 	pb->dev = &pdev->dev;
 
-	pb->pwm = pwm_request(data->pwm_id, "backlight");
+	if (!data->name)
+		data->name = "backlight";
+	pb->pwm = pwm_request(data->pwm_id, data->name);
 	if (IS_ERR(pb->pwm)) {
 		dev_err(&pdev->dev, "unable to request PWM for backlight\n");
 		ret = PTR_ERR(pb->pwm);
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 01b3d75..c2ce8f8 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -6,6 +6,7 @@
 
 struct platform_pwm_backlight_data {
 	int pwm_id;
+	char *name;
 	unsigned int max_brightness;
 	unsigned int dft_brightness;
 	unsigned int pwm_period_ns;
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 3/7] leds: pwm: add a new element 'name' to platform data
  2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
  2010-09-28 10:35 ` [PATCH 1/7] pwm: Add pwm core driver Arun Murthy
  2010-09-28 10:35 ` [PATCH 2/7] backlight:pwm: add an element 'name' to platform data Arun Murthy
@ 2010-09-28 10:35 ` Arun Murthy
  2010-09-28 10:43   ` Sergei Shtylyov
  2010-09-28 10:35 ` [PATCH 4/7] pwm: Align existing pwm drivers with pwm-core driver Arun Murthy
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
A new element 'name' is added to pwm led platform data structure.
This is required to identify the pwm device.
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 drivers/leds/leds-pwm.c  |    4 +++-
 include/linux/leds_pwm.h |    1 +
 2 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index da3fa8d..8da2be6 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -66,8 +66,10 @@ static int led_pwm_probe(struct platform_device *pdev)
 		cur_led = &pdata->leds[i];
 		led_dat = &leds_data[i];
 
+		if (!pdata->name)
+			pdata->name = cur_led->name;
 		led_dat->pwm = pwm_request(cur_led->pwm_id,
-				cur_led->name);
+				pdata->name);
 		if (IS_ERR(led_dat->pwm)) {
 			dev_err(&pdev->dev, "unable to request PWM %d\n",
 					cur_led->pwm_id);
diff --git a/include/linux/leds_pwm.h b/include/linux/leds_pwm.h
index 33a0711..7a847a0 100644
--- a/include/linux/leds_pwm.h
+++ b/include/linux/leds_pwm.h
@@ -16,6 +16,7 @@ struct led_pwm {
 struct led_pwm_platform_data {
 	int			num_leds;
 	struct led_pwm	*leds;
+	char *name;
 };
 
 #endif
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 4/7] pwm: Align existing pwm drivers with pwm-core driver
  2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
                   ` (2 preceding siblings ...)
  2010-09-28 10:35 ` [PATCH 3/7] leds: pwm: add a new " Arun Murthy
@ 2010-09-28 10:35 ` Arun Murthy
  2010-09-28 10:35 ` [PATCH 5/7] platform: Update the pwm based led and backlight platform data Arun Murthy
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
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).
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@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
--- 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);
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 5/7] platform: Update the pwm based led and backlight platform data
  2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
                   ` (3 preceding siblings ...)
  2010-09-28 10:35 ` [PATCH 4/7] pwm: Align existing pwm drivers with pwm-core driver Arun Murthy
@ 2010-09-28 10:35 ` Arun Murthy
  2010-09-28 10:35 ` [PATCH 6/7] pwm: move existing pwm driver to drivers/pwm Arun Murthy
  2010-09-28 10:35 ` [PATCH 7/7] pwm: Modify backlight and led Kconfig aligning to pwm core Arun Murthy
  6 siblings, 0 replies; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
	mxc-pwm: Update the platform data with pwm name for backlight
	s3c24xx-pwm: update platform data for backlight with pwm name
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 arch/arm/mach-pxa/cm-x300.c               |    1 +
 arch/arm/mach-pxa/colibri-pxa270-income.c |    1 +
 arch/arm/mach-pxa/ezx.c                   |    1 +
 arch/arm/mach-pxa/hx4700.c                |    1 +
 arch/arm/mach-pxa/lpd270.c                |    1 +
 arch/arm/mach-pxa/magician.c              |    1 +
 arch/arm/mach-pxa/mainstone.c             |    1 +
 arch/arm/mach-pxa/mioa701.c               |    1 +
 arch/arm/mach-pxa/palm27x.c               |    1 +
 arch/arm/mach-pxa/palmtc.c                |    1 +
 arch/arm/mach-pxa/palmte2.c               |    1 +
 arch/arm/mach-pxa/pcm990-baseboard.c      |    1 +
 arch/arm/mach-pxa/raumfeld.c              |    1 +
 arch/arm/mach-pxa/tavorevb.c              |    2 ++
 arch/arm/mach-pxa/viper.c                 |    1 +
 arch/arm/mach-pxa/z2.c                    |    2 ++
 arch/arm/mach-pxa/zylonite.c              |    1 +
 arch/arm/mach-s3c2410/mach-h1940.c        |    1 +
 arch/arm/mach-s3c2440/mach-rx1950.c       |    1 +
 arch/arm/mach-s3c64xx/mach-hmt.c          |    1 +
 arch/arm/mach-s3c64xx/mach-smartq.c       |    1 +
 21 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index c70e6c2..ddf763b 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -301,6 +301,7 @@ static inline void cm_x300_init_lcd(void) {}
 #if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
 static struct platform_pwm_backlight_data cm_x300_backlight_data = {
 	.pwm_id		= 2,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 100,
 	.dft_brightness	= 100,
 	.pwm_period_ns	= 10000,
diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c
index 37f0f3e..d5b5874 100644
--- a/arch/arm/mach-pxa/colibri-pxa270-income.c
+++ b/arch/arm/mach-pxa/colibri-pxa270-income.c
@@ -234,6 +234,7 @@ static inline void income_lcd_init(void) {}
 #if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM__MODULE)
 static struct platform_pwm_backlight_data income_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 0x3ff,
 	.dft_brightness	= 0x1ff,
 	.pwm_period_ns	= 1000000,
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index 626c82b..747f217 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -49,6 +49,7 @@
 
 static struct platform_pwm_backlight_data ezx_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 1023,
 	.dft_brightness	= 1023,
 	.pwm_period_ns	= 78770,
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index 848c861..8e4905a 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -565,6 +565,7 @@ static struct platform_device hx4700_lcd = {
 
 static struct platform_pwm_backlight_data backlight_data = {
 	.pwm_id         = 1,
+	.name		= "pxa25x-pwm",
 	.max_brightness = 200,
 	.dft_brightness = 100,
 	.pwm_period_ns  = 30923,
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index d279507..91efade 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -273,6 +273,7 @@ static struct platform_device lpd270_flash_device[2] = {
 
 static struct platform_pwm_backlight_data lpd270_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 1,
 	.dft_brightness	= 1,
 	.pwm_period_ns	= 78770,
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index e81dd0c..bb657a4 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -382,6 +382,7 @@ static void magician_backlight_exit(struct device *dev)
 
 static struct platform_pwm_backlight_data backlight_data = {
 	.pwm_id         = 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness = 272,
 	.dft_brightness = 100,
 	.pwm_period_ns  = 30923,
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 5543c64..cbd359c 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -342,6 +342,7 @@ static struct platform_device mst_flash_device[2] = {
 #if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
 static struct platform_pwm_backlight_data mainstone_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 1023,
 	.dft_brightness	= 1023,
 	.pwm_period_ns	= 78770,
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index dc66942..e442088 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -224,6 +224,7 @@ static void mio_gpio_free(struct gpio_ress *gpios, int size)
 /* LCD Screen and Backlight */
 static struct platform_pwm_backlight_data mioa701_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 100,
 	.dft_brightness	= 50,
 	.pwm_period_ns	= 4000 * 1024,	/* Fl = 250kHz */
diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c
index 77ad6d3..46677a4 100644
--- a/arch/arm/mach-pxa/palm27x.c
+++ b/arch/arm/mach-pxa/palm27x.c
@@ -321,6 +321,7 @@ static void palm27x_backlight_exit(struct device *dev)
 
 static struct platform_pwm_backlight_data palm27x_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 0xfe,
 	.dft_brightness	= 0x7e,
 	.pwm_period_ns	= 3500,
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
index ce1104d..385a0b5 100644
--- a/arch/arm/mach-pxa/palmtc.c
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -180,6 +180,7 @@ static void palmtc_backlight_exit(struct device *dev)
 
 static struct platform_pwm_backlight_data palmtc_backlight_data = {
 	.pwm_id		= 1,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= PALMTC_MAX_INTENSITY,
 	.dft_brightness	= PALMTC_MAX_INTENSITY,
 	.pwm_period_ns	= PALMTC_PERIOD_NS,
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index 93c11a0..b7e95f4 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -177,6 +177,7 @@ static void palmte2_backlight_exit(struct device *dev)
 
 static struct platform_pwm_backlight_data palmte2_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= PALMTE2_MAX_INTENSITY,
 	.dft_brightness	= PALMTE2_MAX_INTENSITY,
 	.pwm_period_ns	= PALMTE2_PERIOD_NS,
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index f56ae10..29c7e88 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -138,6 +138,7 @@ static struct pxafb_mach_info pcm990_fbinfo __initdata = {
 
 static struct platform_pwm_backlight_data pcm990_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 1023,
 	.dft_brightness	= 1023,
 	.pwm_period_ns	= 78770,
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 67e04f4..98dc2e3 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -535,6 +535,7 @@ static void __init raumfeld_w1_init(void)
 /* PWM controlled backlight */
 static struct platform_pwm_backlight_data raumfeld_pwm_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 100,
 	.dft_brightness	= 100,
 	/* 10000 ns = 10 ms ^= 100 kHz */
diff --git a/arch/arm/mach-pxa/tavorevb.c b/arch/arm/mach-pxa/tavorevb.c
index f02dcb5..3164de8 100644
--- a/arch/arm/mach-pxa/tavorevb.c
+++ b/arch/arm/mach-pxa/tavorevb.c
@@ -168,6 +168,7 @@ static struct platform_pwm_backlight_data tavorevb_backlight_data[] = {
 	[0] = {
 		/* primary backlight */
 		.pwm_id		= 2,
+		.name		= "pxa25x-pwm",
 		.max_brightness	= 100,
 		.dft_brightness	= 100,
 		.pwm_period_ns	= 100000,
@@ -175,6 +176,7 @@ static struct platform_pwm_backlight_data tavorevb_backlight_data[] = {
 	[1] = {
 		/* secondary backlight */
 		.pwm_id		= 0,
+		.name		= "pxa25x-pwm",
 		.max_brightness	= 100,
 		.dft_brightness	= 100,
 		.pwm_period_ns	= 100000,
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index e90114a..fdb768c 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -397,6 +397,7 @@ static void viper_backlight_exit(struct device *dev)
 
 static struct platform_pwm_backlight_data viper_backlight_data = {
 	.pwm_id		= 0,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 100,
 	.dft_brightness	= 100,
 	.pwm_period_ns	= 1000000,
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index f0d0228..bb3d821 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -204,6 +204,7 @@ static struct platform_pwm_backlight_data z2_backlight_data[] = {
 	[0] = {
 		/* Keypad Backlight */
 		.pwm_id		= 1,
+		.name		= "pxa25x-pwm",
 		.max_brightness	= 1023,
 		.dft_brightness	= 512,
 		.pwm_period_ns	= 1260320,
@@ -211,6 +212,7 @@ static struct platform_pwm_backlight_data z2_backlight_data[] = {
 	[1] = {
 		/* LCD Backlight */
 		.pwm_id		= 2,
+		.name		= "pxa25x-pwm",
 		.max_brightness	= 1023,
 		.dft_brightness	= 512,
 		.pwm_period_ns	= 1260320,
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 5ba9d99..29492bf 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -122,6 +122,7 @@ static inline void zylonite_init_leds(void) {}
 #if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
 static struct platform_pwm_backlight_data zylonite_backlight_data = {
 	.pwm_id		= 3,
+	.name		= "pxa25x-pwm",
 	.max_brightness	= 100,
 	.dft_brightness	= 100,
 	.pwm_period_ns	= 10000,
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 3ba3bab..357342f 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -224,6 +224,7 @@ static void h1940_backlight_exit(struct device *dev)
 
 static struct platform_pwm_backlight_data backlight_data = {
 	.pwm_id         = 0,
+	.name		= "s3c24xx-pwm",
 	.max_brightness = 100,
 	.dft_brightness = 50,
 	/* tcnt = 0x31 */
diff --git a/arch/arm/mach-s3c2440/mach-rx1950.c b/arch/arm/mach-s3c2440/mach-rx1950.c
index 142d1f9..6d993de 100644
--- a/arch/arm/mach-s3c2440/mach-rx1950.c
+++ b/arch/arm/mach-s3c2440/mach-rx1950.c
@@ -291,6 +291,7 @@ static int rx1950_backlight_notify(struct device *dev, int brightness)
 
 static struct platform_pwm_backlight_data rx1950_backlight_data = {
 	.pwm_id = 0,
+	.name = "s3c24xx-pwm",
 	.max_brightness = 24,
 	.dft_brightness = 4,
 	.pwm_period_ns = 48000,
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index fba9022..14e9011 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -109,6 +109,7 @@ static void hmt_bl_exit(struct device *dev)
 
 static struct platform_pwm_backlight_data hmt_backlight_data = {
 	.pwm_id		= 1,
+	.name		= "s3c24xx-pwm",
 	.max_brightness	= 100 * 256,
 	.dft_brightness	= 40 * 256,
 	.pwm_period_ns	= 1000000000 / (100 * 256 * 20),
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index cb1ebeb..20999d5 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -145,6 +145,7 @@ static int smartq_bl_init(struct device *dev)
 
 static struct platform_pwm_backlight_data smartq_backlight_data = {
 	.pwm_id		= 1,
+	.name		= "s3c24xx-pwm",
 	.max_brightness	= 1000,
 	.dft_brightness	= 600,
 	.pwm_period_ns	= 1000000000 / (1000 * 20),
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 6/7] pwm: move existing pwm driver to drivers/pwm
  2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
                   ` (4 preceding siblings ...)
  2010-09-28 10:35 ` [PATCH 5/7] platform: Update the pwm based led and backlight platform data Arun Murthy
@ 2010-09-28 10:35 ` Arun Murthy
  2010-09-28 10:35 ` [PATCH 7/7] pwm: Modify backlight and led Kconfig aligning to pwm core Arun Murthy
  6 siblings, 0 replies; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
As of now only ab8500 and twl6030 are moved.
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 drivers/mfd/Kconfig                              |    9 ---------
 drivers/mfd/Makefile                             |    1 -
 drivers/misc/Kconfig                             |    9 ---------
 drivers/misc/Makefile                            |    1 -
 drivers/pwm/Kconfig                              |   18 ++++++++++++++++++
 drivers/pwm/Makefile                             |    3 +++
 drivers/{misc/ab8500-pwm.c => pwm/pwm-ab8500.c}  |    0
 drivers/{mfd/twl6030-pwm.c => pwm/pwm-twl6040.c} |    0
 8 files changed, 21 insertions(+), 20 deletions(-)
 rename drivers/{misc/ab8500-pwm.c => pwm/pwm-ab8500.c} (100%)
 rename drivers/{mfd/twl6030-pwm.c => pwm/pwm-twl6040.c} (100%)
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/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/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/misc/ab8500-pwm.c b/drivers/pwm/pwm-ab8500.c
similarity index 100%
rename from drivers/misc/ab8500-pwm.c
rename to drivers/pwm/pwm-ab8500.c
diff --git a/drivers/mfd/twl6030-pwm.c b/drivers/pwm/pwm-twl6040.c
similarity index 100%
rename from drivers/mfd/twl6030-pwm.c
rename to drivers/pwm/pwm-twl6040.c
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 7/7] pwm: Modify backlight and led Kconfig aligning to pwm core
  2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
                   ` (5 preceding siblings ...)
  2010-09-28 10:35 ` [PATCH 6/7] pwm: move existing pwm driver to drivers/pwm Arun Murthy
@ 2010-09-28 10:35 ` Arun Murthy
  6 siblings, 0 replies; 15+ messages in thread
From: Arun Murthy @ 2010-09-28 10:35 UTC (permalink / raw)
  To: linux-arm-kernel
PWM based backlight and led driver will not be calling the pwm drivers
through the pwm core driver and hence adding dependancy on the same.
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 drivers/leds/Kconfig            |    2 +-
 drivers/pwm/Kconfig             |    2 --
 drivers/video/backlight/Kconfig |    2 +-
 3 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index e411262..eba388f 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -244,7 +244,7 @@ config LEDS_DAC124S085
 
 config LEDS_PWM
 	tristate "PWM driven LED Support"
-	depends on HAVE_PWM
+	depends on HAVE_PWM || PWM_CORE
 	help
 	  This option enables support for pwm driven LEDs
 
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e347365..1f8cbc0 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -17,7 +17,6 @@ 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.
@@ -26,7 +25,6 @@ config AB8500_PWM
 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.
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index e54a337..73fc17b 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -217,7 +217,7 @@ config BACKLIGHT_CARILLO_RANCH
 
 config BACKLIGHT_PWM
 	tristate "Generic PWM based Backlight Driver"
-	depends on HAVE_PWM
+	depends on HAVE_PWM || PWM_CORE
 	help
 	  If you have a LCD backlight adjustable by PWM, say Y to enable
 	  this driver.
-- 
1.7.2.dirty
^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH 3/7] leds: pwm: add a new element 'name' to platform data
  2010-09-28 10:35 ` [PATCH 3/7] leds: pwm: add a new " Arun Murthy
@ 2010-09-28 10:43   ` Sergei Shtylyov
  2010-09-28 10:48     ` Arun MURTHY
  0 siblings, 1 reply; 15+ messages in thread
From: Sergei Shtylyov @ 2010-09-28 10:43 UTC (permalink / raw)
  To: linux-arm-kernel
Hello.
On 28-09-2010 14:35, Arun Murthy wrote:
> A new element 'name' is added to pwm led platform data structure.
> This is required to identify the pwm device.
> Signed-off-by: Arun Murthy<arun.murthy@stericsson.com>
> Acked-by: Linus Walleij<linus.walleij@stericsson.com>
[...]
> diff --git a/include/linux/leds_pwm.h b/include/linux/leds_pwm.h
> index 33a0711..7a847a0 100644
> --- a/include/linux/leds_pwm.h
> +++ b/include/linux/leds_pwm.h
> @@ -16,6 +16,7 @@ struct led_pwm {
>   struct led_pwm_platform_data {
>   	int			num_leds;
>   	struct led_pwm	*leds;
> +	char *name;
>   };
    Shouldn't '*name'be aligned, at least with '*leds'?
WBR, Sergei
^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH 3/7] leds: pwm: add a new element 'name' to platform data
  2010-09-28 10:43   ` Sergei Shtylyov
@ 2010-09-28 10:48     ` Arun MURTHY
  0 siblings, 0 replies; 15+ messages in thread
From: Arun MURTHY @ 2010-09-28 10:48 UTC (permalink / raw)
  To: linux-arm-kernel
> > @@ -16,6 +16,7 @@ struct led_pwm {
> >   struct led_pwm_platform_data {
> >   	int			num_leds;
> >   	struct led_pwm	*leds;
> > +	char *name;
> >   };
> 
>     Shouldn't '*name'be aligned, at least with '*leds'?
Sure, will take care of this in the v2 patch.
Thanks and Regards,
Arun R Murthy
-------------
^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH 1/7] pwm: Add pwm core driver
  2010-09-28 10:35 ` [PATCH 1/7] pwm: Add pwm core driver Arun Murthy
@ 2010-09-28 12:53   ` Hemanth V
  2010-09-28 13:06     ` Samuel Ortiz
  0 siblings, 1 reply; 15+ messages in thread
From: Hemanth V @ 2010-09-28 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
----- Original Message ----- 
From: "Arun Murthy" <arun.murthy@stericsson.com>
> The existing pwm based led and backlight driver makes use of the
> pwm(include/linux/pwm.h). So all the board specific pwm drivers will
> be exposing the same set of function name as in include/linux/pwm.h.
> As a result build fails in case of multi soc environments where each soc
> has a pwm device in it.
This seems very specific to ST environment,  looking at the driver list from
( [PATCH 4/7] pwm: Align existing pwm drivers with pwm-core ) it seems
most multi SOC environments might support PWM in either one of the SOC.
arch/arm/plat-mxc/pwm.c
arch/arm/plat-pxa/pwm.c
arch/arm/plat-samsung/pwm.c
arch/mips/jz4740/pwm.c
drivers/mfd/twl6030-pwm.c
Unless people have examples of other SOCs which might use this,
the better approach might be to go for a custom driver rather than changing
the framework.
Thanks
Hemanth 
^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH 1/7] pwm: Add pwm core driver
  2010-09-28 12:53   ` Hemanth V
@ 2010-09-28 13:06     ` Samuel Ortiz
  2010-09-28 13:35       ` Felipe Balbi
  0 siblings, 1 reply; 15+ messages in thread
From: Samuel Ortiz @ 2010-09-28 13:06 UTC (permalink / raw)
  To: linux-arm-kernel
On Tue, Sep 28, 2010 at 06:23:24PM +0530, Hemanth V wrote:
> ----- Original Message ----- From: "Arun Murthy"
> <arun.murthy@stericsson.com>
> 
> 
> >The existing pwm based led and backlight driver makes use of the
> >pwm(include/linux/pwm.h). So all the board specific pwm drivers will
> >be exposing the same set of function name as in include/linux/pwm.h.
> >As a result build fails in case of multi soc environments where each soc
> >has a pwm device in it.
> 
> This seems very specific to ST environment,  
No it's not. It's an issue Arun has hit while enabling one of the ST MFD chip,
but he's tackling a generic issue.
> looking at the driver list from
> ( [PATCH 4/7] pwm: Align existing pwm drivers with pwm-core ) it seems
> most multi SOC environments might support PWM in either one of the SOC.
> 
> arch/arm/plat-mxc/pwm.c
> arch/arm/plat-pxa/pwm.c
> arch/arm/plat-samsung/pwm.c
> arch/mips/jz4740/pwm.c
> drivers/mfd/twl6030-pwm.c
> 
> Unless people have examples of other SOCs which might use this,
> the better approach might be to go for a custom driver rather than changing
> the framework.
I wouldn't call the current pwm code a framework. It's a bunch of header
definitions that happens to work in the specific case of 1 pwm per
sub architecture.
What Arun is proposing is an actual framework. And it seems to be clean and
simple enough.
Cheers,
Samuel.
-- 
Intel Open Source Technology Centre
http://oss.intel.com/
^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH 1/7] pwm: Add pwm core driver
  2010-09-28 13:06     ` Samuel Ortiz
@ 2010-09-28 13:35       ` Felipe Balbi
  0 siblings, 0 replies; 15+ messages in thread
From: Felipe Balbi @ 2010-09-28 13:35 UTC (permalink / raw)
  To: linux-arm-kernel
On Tue, Sep 28, 2010 at 08:06:11AM -0500, Samuel Ortiz wrote:
>On Tue, Sep 28, 2010 at 06:23:24PM +0530, Hemanth V wrote:
>> ----- Original Message ----- From: "Arun Murthy"
>> <arun.murthy@stericsson.com>
>>
>>
>> >The existing pwm based led and backlight driver makes use of the
>> >pwm(include/linux/pwm.h). So all the board specific pwm drivers will
>> >be exposing the same set of function name as in include/linux/pwm.h.
>> >As a result build fails in case of multi soc environments where each soc
>> >has a pwm device in it.
>>
>> This seems very specific to ST environment,
>No it's not. It's an issue Arun has hit while enabling one of the ST MFD chip,
>but he's tackling a generic issue.
>
>> looking at the driver list from
>> ( [PATCH 4/7] pwm: Align existing pwm drivers with pwm-core ) it seems
>> most multi SOC environments might support PWM in either one of the SOC.
>>
>> arch/arm/plat-mxc/pwm.c
>> arch/arm/plat-pxa/pwm.c
>> arch/arm/plat-samsung/pwm.c
>> arch/mips/jz4740/pwm.c
>> drivers/mfd/twl6030-pwm.c
>>
>> Unless people have examples of other SOCs which might use this,
>> the better approach might be to go for a custom driver rather than changing
>> the framework.
>I wouldn't call the current pwm code a framework. It's a bunch of header
>definitions that happens to work in the specific case of 1 pwm per
>sub architecture.
>What Arun is proposing is an actual framework. And it seems to be clean and
>simple enough.
FWIW, I agree with you Sam. Sooner or later, this will hit other SoCs.
-- 
balbi
^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH 2/7] backlight:pwm: add an element 'name' to platform data
  2010-09-28  7:40 ` [PATCH 2/7] backlight:pwm: add an element 'name' to platform data Arun Murthy
@ 2010-09-28 17:47   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2010-09-28 17:47 UTC (permalink / raw)
  To: linux-arm-kernel
On Tue, Sep 28, 2010 at 01:10:43PM +0530, Arun Murthy wrote:
> A new element 'name' is added to pwm backlight platform data structure.
> This is required to identify the pwm device.
> -	pb->pwm = pwm_request(data->pwm_id, "backlight");
> +	if (!data->name)
> +		data->name = "backlight";
> +	pb->pwm = pwm_request(data->pwm_id, data->name);
If we're going to go through and require that all PWM API users be
updated to take platform data for the name might it not be better to
switch over to the clock API style request by device interface?
^ permalink raw reply	[flat|nested] 15+ messages in thread
end of thread, other threads:[~2010-09-28 17:47 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-09-28 10:35 [PATCH 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
2010-09-28 10:35 ` [PATCH 1/7] pwm: Add pwm core driver Arun Murthy
2010-09-28 12:53   ` Hemanth V
2010-09-28 13:06     ` Samuel Ortiz
2010-09-28 13:35       ` Felipe Balbi
2010-09-28 10:35 ` [PATCH 2/7] backlight:pwm: add an element 'name' to platform data Arun Murthy
2010-09-28 10:35 ` [PATCH 3/7] leds: pwm: add a new " Arun Murthy
2010-09-28 10:43   ` Sergei Shtylyov
2010-09-28 10:48     ` Arun MURTHY
2010-09-28 10:35 ` [PATCH 4/7] pwm: Align existing pwm drivers with pwm-core driver Arun Murthy
2010-09-28 10:35 ` [PATCH 5/7] platform: Update the pwm based led and backlight platform data Arun Murthy
2010-09-28 10:35 ` [PATCH 6/7] pwm: move existing pwm driver to drivers/pwm Arun Murthy
2010-09-28 10:35 ` [PATCH 7/7] pwm: Modify backlight and led Kconfig aligning to pwm core Arun Murthy
  -- strict thread matches above, loose matches on Subject: below --
2010-09-28  7:40 [PATCHv2 0/7] PWM core driver for pwm based led and backlight driver Arun Murthy
2010-09-28  7:40 ` [PATCH 2/7] backlight:pwm: add an element 'name' to platform data Arun Murthy
2010-09-28 17:47   ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).