linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] unicore32: Move PWM driver to PWM framework
@ 2012-09-18  8:23 Thierry Reding
  2012-09-18  8:23 ` [PATCH v2 1/5] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Thierry Reding @ 2012-09-18  8:23 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Qin Rui, linux-kernel

This series cleans up the PWM driver as well as moves and converts it
to the PWM framework. I don't have any Unicore32 hardware, so all I
could do was test if the kernel builds properly with the patches
applied. I think except for the final patch all of these should go
through the Unicore32 tree.

Changes in v2:
- drop common clock framework support (this series now depends on a
  patch (https://lkml.org/lkml/2012/9/9/54) by Lars-Peter Clausen that
  should soon appear in linux-next and which makes devm_clk_get()
  available outside of the common clock framework)
- update patch 1 to incorporate changes by Guan Xuetao

Thierry

Thierry Reding (5):
  unicore32: pwm: Properly remap memory-mapped registers
  unicore32: pwm: Use module_platform_driver()
  unicore32: pwm: Remove unnecessary indirection
  unicore32: pwm: Use managed resource allocations
  pwm: Move PUV3 PWM driver to PWM framework

 arch/unicore32/Kconfig                 |  12 +-
 arch/unicore32/include/mach/regs-ost.h |  18 +--
 arch/unicore32/kernel/Makefile         |   1 -
 arch/unicore32/kernel/pwm.c            | 263 ---------------------------------
 drivers/pwm/Kconfig                    |  10 +-
 drivers/pwm/Makefile                   |   1 +
 drivers/pwm/pwm-puv3.c                 | 161 ++++++++++++++++++++
 7 files changed, 181 insertions(+), 285 deletions(-)
 delete mode 100644 arch/unicore32/kernel/pwm.c
 create mode 100644 drivers/pwm/pwm-puv3.c

-- 
1.7.12


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/5] unicore32: pwm: Properly remap memory-mapped registers
  2012-09-18  8:23 [PATCH v2 0/5] unicore32: Move PWM driver to PWM framework Thierry Reding
@ 2012-09-18  8:23 ` Thierry Reding
  2012-09-18  8:23 ` [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver() Thierry Reding
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: Thierry Reding @ 2012-09-18  8:23 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Qin Rui, linux-kernel

Instead of writing to the timer controller registers by dereferencing a
pointer to the memory location, properly remap the memory region with a
call to ioremap_nocache() and access the registers using writel().

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
---
 arch/unicore32/include/mach/regs-ost.h | 18 ++++++++----------
 arch/unicore32/kernel/pwm.c            | 21 ++++++++++++++++++---
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/arch/unicore32/include/mach/regs-ost.h b/arch/unicore32/include/mach/regs-ost.h
index 7b91fe6..4a85fb4 100644
--- a/arch/unicore32/include/mach/regs-ost.h
+++ b/arch/unicore32/include/mach/regs-ost.h
@@ -33,18 +33,16 @@
  * Interrupt Enable Reg OST_OIER
  */
 #define OST_OIER	(PKUNITY_OST_BASE + 0x001C)
+
 /*
- * PWM Pulse Width Control Reg OST_PWMPWCR
- */
-#define OST_PWMPWCR	(PKUNITY_OST_BASE + 0x0080)
-/*
- * PWM Duty Cycle Control Reg OST_PWMDCCR
- */
-#define OST_PWMDCCR	(PKUNITY_OST_BASE + 0x0084)
-/*
- * PWM Period Control Reg OST_PWMPCR
+ * PWM Registers: IO base address: PKUNITY_OST_BASE + 0x80
+ *      PWCR: Pulse Width Control Reg
+ *      DCCR: Duty Cycle Control Reg
+ *      PCR: Period Control Reg
  */
-#define OST_PWMPCR	(PKUNITY_OST_BASE + 0x0088)
+#define OST_PWM_PWCR	(0x00)
+#define OST_PWM_DCCR	(0x04)
+#define OST_PWM_PCR 	(0x08)
 
 /*
  * Match detected 0 OST_OSSR_M0
diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
index 4615d51..885bbcd 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -27,6 +27,8 @@ struct pwm_device {
 	struct list_head	node;
 	struct platform_device *pdev;
 
+	void __iomem	*base;
+
 	const char	*label;
 	struct clk	*clk;
 	int		clk_enabled;
@@ -69,9 +71,11 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 	 * before writing to the registers
 	 */
 	clk_enable(pwm->clk);
-	OST_PWMPWCR = prescale;
-	OST_PWMDCCR = pv - dc;
-	OST_PWMPCR  = pv;
+
+	writel(prescale, pwm->base + OST_PWM_PWCR);
+	writel(pv - dc, pwm->base + OST_PWM_DCCR);
+	writel(pv, pwm->base + OST_PWM_PCR);
+
 	clk_disable(pwm->clk);
 
 	return 0;
@@ -190,10 +194,19 @@ static struct pwm_device *pwm_probe(struct platform_device *pdev,
 		goto err_free_clk;
 	}
 
+	pwm->base = ioremap_nocache(r->start, resource_size(r));
+	if (pwm->base == NULL) {
+		dev_err(&pdev->dev, "failed to remap memory resource\n");
+		ret = -EADDRNOTAVAIL;
+		goto err_release_mem;
+	}
+
 	__add_pwm(pwm);
 	platform_set_drvdata(pdev, pwm);
 	return pwm;
 
+err_release_mem:
+	release_mem_region(r->start, resource_size(r));
 err_free_clk:
 	clk_put(pwm->clk);
 err_free:
@@ -224,6 +237,8 @@ static int __devexit pwm_remove(struct platform_device *pdev)
 	list_del(&pwm->node);
 	mutex_unlock(&pwm_lock);
 
+	iounmap(pwm->base);
+
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(r->start, resource_size(r));
 
-- 
1.7.12


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver()
  2012-09-18  8:23 [PATCH v2 0/5] unicore32: Move PWM driver to PWM framework Thierry Reding
  2012-09-18  8:23 ` [PATCH v2 1/5] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
@ 2012-09-18  8:23 ` Thierry Reding
  2012-09-22  2:56   ` guanxuetao
  2012-09-18  8:23 ` [PATCH v2 3/5] unicore32: pwm: Remove unnecessary indirection Thierry Reding
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Thierry Reding @ 2012-09-18  8:23 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Qin Rui, linux-kernel

Some of the boilerplate code can be eliminated by using this macro. The
driver was previously registered with an arch_initcall(), so technically
this is no longer the same, but when the driver is moved to the PWM
framework, deferred probing will take care of any driver probe ordering
issues.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
 arch/unicore32/kernel/pwm.c | 21 +--------------------
 1 file changed, 1 insertion(+), 20 deletions(-)

diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
index 885bbcd..012c54a 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -254,25 +254,6 @@ static struct platform_driver puv3_pwm_driver = {
 	.probe		= puv3_pwm_probe,
 	.remove		= __devexit_p(pwm_remove),
 };
-
-static int __init pwm_init(void)
-{
-	int ret = 0;
-
-	ret = platform_driver_register(&puv3_pwm_driver);
-	if (ret) {
-		printk(KERN_ERR "failed to register puv3_pwm_driver\n");
-		return ret;
-	}
-
-	return ret;
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-	platform_driver_unregister(&puv3_pwm_driver);
-}
-module_exit(pwm_exit);
+module_platform_driver(puv3_pwm_driver);
 
 MODULE_LICENSE("GPL v2");
-- 
1.7.12


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/5] unicore32: pwm: Remove unnecessary indirection
  2012-09-18  8:23 [PATCH v2 0/5] unicore32: Move PWM driver to PWM framework Thierry Reding
  2012-09-18  8:23 ` [PATCH v2 1/5] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
  2012-09-18  8:23 ` [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver() Thierry Reding
@ 2012-09-18  8:23 ` Thierry Reding
  2012-09-22  2:56   ` guanxuetao
  2012-09-18  8:23 ` [PATCH v2 4/5] unicore32: pwm: Use managed resource allocations Thierry Reding
  2012-09-18  8:23 ` [PATCH v2 5/5] pwm: Move PUV3 PWM driver to PWM framework Thierry Reding
  4 siblings, 1 reply; 14+ messages in thread
From: Thierry Reding @ 2012-09-18  8:23 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Qin Rui, linux-kernel

Calling the actual probing function through a proxy isn't required and
makes the code needlessly complex.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
 arch/unicore32/kernel/pwm.c | 23 ++++++-----------------
 1 file changed, 6 insertions(+), 17 deletions(-)

diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
index 012c54a..7e23470 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -156,8 +156,7 @@ static inline void __add_pwm(struct pwm_device *pwm)
 	mutex_unlock(&pwm_lock);
 }
 
-static struct pwm_device *pwm_probe(struct platform_device *pdev,
-		unsigned int pwm_id, struct pwm_device *parent_pwm)
+static int __devinit pwm_probe(struct platform_device *pdev)
 {
 	struct pwm_device *pwm;
 	struct resource *r;
@@ -166,7 +165,7 @@ static struct pwm_device *pwm_probe(struct platform_device *pdev,
 	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
 	if (pwm == NULL) {
 		dev_err(&pdev->dev, "failed to allocate memory\n");
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	pwm->clk = clk_get(NULL, "OST_CLK");
@@ -177,7 +176,7 @@ static struct pwm_device *pwm_probe(struct platform_device *pdev,
 	pwm->clk_enabled = 0;
 
 	pwm->use_count = 0;
-	pwm->pwm_id = pwm_id;
+	pwm->pwm_id = pdev->id;
 	pwm->pdev = pdev;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -203,7 +202,7 @@ static struct pwm_device *pwm_probe(struct platform_device *pdev,
 
 	__add_pwm(pwm);
 	platform_set_drvdata(pdev, pwm);
-	return pwm;
+	return 0;
 
 err_release_mem:
 	release_mem_region(r->start, resource_size(r));
@@ -211,17 +210,7 @@ err_free_clk:
 	clk_put(pwm->clk);
 err_free:
 	kfree(pwm);
-	return ERR_PTR(ret);
-}
-
-static int __devinit puv3_pwm_probe(struct platform_device *pdev)
-{
-	struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
-
-	if (IS_ERR(pwm))
-		return PTR_ERR(pwm);
-
-	return 0;
+	return ret;
 }
 
 static int __devexit pwm_remove(struct platform_device *pdev)
@@ -251,7 +240,7 @@ static struct platform_driver puv3_pwm_driver = {
 	.driver		= {
 		.name	= "PKUnity-v3-PWM",
 	},
-	.probe		= puv3_pwm_probe,
+	.probe		= pwm_probe,
 	.remove		= __devexit_p(pwm_remove),
 };
 module_platform_driver(puv3_pwm_driver);
-- 
1.7.12


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 4/5] unicore32: pwm: Use managed resource allocations
  2012-09-18  8:23 [PATCH v2 0/5] unicore32: Move PWM driver to PWM framework Thierry Reding
                   ` (2 preceding siblings ...)
  2012-09-18  8:23 ` [PATCH v2 3/5] unicore32: pwm: Remove unnecessary indirection Thierry Reding
@ 2012-09-18  8:23 ` Thierry Reding
  2012-09-22  2:57   ` guanxuetao
  2012-09-18  8:23 ` [PATCH v2 5/5] pwm: Move PUV3 PWM driver to PWM framework Thierry Reding
  4 siblings, 1 reply; 14+ messages in thread
From: Thierry Reding @ 2012-09-18  8:23 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Qin Rui, linux-kernel

This commit uses the managed resource allocation functions to simplify
the cleanup paths on error and removal.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
 arch/unicore32/kernel/pwm.c | 47 +++++++++------------------------------------
 1 file changed, 9 insertions(+), 38 deletions(-)

diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
index 7e23470..724e860 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -160,19 +160,17 @@ static int __devinit pwm_probe(struct platform_device *pdev)
 {
 	struct pwm_device *pwm;
 	struct resource *r;
-	int ret = 0;
 
-	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+	pwm = devm_kzalloc(&pdev->dev, sizeof(struct pwm_device), GFP_KERNEL);
 	if (pwm == NULL) {
 		dev_err(&pdev->dev, "failed to allocate memory\n");
 		return -ENOMEM;
 	}
 
-	pwm->clk = clk_get(NULL, "OST_CLK");
-	if (IS_ERR(pwm->clk)) {
-		ret = PTR_ERR(pwm->clk);
-		goto err_free;
-	}
+	pwm->clk = devm_clk_get(&pdev->dev, "OST_CLK");
+	if (IS_ERR(pwm->clk))
+		return PTR_ERR(pwm->clk);
+
 	pwm->clk_enabled = 0;
 
 	pwm->use_count = 0;
@@ -182,41 +180,21 @@ static int __devinit pwm_probe(struct platform_device *pdev)
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (r == NULL) {
 		dev_err(&pdev->dev, "no memory resource defined\n");
-		ret = -ENODEV;
-		goto err_free_clk;
-	}
-
-	r = request_mem_region(r->start, resource_size(r), pdev->name);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "failed to request memory resource\n");
-		ret = -EBUSY;
-		goto err_free_clk;
+		return -ENODEV;
 	}
 
-	pwm->base = ioremap_nocache(r->start, resource_size(r));
-	if (pwm->base == NULL) {
-		dev_err(&pdev->dev, "failed to remap memory resource\n");
-		ret = -EADDRNOTAVAIL;
-		goto err_release_mem;
-	}
+	pwm->base = devm_request_and_ioremap(&pdev->dev, r);
+	if (pwm->base == NULL)
+		return -EADDRNOTAVAIL;
 
 	__add_pwm(pwm);
 	platform_set_drvdata(pdev, pwm);
 	return 0;
