summaryrefslogtreecommitdiff
path: root/arch/arm/plat-mxc/pwm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-mxc/pwm.c')
-rw-r--r--arch/arm/plat-mxc/pwm.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index c36f2630ed93..17f36c10c5c3 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -6,6 +6,7 @@
* published by the Free Software Foundation.
*
* Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
#include <linux/module.h>
@@ -16,6 +17,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/pwm.h>
+#include <linux/fsl_devices.h>
#include <mach/hardware.h>
@@ -36,7 +38,12 @@
#define MX3_PWMCR_CLKSRC_IPG (1 << 16)
#define MX3_PWMCR_EN (1 << 0)
-
+#define MX3_PWMCR_STOPEN (1 << 25)
+#define MX3_PWMCR_DOZEEN (1 << 24)
+#define MX3_PWMCR_WAITEN (1 << 23)
+#define MX3_PWMCR_DBGEN (1 << 22)
+#define MX3_PWMCR_CLKSRC_IPG (1 << 16)
+#define MX3_PWMCR_CLKSRC_IPG_32k (3 << 16)
struct pwm_device {
struct list_head node;
@@ -50,6 +57,9 @@ struct pwm_device {
unsigned int use_count;
unsigned int pwm_id;
+ int pwmo_invert;
+ void (*enable_pwm_pad)(void);
+ void (*disable_pwm_pad)(void);
};
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
@@ -57,11 +67,14 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
return -EINVAL;
- if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
+ if (!(cpu_is_mx1() || cpu_is_mx21())) {
unsigned long long c;
unsigned long period_cycles, duty_cycles, prescale;
u32 cr;
+ if (pwm->pwmo_invert)
+ duty_ns = period_ns - duty_ns;
+
c = clk_get_rate(pwm->clk);
c = c * period_ns;
do_div(c, 1000000000);
@@ -77,7 +90,9 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
- cr = MX3_PWMCR_PRESCALER(prescale) | MX3_PWMCR_EN;
+ cr = MX3_PWMCR_PRESCALER(prescale) |
+ MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEEN |
+ MX3_PWMCR_WAITEN | MX3_PWMCR_DBGEN;
if (cpu_is_mx25())
cr |= MX3_PWMCR_CLKSRC_IPG;
@@ -103,6 +118,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
* (/2 .. /16).
*/
u32 max = readl(pwm->mmio_base + MX1_PWMP);
+ if (pwm->pwmo_invert)
+ duty_ns = period_ns - duty_ns;
u32 p = max * duty_ns / period_ns;
writel(max - p, pwm->mmio_base + MX1_PWMS);
} else {
@@ -115,6 +132,7 @@ EXPORT_SYMBOL(pwm_config);
int pwm_enable(struct pwm_device *pwm)
{
+ unsigned long reg;
int rc = 0;
if (!pwm->clk_enabled) {
@@ -122,12 +140,23 @@ int pwm_enable(struct pwm_device *pwm)
if (!rc)
pwm->clk_enabled = 1;
}
+
+ reg = readl(pwm->mmio_base + MX3_PWMCR);
+ reg |= MX3_PWMCR_EN;
+ writel(reg, pwm->mmio_base + MX3_PWMCR);
+
+ if (pwm->enable_pwm_pad)
+ pwm->enable_pwm_pad();
+
return rc;
}
EXPORT_SYMBOL(pwm_enable);
void pwm_disable(struct pwm_device *pwm)
{
+ if (pwm->disable_pwm_pad)
+ pwm->disable_pwm_pad();
+
writel(0, pwm->mmio_base + MX3_PWMCR);
if (pwm->clk_enabled) {
@@ -186,6 +215,7 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev)
{
struct pwm_device *pwm;
struct resource *r;
+ struct mxc_pwm_platform_data *plat_data = pdev->dev.platform_data;
int ret = 0;
pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
@@ -206,6 +236,11 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev)
pwm->use_count = 0;
pwm->pwm_id = pdev->id;
pwm->pdev = pdev;
+ if (plat_data != NULL) {
+ pwm->pwmo_invert = plat_data->pwmo_invert;
+ pwm->enable_pwm_pad = plat_data->enable_pwm_pad;
+ pwm->disable_pwm_pad = plat_data->disable_pwm_pad;
+ }
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {