From patchwork Tue Sep 14 10:36:43 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sugumar Natarajan X-Patchwork-Id: 179062 Received: from arroyo.ext.ti.com (arroyo.ext.ti.com [192.94.94.40]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o8EBCMC7008376 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 14 Sep 2010 11:12:44 GMT Received: from dlep36.itg.ti.com ([157.170.170.91]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id o8EBAXVH018440 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 14 Sep 2010 06:10:33 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id o8EBAXLq021788; Tue, 14 Sep 2010 06:10:33 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id D07CE807EE; Tue, 14 Sep 2010 06:10:06 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp53.itg.ti.com (dflp53.itg.ti.com [128.247.5.6]) by linux.omap.com (Postfix) with ESMTP id 7B06880751 for ; Tue, 14 Sep 2010 06:09:59 -0500 (CDT) Received: from tidmzi-ftp.india.ext.ti.com (localhost [127.0.0.1]) by dflp53.itg.ti.com (8.13.8/8.13.8) with SMTP id o8EB9vcl004157 for ; Tue, 14 Sep 2010 06:09:58 -0500 (CDT) Received: from symphonyindia.ti.com (symphony-ftp [192.168.247.11]) by tidmzi-ftp.india.ext.ti.com (Postfix) with SMTP id B38D23887A for ; Tue, 14 Sep 2010 16:39:53 +0530 (IST) Received: from localhost.localdomain ([192.168.247.76]) by symphonyindia.ti.com (8.13.1/8.12.10) with ESMTP id o8EB2pJ8030917; Tue, 14 Sep 2010 16:32:51 +0530 From: Sugumar Natarajan To: davinci-linux-open-source@linux.davincidsp.com Subject: [PATCH v5 2/2] davinci: da850: eCAP driver for PWM signal generation Date: Tue, 14 Sep 2010 16:06:43 +0530 Message-Id: <1284460603-24792-1-git-send-email-sugumar@ti.com> X-Mailer: git-send-email 1.5.6 X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 14 Sep 2010 11:12:45 +0000 (UTC) diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 9aca60c..8192866 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,14 @@ config DAVINCI_RESET_CLOCKS probably do not want this option enabled until your device drivers work properly. +config DAVINCI_ECAP_PWM + bool "eCAP driver support for PWM control" + depends on ARCH_DAVINCI_DA8XX + depends on HAVE_PWM + default n + help + Say Y to select the eCAP module for PWM control. + 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..066b489 --- /dev/null +++ b/arch/arm/mach-davinci/ecap.c @@ -0,0 +1,160 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CAPTURE_3_REG 0x10 +#define CAPTURE_4_REG 0x14 +#define CAPTURE_CTRL2_REG 0x2A + +#define ECAPCTRL2_MODESL_ECAP BIT(9) +#define ECAPCTRL2_SYNCOSEL_DISABLE (0x3 << 6) +#define ECAPCTRL2_TSCTRSTOP_FREERUN BIT(4) + +/* + * ecap_config_pwm - configures the eCAP Module for the PWM output with given + * period and duty cycle. + */ + +static int ecap_config_pwm(struct pwm_device *pwm, unsigned int period_cycles, + unsigned int duty_cycle) +{ + clk_enable(pwm->clk); + + __raw_writew(ECAPCTRL2_MODESL_ECAP | ECAPCTRL2_SYNCOSEL_DISABLE | + ECAPCTRL2_TSCTRSTOP_FREERUN, pwm->mmio_base + + CAPTURE_CTRL2_REG); + __raw_writel(period_cycles, pwm->mmio_base + CAPTURE_3_REG); + + /* + * 100% duty cycle is obtained when the duty cycle value is one + * greater than period ie duty cycle = period + 1 + */ + if (duty_cycle == period_cycles) + duty_cycle = duty_cycle + 1; + + __raw_writel(duty_cycle, pwm->mmio_base + CAPTURE_4_REG); + mdelay(10); + + clk_disable(pwm->clk); + return 0; +} + +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) { + 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) { + 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) { + dev_err(&pdev->dev, "failed to request memory resource\n"); + ret = -EBUSY; + goto err_free_clk; + } + + pwm->mmio_base = ioremap(r->start, resource_size(r)); + if (!pwm->mmio_base) { + dev_err(&pdev->dev, "failed to ioremap() registers\n"); + ret = -ENODEV; + goto err_free_mem; + } + + pwm_add(pwm); + platform_set_drvdata(pdev, pwm); + return 0; + +err_free_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 ecap_remove(struct platform_device *pdev) +{ + struct pwm_device *pwm; + struct resource *r; + + pwm = platform_get_drvdata(pdev); + if (!pwm) + return -ENODEV; + + pwm_remove(pwm); + iounmap(pwm->mmio_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; +} + +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 6dd8fb2..db84580 100644 --- a/arch/arm/mach-davinci/include/mach/davinci_pwm.h +++ b/arch/arm/mach-davinci/include/mach/davinci_pwm.h @@ -23,6 +23,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; };