-
-err_release_mem:
-	release_mem_region(r->start, resource_size(r));
-err_free_clk:
-	clk_put(pwm->clk);
-err_free:
-	kfree(pwm);
-	return ret;
 }
 
 static int __devexit pwm_remove(struct platform_device *pdev)
 {
 	struct pwm_device *pwm;
-	struct resource *r;
 
 	pwm = platform_get_drvdata(pdev);
 	if (pwm == NULL)
@@ -226,13 +204,6 @@ static int __devexit pwm_remove(struct platform_device *pdev)
 	list_del(&pwm->node);
 	mutex_unlock(&pwm_lock);
 
-	iounmap(pwm->base);
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(r->start, resource_size(r));
-
-	clk_put(pwm->clk);
-	kfree(pwm);
 	return 0;
 }
 
-- 
1.7.12


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 5/5] pwm: Move PUV3 PWM driver to PWM framework
  2012-09-18  8:23 [PATCH v2 0/5] unicore32: Move PWM driver to PWM framework Thierry Reding
                   ` (3 preceding siblings ...)
  2012-09-18  8:23 ` [PATCH v2 4/5] unicore32: pwm: Use managed resource allocations Thierry Reding
@ 2012-09-18  8:23 ` Thierry Reding
  2012-09-22  2:58   ` guanxuetao
  4 siblings, 1 reply; 14+ messages in thread
From: Thierry Reding @ 2012-09-18  8:23 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Qin Rui, linux-kernel

This commit moves the driver to drivers/pwm and converts it to the new
PWM framework.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
 arch/unicore32/Kconfig         |  12 +--
 arch/unicore32/kernel/Makefile |   1 -
 arch/unicore32/kernel/pwm.c    | 219 -----------------------------------------
 drivers/pwm/Kconfig            |  10 +-
 drivers/pwm/Makefile           |   1 +
 drivers/pwm/pwm-puv3.c         | 161 ++++++++++++++++++++++++++++++
 6 files changed, 173 insertions(+), 231 deletions(-)
 delete mode 100644 arch/unicore32/kernel/pwm.c
 create mode 100644 drivers/pwm/pwm-puv3.c

diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index b0a4743..91e2037 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -20,9 +20,6 @@ config UNICORE32
 	  designs licensed by PKUnity Ltd.
 	  Please see web page at <http://www.pkunity.com/>.
 
-config HAVE_PWM
-	bool
-
 config GENERIC_GPIO
 	def_bool y
 
@@ -105,7 +102,8 @@ config PUV3_DB0913
 
 config PUV3_NB0916
 	bool "NetBook board (0916)"
-	select HAVE_PWM
+	select PWM
+	select PWM_PUV3
 
 config PUV3_SMW0919
 	bool "Security Mini-Workstation board (0919)"
@@ -219,12 +217,6 @@ config PUV3_GPIO
 	select GPIO_SYSFS if EXPERIMENTAL
 	default y
 
-config PUV3_PWM
-	tristate
-	default BACKLIGHT_PWM
-	help
-	  Enable support for NB0916 PWM controllers
-
 if PUV3_NB0916
 
 menu "PKUnity NetBook-0916 Features"
diff --git a/arch/unicore32/kernel/Makefile b/arch/unicore32/kernel/Makefile
index 3240101..fa497e0 100644
--- a/arch/unicore32/kernel/Makefile
+++ b/arch/unicore32/kernel/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_UNICORE_FPU_F64)	+= fpu-ucf64.o
 obj-$(CONFIG_ARCH_PUV3)		+= clock.o irq.o time.o
 
 obj-$(CONFIG_PUV3_GPIO)		+= gpio.o
-obj-$(CONFIG_PUV3_PWM)		+= pwm.o
 obj-$(CONFIG_PUV3_PM)		+= pm.o sleep.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o hibernate_asm.o
 
diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
deleted file mode 100644
index 724e860..0000000
--- a/arch/unicore32/kernel/pwm.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * linux/arch/unicore32/kernel/pwm.c
- *
- * Code specific to PKUnity SoC and UniCore ISA
- *
- *	Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
- *	Copyright (C) 2001-2010 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-#include <mach/hardware.h>
-
-struct pwm_device {
-	struct list_head	node;
-	struct platform_device *pdev;
-
-	void __iomem	*base;
-
-	const char	*label;
-	struct clk	*clk;
-	int		clk_enabled;
-
-	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)
-{
-	unsigned long long c;
-	unsigned long period_cycles, prescale, pv, dc;
-
-	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-		return -EINVAL;
-
-	c = clk_get_rate(pwm->clk);
-	c = c * period_ns;
-	do_div(c, 1000000000);
-	period_cycles = c;
-
-	if (period_cycles < 1)
-		period_cycles = 1;
-	prescale = (period_cycles - 1) / 1024;
-	pv = period_cycles / (prescale + 1) - 1;
-
-	if (prescale > 63)
-		return -EINVAL;
-
-	if (duty_ns == period_ns)
-		dc = OST_PWMDCCR_FDCYCLE;
-	else
-		dc = (pv + 1) * duty_ns / period_ns;
-
-	/* NOTE: the clock to PWM has to be enabled first
-	 * before writing to the registers
-	 */
-	clk_enable(pwm->clk);
-
-	writel(prescale, pwm->base + OST_PWM_PWCR);
-	writel(pv - dc, pwm->base + OST_PWM_DCCR);
-	writel(pv, pwm->base + OST_PWM_PCR);
-
-	clk_disable(pwm->clk);
-
-	return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-	int rc = 0;
-
-	if (!pwm->clk_enabled) {
-		rc = clk_enable(pwm->clk);
-		if (!rc)
-			pwm->clk_enabled = 1;
-	}
-	return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void 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 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 (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);
-}
-
-static int __devinit pwm_probe(struct platform_device *pdev)
-{
-	struct pwm_device *pwm;
-	struct resource *r;
-
-	pwm = devm_kzalloc(&pdev->dev, sizeof(struct pwm_device), GFP_KERNEL);
-	if (pwm == NULL) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
-		return -ENOMEM;
-	}
-
-	pwm->clk = devm_clk_get(&pdev->dev, "OST_CLK");
-	if (IS_ERR(pwm->clk))
-		return PTR_ERR(pwm->clk);
-
-	pwm->clk_enabled = 0;
-
-	pwm->use_count = 0;
-	pwm->pwm_id = pdev->id;
-	pwm->pdev = pdev;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no memory resource defined\n");
-		return -ENODEV;
-	}
-
-	pwm->base = devm_request_and_ioremap(&pdev->dev, r);
-	if (pwm->base == NULL)
-		return -EADDRNOTAVAIL;
-
-	__add_pwm(pwm);
-	platform_set_drvdata(pdev, pwm);
-	return 0;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-	struct pwm_device *pwm;
-
-	pwm = platform_get_drvdata(pdev);
-	if (pwm == NULL)
-		return -ENODEV;
-
-	mutex_lock(&pwm_lock);
-	list_del(&pwm->node);
-	mutex_unlock(&pwm_lock);
-
-	return 0;
-}
-
-static struct platform_driver puv3_pwm_driver = {
-	.driver		= {
-		.name	= "PKUnity-v3-PWM",
-	},
-	.probe		= pwm_probe,
-	.remove		= __devexit_p(pwm_remove),
-};
-module_platform_driver(puv3_pwm_driver);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 5c663df..007c225 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -1,6 +1,5 @@
 menuconfig PWM
 	bool "Pulse-Width Modulation (PWM) Support"
