linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] unicore32: Move PWM driver to PWM framework
@ 2012-09-02 10:21 Thierry Reding
  2012-09-02 10:21 ` [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-02 10:21 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Mike Turquette, linux-kernel

This series cleans up the PWM driver as well as moves and converts it
to the PWM framework.

Part of this series is a patch that converts the Unicore32 clock code
to the common clock framework, which allows devm_clk_get() to be used
for further cleanup. I'm not very familiar with the clock framework,
so this might need some extra thorough review.

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.

Thierry

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

 arch/unicore32/Kconfig              |  13 +-
 arch/unicore32/include/asm/clkdev.h |  26 ++
 arch/unicore32/kernel/Makefile      |   1 -
 arch/unicore32/kernel/clock.c       | 560 ++++++++++++++++++++----------------
 arch/unicore32/kernel/pwm.c         | 263 -----------------
 drivers/pwm/Kconfig                 |  10 +-
 drivers/pwm/Makefile                |   1 +
 drivers/pwm/pwm-puv3.c              | 165 +++++++++++
 8 files changed, 516 insertions(+), 523 deletions(-)
 create mode 100644 arch/unicore32/include/asm/clkdev.h
 delete mode 100644 arch/unicore32/kernel/pwm.c
 create mode 100644 drivers/pwm/pwm-puv3.c

-- 
1.7.12


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

* [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped registers
  2012-09-02 10:21 [PATCH 0/6] unicore32: Move PWM driver to PWM framework Thierry Reding
@ 2012-09-02 10:21 ` Thierry Reding
  2012-09-06  8:38   ` guanxuetao
  2012-09-02 10:21 ` [PATCH 2/6] unicore32: pwm: Use module_platform_driver() Thierry Reding
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Thierry Reding @ 2012-09-02 10:21 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Mike Turquette, 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>
---
 arch/unicore32/kernel/pwm.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
index 4615d51..410b786 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -23,10 +23,16 @@
 #include <asm/div64.h>
 #include <mach/hardware.h>
 
+#define PWCR 0x00
+#define DCCR 0x04
+#define PCR  0x08
+
 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 +75,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 + PWCR);
+	writel(pv - dc, pwm->base + DCCR);
+	writel(pv, pwm->base + PCR);
+
 	clk_disable(pwm->clk);
 
 	return 0;
@@ -190,10 +198,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 +241,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] 12+ messages in thread

* [PATCH 2/6] unicore32: pwm: Use module_platform_driver()
  2012-09-02 10:21 [PATCH 0/6] unicore32: Move PWM driver to PWM framework Thierry Reding
  2012-09-02 10:21 ` [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
@ 2012-09-02 10:21 ` Thierry Reding
  2012-09-02 10:21 ` [PATCH 3/6] unicore32: pwm: Remove unnecessary indirection Thierry Reding
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-02 10:21 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Mike Turquette, 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 410b786..22a7098 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -258,25 +258,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] 12+ messages in thread

* [PATCH 3/6] unicore32: pwm: Remove unnecessary indirection
  2012-09-02 10:21 [PATCH 0/6] unicore32: Move PWM driver to PWM framework Thierry Reding
  2012-09-02 10:21 ` [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
  2012-09-02 10:21 ` [PATCH 2/6] unicore32: pwm: Use module_platform_driver() Thierry Reding
@ 2012-09-02 10:21 ` Thierry Reding
  2012-09-02 10:21 ` [PATCH 4/6] unicore32: Add common clock support Thierry Reding
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-02 10:21 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Mike Turquette, 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 22a7098..d0cdfc0 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -160,8 +160,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;
@@ -170,7 +169,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");
@@ -181,7 +180,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);
@@ -207,7 +206,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));
@@ -215,17 +214,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)
@@ -255,7 +244,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] 12+ messages in thread

* [PATCH 4/6] unicore32: Add common clock support
  2012-09-02 10:21 [PATCH 0/6] unicore32: Move PWM driver to PWM framework Thierry Reding
                   ` (2 preceding siblings ...)
  2012-09-02 10:21 ` [PATCH 3/6] unicore32: pwm: Remove unnecessary indirection Thierry Reding
@ 2012-09-02 10:21 ` Thierry Reding
  2012-09-06  8:42   ` guanxuetao
  2012-09-08  1:22   ` Mike Turquette
  2012-09-02 10:21 ` [PATCH 5/6] unicore32: pwm: Use managed resource allocations Thierry Reding
  2012-09-02 10:21 ` [PATCH 6/6] pwm: Move PUV3 PWM driver to PWM framework Thierry Reding
  5 siblings, 2 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-02 10:21 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Mike Turquette, linux-kernel

This commit adds support for the common clock framework to the Unicore32
architecture.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
 arch/unicore32/Kconfig              |   1 +
 arch/unicore32/include/asm/clkdev.h |  26 ++
 arch/unicore32/kernel/clock.c       | 560 ++++++++++++++++++++----------------
 3 files changed, 339 insertions(+), 248 deletions(-)
 create mode 100644 arch/unicore32/include/asm/clkdev.h

diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index b0a4743..46b3a15 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -14,6 +14,7 @@ config UNICORE32
 	select GENERIC_IRQ_SHOW
 	select ARCH_WANT_FRAME_POINTERS
 	select GENERIC_IOMAP
+	select COMMON_CLK
 	help
 	  UniCore-32 is 32-bit Instruction Set Architecture,
 	  including a series of low-power-consumption RISC chip
diff --git a/arch/unicore32/include/asm/clkdev.h b/arch/unicore32/include/asm/clkdev.h
new file mode 100644
index 0000000..201645d
--- /dev/null
+++ b/arch/unicore32/include/asm/clkdev.h
@@ -0,0 +1,26 @@
+/*
+ *  based on arch/arm/include/asm/clkdev.h
+ *
+ *  Copyright (C) 2008 Russell King.
+ *
+ * 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.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+
+#ifndef __ASM_CLKDEV_H
+#define __ASM_CLKDEV_H
+
+#include <linux/slab.h>
+
+#define __clk_get(clk)	({ 1; })
+#define __clk_put(clk)	do { } while (0)
+
+static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
+{
+	return kzalloc(size, GFP_KERNEL);
+}
+
+#endif
diff --git a/arch/unicore32/kernel/clock.c b/arch/unicore32/kernel/clock.c
index 18d4563..197f885 100644
--- a/arch/unicore32/kernel/clock.c
+++ b/arch/unicore32/kernel/clock.c
@@ -17,223 +17,50 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/string.h>
-#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 
 #include <mach/hardware.h>
 
-/*
- * Very simple clock implementation
- */
-struct clk {
-	struct list_head	node;
-	unsigned long		rate;
-	const char		*name;
-};
-
-static struct clk clk_ost_clk = {
-	.name		= "OST_CLK",
-	.rate		= CLOCK_TICK_RATE,
-};
-
-static struct clk clk_mclk_clk = {
-	.name		= "MAIN_CLK",
-};
-
-static struct clk clk_bclk32_clk = {
-	.name		= "BUS32_CLK",
+struct clk_uc {
+	struct clk_hw hw;
 };
 
-static struct clk clk_ddr_clk = {
-	.name		= "DDR_CLK",
-};
-
-static struct clk clk_vga_clk = {
-	.name		= "VGA_CLK",
-};
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-	struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-	mutex_lock(&clocks_mutex);
-	list_for_each_entry(p, &clocks, node) {
-		if (strcmp(id, p->name) == 0) {
-			clk = p;
-			break;
-		}
-	}
-	mutex_unlock(&clocks_mutex);
-
-	return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
-int clk_enable(struct clk *clk)
-{
-	return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
+static inline struct clk_uc *to_clk_uc(struct clk_hw *hw)
 {
+	return container_of(hw, struct clk_uc, hw);
 }
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-	return clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-struct {
-	unsigned long rate;
-	unsigned long cfg;
-	unsigned long div;
-} vga_clk_table[] = {
-	{.rate =  25175000, .cfg = 0x00002001, .div = 0x9},
-	{.rate =  31500000, .cfg = 0x00002001, .div = 0x7},
-	{.rate =  40000000, .cfg = 0x00003801, .div = 0x9},
-	{.rate =  49500000, .cfg = 0x00003801, .div = 0x7},
-	{.rate =  65000000, .cfg = 0x00002c01, .div = 0x4},
-	{.rate =  78750000, .cfg = 0x00002400, .div = 0x7},
-	{.rate = 108000000, .cfg = 0x00002c01, .div = 0x2},
-	{.rate = 106500000, .cfg = 0x00003c01, .div = 0x3},
-	{.rate =  50650000, .cfg = 0x00106400, .div = 0x9},
-	{.rate =  61500000, .cfg = 0x00106400, .div = 0xa},
-	{.rate =  85500000, .cfg = 0x00002800, .div = 0x6},
-};
-
-struct {
-	unsigned long mrate;
-	unsigned long prate;
-} mclk_clk_table[] = {
-	{.mrate = 500000000, .prate = 0x00109801},
-	{.mrate = 525000000, .prate = 0x00104C00},
-	{.mrate = 550000000, .prate = 0x00105000},
-	{.mrate = 575000000, .prate = 0x00105400},
-	{.mrate = 600000000, .prate = 0x00105800},
-	{.mrate = 625000000, .prate = 0x00105C00},
-	{.mrate = 650000000, .prate = 0x00106000},
-	{.mrate = 675000000, .prate = 0x00106400},
-	{.mrate = 700000000, .prate = 0x00106800},
-	{.mrate = 725000000, .prate = 0x00106C00},
-	{.mrate = 750000000, .prate = 0x00107000},
-	{.mrate = 775000000, .prate = 0x00107400},
-	{.mrate = 800000000, .prate = 0x00107800},
-};
 
-int clk_set_rate(struct clk *clk, unsigned long rate)
+static struct clk *clk_register_uc(const char *name, const char *parent,
+				   const struct clk_ops *ops)
 {
-	if (clk == &clk_vga_clk) {
-		unsigned long pll_vgacfg, pll_vgadiv;
-		int ret, i;
-
-		/* lookup vga_clk_table */
-		ret = -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
-			if (rate == vga_clk_table[i].rate) {
-				pll_vgacfg = vga_clk_table[i].cfg;
-				pll_vgadiv = vga_clk_table[i].div;
-				ret = 0;
-				break;
-			}
-		}
-
-		if (ret)
-			return ret;
-
-		if (readl(PM_PLLVGACFG) == pll_vgacfg)
-			return 0;
+	struct clk_init_data init;
+	struct clk_uc *uc;
+	struct clk *clk;
 
-		/* set pll vga cfg reg. */
-		writel(pll_vgacfg, PM_PLLVGACFG);
+	uc = kzalloc(sizeof(*uc), GFP_KERNEL);
+	if (!uc)
+		return NULL;
 
-		writel(PM_PMCR_CFBVGA, PM_PMCR);
-		while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_VGADFC)
-				!= PM_PLLDFCDONE_VGADFC)
-			udelay(100); /* about 1ms */
+	init.name = name;
+	init.ops = ops;
+	init.flags = 0;
+	init.parent_names = parent ? &parent : NULL;
+	init.num_parents = parent ? 1 : 0;
 
-		/* set div cfg reg. */
-		writel(readl(PM_PCGR) | PM_PCGR_VGACLK, PM_PCGR);
+	uc->hw.init = &init;
 
-		writel((readl(PM_DIVCFG) & ~PM_DIVCFG_VGACLK_MASK)
-				| PM_DIVCFG_VGACLK(pll_vgadiv), PM_DIVCFG);
+	clk = clk_register(NULL, &uc->hw);
+	if (IS_ERR(clk))
+		kfree(uc);
 
-		writel(readl(PM_SWRESET) | PM_SWRESET_VGADIV, PM_SWRESET);
-		while ((readl(PM_SWRESET) & PM_SWRESET_VGADIV)
-				== PM_SWRESET_VGADIV)
-			udelay(100); /* 65536 bclk32, about 320us */
-
-		writel(readl(PM_PCGR) & ~PM_PCGR_VGACLK, PM_PCGR);
-	}
-#ifdef CONFIG_CPU_FREQ
-	if (clk == &clk_mclk_clk) {
-		u32 pll_rate, divstatus = PM_DIVSTATUS;
-		int ret, i;
-
-		/* lookup mclk_clk_table */
-		ret = -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
-			if (rate == mclk_clk_table[i].mrate) {
-				pll_rate = mclk_clk_table[i].prate;
-				clk_mclk_clk.rate = mclk_clk_table[i].mrate;
-				ret = 0;
-				break;
-			}
-		}
-
-		if (ret)
-			return ret;
-
-		if (clk_mclk_clk.rate)
-			clk_bclk32_clk.rate = clk_mclk_clk.rate
-				/ (((divstatus & 0x0000f000) >> 12) + 1);
-
-		/* set pll sys cfg reg. */
-		PM_PLLSYSCFG = pll_rate;
-
-		PM_PMCR = PM_PMCR_CFBSYS;
-		while ((PM_PLLDFCDONE & PM_PLLDFCDONE_SYSDFC)
-				!= PM_PLLDFCDONE_SYSDFC)
-			udelay(100);
-			/* about 1ms */
-	}
-#endif
-	return 0;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_register(struct clk *clk)
-{
-	mutex_lock(&clocks_mutex);
-	list_add(&clk->node, &clocks);
-	mutex_unlock(&clocks_mutex);
-	printk(KERN_DEFAULT "PKUnity PM: %s %lu.%02luM\n", clk->name,
-		(clk->rate)/1000000, (clk->rate)/10000 % 100);
-	return 0;
-}
-EXPORT_SYMBOL(clk_register);
-
-void clk_unregister(struct clk *clk)
-{
-	mutex_lock(&clocks_mutex);
-	list_del(&clk->node);
-	mutex_unlock(&clocks_mutex);
+	return clk;
 }
-EXPORT_SYMBOL(clk_unregister);
 
