* [PATCH] move pwm drivers to new framework
@ 2012-03-15 9:04 Sascha Hauer
2012-03-15 9:04 ` [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework Sascha Hauer
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Sascha Hauer @ 2012-03-15 9:04 UTC (permalink / raw)
To: linux-arm-kernel
This series is based on Thierrys pwm-v4 patches. It moves the existing
i.MX, samsung and vt8500 drivers over to the new framework. This is only
compile tested, no runtime tests at all. I can test the i.MX driver myself,
but it would be good to have some testers for samsung and vt8500.
Sascha
The following changes since commit 07e34a1f9a21c9f72e86a4e1ec64cc2150c89389:
pwm: temporary fixup (2012-03-15 09:44:52 +0100)
are available in the git repository at:
git://git.pengutronix.de/git/imx/linux-2.6.git pwm-v4
for you to fetch changes up to dc7c38dab4355ff3a43e5b9356d180e72a923ed3:
ARM vt8500: Move vt8500 pwm driver to pwm framework (2012-03-15 09:45:49 +0100)
----------------------------------------------------------------
Sascha Hauer (3):
ARM i.MX: Move i.MX pwm driver to pwm framework
ARM Samsung: Move s3c pwm driver to pwm framework
ARM vt8500: Move vt8500 pwm driver to pwm framework
arch/arm/mach-vt8500/Makefile | 2 -
arch/arm/plat-mxc/Kconfig | 6 -
arch/arm/plat-mxc/Makefile | 1 -
arch/arm/plat-samsung/Makefile | 4 -
drivers/pwm/Kconfig | 27 +++
drivers/pwm/Makefile | 5 +
arch/arm/plat-mxc/pwm.c => drivers/pwm/pwm-imx.c | 155 ++++++---------
.../pwm.c => drivers/pwm/pwm-samsung.c | 215 ++++++++------------
.../mach-vt8500/pwm.c => drivers/pwm/pwm-vt8500.c | 124 ++++--------
9 files changed, 216 insertions(+), 323 deletions(-)
rename arch/arm/plat-mxc/pwm.c => drivers/pwm/pwm-imx.c (66%)
rename arch/arm/plat-samsung/pwm.c => drivers/pwm/pwm-samsung.c (61%)
rename arch/arm/mach-vt8500/pwm.c => drivers/pwm/pwm-vt8500.c (64%)
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework
2012-03-15 9:04 [PATCH] move pwm drivers to new framework Sascha Hauer
@ 2012-03-15 9:04 ` Sascha Hauer
2012-03-16 7:49 ` Shawn Guo
2012-03-15 9:04 ` [PATCH 2/3] ARM Samsung: Move s3c " Sascha Hauer
2012-03-15 9:04 ` [PATCH 3/3] ARM vt8500: Move vt8500 " Sascha Hauer
2 siblings, 1 reply; 8+ messages in thread
From: Sascha Hauer @ 2012-03-15 9:04 UTC (permalink / raw)
To: linux-arm-kernel
Move the driver to drivers/pwm/ and convert it to use the framework.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/plat-mxc/Kconfig | 6 -
arch/arm/plat-mxc/Makefile | 1 -
drivers/pwm/Kconfig | 9 ++
drivers/pwm/Makefile | 1 +
arch/arm/plat-mxc/pwm.c => drivers/pwm/pwm-imx.c | 155 ++++++++-------------
5 files changed, 69 insertions(+), 103 deletions(-)
rename arch/arm/plat-mxc/pwm.c => drivers/pwm/pwm-imx.c (66%)
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index dcebb12..ee09395 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -47,12 +47,6 @@ config MXC_TZIC
config MXC_AVIC
bool
-config MXC_PWM
- tristate "Enable PWM driver"
- select HAVE_PWM
- help
- Enable support for the i.MX PWM controller(s).
-
config MXC_DEBUG_BOARD
bool "Enable MXC debug board(for 3-stack)"
help
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 076db84f..d75ab5a 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_MXC_AVIC) += avic.o
obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
-obj-$(CONFIG_MXC_PWM) += pwm.o
obj-$(CONFIG_MXC_ULPI) += ulpi.o
obj-$(CONFIG_MXC_USE_EPIT) += epit.o
obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0ef4f30..a9a9715 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -18,6 +18,15 @@ config PWM_BFIN
To compile this driver as a module, choose M here: the module
will be called pwm-bfin.
+config PWM_IMX
+ tristate "i.MX pwm support"
+ depends on ARCH_MXC
+ help
+ Generic PWM framework driver for i.MX.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-imx.
+
config PWM_PXA
tristate "PXA PWM support"
depends on ARCH_PXA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index e859c51..fc7571e 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_PWM) += core.o
obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
+obj-$(CONFIG_PWM_IMX) += imx-pwm.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/arch/arm/plat-mxc/pwm.c b/drivers/pwm/pwm-imx.c
similarity index 66%
rename from arch/arm/plat-mxc/pwm.c
rename to drivers/pwm/pwm-imx.c
index e032717..cdb02b0 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/drivers/pwm/pwm-imx.c
@@ -39,24 +39,24 @@
#define MX3_PWMCR_CLKSRC_IPG (1 << 16)
#define MX3_PWMCR_EN (1 << 0)
-
-
-struct pwm_device {
+struct imx_pwm_device {
struct list_head node;
- struct platform_device *pdev;
- const char *label;
struct clk *clk;
int clk_enabled;
void __iomem *mmio_base;
- unsigned int use_count;
- unsigned int pwm_id;
+ struct pwm_chip chip;
};
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+#define to_imx_pwm_device(chip) container_of(chip, struct imx_pwm_device, chip)
+
+static int imx_pwm_config(struct pwm_chip *chip,
+ struct pwm_device *pwm, int duty_ns, int period_ns)
{
+ struct imx_pwm_device *imxpwm = to_imx_pwm_device(chip);
+
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
return -EINVAL;
@@ -65,7 +65,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
unsigned long period_cycles, duty_cycles, prescale;
u32 cr;
- c = clk_get_rate(pwm->clk);
+ c = clk_get_rate(imxpwm->clk);
c = c * period_ns;
do_div(c, 1000000000);
period_cycles = c;
@@ -86,8 +86,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
else
period_cycles = 0;
- writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
- writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
+ writel(duty_cycles, imxpwm->mmio_base + MX3_PWMSAR);
+ writel(period_cycles, imxpwm->mmio_base + MX3_PWMPR);
cr = MX3_PWMCR_PRESCALER(prescale) |
MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
@@ -98,7 +98,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
else
cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
- writel(cr, pwm->mmio_base + MX3_PWMCR);
+ writel(cr, imxpwm->mmio_base + MX3_PWMCR);
} else if (cpu_is_mx1() || cpu_is_mx21()) {
/* The PWM subsystem allows for exact frequencies. However,
* I cannot connect a scope on my device to the PWM line and
@@ -116,110 +116,70 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
* both the prescaler (/1 .. /128) and then by CLKSEL
* (/2 .. /16).
*/
- u32 max = readl(pwm->mmio_base + MX1_PWMP);
+ u32 max = readl(imxpwm->mmio_base + MX1_PWMP);
u32 p = max * duty_ns / period_ns;
- writel(max - p, pwm->mmio_base + MX1_PWMS);
+ writel(max - p, imxpwm->mmio_base + MX1_PWMS);
} else {
BUG();
}
return 0;
}
-EXPORT_SYMBOL(pwm_config);
-int pwm_enable(struct pwm_device *pwm)
+static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
+ struct imx_pwm_device *imxpwm = to_imx_pwm_device(chip);
int rc = 0;
- if (!pwm->clk_enabled) {
- rc = clk_enable(pwm->clk);
+ if (!imxpwm->clk_enabled) {
+ rc = clk_enable(imxpwm->clk);
if (!rc)
- pwm->clk_enabled = 1;
+ imxpwm->clk_enabled = 1;
}
return rc;
}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
- writel(0, pwm->mmio_base + MX3_PWMCR);
-
- if (pwm->clk_enabled) {
- clk_disable(pwm->clk);
- pwm->clk_enabled = 0;
- }
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-struct pwm_device *pwm_request(int pwm_id, const char *label)
+static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct pwm_device *pwm;
- int found = 0;
+ struct imx_pwm_device *imxpwm = to_imx_pwm_device(chip);
- mutex_lock(&pwm_lock);
+ writel(0, imxpwm->mmio_base + MX3_PWMCR);
- list_for_each_entry(pwm, &pwm_list, node) {
- if (pwm->pwm_id == pwm_id) {
- found = 1;
- break;
- }
+ if (imxpwm->clk_enabled) {
+ clk_disable(imxpwm->clk);
+ imxpwm->clk_enabled = 0;
}
-
- if (found) {
- if (pwm->use_count == 0) {
- pwm->use_count++;
- pwm->label = label;
- } else
- pwm = ERR_PTR(-EBUSY);
- } else
- pwm = ERR_PTR(-ENOENT);
-
- mutex_unlock(&pwm_lock);
- return pwm;
}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
- mutex_lock(&pwm_lock);
-
- if (pwm->use_count) {
- pwm->use_count--;
- pwm->label = NULL;
- } else
- pr_warning("PWM device already freed\n");
- mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
+static struct pwm_ops imx_pwm_ops = {
+ .enable = imx_pwm_enable,
+ .disable = imx_pwm_disable,
+ .config = imx_pwm_config,
+ .owner = THIS_MODULE,
+};
static int __devinit mxc_pwm_probe(struct platform_device *pdev)
{
- struct pwm_device *pwm;
+ struct imx_pwm_device *imxpwm;
struct resource *r;
int ret = 0;
- pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
- if (pwm == NULL) {
+ imxpwm = kzalloc(sizeof(*imxpwm), GFP_KERNEL);
+ if (imxpwm == NULL) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
}
- pwm->clk = clk_get(&pdev->dev, "pwm");
+ imxpwm->clk = clk_get(&pdev->dev, "pwm");
- if (IS_ERR(pwm->clk)) {
- ret = PTR_ERR(pwm->clk);
+ if (IS_ERR(imxpwm->clk)) {
+ ret = PTR_ERR(imxpwm->clk);
goto err_free;
}
- pwm->clk_enabled = 0;
+ imxpwm->chip.ops = &imx_pwm_ops;
- pwm->use_count = 0;
- pwm->pwm_id = pdev->id;
- pwm->pdev = pdev;
+ imxpwm->clk_enabled = 0;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {
@@ -235,50 +195,53 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev)
goto err_free_clk;
}
- pwm->mmio_base = ioremap(r->start, resource_size(r));
- if (pwm->mmio_base == NULL) {
+ imxpwm->mmio_base = ioremap(r->start, resource_size(r));
+ if (imxpwm->mmio_base == NULL) {
dev_err(&pdev->dev, "failed to ioremap() registers\n");
ret = -ENODEV;
goto err_free_mem;
}
- mutex_lock(&pwm_lock);
- list_add_tail(&pwm->node, &pwm_list);
- mutex_unlock(&pwm_lock);
+ ret = pwmchip_add(&imxpwm->chip);
+ if (ret)
+ goto err_iounmap;
- platform_set_drvdata(pdev, pwm);
+ platform_set_drvdata(pdev, imxpwm);
return 0;
+err_iounmap:
+ iounmap(imxpwm->mmio_base);
err_free_mem:
release_mem_region(r->start, resource_size(r));
err_free_clk:
- clk_put(pwm->clk);
+ clk_put(imxpwm->clk);
err_free:
- kfree(pwm);
+ kfree(imxpwm);
return ret;
}
static int __devexit mxc_pwm_remove(struct platform_device *pdev)
{
- struct pwm_device *pwm;
+ struct imx_pwm_device *imxpwm;
struct resource *r;
+ int ret;
- pwm = platform_get_drvdata(pdev);
- if (pwm == NULL)
+ imxpwm = platform_get_drvdata(pdev);
+ if (imxpwm == NULL)
return -ENODEV;
- mutex_lock(&pwm_lock);
- list_del(&pwm->node);
- mutex_unlock(&pwm_lock);
+ ret = pwmchip_remove(&imxpwm->chip);
+ if (ret)
+ return ret;
- iounmap(pwm->mmio_base);
+ iounmap(imxpwm->mmio_base);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, resource_size(r));
- clk_put(pwm->clk);
+ clk_put(imxpwm->clk);
- kfree(pwm);
+ kfree(imxpwm);
return 0;
}
--
1.7.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/3] ARM Samsung: Move s3c pwm driver to pwm framework
2012-03-15 9:04 [PATCH] move pwm drivers to new framework Sascha Hauer
2012-03-15 9:04 ` [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework Sascha Hauer
@ 2012-03-15 9:04 ` Sascha Hauer
2012-03-15 9:04 ` [PATCH 3/3] ARM vt8500: Move vt8500 " Sascha Hauer
2 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2012-03-15 9:04 UTC (permalink / raw)
To: linux-arm-kernel
Move the driver to drivers/pwm/ and convert it to use the framework.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
---
arch/arm/plat-samsung/Makefile | 4 -
drivers/pwm/Kconfig | 9 +
drivers/pwm/Makefile | 1 +
.../pwm.c => drivers/pwm/pwm-samsung.c | 215 ++++++++------------
4 files changed, 91 insertions(+), 138 deletions(-)
rename arch/arm/plat-samsung/pwm.c => drivers/pwm/pwm-samsung.c (61%)
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 6012366..f09a7cf 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -50,7 +50,3 @@ obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o
# PD support
obj-$(CONFIG_SAMSUNG_PD) += pd.o
-
-# PWM support
-
-obj-$(CONFIG_HAVE_PWM) += pwm.o
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index a9a9715..0d9aa92 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -36,6 +36,15 @@ config PWM_PXA
To compile this driver as a module, choose M here: the module
will be called pwm-pxa.
+config PWM_SAMSUNG
+ tristate "Samsung pwm support"
+ depends on PLAT_SAMSUNG
+ help
+ Generic PWM framework driver for Samsung.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-samsung.
+
config PWM_TEGRA
tristate "NVIDIA Tegra PWM support"
depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index fc7571e..2d613e0 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -2,4 +2,5 @@ obj-$(CONFIG_PWM) += core.o
obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
obj-$(CONFIG_PWM_IMX) += imx-pwm.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
+obj-$(CONFIG_PWM_SAMSUNG) += samsung-pwm.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/arch/arm/plat-samsung/pwm.c b/drivers/pwm/pwm-samsung.c
similarity index 61%
rename from arch/arm/plat-samsung/pwm.c
rename to drivers/pwm/pwm-samsung.c
index c559d84..5640ba3 100644
--- a/arch/arm/plat-samsung/pwm.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -24,7 +24,7 @@
#include <plat/regs-timer.h>
-struct pwm_device {
+struct s3c_pwm_device {
struct list_head list;
struct platform_device *pdev;
@@ -37,110 +37,62 @@ struct pwm_device {
unsigned char tcon_base;
unsigned char running;
- unsigned char use_count;
unsigned char pwm_id;
+ struct pwm_chip chip;
};
+#define to_s3c_pwm_device(chip) container_of(chip, struct s3c_pwm_device, chip)
+
#define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg)
static struct clk *clk_scaler[2];
-static inline int pwm_is_tdiv(struct pwm_device *pwm)
+static inline int pwm_is_tdiv(struct s3c_pwm_device *pwm)
{
return clk_get_parent(pwm->clk) == pwm->clk_div;
}
-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, list) {
- if (pwm->pwm_id == pwm_id) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- if (pwm->use_count == 0) {
- pwm->use_count = 1;
- pwm->label = label;
- } else
- pwm = ERR_PTR(-EBUSY);
- } else
- pwm = ERR_PTR(-ENOENT);
-
- mutex_unlock(&pwm_lock);
- return pwm;
-}
-
-EXPORT_SYMBOL(pwm_request);
-
-
-void pwm_free(struct pwm_device *pwm)
-{
- mutex_lock(&pwm_lock);
-
- if (pwm->use_count) {
- pwm->use_count--;
- pwm->label = NULL;
- } else
- printk(KERN_ERR "PWM%d device already freed\n", pwm->pwm_id);
-
- mutex_unlock(&pwm_lock);
-}
-
-EXPORT_SYMBOL(pwm_free);
-
#define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0))
#define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2))
#define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3))
#define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1))
-int pwm_enable(struct pwm_device *pwm)
+static int s3c_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
+ struct s3c_pwm_device *s3c_pwm = to_s3c_pwm_device(chip);
unsigned long flags;
unsigned long tcon;
local_irq_save(flags);
tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_start(pwm);
+ tcon |= pwm_tcon_start(s3c_pwm);
__raw_writel(tcon, S3C2410_TCON);
local_irq_restore(flags);
- pwm->running = 1;
+ s3c_pwm->running = 1;
return 0;
}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
+static void s3c_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
+ struct s3c_pwm_device *s3c_pwm = to_s3c_pwm_device(chip);
unsigned long flags;
unsigned long tcon;
local_irq_save(flags);
tcon = __raw_readl(S3C2410_TCON);
- tcon &= ~pwm_tcon_start(pwm);
+ tcon &= ~pwm_tcon_start(s3c_pwm);
__raw_writel(tcon, S3C2410_TCON);
local_irq_restore(flags);
- pwm->running = 0;
+ s3c_pwm->running = 0;
}
-EXPORT_SYMBOL(pwm_disable);
-
-static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq)
+static unsigned long pwm_calc_tin(struct s3c_pwm_device *pwm, unsigned long freq)
{
unsigned long tin_parent_rate;
unsigned int div;
@@ -158,8 +110,10 @@ static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq)
#define NS_IN_HZ (1000000000UL)
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
{
+ struct s3c_pwm_device *s3c_pwm = to_s3c_pwm_device(chip);
unsigned long tin_rate;
unsigned long tin_ns;
unsigned long period;
@@ -178,38 +132,38 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (duty_ns > period_ns)
return -EINVAL;
- if (period_ns == pwm->period_ns &&
- duty_ns == pwm->duty_ns)
+ if (period_ns == s3c_pwm->period_ns &&
+ duty_ns == s3c_pwm->duty_ns)
return 0;
/* The TCMP and TCNT can be read without a lock, they're not
* shared between the timers. */
- tcmp = __raw_readl(S3C2410_TCMPB(pwm->pwm_id));
- tcnt = __raw_readl(S3C2410_TCNTB(pwm->pwm_id));
+ tcmp = __raw_readl(S3C2410_TCMPB(s3c_pwm->pwm_id));
+ tcnt = __raw_readl(S3C2410_TCNTB(s3c_pwm->pwm_id));
period = NS_IN_HZ / period_ns;
- pwm_dbg(pwm, "duty_ns=%d, period_ns=%d (%lu)\n",
+ pwm_dbg(s3c_pwm, "duty_ns=%d, period_ns=%d (%lu)\n",
duty_ns, period_ns, period);
/* Check to see if we are changing the clock rate of the PWM */
- if (pwm->period_ns != period_ns) {
- if (pwm_is_tdiv(pwm)) {
- tin_rate = pwm_calc_tin(pwm, period);
- clk_set_rate(pwm->clk_div, tin_rate);
+ if (s3c_pwm->period_ns != period_ns) {
+ if (pwm_is_tdiv(s3c_pwm)) {
+ tin_rate = pwm_calc_tin(s3c_pwm, period);
+ clk_set_rate(s3c_pwm->clk_div, tin_rate);
} else
- tin_rate = clk_get_rate(pwm->clk);
+ tin_rate = clk_get_rate(s3c_pwm->clk);
- pwm->period_ns = period_ns;
+ s3c_pwm->period_ns = period_ns;
- pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate);
+ pwm_dbg(s3c_pwm, "tin_rate=%lu\n", tin_rate);
tin_ns = NS_IN_HZ / tin_rate;
tcnt = period_ns / tin_ns;
} else
- tin_ns = NS_IN_HZ / clk_get_rate(pwm->clk);
+ tin_ns = NS_IN_HZ / clk_get_rate(s3c_pwm->clk);
/* Note, counters count down */
@@ -220,7 +174,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (tcmp == tcnt)
tcmp--;
- pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
+ pwm_dbg(s3c_pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
if (tcmp < 0)
tcmp = 0;
@@ -229,15 +183,15 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
local_irq_save(flags);
- __raw_writel(tcmp, S3C2410_TCMPB(pwm->pwm_id));
- __raw_writel(tcnt, S3C2410_TCNTB(pwm->pwm_id));
+ __raw_writel(tcmp, S3C2410_TCMPB(s3c_pwm->pwm_id));
+ __raw_writel(tcnt, S3C2410_TCNTB(s3c_pwm->pwm_id));
tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_manulupdate(pwm);
- tcon |= pwm_tcon_autoreload(pwm);
+ tcon |= pwm_tcon_manulupdate(s3c_pwm);
+ tcon |= pwm_tcon_autoreload(s3c_pwm);
__raw_writel(tcon, S3C2410_TCON);
- tcon &= ~pwm_tcon_manulupdate(pwm);
+ tcon &= ~pwm_tcon_manulupdate(s3c_pwm);
__raw_writel(tcon, S3C2410_TCON);
local_irq_restore(flags);
@@ -245,24 +199,17 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
return 0;
}
-EXPORT_SYMBOL(pwm_config);
-
-static int pwm_register(struct pwm_device *pwm)
-{
- pwm->duty_ns = -1;
- pwm->period_ns = -1;
-
- mutex_lock(&pwm_lock);
- list_add_tail(&pwm->list, &pwm_list);
- mutex_unlock(&pwm_lock);
-
- return 0;
-}
+static struct pwm_ops s3c_pwm_ops = {
+ .enable = s3c_pwm_enable,
+ .disable = s3c_pwm_disable,
+ .config = s3c_pwm_config,
+ .owner = THIS_MODULE,
+};
static int s3c_pwm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct pwm_device *pwm;
+ struct s3c_pwm_device *s3c_pwm;
unsigned long flags;
unsigned long tcon;
unsigned int id = pdev->id;
@@ -273,83 +220,83 @@ static int s3c_pwm_probe(struct platform_device *pdev)
return -ENXIO;
}
- pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
- if (pwm == NULL) {
+ s3c_pwm = kzalloc(sizeof(*s3c_pwm), GFP_KERNEL);
+ if (s3c_pwm == NULL) {
dev_err(dev, "failed to allocate pwm_device\n");
return -ENOMEM;
}
- pwm->pdev = pdev;
- pwm->pwm_id = id;
-
/* calculate base of control bits in TCON */
- pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;
+ s3c_pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;
+ s3c_pwm->chip.ops = &s3c_pwm_ops;
- pwm->clk = clk_get(dev, "pwm-tin");
- if (IS_ERR(pwm->clk)) {
+ s3c_pwm->clk = clk_get(dev, "pwm-tin");
+ if (IS_ERR(s3c_pwm->clk)) {
dev_err(dev, "failed to get pwm tin clk\n");
- ret = PTR_ERR(pwm->clk);
+ ret = PTR_ERR(s3c_pwm->clk);
goto err_alloc;
}
- pwm->clk_div = clk_get(dev, "pwm-tdiv");
- if (IS_ERR(pwm->clk_div)) {
+ s3c_pwm->clk_div = clk_get(dev, "pwm-tdiv");
+ if (IS_ERR(s3c_pwm->clk_div)) {
dev_err(dev, "failed to get pwm tdiv clk\n");
- ret = PTR_ERR(pwm->clk_div);
+ ret = PTR_ERR(s3c_pwm->clk_div);
goto err_clk_tin;
}
- clk_enable(pwm->clk);
- clk_enable(pwm->clk_div);
+ clk_enable(s3c_pwm->clk);
+ clk_enable(s3c_pwm->clk_div);
local_irq_save(flags);
tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_invert(pwm);
+ tcon |= pwm_tcon_invert(s3c_pwm);
__raw_writel(tcon, S3C2410_TCON);
local_irq_restore(flags);
- ret = pwm_register(pwm);
+ ret = pwmchip_add(&s3c_pwm->chip);
if (ret) {
dev_err(dev, "failed to register pwm\n");
goto err_clk_tdiv;
}
- pwm_dbg(pwm, "config bits %02x\n",
- (__raw_readl(S3C2410_TCON) >> pwm->tcon_base) & 0x0f);
+ pwm_dbg(s3c_pwm, "config bits %02x\n",
+ (__raw_readl(S3C2410_TCON) >> s3c_pwm->tcon_base) & 0x0f);
dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n",
- clk_get_rate(pwm->clk),
- clk_get_rate(pwm->clk_div),
- pwm_is_tdiv(pwm) ? "div" : "ext", pwm->tcon_base);
+ clk_get_rate(s3c_pwm->clk),
+ clk_get_rate(s3c_pwm->clk_div),
+ pwm_is_tdiv(s3c_pwm) ? "div" : "ext", s3c_pwm->tcon_base);
- platform_set_drvdata(pdev, pwm);
+ platform_set_drvdata(pdev, s3c_pwm);
return 0;
err_clk_tdiv:
- clk_disable(pwm->clk_div);
- clk_disable(pwm->clk);
- clk_put(pwm->clk_div);
+ clk_disable(s3c_pwm->clk_div);
+ clk_disable(s3c_pwm->clk);
+ clk_put(s3c_pwm->clk_div);
err_clk_tin:
- clk_put(pwm->clk);
+ clk_put(s3c_pwm->clk);
err_alloc:
- kfree(pwm);
+ kfree(s3c_pwm);
return ret;
}
static int __devexit s3c_pwm_remove(struct platform_device *pdev)
{
- struct pwm_device *pwm = platform_get_drvdata(pdev);
+ struct s3c_pwm_device *s3c_pwm = platform_get_drvdata(pdev);
+
+ pwmchip_remove(&s3c_pwm->chip);
- clk_disable(pwm->clk_div);
- clk_disable(pwm->clk);
- clk_put(pwm->clk_div);
- clk_put(pwm->clk);
- kfree(pwm);
+ clk_disable(s3c_pwm->clk_div);
+ clk_disable(s3c_pwm->clk);
+ clk_put(s3c_pwm->clk_div);
+ clk_put(s3c_pwm->clk);
+ kfree(s3c_pwm);
return 0;
}
@@ -357,26 +304,26 @@ static int __devexit s3c_pwm_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct pwm_device *pwm = platform_get_drvdata(pdev);
+ struct s3c_pwm_device *s3c_pwm = platform_get_drvdata(pdev);
/* No one preserve these values during suspend so reset them
* Otherwise driver leaves PWM unconfigured if same values
* passed to pwm_config
*/
- pwm->period_ns = 0;
- pwm->duty_ns = 0;
+ s3c_pwm->period_ns = 0;
+ s3c_pwm->duty_ns = 0;
return 0;
}
static int s3c_pwm_resume(struct platform_device *pdev)
{
- struct pwm_device *pwm = platform_get_drvdata(pdev);
+ struct s3c_pwm_device *s3c_pwmwm = platform_get_drvdata(pdev);
unsigned long tcon;
/* Restore invertion */
tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_invert(pwm);
+ tcon |= pwm_tcon_invert(s3c_pwmwm);
__raw_writel(tcon, S3C2410_TCON);
return 0;
--
1.7.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/3] ARM vt8500: Move vt8500 pwm driver to pwm framework
2012-03-15 9:04 [PATCH] move pwm drivers to new framework Sascha Hauer
2012-03-15 9:04 ` [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework Sascha Hauer
2012-03-15 9:04 ` [PATCH 2/3] ARM Samsung: Move s3c " Sascha Hauer
@ 2012-03-15 9:04 ` Sascha Hauer
2 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2012-03-15 9:04 UTC (permalink / raw)
To: linux-arm-kernel
Move the driver to drivers/pwm/ and convert it to use the framework.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Alexey Charkov <alchark@gmail.com>
---
arch/arm/mach-vt8500/Makefile | 2 -
drivers/pwm/Kconfig | 9 ++
drivers/pwm/Makefile | 3 +
.../mach-vt8500/pwm.c => drivers/pwm/pwm-vt8500.c | 124 +++++++-------------
4 files changed, 56 insertions(+), 82 deletions(-)
rename arch/arm/mach-vt8500/pwm.c => drivers/pwm/pwm-vt8500.c (64%)
diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile
index 81aedb7..8df9e4a 100644
--- a/arch/arm/mach-vt8500/Makefile
+++ b/arch/arm/mach-vt8500/Makefile
@@ -5,5 +5,3 @@ obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o
obj-$(CONFIG_MACH_BV07) += bv07.o
obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o
-
-obj-$(CONFIG_HAVE_PWM) += pwm.o
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0d9aa92..a93feff 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -55,4 +55,13 @@ config PWM_TEGRA
To compile this driver as a module, choose M here: the module
will be called pwm-tegra.
+config PWM_VT8500
+ tristate "vt8500 pwm support"
+ depends on ARCH_VT8500
+ help
+ Generic PWM framework driver for vt8500.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-vt8500.
+
endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 2d613e0..fe745b0 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -4,3 +4,6 @@ obj-$(CONFIG_PWM_IMX) += imx-pwm.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
obj-$(CONFIG_PWM_SAMSUNG) += samsung-pwm.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
+obj-$(CONFIG_PWM_IMX) += pwm-imx.o
+obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
+obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
diff --git a/arch/arm/mach-vt8500/pwm.c b/drivers/pwm/pwm-vt8500.c
similarity index 64%
rename from arch/arm/mach-vt8500/pwm.c
rename to drivers/pwm/pwm-vt8500.c
index 8ad825e..6ebea33 100644
--- a/arch/arm/mach-vt8500/pwm.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -26,10 +26,7 @@
#define VT8500_NR_PWMS 4
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device {
+struct vt8500_pwm_device {
struct list_head node;
struct platform_device *pdev;
@@ -39,8 +36,11 @@ struct pwm_device {
unsigned int use_count;
unsigned int pwm_id;
+ struct pwm_chip chip;
};
+#define to_vt8500_pwm_device(chip) container_of(chip, struct vt8500_pwm_device, chip)
+
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
{
@@ -53,12 +53,14 @@ static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
bitmask);
}
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
{
+ struct vt8500_pwm_device *vt8500_pwm = to_vt8500_pwm_device(chip);
unsigned long long c;
unsigned long period_cycles, prescale, pv, dc;
- if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+ if (vt8500_pwm == NULL || period_ns == 0 || duty_ns > period_ns)
return -EINVAL;
c = 25000000/2; /* wild guess --- need to implement clocks */
@@ -80,94 +82,50 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
do_div(c, period_ns);
dc = c;
- pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 1));
- writel(prescale, pwm->regbase + 0x4 + (pwm->pwm_id << 4));
+ pwm_busy_wait(vt8500_pwm->regbase + 0x40 + vt8500_pwm->pwm_id, (1 << 1));
+ writel(prescale, vt8500_pwm->regbase + 0x4 + (vt8500_pwm->pwm_id << 4));
- pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 2));
- writel(pv, pwm->regbase + 0x8 + (pwm->pwm_id << 4));
+ pwm_busy_wait(vt8500_pwm->regbase + 0x40 + vt8500_pwm->pwm_id, (1 << 2));
+ writel(pv, vt8500_pwm->regbase + 0x8 + (vt8500_pwm->pwm_id << 4));
- pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 3));
- writel(dc, pwm->regbase + 0xc + (pwm->pwm_id << 4));
+ pwm_busy_wait(vt8500_pwm->regbase + 0x40 + vt8500_pwm->pwm_id, (1 << 3));
+ writel(dc, vt8500_pwm->regbase + 0xc + (vt8500_pwm->pwm_id << 4));
return 0;
}
-EXPORT_SYMBOL(pwm_config);
-int pwm_enable(struct pwm_device *pwm)
+static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
- pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0));
- writel(5, pwm->regbase + (pwm->pwm_id << 4));
- return 0;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
- pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0));
- writel(0, pwm->regbase + (pwm->pwm_id << 4));
-}
-EXPORT_SYMBOL(pwm_disable);
+ struct vt8500_pwm_device *vt8500_pwm = to_vt8500_pwm_device(chip);
-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;
+ pwm_busy_wait(vt8500_pwm->regbase + 0x40 + vt8500_pwm->pwm_id, (1 << 0));
+ writel(5, vt8500_pwm->regbase + (vt8500_pwm->pwm_id << 4));
+ return 0;
}
-EXPORT_SYMBOL(pwm_request);
-void pwm_free(struct pwm_device *pwm)
+static void vt8500_pwm_disable(struct pwm_chip *chip, 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");
- }
+ struct vt8500_pwm_device *vt8500_pwm = to_vt8500_pwm_device(chip);
- mutex_unlock(&pwm_lock);
+ pwm_busy_wait(vt8500_pwm->regbase + 0x40 + vt8500_pwm->pwm_id, (1 << 0));
+ writel(0, vt8500_pwm->regbase + (vt8500_pwm->pwm_id << 4));
}
-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 struct pwm_ops vt8500_pwm_ops = {
+ .enable = vt8500_pwm_enable,
+ .disable = vt8500_pwm_disable,
+ .config = vt8500_pwm_config,
+ .owner = THIS_MODULE,
+};
static int __devinit pwm_probe(struct platform_device *pdev)
{
- struct pwm_device *pwms;
+ struct vt8500_pwm_device *pwms;
struct resource *r;
int ret = 0;
int i;
- pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL);
+ pwms = kzalloc(sizeof(*pwms) * VT8500_NR_PWMS, GFP_KERNEL);
if (pwms == NULL) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
@@ -177,6 +135,7 @@ static int __devinit pwm_probe(struct platform_device *pdev)
pwms[i].use_count = 0;
pwms[i].pwm_id = i;
pwms[i].pdev = pdev;
+ pwms[i].chip.ops = &vt8500_pwm_ops;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -203,12 +162,20 @@ static int __devinit pwm_probe(struct platform_device *pdev)
for (i = 1; i < VT8500_NR_PWMS; i++)
pwms[i].regbase = pwms[0].regbase;
- for (i = 0; i < VT8500_NR_PWMS; i++)
- __add_pwm(&pwms[i]);
+ for (i = 0; i < VT8500_NR_PWMS; i++) {
+ ret = pwmchip_add(&pwms[i].chip);
+ if (ret)
+ goto err_unregister;
+ }
platform_set_drvdata(pdev, pwms);
return 0;
+err_unregister:
+ while (i) {
+ i--;
+ pwmchip_remove(&pwms[i].chip);
+ }
err_free_mem:
release_mem_region(r->start, resource_size(r));
err_free:
@@ -218,7 +185,7 @@ err_free:
static int __devexit pwm_remove(struct platform_device *pdev)
{
- struct pwm_device *pwms;
+ struct vt8500_pwm_device *pwms;
struct resource *r;
int i;
@@ -226,11 +193,8 @@ static int __devexit pwm_remove(struct platform_device *pdev)
if (pwms == NULL)
return -ENODEV;
- mutex_lock(&pwm_lock);
-
for (i = 0; i < VT8500_NR_PWMS; i++)
- list_del(&pwms[i].node);
- mutex_unlock(&pwm_lock);
+ pwmchip_remove(&pwms[i].chip);
iounmap(pwms[0].regbase);
--
1.7.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework
2012-03-15 9:04 ` [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework Sascha Hauer
@ 2012-03-16 7:49 ` Shawn Guo
2012-03-16 8:08 ` Thierry Reding
0 siblings, 1 reply; 8+ messages in thread
From: Shawn Guo @ 2012-03-16 7:49 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Mar 15, 2012 at 10:04:35AM +0100, Sascha Hauer wrote:
> Move the driver to drivers/pwm/ and convert it to use the framework.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> arch/arm/plat-mxc/Kconfig | 6 -
> arch/arm/plat-mxc/Makefile | 1 -
> drivers/pwm/Kconfig | 9 ++
> drivers/pwm/Makefile | 1 +
> arch/arm/plat-mxc/pwm.c => drivers/pwm/pwm-imx.c | 155 ++++++++-------------
> 5 files changed, 69 insertions(+), 103 deletions(-)
> rename arch/arm/plat-mxc/pwm.c => drivers/pwm/pwm-imx.c (66%)
>
> diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
> index dcebb12..ee09395 100644
> --- a/arch/arm/plat-mxc/Kconfig
> +++ b/arch/arm/plat-mxc/Kconfig
> @@ -47,12 +47,6 @@ config MXC_TZIC
> config MXC_AVIC
> bool
>
> -config MXC_PWM
> - tristate "Enable PWM driver"
> - select HAVE_PWM
> - help
> - Enable support for the i.MX PWM controller(s).
> -
> config MXC_DEBUG_BOARD
> bool "Enable MXC debug board(for 3-stack)"
> help
> diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
> index 076db84f..d75ab5a 100644
> --- a/arch/arm/plat-mxc/Makefile
> +++ b/arch/arm/plat-mxc/Makefile
> @@ -11,7 +11,6 @@ obj-$(CONFIG_MXC_AVIC) += avic.o
> obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
> obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
> obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
> -obj-$(CONFIG_MXC_PWM) += pwm.o
> obj-$(CONFIG_MXC_ULPI) += ulpi.o
> obj-$(CONFIG_MXC_USE_EPIT) += epit.o
> obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 0ef4f30..a9a9715 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -18,6 +18,15 @@ config PWM_BFIN
> To compile this driver as a module, choose M here: the module
> will be called pwm-bfin.
>
> +config PWM_IMX
> + tristate "i.MX pwm support"
> + depends on ARCH_MXC
> + help
> + Generic PWM framework driver for i.MX.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called pwm-imx.
> +
> config PWM_PXA
> tristate "PXA PWM support"
> depends on ARCH_PXA
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index e859c51..fc7571e 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -1,4 +1,5 @@
> obj-$(CONFIG_PWM) += core.o
> obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
> +obj-$(CONFIG_PWM_IMX) += imx-pwm.o
s/imx-pwm.o/pwm-imx.o
> obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
> obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> diff --git a/arch/arm/plat-mxc/pwm.c b/drivers/pwm/pwm-imx.c
> similarity index 66%
> rename from arch/arm/plat-mxc/pwm.c
> rename to drivers/pwm/pwm-imx.c
> index e032717..cdb02b0 100644
> --- a/arch/arm/plat-mxc/pwm.c
> +++ b/drivers/pwm/pwm-imx.c
> @@ -39,24 +39,24 @@
> #define MX3_PWMCR_CLKSRC_IPG (1 << 16)
> #define MX3_PWMCR_EN (1 << 0)
>
> -
> -
> -struct pwm_device {
> +struct imx_pwm_device {
> struct list_head node;
> - struct platform_device *pdev;
>
> - const char *label;
> struct clk *clk;
>
> int clk_enabled;
> void __iomem *mmio_base;
>
> - unsigned int use_count;
> - unsigned int pwm_id;
> + struct pwm_chip chip;
> };
>
> -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> +#define to_imx_pwm_device(chip) container_of(chip, struct imx_pwm_device, chip)
> +
> +static int imx_pwm_config(struct pwm_chip *chip,
> + struct pwm_device *pwm, int duty_ns, int period_ns)
> {
> + struct imx_pwm_device *imxpwm = to_imx_pwm_device(chip);
> +
> if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
> return -EINVAL;
>
> @@ -65,7 +65,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> unsigned long period_cycles, duty_cycles, prescale;
> u32 cr;
>
> - c = clk_get_rate(pwm->clk);
> + c = clk_get_rate(imxpwm->clk);
> c = c * period_ns;
> do_div(c, 1000000000);
> period_cycles = c;
> @@ -86,8 +86,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> else
> period_cycles = 0;
>
> - writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
> - writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
> + writel(duty_cycles, imxpwm->mmio_base + MX3_PWMSAR);
> + writel(period_cycles, imxpwm->mmio_base + MX3_PWMPR);
>
> cr = MX3_PWMCR_PRESCALER(prescale) |
> MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
> @@ -98,7 +98,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> else
> cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
>
> - writel(cr, pwm->mmio_base + MX3_PWMCR);
> + writel(cr, imxpwm->mmio_base + MX3_PWMCR);
> } else if (cpu_is_mx1() || cpu_is_mx21()) {
Since we are here, can we move one step further to get rid of these
cpu_is_xxx()? Then, we can remove <mach/hardware.h> inclusion from
the driver.
> /* The PWM subsystem allows for exact frequencies. However,
> * I cannot connect a scope on my device to the PWM line and
> @@ -116,110 +116,70 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> * both the prescaler (/1 .. /128) and then by CLKSEL
> * (/2 .. /16).
> */
> - u32 max = readl(pwm->mmio_base + MX1_PWMP);
> + u32 max = readl(imxpwm->mmio_base + MX1_PWMP);
> u32 p = max * duty_ns / period_ns;
> - writel(max - p, pwm->mmio_base + MX1_PWMS);
> + writel(max - p, imxpwm->mmio_base + MX1_PWMS);
> } else {
> BUG();
> }
>
> return 0;
> }
> -EXPORT_SYMBOL(pwm_config);
>
> -int pwm_enable(struct pwm_device *pwm)
> +static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> {
> + struct imx_pwm_device *imxpwm = to_imx_pwm_device(chip);
> int rc = 0;
>
> - if (!pwm->clk_enabled) {
> - rc = clk_enable(pwm->clk);
> + if (!imxpwm->clk_enabled) {
> + rc = clk_enable(imxpwm->clk);
> if (!rc)
> - pwm->clk_enabled = 1;
> + imxpwm->clk_enabled = 1;
> }
> return rc;
> }
> -EXPORT_SYMBOL(pwm_enable);
> -
> -void pwm_disable(struct pwm_device *pwm)
> -{
> - writel(0, pwm->mmio_base + MX3_PWMCR);
> -
> - if (pwm->clk_enabled) {
> - clk_disable(pwm->clk);
> - pwm->clk_enabled = 0;
> - }
> -}
> -EXPORT_SYMBOL(pwm_disable);
> -
> -static DEFINE_MUTEX(pwm_lock);
> -static LIST_HEAD(pwm_list);
>
> -struct pwm_device *pwm_request(int pwm_id, const char *label)
> +static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
> {
> - struct pwm_device *pwm;
> - int found = 0;
> + struct imx_pwm_device *imxpwm = to_imx_pwm_device(chip);
>
> - mutex_lock(&pwm_lock);
> + writel(0, imxpwm->mmio_base + MX3_PWMCR);
>
> - list_for_each_entry(pwm, &pwm_list, node) {
> - if (pwm->pwm_id == pwm_id) {
> - found = 1;
> - break;
> - }
> + if (imxpwm->clk_enabled) {
> + clk_disable(imxpwm->clk);
> + imxpwm->clk_enabled = 0;
> }
> -
> - if (found) {
> - if (pwm->use_count == 0) {
> - pwm->use_count++;
> - pwm->label = label;
> - } else
> - pwm = ERR_PTR(-EBUSY);
> - } else
> - pwm = ERR_PTR(-ENOENT);
> -
> - mutex_unlock(&pwm_lock);
> - return pwm;
> }
> -EXPORT_SYMBOL(pwm_request);
> -
> -void pwm_free(struct pwm_device *pwm)
> -{
> - mutex_lock(&pwm_lock);
> -
> - if (pwm->use_count) {
> - pwm->use_count--;
> - pwm->label = NULL;
> - } else
> - pr_warning("PWM device already freed\n");
>
> - mutex_unlock(&pwm_lock);
> -}
> -EXPORT_SYMBOL(pwm_free);
> +static struct pwm_ops imx_pwm_ops = {
> + .enable = imx_pwm_enable,
> + .disable = imx_pwm_disable,
> + .config = imx_pwm_config,
> + .owner = THIS_MODULE,
> +};
>
> static int __devinit mxc_pwm_probe(struct platform_device *pdev)
Should we take this opportunity to rename the driver from mxc_pwm to
imx_pwm?
Also, does mxc_pwm_init need necessarily to be an arch_initcall?
Otherwise, we can have the following change.
-static int __init mxc_pwm_init(void)
-{
- return platform_driver_register(&mxc_pwm_driver);
-}
-arch_initcall(mxc_pwm_init);
-
-static void __exit mxc_pwm_exit(void)
-{
- platform_driver_unregister(&mxc_pwm_driver);
-}
-module_exit(mxc_pwm_exit);
+module_platform_driver(imx_pwm_driver);
Regards,
Shawn
> {
> - struct pwm_device *pwm;
> + struct imx_pwm_device *imxpwm;
> struct resource *r;
> int ret = 0;
>
> - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
> - if (pwm == NULL) {
> + imxpwm = kzalloc(sizeof(*imxpwm), GFP_KERNEL);
> + if (imxpwm == NULL) {
> dev_err(&pdev->dev, "failed to allocate memory\n");
> return -ENOMEM;
> }
>
> - pwm->clk = clk_get(&pdev->dev, "pwm");
> + imxpwm->clk = clk_get(&pdev->dev, "pwm");
>
> - if (IS_ERR(pwm->clk)) {
> - ret = PTR_ERR(pwm->clk);
> + if (IS_ERR(imxpwm->clk)) {
> + ret = PTR_ERR(imxpwm->clk);
> goto err_free;
> }
>
> - pwm->clk_enabled = 0;
> + imxpwm->chip.ops = &imx_pwm_ops;
>
> - pwm->use_count = 0;
> - pwm->pwm_id = pdev->id;
> - pwm->pdev = pdev;
> + imxpwm->clk_enabled = 0;
>
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (r == NULL) {
> @@ -235,50 +195,53 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev)
> goto err_free_clk;
> }
>
> - pwm->mmio_base = ioremap(r->start, resource_size(r));
> - if (pwm->mmio_base == NULL) {
> + imxpwm->mmio_base = ioremap(r->start, resource_size(r));
> + if (imxpwm->mmio_base == NULL) {
> dev_err(&pdev->dev, "failed to ioremap() registers\n");
> ret = -ENODEV;
> goto err_free_mem;
> }
>
> - mutex_lock(&pwm_lock);
> - list_add_tail(&pwm->node, &pwm_list);
> - mutex_unlock(&pwm_lock);
> + ret = pwmchip_add(&imxpwm->chip);
> + if (ret)
> + goto err_iounmap;
>
> - platform_set_drvdata(pdev, pwm);
> + platform_set_drvdata(pdev, imxpwm);
> return 0;
>
> +err_iounmap:
> + iounmap(imxpwm->mmio_base);
> err_free_mem:
> release_mem_region(r->start, resource_size(r));
> err_free_clk:
> - clk_put(pwm->clk);
> + clk_put(imxpwm->clk);
> err_free:
> - kfree(pwm);
> + kfree(imxpwm);
> return ret;
> }
>
> static int __devexit mxc_pwm_remove(struct platform_device *pdev)
> {
> - struct pwm_device *pwm;
> + struct imx_pwm_device *imxpwm;
> struct resource *r;
> + int ret;
>
> - pwm = platform_get_drvdata(pdev);
> - if (pwm == NULL)
> + imxpwm = platform_get_drvdata(pdev);
> + if (imxpwm == NULL)
> return -ENODEV;
>
> - mutex_lock(&pwm_lock);
> - list_del(&pwm->node);
> - mutex_unlock(&pwm_lock);
> + ret = pwmchip_remove(&imxpwm->chip);
> + if (ret)
> + return ret;
>
> - iounmap(pwm->mmio_base);
> + iounmap(imxpwm->mmio_base);
>
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> release_mem_region(r->start, resource_size(r));
>
> - clk_put(pwm->clk);
> + clk_put(imxpwm->clk);
>
> - kfree(pwm);
> + kfree(imxpwm);
> return 0;
> }
>
> --
> 1.7.9.1
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework
2012-03-16 7:49 ` Shawn Guo
@ 2012-03-16 8:08 ` Thierry Reding
2012-03-16 8:17 ` Shawn Guo
0 siblings, 1 reply; 8+ messages in thread
From: Thierry Reding @ 2012-03-16 8:08 UTC (permalink / raw)
To: linux-arm-kernel
* Shawn Guo wrote:
> On Thu, Mar 15, 2012 at 10:04:35AM +0100, Sascha Hauer wrote:
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index e859c51..fc7571e 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -1,4 +1,5 @@
> > obj-$(CONFIG_PWM) += core.o
> > obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
> > +obj-$(CONFIG_PWM_IMX) += imx-pwm.o
>
> s/imx-pwm.o/pwm-imx.o
Yes, I'll make that change when I integrate the patch in my series.
> > @@ -98,7 +98,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> > else
> > cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
> >
> > - writel(cr, pwm->mmio_base + MX3_PWMCR);
> > + writel(cr, imxpwm->mmio_base + MX3_PWMCR);
> > } else if (cpu_is_mx1() || cpu_is_mx21()) {
>
> Since we are here, can we move one step further to get rid of these
> cpu_is_xxx()? Then, we can remove <mach/hardware.h> inclusion from
> the driver.
I guess this could be handled by using several names for the driver and
handling the differences using a table of platform_device_id:s. Perhaps
you had something different in mind?
> > static int __devinit mxc_pwm_probe(struct platform_device *pdev)
>
> Should we take this opportunity to rename the driver from mxc_pwm to
> imx_pwm?
If we decide to rename maybe it should be done in two steps. First it can be
renamed internally and in the second step the name could be changed along
with all users. I just want to avoid too much churn in this series, which is
already growing way larger than I had hoped.
> Also, does mxc_pwm_init need necessarily to be an arch_initcall?
> Otherwise, we can have the following change.
>
> -static int __init mxc_pwm_init(void)
> -{
> - return platform_driver_register(&mxc_pwm_driver);
> -}
> -arch_initcall(mxc_pwm_init);
> -
> -static void __exit mxc_pwm_exit(void)
> -{
> - platform_driver_unregister(&mxc_pwm_driver);
> -}
> -module_exit(mxc_pwm_exit);
> +module_platform_driver(imx_pwm_driver);
I assume that some platforms may require it to be initialized early because
other drivers may depend on the PWMs being present. However this can probably
be solved in a much better way by using deferred driver probing, which should
be available in 3.4.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120316/12a171b8/attachment.sig>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework
2012-03-16 8:08 ` Thierry Reding
@ 2012-03-16 8:17 ` Shawn Guo
2012-03-16 9:27 ` Sascha Hauer
0 siblings, 1 reply; 8+ messages in thread
From: Shawn Guo @ 2012-03-16 8:17 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Mar 16, 2012 at 09:08:32AM +0100, Thierry Reding wrote:
> * Shawn Guo wrote:
> > On Thu, Mar 15, 2012 at 10:04:35AM +0100, Sascha Hauer wrote:
> > > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > > index e859c51..fc7571e 100644
> > > --- a/drivers/pwm/Makefile
> > > +++ b/drivers/pwm/Makefile
> > > @@ -1,4 +1,5 @@
> > > obj-$(CONFIG_PWM) += core.o
> > > obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
> > > +obj-$(CONFIG_PWM_IMX) += imx-pwm.o
> >
> > s/imx-pwm.o/pwm-imx.o
>
> Yes, I'll make that change when I integrate the patch in my series.
>
Thanks for taking this on.
> > > @@ -98,7 +98,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> > > else
> > > cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
> > >
> > > - writel(cr, pwm->mmio_base + MX3_PWMCR);
> > > + writel(cr, imxpwm->mmio_base + MX3_PWMCR);
> > > } else if (cpu_is_mx1() || cpu_is_mx21()) {
> >
> > Since we are here, can we move one step further to get rid of these
> > cpu_is_xxx()? Then, we can remove <mach/hardware.h> inclusion from
> > the driver.
>
> I guess this could be handled by using several names for the driver and
> handling the differences using a table of platform_device_id:s. Perhaps
> you had something different in mind?
>
Same thing on my mind.
> > > static int __devinit mxc_pwm_probe(struct platform_device *pdev)
> >
> > Should we take this opportunity to rename the driver from mxc_pwm to
> > imx_pwm?
>
> If we decide to rename maybe it should be done in two steps. First it can be
> renamed internally and in the second step the name could be changed along
> with all users. I just want to avoid too much churn in this series, which is
> already growing way larger than I had hoped.
>
It seems I'm asking too much. Okay, we can do that after it gets moved.
> > Also, does mxc_pwm_init need necessarily to be an arch_initcall?
> > Otherwise, we can have the following change.
> >
> > -static int __init mxc_pwm_init(void)
> > -{
> > - return platform_driver_register(&mxc_pwm_driver);
> > -}
> > -arch_initcall(mxc_pwm_init);
> > -
> > -static void __exit mxc_pwm_exit(void)
> > -{
> > - platform_driver_unregister(&mxc_pwm_driver);
> > -}
> > -module_exit(mxc_pwm_exit);
> > +module_platform_driver(imx_pwm_driver);
>
> I assume that some platforms may require it to be initialized early because
> other drivers may depend on the PWMs being present. However this can probably
> be solved in a much better way by using deferred driver probing, which should
> be available in 3.4.
>
Ditto.
--
Regards,
Shawn
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework
2012-03-16 8:17 ` Shawn Guo
@ 2012-03-16 9:27 ` Sascha Hauer
0 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2012-03-16 9:27 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Mar 16, 2012 at 04:17:51PM +0800, Shawn Guo wrote:
> On Fri, Mar 16, 2012 at 09:08:32AM +0100, Thierry Reding wrote:
> > * Shawn Guo wrote:
> > > On Thu, Mar 15, 2012 at 10:04:35AM +0100, Sascha Hauer wrote:
> > > > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > > > index e859c51..fc7571e 100644
> > > > --- a/drivers/pwm/Makefile
> > > > +++ b/drivers/pwm/Makefile
> > > > @@ -1,4 +1,5 @@
> > > > obj-$(CONFIG_PWM) += core.o
> > > > obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
> > > > +obj-$(CONFIG_PWM_IMX) += imx-pwm.o
> > >
> > > s/imx-pwm.o/pwm-imx.o
> >
> > Yes, I'll make that change when I integrate the patch in my series.
> >
> Thanks for taking this on.
>
> > > > @@ -98,7 +98,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
> > > > else
> > > > cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
> > > >
> > > > - writel(cr, pwm->mmio_base + MX3_PWMCR);
> > > > + writel(cr, imxpwm->mmio_base + MX3_PWMCR);
> > > > } else if (cpu_is_mx1() || cpu_is_mx21()) {
> > >
> > > Since we are here, can we move one step further to get rid of these
> > > cpu_is_xxx()? Then, we can remove <mach/hardware.h> inclusion from
> > > the driver.
> >
> > I guess this could be handled by using several names for the driver and
> > handling the differences using a table of platform_device_id:s. Perhaps
> > you had something different in mind?
> >
> Same thing on my mind.
>
> > > > static int __devinit mxc_pwm_probe(struct platform_device *pdev)
> > >
> > > Should we take this opportunity to rename the driver from mxc_pwm to
> > > imx_pwm?
> >
> > If we decide to rename maybe it should be done in two steps. First it can be
> > renamed internally and in the second step the name could be changed along
> > with all users. I just want to avoid too much churn in this series, which is
> > already growing way larger than I had hoped.
> >
> It seems I'm asking too much. Okay, we can do that after it gets moved.
Indeed. The pwm driver became a horrible piece of code over time, it's
time to refactor it. I just wanted to make the move first, then look for
further cleanups.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2012-03-16 9:27 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-15 9:04 [PATCH] move pwm drivers to new framework Sascha Hauer
2012-03-15 9:04 ` [PATCH 1/3] ARM i.MX: Move i.MX pwm driver to pwm framework Sascha Hauer
2012-03-16 7:49 ` Shawn Guo
2012-03-16 8:08 ` Thierry Reding
2012-03-16 8:17 ` Shawn Guo
2012-03-16 9:27 ` Sascha Hauer
2012-03-15 9:04 ` [PATCH 2/3] ARM Samsung: Move s3c " Sascha Hauer
2012-03-15 9:04 ` [PATCH 3/3] ARM vt8500: Move vt8500 " Sascha Hauer
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).