-	depends on !PUV3_PWM
 	help
 	  Generic Pulse-Width Modulation (PWM) support.
 
@@ -77,6 +76,15 @@ config PWM_MXS
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-mxs.
 
+config PWM_PUV3
+	tristate "PKUnity NetBook-0916 PWM support"
+	depends on ARCH_PUV3
+	help
+	  Generic PWM framework driver for PKUnity NetBook-0916.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-puv3.
+
 config PWM_PXA
 	tristate "PXA PWM support"
 	depends on ARCH_PXA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index a1d6169..c8e521b 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_PWM_IMX)		+= pwm-imx.o
 obj-$(CONFIG_PWM_JZ4740)	+= pwm-jz4740.o
 obj-$(CONFIG_PWM_LPC32XX)	+= pwm-lpc32xx.o
 obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
+obj-$(CONFIG_PWM_PUV3)		+= pwm-puv3.o
 obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
new file mode 100644
index 0000000..2a93f37
--- /dev/null
+++ b/drivers/pwm/pwm-puv3.c
@@ -0,0 +1,161 @@
+/*
+ * linux/arch/unicore32/kernel/pwm.c
+ *
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ *	Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
+ *	Copyright (C) 2001-2010 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+#include <mach/hardware.h>
+
+struct puv3_pwm_chip {
+	struct pwm_chip chip;
+	void __iomem *base;
+	struct clk *clk;
+	bool enabled;
+};
+
+static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip)
+{
+	return container_of(chip, struct puv3_pwm_chip, chip);
+}
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			   int duty_ns, int period_ns)
+{
+	unsigned long period_cycles, prescale, pv, dc;
+	struct puv3_pwm_chip *puv3 = to_puv3(chip);
+	unsigned long long c;
+
+	c = clk_get_rate(puv3->clk);
+	c = c * period_ns;
+	do_div(c, 1000000000);
+	period_cycles = c;
+
+	if (period_cycles < 1)
+		period_cycles = 1;
+
+	prescale = (period_cycles - 1) / 1024;
+	pv = period_cycles / (prescale + 1) - 1;
+
+	if (prescale > 63)
+		return -EINVAL;
+
+	if (duty_ns == period_ns)
+		dc = OST_PWMDCCR_FDCYCLE;
+	else
+		dc = (pv + 1) * duty_ns / period_ns;
+
+	/*
+	 * NOTE: the clock to PWM has to be enabled first
+	 * before writing to the registers
+	 */
+	clk_prepare_enable(puv3->clk);
+
+	writel(prescale, puv3->base + OST_PWM_PWCR);
+	writel(pv - dc, puv3->base + OST_PWM_DCCR);
+	writel(pv, puv3->base + OST_PWM_PCR);
+
+	clk_disable_unprepare(puv3->clk);
+
+	return 0;
+}
+
+static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct puv3_pwm_chip *puv3 = to_puv3(chip);
+
+	return clk_prepare_enable(puv3->clk);
+}
+
+static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct puv3_pwm_chip *puv3 = to_puv3(chip);
+
+	clk_disable_unprepare(puv3->clk);
+}
+
+static const struct pwm_ops puv3_pwm_ops = {
+	.config = puv3_pwm_config,
+	.enable = puv3_pwm_enable,
+	.disable = puv3_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+	struct puv3_pwm_chip *puv3;
+	struct resource *r;
+	int ret;
+
+	puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL);
+	if (puv3 == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK");
+	if (IS_ERR(puv3->clk))
+		return PTR_ERR(puv3->clk);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no memory resource defined\n");
+		return -ENODEV;
+	}
+
+	puv3->base = devm_request_and_ioremap(&pdev->dev, r);
+	if (puv3->base == NULL)
+		return -EADDRNOTAVAIL;
+
+	puv3->chip.dev = &pdev->dev;
+	puv3->chip.ops = &puv3_pwm_ops;
+	puv3->chip.base = -1;
+	puv3->chip.npwm = 1;
+
+	ret = pwmchip_add(&puv3->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, puv3);
+	return 0;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+	struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev);
+
+	return pwmchip_remove(&puv3->chip);
+}
+
+static struct platform_driver puv3_pwm_driver = {
+	.driver = {
+		.name = "PKUnity-v3-PWM",
+	},
+	.probe = pwm_probe,
+	.remove = __devexit_p(pwm_remove),
+};
+module_platform_driver(puv3_pwm_driver);
+
+MODULE_LICENSE("GPL v2");
-- 
1.7.12


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver()
  2012-09-18  8:23 ` [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver() Thierry Reding
@ 2012-09-22  2:56   ` guanxuetao
  2012-09-22  7:32     ` Thierry Reding
  0 siblings, 1 reply; 14+ messages in thread
From: guanxuetao @ 2012-09-22  2:56 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Guan Xuetao, Qin Rui, linux-kernel

> Some of the boilerplate code can be eliminated by using this macro. The
> driver was previously registered with an arch_initcall(), so technically
> this is no longer the same, but when the driver is moved to the PWM
> framework, deferred probing will take care of any driver probe ordering
> issues.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>

Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>

Thanks & Regards,
Guan Xuetao

> ---
>  arch/unicore32/kernel/pwm.c | 21 +--------------------
>  1 file changed, 1 insertion(+), 20 deletions(-)
>
> diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
> index 885bbcd..012c54a 100644
> --- a/arch/unicore32/kernel/pwm.c
> +++ b/arch/unicore32/kernel/pwm.c
> @@ -254,25 +254,6 @@ static struct platform_driver puv3_pwm_driver = {
>  	.probe		= puv3_pwm_probe,
>  	.remove		= __devexit_p(pwm_remove),
>  };
> -
> -static int __init pwm_init(void)
> -{
> -	int ret = 0;
> -
> -	ret = platform_driver_register(&puv3_pwm_driver);
> -	if (ret) {
> -		printk(KERN_ERR "failed to register puv3_pwm_driver\n");
> -		return ret;
> -	}
> -
> -	return ret;
> -}
> -arch_initcall(pwm_init);
> -
> -static void __exit pwm_exit(void)
> -{
> -	platform_driver_unregister(&puv3_pwm_driver);
> -}
> -module_exit(pwm_exit);
> +module_platform_driver(puv3_pwm_driver);
>
>  MODULE_LICENSE("GPL v2");
> --
> 1.7.12
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 3/5] unicore32: pwm: Remove unnecessary indirection
  2012-09-18  8:23 ` [PATCH v2 3/5] unicore32: pwm: Remove unnecessary indirection Thierry Reding
@ 2012-09-22  2:56   ` guanxuetao
  0 siblings, 0 replies; 14+ messages in thread
From: guanxuetao @ 2012-09-22  2:56 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Guan Xuetao, Qin Rui, linux-kernel

> Calling the actual probing function through a proxy isn't required and
> makes the code needlessly complex.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>

Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>

Thanks & Regards,
Guan Xuetao


> ---
>  arch/unicore32/kernel/pwm.c | 23 ++++++-----------------
>  1 file changed, 6 insertions(+), 17 deletions(-)
>
> diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
> index 012c54a..7e23470 100644
> --- a/arch/unicore32/kernel/pwm.c
> +++ b/arch/unicore32/kernel/pwm.c
> @@ -156,8 +156,7 @@ static inline void __add_pwm(struct pwm_device *pwm)
>  	mutex_unlock(&pwm_lock);
>  }
>
> -static struct pwm_device *pwm_probe(struct platform_device *pdev,
> -		unsigned int pwm_id, struct pwm_device *parent_pwm)
> +static int __devinit pwm_probe(struct platform_device *pdev)
>  {
>  	struct pwm_device *pwm;
>  	struct resource *r;
> @@ -166,7 +165,7 @@ static struct pwm_device *pwm_probe(struct
> platform_device *pdev,
>  	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
>  	if (pwm == NULL) {
>  		dev_err(&pdev->dev, "failed to allocate memory\n");
> -		return ERR_PTR(-ENOMEM);
> +		return -ENOMEM;
>  	}
>
>  	pwm->clk = clk_get(NULL, "OST_CLK");
> @@ -177,7 +176,7 @@ static struct pwm_device *pwm_probe(struct
> platform_device *pdev,
>  	pwm->clk_enabled = 0;
>
>  	pwm->use_count = 0;
> -	pwm->pwm_id = pwm_id;
> +	pwm->pwm_id = pdev->id;
>  	pwm->pdev = pdev;
>
>  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> @@ -203,7 +202,7 @@ static struct pwm_device *pwm_probe(struct
> platform_device *pdev,
>
>  	__add_pwm(pwm);
>  	platform_set_drvdata(pdev, pwm);
> -	return pwm;
> +	return 0;
>
>  err_release_mem:
>  	release_mem_region(r->start, resource_size(r));
> @@ -211,17 +210,7 @@ err_free_clk:
>  	clk_put(pwm->clk);
>  err_free:
>  	kfree(pwm);
> -	return ERR_PTR(ret);
> -}
> -
> -static int __devinit puv3_pwm_probe(struct platform_device *pdev)
> -{
> -	struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
> -
> -	if (IS_ERR(pwm))
> -		return PTR_ERR(pwm);
> -
> -	return 0;
> +	return ret;
>  }
>
>  static int __devexit pwm_remove(struct platform_device *pdev)
> @@ -251,7 +240,7 @@ static struct platform_driver puv3_pwm_driver = {
>  	.driver		= {
>  		.name	= "PKUnity-v3-PWM",
>  	},
> -	.probe		= puv3_pwm_probe,
> +	.probe		= pwm_probe,
>  	.remove		= __devexit_p(pwm_remove),
>  };
>  module_platform_driver(puv3_pwm_driver);
> --
> 1.7.12
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 4/5] unicore32: pwm: Use managed resource allocations
  2012-09-18  8:23 ` [PATCH v2 4/5] unicore32: pwm: Use managed resource allocations Thierry Reding
@ 2012-09-22  2:57   ` guanxuetao
  0 siblings, 0 replies; 14+ messages in thread
From: guanxuetao @ 2012-09-22  2:57 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Guan Xuetao, Qin Rui, linux-kernel

> This commit uses the managed resource allocation functions to simplify
> the cleanup paths on error and removal.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>

Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>

Thanks & Regards,
Guan Xuetao

> ---
>  arch/unicore32/kernel/pwm.c | 47
> +++++++++------------------------------------
>  1 file changed, 9 insertions(+), 38 deletions(-)
>
> diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
> index 7e23470..724e860 100644
> --- a/arch/unicore32/kernel/pwm.c
> +++ b/arch/unicore32/kernel/pwm.c
> @@ -160,19 +160,17 @@ static int __devinit pwm_probe(struct
> platform_device *pdev)
>  {
>  	struct pwm_device *pwm;
>  	struct resource *r;
> -	int ret = 0;
>
> -	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> +	pwm = devm_kzalloc(&pdev->dev, sizeof(struct pwm_device), GFP_KERNEL);
>  	if (pwm == NULL) {
>  		dev_err(&pdev->dev, "failed to allocate memory\n");
>  		return -ENOMEM;
>  	}
>
> -	pwm->clk = clk_get(NULL, "OST_CLK");
> -	if (IS_ERR(pwm->clk)) {
> -		ret = PTR_ERR(pwm->clk);
> -		goto err_free;
> -	}
> +	pwm->clk = devm_clk_get(&pdev->dev, "OST_CLK");
> +	if (IS_ERR(pwm->clk))
> +		return PTR_ERR(pwm->clk);
> +
>  	pwm->clk_enabled = 0;
>
>  	pwm->use_count = 0;
> @@ -182,41 +180,21 @@ static int __devinit pwm_probe(struct
> platform_device *pdev)
>  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	if (r == NULL) {
>  		dev_err(&pdev->dev, "no memory resource defined\n");
> -		ret = -ENODEV;
> -		goto err_free_clk;
> -	}
> -
> -	r = request_mem_region(r->start, resource_size(r), pdev->name);
> -	if (r == NULL) {
> -		dev_err(&pdev->dev, "failed to request memory resource\n");
> -		ret = -EBUSY;
> -		goto err_free_clk;
> +		return -ENODEV;
>  	}
>
> -	pwm->base = ioremap_nocache(r->start, resource_size(r));
> -	if (pwm->base == NULL) {
> -		dev_err(&pdev->dev, "failed to remap memory resource\n");
> -		ret = -EADDRNOTAVAIL;
> -		goto err_release_mem;
> -	}
> +	pwm->base = devm_request_and_ioremap(&pdev->dev, r);
> +	if (pwm->base == NULL)
> +		return -EADDRNOTAVAIL;
>
>  	__add_pwm(pwm);
>  	platform_set_drvdata(pdev, pwm);
>  	return 0;
> -
> -err_release_mem:
> -	release_mem_region(r->start, resource_size(r));
> -err_free_clk:
> -	clk_put(pwm->clk);
> -err_free:
> -	kfree(pwm);
> -	return ret;
>  }
>
>  static int __devexit pwm_remove(struct platform_device *pdev)
>  {
>  	struct pwm_device *pwm;
> -	struct resource *r;
>
>  	pwm = platform_get_drvdata(pdev);
>  	if (pwm == NULL)
> @@ -226,13 +204,6 @@ static int __devexit pwm_remove(struct
> platform_device *pdev)
>  	list_del(&pwm->node);
>  	mutex_unlock(&pwm_lock);
>
> -	iounmap(pwm->base);
> -
> -	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	release_mem_region(r->start, resource_size(r));
> -
> -	clk_put(pwm->clk);
> -	kfree(pwm);
>  	return 0;
>  }
>
> --
> 1.7.12
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 5/5] pwm: Move PUV3 PWM driver to PWM framework
  2012-09-18  8:23 ` [PATCH v2 5/5] pwm: Move PUV3 PWM driver to PWM framework Thierry Reding
