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