-struct {
+static const struct {
 	unsigned long prate;
 	unsigned long rate;
 } pllrate_table[] = {
@@ -301,7 +128,232 @@ struct {
 	{.prate = 0x00109800, .rate = 1000000000},
 };
 
-struct {
+static unsigned long clk_vga_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	unsigned long pllrate = readl(PM_PLLVGASTATUS);
+	unsigned long divstatus = readl(PM_DIVSTATUS);
+	unsigned long rate = 0;
+	unsigned int i;
+
+	/* lookup pvga_table */
+	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
+		if (pllrate == pllrate_table[i].prate) {
+			rate = pllrate_table[i].rate;
+			break;
+		}
+	}
+
+	if (rate)
+		rate = rate / (((divstatus & 0x00f00000) >> 20) + 1);
+
+	return rate;
+}
+
+static const struct {
+	unsigned long rate;
+	unsigned long cfg;
+	unsigned long div;
+} vga_clk_table[] = {
+	{.rate =  25175000, .cfg = 0x00002001, .div = 0x9},
+	{.rate =  31500000, .cfg = 0x00002001, .div = 0x7},
+	{.rate =  40000000, .cfg = 0x00003801, .div = 0x9},
+	{.rate =  49500000, .cfg = 0x00003801, .div = 0x7},
+	{.rate =  65000000, .cfg = 0x00002c01, .div = 0x4},
+	{.rate =  78750000, .cfg = 0x00002400, .div = 0x7},
+	{.rate = 108000000, .cfg = 0x00002c01, .div = 0x2},
+	{.rate = 106500000, .cfg = 0x00003c01, .div = 0x3},
+	{.rate =  50650000, .cfg = 0x00106400, .div = 0x9},
+	{.rate =  61500000, .cfg = 0x00106400, .div = 0xa},
+	{.rate =  85500000, .cfg = 0x00002800, .div = 0x6},
+};
+
+static long clk_vga_round_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long *parent_rate)
+{
+	unsigned long min = ULONG_MAX;
+	unsigned int i, best = 0;
+
+	for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
+		unsigned long diff = abs(rate - vga_clk_table[i].rate);
+
+		if (diff < min) {
+			min = diff;
+			best = i;
+		}
+	}
+
+	return vga_clk_table[best].rate;
+}
+
+static int clk_vga_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	unsigned long pll_vgacfg, pll_vgadiv;
+	int ret = -EINVAL;
+	unsigned int i;
+
+	/* lookup vga_clk_table */
+	for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
+		if (rate == vga_clk_table[i].rate) {
+			pll_vgacfg = vga_clk_table[i].cfg;
+			pll_vgadiv = vga_clk_table[i].div;
+			ret = 0;
+			break;
+		}
+	}
+
+	if (ret)
+		return ret;
+
+	if (readl(PM_PLLVGACFG) == pll_vgacfg)
+		return 0;
+
+	/* set pll vga cfg reg. */
+	writel(pll_vgacfg, PM_PLLVGACFG);
+
+	writel(PM_PMCR_CFBVGA, PM_PMCR);
+	while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_VGADFC)
+			!= PM_PLLDFCDONE_VGADFC)
+		udelay(100); /* about 1ms */
+
+	/* set div cfg reg. */
+	writel(readl(PM_PCGR) | PM_PCGR_VGACLK, PM_PCGR);
+
+	writel((readl(PM_DIVCFG) & ~PM_DIVCFG_VGACLK_MASK)
+			| PM_DIVCFG_VGACLK(pll_vgadiv), PM_DIVCFG);
+
+	writel(readl(PM_SWRESET) | PM_SWRESET_VGADIV, PM_SWRESET);
+	while ((readl(PM_SWRESET) & PM_SWRESET_VGADIV)
+			== PM_SWRESET_VGADIV)
+		udelay(100); /* 65536 bclk32, about 320us */
+
+	writel(readl(PM_PCGR) & ~PM_PCGR_VGACLK, PM_PCGR);
+
+	return 0;
+}
+
+static const struct clk_ops clk_vga_ops = {
+	.recalc_rate = clk_vga_recalc_rate,
+	.round_rate = clk_vga_round_rate,
+	.set_rate = clk_vga_set_rate,
+};
+
+static unsigned long clk_mclk_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+#ifndef CONFIG_ARCH_FPGA
+	unsigned long pllrate = readl(PM_PLLSYSSTATUS);
+	unsigned long rate = 0;
+	unsigned int i;
+
+	/* lookup pllrate_table */
+	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
+		if (pllrate == pllrate_table[i].prate) {
+			rate = pllrate_table[i].rate;
+			break;
+		}
+	}
+
+	return rate;
+#else
+	return 33000000;
+#endif
+}
+
+static const struct {
+	unsigned long mrate;
+	unsigned long prate;
+} mclk_clk_table[] = {
+	{.mrate = 500000000, .prate = 0x00109801},
+	{.mrate = 525000000, .prate = 0x00104C00},
+	{.mrate = 550000000, .prate = 0x00105000},
+	{.mrate = 575000000, .prate = 0x00105400},
+	{.mrate = 600000000, .prate = 0x00105800},
+	{.mrate = 625000000, .prate = 0x00105C00},
+	{.mrate = 650000000, .prate = 0x00106000},
+	{.mrate = 675000000, .prate = 0x00106400},
+	{.mrate = 700000000, .prate = 0x00106800},
+	{.mrate = 725000000, .prate = 0x00106C00},
+	{.mrate = 750000000, .prate = 0x00107000},
+	{.mrate = 775000000, .prate = 0x00107400},
+	{.mrate = 800000000, .prate = 0x00107800},
+};
+
+static long clk_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
+			        unsigned long *ratep)
+{
+	unsigned long min = ULONG_MAX;
+	unsigned int i, best = 0;
+
+	for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
+		unsigned long diff = abs(rate - mclk_clk_table[i].mrate);
+
+		if (diff < min) {
+			min = diff;
+			best = i;
+		}
+	}
+
+	return mclk_clk_table[best].mrate;
+}
+
+static int clk_mclk_set_rate(struct clk_hw *hw, unsigned long rate,
+			     unsigned long parent_rate)
+{
+	int ret = -EINVAL;
+	unsigned int i;
+	u32 pll_rate;
+
+	/* lookup mclk_clk_table */
+	for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
+		if (rate == mclk_clk_table[i].mrate) {
+			pll_rate = mclk_clk_table[i].prate;
+			ret = 0;
+			break;
+		}
+	}
+
+	if (ret)
+		return ret;
+
+	/* set pll sys cfg reg. */
+	writel(pll_rate, PM_PLLSYSCFG);
+
+	writel(PM_PMCR_CFBSYS, PM_PMCR);
+
+	while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_SYSDFC)
+			!= PM_PLLDFCDONE_SYSDFC)
+		udelay(100);
+		/* about 1ms */
+
+	return 0;
+}
+
+static const struct clk_ops clk_mclk_ops = {
+	.recalc_rate = clk_mclk_recalc_rate,
+	.round_rate = clk_mclk_round_rate,
+	.set_rate = clk_mclk_set_rate,
+};
+
+static unsigned long clk_bclk32_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+#ifndef CONFIG_ARCH_FPGA
+	u32 divstatus = readl(PM_DIVSTATUS);
+
+	return parent_rate / (((divstatus & 0x0000f000) >> 12) + 1);
+#else
+	return 33000000;
+#endif
+}
+
+static const struct clk_ops clk_bclk32_ops = {
+	.recalc_rate = clk_bclk32_recalc_rate,
+};
+
+#ifndef CONFIG_ARCH_FPGA
+static const struct {
 	unsigned long prate;
 	unsigned long drate;
 } pddr_table[] = {
@@ -322,69 +374,81 @@ struct {
 	{.prate = 0x00104001, .drate = 353894400},
 };
 
-static int __init clk_init(void)
+static unsigned long clk_ddr_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
 {
-#ifdef CONFIG_PUV3_PM
-	u32 pllrate, divstatus = readl(PM_DIVSTATUS);
-	u32 pcgr_val = readl(PM_PCGR);
-	int i;
-
-	pcgr_val |= PM_PCGR_BCLKMME | PM_PCGR_BCLKH264E | PM_PCGR_BCLKH264D
-			| PM_PCGR_HECLK | PM_PCGR_HDCLK;
-	writel(pcgr_val, PM_PCGR);
+	unsigned long pllrate = readl(PM_PLLDDRSTATUS);
+	unsigned long rate = 0;
+	unsigned int i;
 
-	pllrate = readl(PM_PLLSYSSTATUS);
-
-	/* lookup pmclk_table */
-	clk_mclk_clk.rate = 0;
-	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
-		if (pllrate == pllrate_table[i].prate) {
-			clk_mclk_clk.rate = pllrate_table[i].rate;
+	/* lookup pddr_table */
+	for (i = 0; i < ARRAY_SIZE(pddr_table); i++) {
+		if (pllrate == pddr_table[i].prate) {
+			rate = pddr_table[i].drate;
 			break;
 		}
 	}
 
-	if (clk_mclk_clk.rate)
-		clk_bclk32_clk.rate = clk_mclk_clk.rate /
-			(((divstatus & 0x0000f000) >> 12) + 1);
+	return rate;
+}
+#else
+static unsigned long clk_ddr_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	return 33000000;
+}
+#endif
 
-	pllrate = readl(PM_PLLDDRSTATUS);
+static const struct clk_ops clk_ddr_ops = {
+	.recalc_rate = clk_ddr_recalc_rate,
+};
 
-	/* lookup pddr_table */
-	clk_ddr_clk.rate = 0;
-	for (i = 0; i < ARRAY_SIZE(pddr_table); i++) {
-		if (pllrate == pddr_table[i].prate) {
-			clk_ddr_clk.rate = pddr_table[i].drate;
-			break;
-		}
+static int __init clk_init(void)
+{
+	unsigned long value;
+	struct clk *clk;
+
+	value = readl(PM_PCGR);
+	value |= PM_PCGR_BCLKMME | PM_PCGR_BCLKH264E | PM_PCGR_BCLKH264D |
+		 PM_PCGR_HECLK | PM_PCGR_HDCLK;
+	writel(value, PM_PCGR);
+
+	clk = clk_register_uc("MAIN_CLK", NULL, &clk_mclk_ops);
+	if (IS_ERR(clk)) {
+		pr_err("%s(): failed to register main clock: %ld\n", __func__,
+		       PTR_ERR(clk));
+		return PTR_ERR(clk);
 	}
 
-	pllrate = readl(PM_PLLVGASTATUS);
+	clk = clk_register_uc("BUS32_CLK", "MAIN_CLK", &clk_bclk32_ops);
+	if (IS_ERR(clk)) {
+		pr_err("%s(): failed to register bus clock: %ld\n", __func__,
+		       PTR_ERR(clk));
+		return PTR_ERR(clk);
+	}
 
-	/* lookup pvga_table */
-	clk_vga_clk.rate = 0;
-	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
-		if (pllrate == pllrate_table[i].prate) {
-			clk_vga_clk.rate = pllrate_table[i].rate;
-			break;
-		}
+	clk = clk_register_uc("VGA_CLK", NULL, &clk_vga_ops);
+	if (IS_ERR(clk)) {
+		pr_err("%s(): failed to register VGA clock: %ld\n", __func__,
+		       PTR_ERR(clk));
+		return PTR_ERR(clk);
 	}
 
-	if (clk_vga_clk.rate)
-		clk_vga_clk.rate = clk_vga_clk.rate /
-			(((divstatus & 0x00f00000) >> 20) + 1);
+	clk = clk_register_uc("DDR_CLK", NULL, &clk_ddr_ops);
+	if (IS_ERR(clk)) {
+		pr_err("%s(): failed to register DDR clock: %ld\n", __func__,
+		       PTR_ERR(clk));
+		return PTR_ERR(clk);
+	}
+
+	clk = clk_register_fixed_rate(NULL, "OST_CLK", NULL, 0,
+				      CLOCK_TICK_RATE);
+	if (IS_ERR(clk)) {
+		pr_err("%s(): failed to register timer clock: %ld\n", __func__,
+		       PTR_ERR(clk));
+		return PTR_ERR(clk);
+	}
 
-	clk_register(&clk_vga_clk);
-#endif
-#ifdef CONFIG_ARCH_FPGA
-	clk_ddr_clk.rate = 33000000;
-	clk_mclk_clk.rate = 33000000;
-	clk_bclk32_clk.rate = 33000000;
-#endif
-	clk_register(&clk_ddr_clk);
-	clk_register(&clk_mclk_clk);
-	clk_register(&clk_bclk32_clk);
-	clk_register(&clk_ost_clk);
 	return 0;
 }
 core_initcall(clk_init);
-- 
1.7.12


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

* [PATCH 5/6] unicore32: pwm: Use managed resource allocations
  2012-09-02 10:21 [PATCH 0/6] unicore32: Move PWM driver to PWM framework Thierry Reding
                   ` (3 preceding siblings ...)
  2012-09-02 10:21 ` [PATCH 4/6] unicore32: Add common clock support Thierry Reding
@ 2012-09-02 10:21 ` Thierry Reding
  2012-09-02 10:21 ` [PATCH 6/6] pwm: Move PUV3 PWM driver to PWM framework Thierry Reding
  5 siblings, 0 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-02 10:21 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Mike Turquette, 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 d0cdfc0..795c1ba 100644
--- a/arch/unicore32/kernel/pwm.c
+++ b/arch/unicore32/kernel/pwm.c
@@ -164,19 +164,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;
@@ -186,41 +184,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)
@@ -230,13 +208,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] 12+ messages in thread