@ 2012-09-22  2:58   ` guanxuetao
  0 siblings, 0 replies; 14+ messages in thread
From: guanxuetao @ 2012-09-22  2:58 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Guan Xuetao, Qin Rui, linux-kernel

> This commit moves the driver to drivers/pwm and converts it to the new
> PWM framework.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>

Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>

Thanks & Regards,
Guan Xuetao


> ---
>  arch/unicore32/Kconfig         |  12 +--
>  arch/unicore32/kernel/Makefile |   1 -
>  arch/unicore32/kernel/pwm.c    | 219
> -----------------------------------------
>  drivers/pwm/Kconfig            |  10 +-
>  drivers/pwm/Makefile           |   1 +
>  drivers/pwm/pwm-puv3.c         | 161 ++++++++++++++++++++++++++++++
>  6 files changed, 173 insertions(+), 231 deletions(-)
>  delete mode 100644 arch/unicore32/kernel/pwm.c
>  create mode 100644 drivers/pwm/pwm-puv3.c
>
> diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
> index b0a4743..91e2037 100644
> --- a/arch/unicore32/Kconfig
> +++ b/arch/unicore32/Kconfig
> @@ -20,9 +20,6 @@ config UNICORE32
>  	  designs licensed by PKUnity Ltd.
>  	  Please see web page at <http://www.pkunity.com/>.
>
> -config HAVE_PWM
> -	bool
> -
>  config GENERIC_GPIO
>  	def_bool y
>
> @@ -105,7 +102,8 @@ config PUV3_DB0913
>
>  config PUV3_NB0916
>  	bool "NetBook board (0916)"
> -	select HAVE_PWM
> +	select PWM
> +	select PWM_PUV3
>
>  config PUV3_SMW0919
>  	bool "Security Mini-Workstation board (0919)"
> @@ -219,12 +217,6 @@ config PUV3_GPIO
>  	select GPIO_SYSFS if EXPERIMENTAL
>  	default y
>
> -config PUV3_PWM
> -	tristate
> -	default BACKLIGHT_PWM
> -	help
> -	  Enable support for NB0916 PWM controllers
> -
>  if PUV3_NB0916
>
>  menu "PKUnity NetBook-0916 Features"
> diff --git a/arch/unicore32/kernel/Makefile
> b/arch/unicore32/kernel/Makefile
> index 3240101..fa497e0 100644
> --- a/arch/unicore32/kernel/Makefile
> +++ b/arch/unicore32/kernel/Makefile
> @@ -16,7 +16,6 @@ obj-$(CONFIG_UNICORE_FPU_F64)	+= fpu-ucf64.o
>  obj-$(CONFIG_ARCH_PUV3)		+= clock.o irq.o time.o
>
>  obj-$(CONFIG_PUV3_GPIO)		+= gpio.o
> -obj-$(CONFIG_PUV3_PWM)		+= pwm.o
>  obj-$(CONFIG_PUV3_PM)		+= pm.o sleep.o
>  obj-$(CONFIG_HIBERNATION)	+= hibernate.o hibernate_asm.o
>
> diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
> deleted file mode 100644
> index 724e860..0000000
> --- a/arch/unicore32/kernel/pwm.c
> +++ /dev/null
> @@ -1,219 +0,0 @@
> -/*
> - * linux/arch/unicore32/kernel/pwm.c
> - *
> - * Code specific to PKUnity SoC and UniCore ISA
> - *
> - *	Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
> - *	Copyright (C) 2001-2010 Guan Xuetao
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - */
> -
> -#include <linux/module.h>
> -#include <linux/kernel.h>
> -#include <linux/platform_device.h>
> -#include <linux/slab.h>
> -#include <linux/err.h>
> -#include <linux/clk.h>
> -#include <linux/io.h>
> -#include <linux/pwm.h>
> -
> -#include <asm/div64.h>
> -#include <mach/hardware.h>
> -
> -struct pwm_device {
> -	struct list_head	node;
> -	struct platform_device *pdev;
> -
> -	void __iomem	*base;
> -
> -	const char	*label;
> -	struct clk	*clk;
> -	int		clk_enabled;
> -
> -	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)
> -{
> -	unsigned long long c;
> -	unsigned long period_cycles, prescale, pv, dc;
> -
> -	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
> -		return -EINVAL;
> -
> -	c = clk_get_rate(pwm->clk);
> -	c = c * period_ns;
> -	do_div(c, 1000000000);
> -	period_cycles = c;
> -
> -	if (period_cycles < 1)
> -		period_cycles = 1;
> -	prescale = (period_cycles - 1) / 1024;
> -	pv = period_cycles / (prescale + 1) - 1;
> -
> -	if (prescale > 63)
> -		return -EINVAL;
> -
> -	if (duty_ns == period_ns)
> -		dc = OST_PWMDCCR_FDCYCLE;
> -	else
> -		dc = (pv + 1) * duty_ns / period_ns;
> -
> -	/* NOTE: the clock to PWM has to be enabled first
> -	 * before writing to the registers
> -	 */
> -	clk_enable(pwm->clk);
> -
> -	writel(prescale, pwm->base + OST_PWM_PWCR);
> -	writel(pv - dc, pwm->base + OST_PWM_DCCR);
> -	writel(pv, pwm->base + OST_PWM_PCR);
> -
> -	clk_disable(pwm->clk);
> -
> -	return 0;
> -}
> -EXPORT_SYMBOL(pwm_config);
> -
> -int pwm_enable(struct pwm_device *pwm)
> -{
> -	int rc = 0;
> -
> -	if (!pwm->clk_enabled) {
> -		rc = clk_enable(pwm->clk);
> -		if (!rc)
> -			pwm->clk_enabled = 1;
> -	}
> -	return rc;
> -}
> -EXPORT_SYMBOL(pwm_enable);
> -
> -void 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 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 (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);
> -}
> -
> -static int __devinit pwm_probe(struct platform_device *pdev)
> -{
> -	struct pwm_device *pwm;
> -	struct resource *r;
> -
> -	pwm = devm_kzalloc(&pdev->dev, sizeof(struct pwm_device), GFP_KERNEL);
> -	if (pwm == NULL) {
> -		dev_err(&pdev->dev, "failed to allocate memory\n");
> -		return -ENOMEM;
> -	}
> -
> -	pwm->clk = devm_clk_get(&pdev->dev, "OST_CLK");
> -	if (IS_ERR(pwm->clk))
> -		return PTR_ERR(pwm->clk);
> -
> -	pwm->clk_enabled = 0;
> -
> -	pwm->use_count = 0;
> -	pwm->pwm_id = pdev->id;
> -	pwm->pdev = pdev;
> -
> -	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (r == NULL) {
> -		dev_err(&pdev->dev, "no memory resource defined\n");
> -		return -ENODEV;
> -	}
> -
> -	pwm->base = devm_request_and_ioremap(&pdev->dev, r);
> -	if (pwm->base == NULL)
> -		return -EADDRNOTAVAIL;
> -
> -	__add_pwm(pwm);
> -	platform_set_drvdata(pdev, pwm);
> -	return 0;
> -}
> -
> -static int __devexit pwm_remove(struct platform_device *pdev)
> -{
> -	struct pwm_device *pwm;
> -
> -	pwm = platform_get_drvdata(pdev);
> -	if (pwm == NULL)
> -		return -ENODEV;
> -
> -	mutex_lock(&pwm_lock);
> -	list_del(&pwm->node);
> -	mutex_unlock(&pwm_lock);
> -
> -	return 0;
> -}
> -
> -static struct platform_driver puv3_pwm_driver = {
> -	.driver		= {
> -		.name	= "PKUnity-v3-PWM",
> -	},
> -	.probe		= pwm_probe,
> -	.remove		= __devexit_p(pwm_remove),
> -};
> -module_platform_driver(puv3_pwm_driver);
> -
> -MODULE_LICENSE("GPL v2");
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 5c663df..007c225 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -1,6 +1,5 @@
>  menuconfig PWM
>  	bool "Pulse-Width Modulation (PWM) Support"
> -	depends on !PUV3_PWM
>  	help
>  	  Generic Pulse-Width Modulation (PWM) support.
>
> @@ -77,6 +76,15 @@ config PWM_MXS
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called pwm-mxs.
>
> +config PWM_PUV3
> +	tristate "PKUnity NetBook-0916 PWM support"
> +	depends on ARCH_PUV3
> +	help
> +	  Generic PWM framework driver for PKUnity NetBook-0916.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called pwm-puv3.
> +
>  config PWM_PXA
>  	tristate "PXA PWM support"
>  	depends on ARCH_PXA
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index a1d6169..c8e521b 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -4,6 +4,7 @@ obj-$(CONFIG_PWM_IMX)		+= pwm-imx.o
>  obj-$(CONFIG_PWM_JZ4740)	+= pwm-jz4740.o
>  obj-$(CONFIG_PWM_LPC32XX)	+= pwm-lpc32xx.o
>  obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
> +obj-$(CONFIG_PWM_PUV3)		+= pwm-puv3.o
>  obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
>  obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
>  obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
> diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
> new file mode 100644
> index 0000000..2a93f37
> --- /dev/null
> +++ b/drivers/pwm/pwm-puv3.c
> @@ -0,0 +1,161 @@
> +/*
> + * linux/arch/unicore32/kernel/pwm.c
> + *
> + * Code specific to PKUnity SoC and UniCore ISA
> + *
> + *	Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
> + *	Copyright (C) 2001-2010 Guan Xuetao
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/pwm.h>
> +
> +#include <asm/div64.h>
> +#include <mach/hardware.h>
> +
> +struct puv3_pwm_chip {
> +	struct pwm_chip chip;
> +	void __iomem *base;
> +	struct clk *clk;
> +	bool enabled;
> +};
> +
> +static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip)
> +{
> +	return container_of(chip, struct puv3_pwm_chip, chip);
> +}
> +
> +/*
> + * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
> + * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
> + */
> +static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> +			   int duty_ns, int period_ns)
> +{
> +	unsigned long period_cycles, prescale, pv, dc;
> +	struct puv3_pwm_chip *puv3 = to_puv3(chip);
> +	unsigned long long c;
> +
> +	c = clk_get_rate(puv3->clk);
> +	c = c * period_ns;
> +	do_div(c, 1000000000);
> +	period_cycles = c;
> +
> +	if (period_cycles < 1)
> +		period_cycles = 1;
> +
> +	prescale = (period_cycles - 1) / 1024;
> +	pv = period_cycles / (prescale + 1) - 1;
> +
> +	if (prescale > 63)
> +		return -EINVAL;
> +
> +	if (duty_ns == period_ns)
> +		dc = OST_PWMDCCR_FDCYCLE;
> +	else
> +		dc = (pv + 1) * duty_ns / period_ns;
> +
> +	/*
> +	 * NOTE: the clock to PWM has to be enabled first
> +	 * before writing to the registers
> +	 */
> +	clk_prepare_enable(puv3->clk);
> +
> +	writel(prescale, puv3->base + OST_PWM_PWCR);
> +	writel(pv - dc, puv3->base + OST_PWM_DCCR);
> +	writel(pv, puv3->base + OST_PWM_PCR);
> +
> +	clk_disable_unprepare(puv3->clk);
> +
> +	return 0;
> +}
> +
> +static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> +	struct puv3_pwm_chip *puv3 = to_puv3(chip);
> +
> +	return clk_prepare_enable(puv3->clk);
> +}
> +
> +static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device
> *pwm)
> +{
> +	struct puv3_pwm_chip *puv3 = to_puv3(chip);
> +
> +	clk_disable_unprepare(puv3->clk);
> +}
> +
> +static const struct pwm_ops puv3_pwm_ops = {
> +	.config = puv3_pwm_config,
> +	.enable = puv3_pwm_enable,
> +	.disable = puv3_pwm_disable,
> +	.owner = THIS_MODULE,
> +};
> +
> +static int __devinit pwm_probe(struct platform_device *pdev)
> +{
> +	struct puv3_pwm_chip *puv3;
> +	struct resource *r;
> +	int ret;
> +
> +	puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL);
> +	if (puv3 == NULL) {
> +		dev_err(&pdev->dev, "failed to allocate memory\n");
> +		return -ENOMEM;
> +	}
> +
> +	puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK");
> +	if (IS_ERR(puv3->clk))
> +		return PTR_ERR(puv3->clk);
> +
> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (r == NULL) {
> +		dev_err(&pdev->dev, "no memory resource defined\n");
> +		return -ENODEV;
> +	}
> +
> +	puv3->base = devm_request_and_ioremap(&pdev->dev, r);
> +	if (puv3->base == NULL)
> +		return -EADDRNOTAVAIL;
> +
> +	puv3->chip.dev = &pdev->dev;
> +	puv3->chip.ops = &puv3_pwm_ops;
> +	puv3->chip.base = -1;
> +	puv3->chip.npwm = 1;
> +
> +	ret = pwmchip_add(&puv3->chip);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, puv3);
> +	return 0;
> +}
> +
> +static int __devexit pwm_remove(struct platform_device *pdev)
> +{
> +	struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev);
> +
> +	return pwmchip_remove(&puv3->chip);
> +}
> +
> +static struct platform_driver puv3_pwm_driver = {
> +	.driver = {
> +		.name = "PKUnity-v3-PWM",
> +	},
> +	.probe = pwm_probe,
> +	.remove = __devexit_p(pwm_remove),
> +};
> +module_platform_driver(puv3_pwm_driver);
> +
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.12
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver()
  2012-09-22  2:56   ` guanxuetao
