diff mbox

[2/2] DA850/OMAPL138: eCAP driver support for PWM signal generation

Message ID 1283841484-27121-1-git-send-email-sugumar@ti.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

Sugumar Natarajan Sept. 7, 2010, 6:38 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 9aca60c..3e821b4 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -40,6 +40,7 @@  config ARCH_DAVINCI_DA850
 	select CP_INTC
 	select ARCH_DAVINCI_DA8XX
 	select ARCH_HAS_CPUFREQ
+	select HAVE_PWM
 
 config ARCH_DAVINCI_DA8XX
 	select CPU_ARM926T
@@ -230,6 +231,12 @@  config DAVINCI_RESET_CLOCKS
 	  probably do not want this option enabled until your
 	  device drivers work properly.
 
+config DAVINCI_ECAP_PWM
+	bool
+	depends on ARCH_DAVINCI_DA8XX
+	depends on HAVE_PWM
+	default y
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 90ca821..90bd88e 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -42,3 +42,6 @@  obj-$(CONFIG_SUSPEND)			+= pm.o sleep.o
 
 # Generic PWM control support
 obj-$(CONFIG_HAVE_PWM)			+= davinci_pwm.o
+
+# eCAP driver support for PWM
+obj-$(CONFIG_DAVINCI_ECAP_PWM)		+= ecap.o
diff --git a/arch/arm/mach-davinci/ecap.c b/arch/arm/mach-davinci/ecap.c
new file mode 100644
index 0000000..7032009
--- /dev/null
+++ b/arch/arm/mach-davinci/ecap.c
@@ -0,0 +1,131 @@ 
+/*
+ * DA850/OMAP-L138 eCAP driver for PWM output generation
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <mach/davinci_pwm.h>
+
+#define CAPTURE_1_REG		0x8
+#define CAPTURE_2_REG		0xC
+#define CAPTURE_3_REG		0x10
+#define CAPTURE_4_REG		0x14
+#define CAPTURE_CTRL2_REG	0x2A
+#define PWM_CONFIG		0x290
+
+/*
+ * ecap_config_pwm - configures the eCAP Module for the PWM output with given
+ * period and duty cycle.
+ *
+ * Maximum brightness is obtained when the duty cycle value is one greater than
+ * period ie duty cycle >= period + 1
+ *
+ */
+
+static void ecap_config_pwm(struct pwm_device *pwm, unsigned int period_cycles,
+			unsigned int duty_cycle)
+{
+	__raw_writew(PWM_CONFIG, pwm->mmio_base + CAPTURE_CTRL2_REG);
+	__raw_writel(period_cycles, pwm->mmio_base + CAPTURE_3_REG);
+	__raw_writel(duty_cycle + 1, pwm->mmio_base + CAPTURE_4_REG);
+}
+
+static int __devinit ecap_probe(struct platform_device *pdev)
+{
+	struct pwm_device *pwm = NULL;
+	struct resource *r;
+	int ret = 0;
+
+	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+	if (pwm == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	pwm->clk = clk_get(&pdev->dev, "ecap");
+	if (IS_ERR(pwm->clk)) {
+		ret = PTR_ERR(pwm->clk);
+		goto err_free;
+	}
+
+	pwm->pwm_id = pdev->id;
+	pwm->pdev = pdev;
+	pwm->pwm_config_device = ecap_config_pwm;
+	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;
+	}
+
+	pwm->mmio_base = ioremap(r->start, resource_size(r));
+	if (pwm->mmio_base == NULL) {
+		dev_err(&pdev->dev, "failed to ioremap() registers\n");
+		ret = -ENODEV;
+		goto err_free_clk;
+	}
+
+	clk_enable(pwm->clk);
+	add_pwm(pwm);
+	platform_set_drvdata(pdev, pwm);
+	return 0;
+
+err_free_clk:
+	clk_put(pwm->clk);
+err_free:
+	kfree(pwm);
+	return ret;
+}
+
+static int __devexit ecap_remove(struct platform_device *pdev)
+{
+	struct pwm_device *pwm;
+
+	pwm = platform_get_drvdata(pdev);
+	remove_pwm(pwm);
+	iounmap(pwm->mmio_base);
+	clk_put(pwm->clk);
+	kfree(pwm);
+	return 0;
+}
+
+static struct platform_driver ecap_driver = {
+	.driver	= {
+		.name	= "ecap",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= ecap_probe,
+	.remove	= __devexit_p(ecap_remove),
+};
+
+static int __init ecap_init(void)
+{
+	return platform_driver_register(&ecap_driver);
+}
+
+static void __exit ecap_exit(void)
+{
+	platform_driver_unregister(&ecap_driver);
+}
+
+module_init(ecap_init);
+module_exit(ecap_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-davinci/include/mach/davinci_pwm.h b/arch/arm/mach-davinci/include/mach/davinci_pwm.h
index b89e823..9f66ae7 100644
--- a/arch/arm/mach-davinci/include/mach/davinci_pwm.h
+++ b/arch/arm/mach-davinci/include/mach/davinci_pwm.h
@@ -22,6 +22,7 @@  struct pwm_device {
 		unsigned int period, unsigned int dutycycle);
 	const char	*label;
 	struct clk	*clk;
+	void __iomem    *mmio_base;
 	unsigned int	use_count;
 	unsigned int	pwm_id;
 };