* [PATCH 6/6] pwm: Move PUV3 PWM driver to PWM framework
  2012-09-02 10:21 [PATCH 0/6] unicore32: Move PWM driver to PWM framework Thierry Reding
                   ` (4 preceding siblings ...)
  2012-09-02 10:21 ` [PATCH 5/6] unicore32: pwm: Use managed resource allocations Thierry Reding
@ 2012-09-02 10:21 ` Thierry Reding
  5 siblings, 0 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-02 10:21 UTC (permalink / raw)
  To: Guan Xuetao; +Cc: Mike Turquette, 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    | 223 -----------------------------------------
 drivers/pwm/Kconfig            |  10 +-
 drivers/pwm/Makefile           |   1 +
 drivers/pwm/pwm-puv3.c         | 165 ++++++++++++++++++++++++++++++
 6 files changed, 177 insertions(+), 235 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 46b3a15..abbc7e4 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -21,9 +21,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
 
@@ -106,7 +103,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)"
@@ -220,12 +218,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 795c1ba..0000000
--- a/arch/unicore32/kernel/pwm.c
+++ /dev/null
@@ -1,223 +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>
-
-#define PWCR 0x00
-#define DCCR 0x04
-#define PCR  0x08
-
-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 + PWCR);
-	writel(pv - dc, pwm->base + DCCR);
-	writel(pv, pwm->base + 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..bd802e3
--- /dev/null
+++ b/drivers/pwm/pwm-puv3.c
@@ -0,0 +1,165 @@
+/*
+ * 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>
+
+#define PWCR 0x00
+#define DCCR 0x04
+#define PCR  0x08
+
+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 + PWCR);
+	writel(pv - dc, puv3->base + DCCR);
+	writel(pv, puv3->base + 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] 12+ messages in thread

* Re: [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped  registers
  2012-09-02 10:21 ` [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
@ 2012-09-06  8:38   ` guanxuetao
  2012-09-07 12:50     ` Thierry Reding
  0 siblings, 1 reply; 12+ messages in thread
From: guanxuetao @ 2012-09-06  8:38 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Guan Xuetao, Mike Turquette, 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>
> ---
>  arch/unicore32/kernel/pwm.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
>
> diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
> index 4615d51..410b786 100644
> --- a/arch/unicore32/kernel/pwm.c
> +++ b/arch/unicore32/kernel/pwm.c
> @@ -23,10 +23,16 @@
>  #include <asm/div64.h>
>  #include <mach/hardware.h>
>
> +#define PWCR 0x00
> +#define DCCR 0x04
> +#define PCR  0x08
I think old register names could be used here by some small modifications.
Please see arch/unicore32/include/mach/regs-ost.h
We can avoid ioremap and use writel/readl directly on these registers.

Guan

> +
>  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 +75,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 + PWCR);
> +	writel(pv - dc, pwm->base + DCCR);
> +	writel(pv, pwm->base + PCR);
> +
>  	clk_disable(pwm->clk);
>
>  	return 0;
> @@ -190,10 +198,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 +241,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	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/6] unicore32: Add common clock support
  2012-09-02 10:21 ` [PATCH 4/6] unicore32: Add common clock support Thierry Reding
@ 2012-09-06  8:42   ` guanxuetao
  2012-09-07 12:53     ` Thierry Reding
  2012-09-08  1:22   ` Mike Turquette
  1 sibling, 1 reply; 12+ messages in thread
From: guanxuetao @ 2012-09-06  8:42 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Guan Xuetao, Mike Turquette, linux-kernel

> This commit adds support for the common clock framework to the Unicore32
> architecture.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>

This patch can't work.
Could you disintegrate it into several small patches, so I could check it
out.

Thanks,
Guan Xuetao

> ---
>  arch/unicore32/Kconfig              |   1 +
>  arch/unicore32/include/asm/clkdev.h |  26 ++
>  arch/unicore32/kernel/clock.c       | 560
> ++++++++++++++++++++----------------
>  3 files changed, 339 insertions(+), 248 deletions(-)
>  create mode 100644 arch/unicore32/include/asm/clkdev.h
>
> diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
> index b0a4743..46b3a15 100644
> --- a/arch/unicore32/Kconfig
> +++ b/arch/unicore32/Kconfig
> @@ -14,6 +14,7 @@ config UNICORE32
>  	select GENERIC_IRQ_SHOW
>  	select ARCH_WANT_FRAME_POINTERS
>  	select GENERIC_IOMAP
> +	select COMMON_CLK
>  	help
>  	  UniCore-32 is 32-bit Instruction Set Architecture,
>  	  including a series of low-power-consumption RISC chip
> diff --git a/arch/unicore32/include/asm/clkdev.h
> b/arch/unicore32/include/asm/clkdev.h
> new file mode 100644
> index 0000000..201645d
> --- /dev/null
> +++ b/arch/unicore32/include/asm/clkdev.h
> @@ -0,0 +1,26 @@
> +/*
> + *  based on arch/arm/include/asm/clkdev.h
> + *
> + *  Copyright (C) 2008 Russell King.
> + *
> + * 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.
> + *
> + * Helper for the clk API to assist looking up a struct clk.
> + */
> +
> +#ifndef __ASM_CLKDEV_H
> +#define __ASM_CLKDEV_H
> +
> +#include <linux/slab.h>
> +
> +#define __clk_get(clk)	({ 1; })
> +#define __clk_put(clk)	do { } while (0)
> +
> +static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
> +{
> +	return kzalloc(size, GFP_KERNEL);
> +}
> +
> +#endif
> diff --git a/arch/unicore32/kernel/clock.c b/arch/unicore32/kernel/clock.c
> index 18d4563..197f885 100644
> --- a/arch/unicore32/kernel/clock.c
> +++ b/arch/unicore32/kernel/clock.c
> @@ -17,223 +17,50 @@
>  #include <linux/errno.h>
>  #include <linux/err.h>
>  #include <linux/string.h>
> -#include <linux/clk.h>
> +#include <linux/clk-provider.h>
>  #include <linux/mutex.h>
>  #include <linux/delay.h>
>  #include <linux/io.h>
> +#include <linux/slab.h>
>
>  #include <mach/hardware.h>
>
> -/*
> - * Very simple clock implementation
> - */
> -struct clk {
> -	struct list_head	node;
> -	unsigned long		rate;
> -	const char		*name;
> -};
> -
> -static struct clk clk_ost_clk = {
> -	.name		= "OST_CLK",
> -	.rate		= CLOCK_TICK_RATE,
> -};
> -
> -static struct clk clk_mclk_clk = {
> -	.name		= "MAIN_CLK",
> -};
> -
> -static struct clk clk_bclk32_clk = {
> -	.name		= "BUS32_CLK",
> +struct clk_uc {
> +	struct clk_hw hw;
>  };
>
> -static struct clk clk_ddr_clk = {
> -	.name		= "DDR_CLK",
> -};
> -
> -static struct clk clk_vga_clk = {
> -	.name		= "VGA_CLK",
> -};
> -
> -static LIST_HEAD(clocks);
> -static DEFINE_MUTEX(clocks_mutex);
> -
> -struct clk *clk_get(struct device *dev, const char *id)
> -{
> -	struct clk *p, *clk = ERR_PTR(-ENOENT);
> -
> -	mutex_lock(&clocks_mutex);
> -	list_for_each_entry(p, &clocks, node) {
> -		if (strcmp(id, p->name) == 0) {
> -			clk = p;
> -			break;
> -		}
> -	}
> -	mutex_unlock(&clocks_mutex);
> -
> -	return clk;
> -}
> -EXPORT_SYMBOL(clk_get);
> -
> -void clk_put(struct clk *clk)
> -{
> -}
> -EXPORT_SYMBOL(clk_put);
> -
> -int clk_enable(struct clk *clk)
> -{
> -	return 0;
> -}
> -EXPORT_SYMBOL(clk_enable);
> -
> -void clk_disable(struct clk *clk)
> +static inline struct clk_uc *to_clk_uc(struct clk_hw *hw)
>  {
> +	return container_of(hw, struct clk_uc, hw);
>  }
> -EXPORT_SYMBOL(clk_disable);
> -
> -unsigned long clk_get_rate(struct clk *clk)
> -{
> -	return clk->rate;
> -}
> -EXPORT_SYMBOL(clk_get_rate);
> -
> -struct {
> -	unsigned long rate;
> -	unsigned long cfg;
> -	unsigned long div;
> -} vga_clk_table[] = {
> -	{.rate =  25175000, .cfg = 0x00002001, .div = 0x9},
> -	{.rate =  31500000, .cfg = 0x00002001, .div = 0x7},
> -	{.rate =  40000000, .cfg = 0x00003801, .div = 0x9},
> -	{.rate =  49500000, .cfg = 0x00003801, .div = 0x7},
> -	{.rate =  65000000, .cfg = 0x00002c01, .div = 0x4},
> -	{.rate =  78750000, .cfg = 0x00002400, .div = 0x7},
> -	{.rate = 108000000, .cfg = 0x00002c01, .div = 0x2},
> -	{.rate = 106500000, .cfg = 0x00003c01, .div = 0x3},
> -	{.rate =  50650000, .cfg = 0x00106400, .div = 0x9},
> -	{.rate =  61500000, .cfg = 0x00106400, .div = 0xa},
> -	{.rate =  85500000, .cfg = 0x00002800, .div = 0x6},
> -};
> -
> -struct {
> -	unsigned long mrate;
> -	unsigned long prate;
> -} mclk_clk_table[] = {
> -	{.mrate = 500000000, .prate = 0x00109801},
> -	{.mrate = 525000000, .prate = 0x00104C00},
> -	{.mrate = 550000000, .prate = 0x00105000},
> -	{.mrate = 575000000, .prate = 0x00105400},
> -	{.mrate = 600000000, .prate = 0x00105800},
> -	{.mrate = 625000000, .prate = 0x00105C00},
> -	{.mrate = 650000000, .prate = 0x00106000},
> -	{.mrate = 675000000, .prate = 0x00106400},
> -	{.mrate = 700000000, .prate = 0x00106800},
> -	{.mrate = 725000000, .prate = 0x00106C00},
> -	{.mrate = 750000000, .prate = 0x00107000},
> -	{.mrate = 775000000, .prate = 0x00107400},
> -	{.mrate = 800000000, .prate = 0x00107800},
> -};
>
> -int clk_set_rate(struct clk *clk, unsigned long rate)
> +static struct clk *clk_register_uc(const char *name, const char *parent,
> +				   const struct clk_ops *ops)
>  {
> -	if (clk == &clk_vga_clk) {
> -		unsigned long pll_vgacfg, pll_vgadiv;
> -		int ret, i;
> -
> -		/* lookup vga_clk_table */
> -		ret = -EINVAL;
> -		for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
> -			if (rate == vga_clk_table[i].rate) {
> -				pll_vgacfg = vga_clk_table[i].cfg;
> -				pll_vgadiv = vga_clk_table[i].div;
> -				ret = 0;
> -				break;
> -			}
> -		}
> -
> -		if (ret)
> -			return ret;
> -
> -		if (readl(PM_PLLVGACFG) == pll_vgacfg)
> -			return 0;
> +	struct clk_init_data init;
> +	struct clk_uc *uc;
> +	struct clk *clk;
>
> -		/* set pll vga cfg reg. */
> -		writel(pll_vgacfg, PM_PLLVGACFG);
> +	uc = kzalloc(sizeof(*uc), GFP_KERNEL);
> +	if (!uc)
> +		return NULL;
>
> -		writel(PM_PMCR_CFBVGA, PM_PMCR);
> -		while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_VGADFC)
> -				!= PM_PLLDFCDONE_VGADFC)
> -			udelay(100); /* about 1ms */
> +	init.name = name;
> +	init.ops = ops;
> +	init.flags = 0;
> +	init.parent_names = parent ? &parent : NULL;
> +	init.num_parents = parent ? 1 : 0;
>
> -		/* set div cfg reg. */
> -		writel(readl(PM_PCGR) | PM_PCGR_VGACLK, PM_PCGR);
> +	uc->hw.init = &init;
>
> -		writel((readl(PM_DIVCFG) & ~PM_DIVCFG_VGACLK_MASK)
> -				| PM_DIVCFG_VGACLK(pll_vgadiv), PM_DIVCFG);
> +	clk = clk_register(NULL, &uc->hw);
> +	if (IS_ERR(clk))
> +		kfree(uc);
>
> -		writel(readl(PM_SWRESET) | PM_SWRESET_VGADIV, PM_SWRESET);
> -		while ((readl(PM_SWRESET) & PM_SWRESET_VGADIV)
> -				== PM_SWRESET_VGADIV)
> -			udelay(100); /* 65536 bclk32, about 320us */
> -
> -		writel(readl(PM_PCGR) & ~PM_PCGR_VGACLK, PM_PCGR);
> -	}
> -#ifdef CONFIG_CPU_FREQ
> -	if (clk == &clk_mclk_clk) {
> -		u32 pll_rate, divstatus = PM_DIVSTATUS;
> -		int ret, i;
> -
> -		/* lookup mclk_clk_table */
> -		ret = -EINVAL;
> -		for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
> -			if (rate == mclk_clk_table[i].mrate) {
> -				pll_rate = mclk_clk_table[i].prate;
> -				clk_mclk_clk.rate = mclk_clk_table[i].mrate;
> -				ret = 0;
> -				break;
> -			}
> -		}
> -
> -		if (ret)
> -			return ret;
> -
> -		if (clk_mclk_clk.rate)
> -			clk_bclk32_clk.rate = clk_mclk_clk.rate
> -				/ (((divstatus & 0x0000f000) >> 12) + 1);
> -
> -		/* set pll sys cfg reg. */
> -		PM_PLLSYSCFG = pll_rate;
> -
> -		PM_PMCR = PM_PMCR_CFBSYS;
> -		while ((PM_PLLDFCDONE & PM_PLLDFCDONE_SYSDFC)
> -				!= PM_PLLDFCDONE_SYSDFC)
> -			udelay(100);
> -			/* about 1ms */
> -	}
> -#endif
> -	return 0;
> -}
> -EXPORT_SYMBOL(clk_set_rate);
> -
> -int clk_register(struct clk *clk)
> -{
> -	mutex_lock(&clocks_mutex);
> -	list_add(&clk->node, &clocks);
> -	mutex_unlock(&clocks_mutex);
> -	printk(KERN_DEFAULT "PKUnity PM: %s %lu.%02luM\n", clk->name,
> -		(clk->rate)/1000000, (clk->rate)/10000 % 100);
> -	return 0;
> -}
> -EXPORT_SYMBOL(clk_register);
> -
> -void clk_unregister(struct clk *clk)
> -{
> -	mutex_lock(&clocks_mutex);
> -	list_del(&clk->node);
> -	mutex_unlock(&clocks_mutex);
> +	return clk;
>  }
> -EXPORT_SYMBOL(clk_unregister);
>
> -struct {
> +static const struct {
>  	unsigned long prate;
>  	unsigned long rate;
>  } pllrate_table[] = {
> @@ -301,7 +128,232 @@ struct {
>  	{.prate = 0x00109800, .rate = 1000000000},
>  };
>
> -struct {
> +static unsigned long clk_vga_recalc_rate(struct clk_hw *hw,
> +					 unsigned long parent_rate)
> +{
> +	unsigned long pllrate = readl(PM_PLLVGASTATUS);
> +	unsigned long divstatus = readl(PM_DIVSTATUS);
> +	unsigned long rate = 0;
> +	unsigned int i;
> +
> +	/* lookup pvga_table */
> +	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
> +		if (pllrate == pllrate_table[i].prate) {
> +			rate = pllrate_table[i].rate;
> +			break;
> +		}
> +	}
> +
> +	if (rate)
> +		rate = rate / (((divstatus & 0x00f00000) >> 20) + 1);
> +
> +	return rate;
> +}
> +
> +static const struct {
> +	unsigned long rate;
> +	unsigned long cfg;
> +	unsigned long div;
> +} vga_clk_table[] = {
> +	{.rate =  25175000, .cfg = 0x00002001, .div = 0x9},
> +	{.rate =  31500000, .cfg = 0x00002001, .div = 0x7},
> +	{.rate =  40000000, .cfg = 0x00003801, .div = 0x9},
> +	{.rate =  49500000, .cfg = 0x00003801, .div = 0x7},
> +	{.rate =  65000000, .cfg = 0x00002c01, .div = 0x4},
> +	{.rate =  78750000, .cfg = 0x00002400, .div = 0x7},
> +	{.rate = 108000000, .cfg = 0x00002c01, .div = 0x2},
> +	{.rate = 106500000, .cfg = 0x00003c01, .div = 0x3},
> +	{.rate =  50650000, .cfg = 0x00106400, .div = 0x9},
> +	{.rate =  61500000, .cfg = 0x00106400, .div = 0xa},
> +	{.rate =  85500000, .cfg = 0x00002800, .div = 0x6},
> +};
> +
> +static long clk_vga_round_rate(struct clk_hw *hw, unsigned long rate,
> +			       unsigned long *parent_rate)
> +{
> +	unsigned long min = ULONG_MAX;
> +	unsigned int i, best = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
> +		unsigned long diff = abs(rate - vga_clk_table[i].rate);
> +
> +		if (diff < min) {
> +			min = diff;
> +			best = i;
> +		}
> +	}
> +
> +	return vga_clk_table[best].rate;
> +}
> +
> +static int clk_vga_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	unsigned long pll_vgacfg, pll_vgadiv;
> +	int ret = -EINVAL;
> +	unsigned int i;
> +
> +	/* lookup vga_clk_table */
> +	for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
> +		if (rate == vga_clk_table[i].rate) {
> +			pll_vgacfg = vga_clk_table[i].cfg;
> +			pll_vgadiv = vga_clk_table[i].div;
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	if (ret)
> +		return ret;
> +
> +	if (readl(PM_PLLVGACFG) == pll_vgacfg)
> +		return 0;
> +
> +	/* set pll vga cfg reg. */
> +	writel(pll_vgacfg, PM_PLLVGACFG);
> +
> +	writel(PM_PMCR_CFBVGA, PM_PMCR);
> +	while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_VGADFC)
> +			!= PM_PLLDFCDONE_VGADFC)
> +		udelay(100); /* about 1ms */
> +
> +	/* set div cfg reg. */
> +	writel(readl(PM_PCGR) | PM_PCGR_VGACLK, PM_PCGR);
> +
> +	writel((readl(PM_DIVCFG) & ~PM_DIVCFG_VGACLK_MASK)
> +			| PM_DIVCFG_VGACLK(pll_vgadiv), PM_DIVCFG);
> +
> +	writel(readl(PM_SWRESET) | PM_SWRESET_VGADIV, PM_SWRESET);
> +	while ((readl(PM_SWRESET) & PM_SWRESET_VGADIV)
> +			== PM_SWRESET_VGADIV)
> +		udelay(100); /* 65536 bclk32, about 320us */
> +
> +	writel(readl(PM_PCGR) & ~PM_PCGR_VGACLK, PM_PCGR);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops clk_vga_ops = {
> +	.recalc_rate = clk_vga_recalc_rate,
> +	.round_rate = clk_vga_round_rate,
> +	.set_rate = clk_vga_set_rate,
> +};
> +
> +static unsigned long clk_mclk_recalc_rate(struct clk_hw *hw,
> +					  unsigned long parent_rate)
> +{
> +#ifndef CONFIG_ARCH_FPGA
> +	unsigned long pllrate = readl(PM_PLLSYSSTATUS);
> +	unsigned long rate = 0;
> +	unsigned int i;
> +
> +	/* lookup pllrate_table */
> +	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
> +		if (pllrate == pllrate_table[i].prate) {
> +			rate = pllrate_table[i].rate;
> +			break;
> +		}
> +	}
> +
> +	return rate;
> +#else
> +	return 33000000;
> +#endif
> +}
> +
> +static const struct {
> +	unsigned long mrate;
> +	unsigned long prate;
> +} mclk_clk_table[] = {
> +	{.mrate = 500000000, .prate = 0x00109801},
> +	{.mrate = 525000000, .prate = 0x00104C00},
> +	{.mrate = 550000000, .prate = 0x00105000},
> +	{.mrate = 575000000, .prate = 0x00105400},
> +	{.mrate = 600000000, .prate = 0x00105800},
> +	{.mrate = 625000000, .prate = 0x00105C00},
> +	{.mrate = 650000000, .prate = 0x00106000},
> +	{.mrate = 675000000, .prate = 0x00106400},
> +	{.mrate = 700000000, .prate = 0x00106800},
> +	{.mrate = 725000000, .prate = 0x00106C00},
> +	{.mrate = 750000000, .prate = 0x00107000},
> +	{.mrate = 775000000, .prate = 0x00107400},
> +	{.mrate = 800000000, .prate = 0x00107800},
> +};
> +
> +static long clk_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
> +			        unsigned long *ratep)
> +{
> +	unsigned long min = ULONG_MAX;
> +	unsigned int i, best = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
> +		unsigned long diff = abs(rate - mclk_clk_table[i].mrate);
> +
> +		if (diff < min) {
> +			min = diff;
> +			best = i;
> +		}
> +	}
> +
> +	return mclk_clk_table[best].mrate;
> +}
> +
> +static int clk_mclk_set_rate(struct clk_hw *hw, unsigned long rate,
> +			     unsigned long parent_rate)
> +{
> +	int ret = -EINVAL;
> +	unsigned int i;
> +	u32 pll_rate;
> +
> +	/* lookup mclk_clk_table */
> +	for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
> +		if (rate == mclk_clk_table[i].mrate) {
> +			pll_rate = mclk_clk_table[i].prate;
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	if (ret)
> +		return ret;
> +
> +	/* set pll sys cfg reg. */
> +	writel(pll_rate, PM_PLLSYSCFG);
> +
> +	writel(PM_PMCR_CFBSYS, PM_PMCR);
> +
> +	while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_SYSDFC)
> +			!= PM_PLLDFCDONE_SYSDFC)
> +		udelay(100);
> +		/* about 1ms */
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops clk_mclk_ops = {
> +	.recalc_rate = clk_mclk_recalc_rate,
> +	.round_rate = clk_mclk_round_rate,
> +	.set_rate = clk_mclk_set_rate,
> +};
> +
> +static unsigned long clk_bclk32_recalc_rate(struct clk_hw *hw,
> +					    unsigned long parent_rate)
> +{
> +#ifndef CONFIG_ARCH_FPGA
> +	u32 divstatus = readl(PM_DIVSTATUS);
> +
> +	return parent_rate / (((divstatus & 0x0000f000) >> 12) + 1);
> +#else
> +	return 33000000;
> +#endif
> +}
> +
> +static const struct clk_ops clk_bclk32_ops = {
> +	.recalc_rate = clk_bclk32_recalc_rate,
> +};
> +
> +#ifndef CONFIG_ARCH_FPGA
> +static const struct {
>  	unsigned long prate;
>  	unsigned long drate;
>  } pddr_table[] = {
> @@ -322,69 +374,81 @@ struct {
>  	{.prate = 0x00104001, .drate = 353894400},
>  };
>
> -static int __init clk_init(void)
> +static unsigned long clk_ddr_recalc_rate(struct clk_hw *hw,
> +					 unsigned long parent_rate)
>  {
> -#ifdef CONFIG_PUV3_PM
> -	u32 pllrate, divstatus = readl(PM_DIVSTATUS);
> -	u32 pcgr_val = readl(PM_PCGR);
> -	int i;
> -
> -	pcgr_val |= PM_PCGR_BCLKMME | PM_PCGR_BCLKH264E | PM_PCGR_BCLKH264D
> -			| PM_PCGR_HECLK | PM_PCGR_HDCLK;
> -	writel(pcgr_val, PM_PCGR);
> +	unsigned long pllrate = readl(PM_PLLDDRSTATUS);
> +	unsigned long rate = 0;
> +	unsigned int i;
>
> -	pllrate = readl(PM_PLLSYSSTATUS);
> -
> -	/* lookup pmclk_table */
> -	clk_mclk_clk.rate = 0;
> -	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
> -		if (pllrate == pllrate_table[i].prate) {
> -			clk_mclk_clk.rate = pllrate_table[i].rate;
> +	/* lookup pddr_table */
> +	for (i = 0; i < ARRAY_SIZE(pddr_table); i++) {
> +		if (pllrate == pddr_table[i].prate) {
> +			rate = pddr_table[i].drate;
>  			break;
>  		}
>  	}
>
> -	if (clk_mclk_clk.rate)
> -		clk_bclk32_clk.rate = clk_mclk_clk.rate /
> -			(((divstatus & 0x0000f000) >> 12) + 1);
> +	return rate;
> +}
> +#else
> +static unsigned long clk_ddr_recalc_rate(struct clk_hw *hw,
> +					 unsigned long parent_rate)
> +{
> +	return 33000000;
> +}
> +#endif
>
> -	pllrate = readl(PM_PLLDDRSTATUS);
> +static const struct clk_ops clk_ddr_ops = {
> +	.recalc_rate = clk_ddr_recalc_rate,
> +};
>
> -	/* lookup pddr_table */
> -	clk_ddr_clk.rate = 0;
> -	for (i = 0; i < ARRAY_SIZE(pddr_table); i++) {
> -		if (pllrate == pddr_table[i].prate) {
> -			clk_ddr_clk.rate = pddr_table[i].drate;
> -			break;
> -		}
> +static int __init clk_init(void)
> +{
> +	unsigned long value;
> +	struct clk *clk;
> +
> +	value = readl(PM_PCGR);
> +	value |= PM_PCGR_BCLKMME | PM_PCGR_BCLKH264E | PM_PCGR_BCLKH264D |
> +		 PM_PCGR_HECLK | PM_PCGR_HDCLK;
> +	writel(value, PM_PCGR);
> +
> +	clk = clk_register_uc("MAIN_CLK", NULL, &clk_mclk_ops);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s(): failed to register main clock: %ld\n", __func__,
> +		       PTR_ERR(clk));
> +		return PTR_ERR(clk);
>  	}
>
> -	pllrate = readl(PM_PLLVGASTATUS);
> +	clk = clk_register_uc("BUS32_CLK", "MAIN_CLK", &clk_bclk32_ops);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s(): failed to register bus clock: %ld\n", __func__,
> +		       PTR_ERR(clk));
> +		return PTR_ERR(clk);
> +	}
>
> -	/* lookup pvga_table */
> -	clk_vga_clk.rate = 0;
> -	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
> -		if (pllrate == pllrate_table[i].prate) {
> -			clk_vga_clk.rate = pllrate_table[i].rate;
> -			break;
> -		}
> +	clk = clk_register_uc("VGA_CLK", NULL, &clk_vga_ops);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s(): failed to register VGA clock: %ld\n", __func__,
> +		       PTR_ERR(clk));
> +		return PTR_ERR(clk);
>  	}
>
> -	if (clk_vga_clk.rate)
> -		clk_vga_clk.rate = clk_vga_clk.rate /
> -			(((divstatus & 0x00f00000) >> 20) + 1);
> +	clk = clk_register_uc("DDR_CLK", NULL, &clk_ddr_ops);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s(): failed to register DDR clock: %ld\n", __func__,
> +		       PTR_ERR(clk));
> +		return PTR_ERR(clk);
> +	}
> +
> +	clk = clk_register_fixed_rate(NULL, "OST_CLK", NULL, 0,
> +				      CLOCK_TICK_RATE);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s(): failed to register timer clock: %ld\n", __func__,
> +		       PTR_ERR(clk));
> +		return PTR_ERR(clk);
> +	}
>
> -	clk_register(&clk_vga_clk);
> -#endif
> -#ifdef CONFIG_ARCH_FPGA
> -	clk_ddr_clk.rate = 33000000;
> -	clk_mclk_clk.rate = 33000000;
> -	clk_bclk32_clk.rate = 33000000;
> -#endif
> -	clk_register(&clk_ddr_clk);
> -	clk_register(&clk_mclk_clk);
> -	clk_register(&clk_bclk32_clk);
> -	clk_register(&clk_ost_clk);
>  	return 0;
>  }
>  core_initcall(clk_init);
> --
> 1.7.12
>


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

* Re: [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped registers
  2012-09-06  8:38   ` guanxuetao
@ 2012-09-07 12:50     ` Thierry Reding
  0 siblings, 0 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-07 12:50 UTC (permalink / raw)
  To: guanxuetao; +Cc: Guan Xuetao, Mike Turquette, linux-kernel

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

On Thu, Sep 06, 2012 at 04:38:15PM +0800, guanxuetao@mprc.pku.edu.cn wrote:
> > 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>
> > ---
> >  arch/unicore32/kernel/pwm.c | 25 ++++++++++++++++++++++---
> >  1 file changed, 22 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
> > index 4615d51..410b786 100644
> > --- a/arch/unicore32/kernel/pwm.c
> > +++ b/arch/unicore32/kernel/pwm.c
> > @@ -23,10 +23,16 @@
> >  #include <asm/div64.h>
> >  #include <mach/hardware.h>
> >
> > +#define PWCR 0x00
> > +#define DCCR 0x04
> > +#define PCR  0x08
> I think old register names could be used here by some small modifications.
> Please see arch/unicore32/include/mach/regs-ost.h
> We can avoid ioremap and use writel/readl directly on these registers.
> 
> Guan

The whole point of this patch was to make the PWM driver behave more
like other drivers. If the registers are addressed directly, there is no
way that the driver will work for a second instance of the PWM
controller. I know that there probably is no second instance right now,
but given that pretty much every regular driver accesses its register
through the ioremap()'ed addresses and this patch doesn't go through
hoops to achieve this, I think this is a perfectly valid cleanup.

Thierry

> > +
> >  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 +75,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 + PWCR);
> > +	writel(pv - dc, pwm->base + DCCR);
> > +	writel(pv, pwm->base + PCR);
> > +
> >  	clk_disable(pwm->clk);
> >
> >  	return 0;
> > @@ -190,10 +198,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 +241,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
> >
> 
> 
> 

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

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