@ 2012-09-22  7:32     ` Thierry Reding
  2012-09-22 10:49       ` guanxuetao
  2012-09-22 10:49       ` guanxuetao
  0 siblings, 2 replies; 14+ messages in thread
From: Thierry Reding @ 2012-09-22  7:32 UTC (permalink / raw)
  To: guanxuetao; +Cc: Guan Xuetao, Qin Rui, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 704 bytes --]

On Sat, Sep 22, 2012 at 10:56:30AM +0800, guanxuetao@mprc.pku.edu.cn wrote:
> > Some of the boilerplate code can be eliminated by using this macro. The
> > driver was previously registered with an arch_initcall(), so technically
> > this is no longer the same, but when the driver is moved to the PWM
> > framework, deferred probing will take care of any driver probe ordering
> > issues.
> >
> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> 
> Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
> Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
> 
> Thanks & Regards,
> Guan Xuetao

Great! If you don't mind I'll take this through the PWM tree with your
Acked-by.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver()
  2012-09-22  7:32     ` Thierry Reding
@ 2012-09-22 10:49       ` guanxuetao
  2012-09-22 10:49       ` guanxuetao
  1 sibling, 0 replies; 14+ messages in thread
From: guanxuetao @ 2012-09-22 10:49 UTC (permalink / raw)
  To: Thierry Reding; +Cc: guanxuetao, Guan Xuetao, Qin Rui, linux-kernel

> On Sat, Sep 22, 2012 at 10:56:30AM +0800, guanxuetao@mprc.pku.edu.cn
> wrote:
>> > Some of the boilerplate code can be eliminated by using this macro.
>> The
>> > driver was previously registered with an arch_initcall(), so
>> technically
>> > this is no longer the same, but when the driver is moved to the PWM
>> > framework, deferred probing will take care of any driver probe
>> ordering
>> > issues.
>> >
>> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
>>
>> Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
>> Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
>>
>> Thanks & Regards,
>> Guan Xuetao
>
> Great! If you don't mind I'll take this through the PWM tree with your
> Acked-by.
>
> Thierry
>

It's my pleasure.

Thanks & Regards,
Guan Xuetao

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver()
  2012-09-22  7:32     ` Thierry Reding
  2012-09-22 10:49       ` guanxuetao
@ 2012-09-22 10:49       ` guanxuetao
  2012-09-27 19:40         ` Thierry Reding
  1 sibling, 1 reply; 14+ messages in thread
From: guanxuetao @ 2012-09-22 10:49 UTC (permalink / raw)
  To: Thierry Reding; +Cc: guanxuetao, Guan Xuetao, Qin Rui, linux-kernel

> On Sat, Sep 22, 2012 at 10:56:30AM +0800, guanxuetao@mprc.pku.edu.cn
> wrote:
>> > Some of the boilerplate code can be eliminated by using this macro.
>> The
>> > driver was previously registered with an arch_initcall(), so
>> technically
>> > this is no longer the same, but when the driver is moved to the PWM
>> > framework, deferred probing will take care of any driver probe
>> ordering
>> > issues.
>> >
>> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
>>
>> Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
>> Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
>>
>> Thanks & Regards,
>> Guan Xuetao
>
> Great! If you don't mind I'll take this through the PWM tree with your
> Acked-by.
>
> Thierry
>

It's my pleasure.

Thanks & Regards,
Guan Xuetao

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver()
  2012-09-22 10:49       ` guanxuetao
@ 2012-09-27 19:40         ` Thierry Reding
  0 siblings, 0 replies; 14+ messages in thread
From: Thierry Reding @ 2012-09-27 19:40 UTC (permalink / raw)
  To: guanxuetao; +Cc: Guan Xuetao, Qin Rui, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 936 bytes --]

On Sat, Sep 22, 2012 at 06:49:19PM +0800, guanxuetao@mprc.pku.edu.cn wrote:
> > On Sat, Sep 22, 2012 at 10:56:30AM +0800, guanxuetao@mprc.pku.edu.cn
> > wrote:
> >> > Some of the boilerplate code can be eliminated by using this macro.
> >> The
> >> > driver was previously registered with an arch_initcall(), so
> >> technically
> >> > this is no longer the same, but when the driver is moved to the PWM
> >> > framework, deferred probing will take care of any driver probe
> >> ordering
> >> > issues.
> >> >
> >> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> >>
> >> Tested-by: Qin Rui <qinrui@mprc.pku.edu.cn>
> >> Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
> >>
> >> Thanks & Regards,
> >> Guan Xuetao
> >
> > Great! If you don't mind I'll take this through the PWM tree with your
> > Acked-by.
> >
> > Thierry
> >
> 
> It's my pleasure.

All patches applied, thanks.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-09-27 19:40 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-18  8:23 [PATCH v2 0/5] unicore32: Move PWM driver to PWM framework Thierry Reding
2012-09-18  8:23 ` [PATCH v2 1/5] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
2012-09-18  8:23 ` [PATCH v2 2/5] unicore32: pwm: Use module_platform_driver() Thierry Reding
2012-09-22  2:56   ` guanxuetao
2012-09-22  7:32     ` Thierry Reding
2012-09-22 10:49       ` guanxuetao
2012-09-22 10:49       ` guanxuetao
2012-09-27 19:40         ` Thierry Reding
2012-09-18  8:23 ` [PATCH v2 3/5] unicore32: pwm: Remove unnecessary indirection Thierry Reding
2012-09-22  2:56   ` guanxuetao
2012-09-18  8:23 ` [PATCH v2 4/5] unicore32: pwm: Use managed resource allocations Thierry Reding
2012-09-22  2:57   ` guanxuetao
2012-09-18  8:23 ` [PATCH v2 5/5] pwm: Move PUV3 PWM driver to PWM framework Thierry Reding
2012-09-22  2:58   ` guanxuetao

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).