* Re: [PATCH 4/6] unicore32: Add common clock support
  2012-09-06  8:42   ` guanxuetao
@ 2012-09-07 12:53     ` Thierry Reding
  0 siblings, 0 replies; 12+ messages in thread
From: Thierry Reding @ 2012-09-07 12:53 UTC (permalink / raw)
  To: guanxuetao; +Cc: Guan Xuetao, Mike Turquette, linux-kernel

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

On Thu, Sep 06, 2012 at 04:42:06PM +0800, guanxuetao@mprc.pku.edu.cn wrote:
> > This commit adds support for the common clock framework to the Unicore32
> > architecture.
> >
> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> 
> This patch can't work.
> Could you disintegrate it into several small patches, so I could check it
> out.

I don't understand. How do you mean it can't work? Are you saying the
patch doesn't build, or does the system no longer boot properly? I don't
see how splitting it into smaller pieces is going to change anything
about that. Splitting it up also isn't going to work very well.
Conversion to the common clock framework is really all or nothing.

Thierry

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

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

* Re: [PATCH 4/6] unicore32: Add common clock support
  2012-09-02 10:21 ` [PATCH 4/6] unicore32: Add common clock support Thierry Reding
  2012-09-06  8:42   ` guanxuetao
@ 2012-09-08  1:22   ` Mike Turquette
  1 sibling, 0 replies; 12+ messages in thread
From: Mike Turquette @ 2012-09-08  1:22 UTC (permalink / raw)
  To: Thierry Reding, Guan Xuetao; +Cc: linux-kernel

Quoting Thierry Reding (2012-09-02 03:21:11)
> diff --git a/arch/unicore32/kernel/clock.c b/arch/unicore32/kernel/clock.c
<snip>
> +struct clk_uc {
> +       struct clk_hw hw;
>  };

This looks ugly.  Normally register addresses, masks and the like would
go here.  Instead you duplicate some functions below (which should be
common) and hard-code the addresses in those functions.  Below I'll use
your recalc_rate as an example...

<snip>
> +static inline struct clk_uc *to_clk_uc(struct clk_hw *hw)
>  {
> +       return container_of(hw, struct clk_uc, hw);
>  }

This is never used.  It should be, but it is not.  I'll address that
more below.

<snip>
> +static struct clk *clk_register_uc(const char *name, const char *parent,
> +                                  const struct clk_ops *ops)
>  {
> -       if (clk == &clk_vga_clk) {
> -               unsigned long pll_vgacfg, pll_vgadiv;
> -               int ret, i;
> -
> -               /* lookup vga_clk_table */
> -               ret = -EINVAL;
> -               for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
> -                       if (rate == vga_clk_table[i].rate) {
> -                               pll_vgacfg = vga_clk_table[i].cfg;
> -                               pll_vgadiv = vga_clk_table[i].div;
> -                               ret = 0;
> -                               break;
> -                       }
> -               }
> -
> -               if (ret)
> -                       return ret;
> -
> -               if (readl(PM_PLLVGACFG) == pll_vgacfg)
> -                       return 0;
> +       struct clk_init_data init;
> +       struct clk_uc *uc;
> +       struct clk *clk;
>  
> -               /* set pll vga cfg reg. */
> -               writel(pll_vgacfg, PM_PLLVGACFG);
> +       uc = kzalloc(sizeof(*uc), GFP_KERNEL);
> +       if (!uc)
> +               return NULL;

-ENOMEM?

<snip>
> +static unsigned long clk_vga_recalc_rate(struct clk_hw *hw,
> +                                        unsigned long parent_rate)
> +{
> +       unsigned long pllrate = readl(PM_PLLVGASTATUS);
> +       unsigned long divstatus = readl(PM_DIVSTATUS);
> +       unsigned long rate = 0;
> +       unsigned int i;
> +
> +       /* lookup pvga_table */
> +       for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
> +               if (pllrate == pllrate_table[i].prate) {
> +                       rate = pllrate_table[i].rate;
> +                       break;
> +               }
> +       }
> +
> +       if (rate)
> +               rate = rate / (((divstatus & 0x00f00000) >> 20) + 1);
> +
> +       return rate;
> +}

This vga recalc_rate code seems very similar to the mclk and ddr
recalc_rate functions (found further down below).  It would be better to
do something like this:

		struct clk_uc *uc = to_clk_uc(hw);
		unsigned long pllrate = readl(uc->pll_status);
		...

This means that you can reuse the same function for vga, mclk and ddr
clocks.  The same logic can be extrapolated to apply to some other bits
of code in here as well, I think.

<snip>
> +static unsigned long clk_mclk_recalc_rate(struct clk_hw *hw,
> +                                         unsigned long parent_rate)
> +{
> +#ifndef CONFIG_ARCH_FPGA
> +       unsigned long pllrate = readl(PM_PLLSYSSTATUS);
> +       unsigned long rate = 0;
> +       unsigned int i;
> +
> +       /* lookup pllrate_table */
> +       for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
> +               if (pllrate == pllrate_table[i].prate) {
> +                       rate = pllrate_table[i].rate;
> +                       break;
> +               }
> +       }
> +
> +       return rate;
> +#else
> +       return 33000000;
> +#endif
> +}

If ARCH_FPGA is defined then register a fixed-rate clock (see
drivers/clk/clk-fixed-rate.c).  Then you won't need ifdefs in these
functions and it will help you consolidate (as mentioned above).  This
same pattern repeats a few times throughout the code.

Regards,
Mike

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

end of thread, other threads:[~2012-09-08  1:23 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-02 10:21 [PATCH 0/6] unicore32: Move PWM driver to PWM framework Thierry Reding
2012-09-02 10:21 ` [PATCH 1/6] unicore32: pwm: Properly remap memory-mapped registers Thierry Reding
2012-09-06  8:38   ` guanxuetao
2012-09-07 12:50     ` Thierry Reding
2012-09-02 10:21 ` [PATCH 2/6] unicore32: pwm: Use module_platform_driver() Thierry Reding
2012-09-02 10:21 ` [PATCH 3/6] unicore32: pwm: Remove unnecessary indirection Thierry Reding
2012-09-02 10:21 ` [PATCH 4/6] unicore32: Add common clock support Thierry Reding
2012-09-06  8:42   ` guanxuetao
2012-09-07 12:53     ` Thierry Reding
2012-09-08  1:22   ` Mike Turquette
2012-09-02 10:21 ` [PATCH 5/6] unicore32: pwm: Use managed resource allocations Thierry Reding
2012-09-02 10:21 ` [PATCH 6/6] pwm: Move PUV3 PWM driver to PWM framework Thierry Reding

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