diff options
author | Ke Qinghua <qinghua.ke@freescale.com> | 2013-12-18 15:50:50 +0800 |
---|---|---|
committer | Ke Qinghua <qinghua.ke@freescale.com> | 2013-12-18 18:05:34 +0800 |
commit | 6aa195c6f430c25f671c00b88601cc7550f5a72c (patch) | |
tree | fe50e18c1e9f7cfcc4bb82145220e7e0a47e51b6 /arch/arm | |
parent | e3a806afa97a199f35b8f1424bdaaedcb6919216 (diff) |
ENGR00292598 Enable EPIT driver
Add EPIT driver
Signed-off-by: Ke Qinghua <qinghua.ke@freescale.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-mx6/clock.c | 22 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/Kconfig | 6 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/Makefile | 2 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/devices/Kconfig | 3 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/devices/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxc/devices/platform-mxc_epit.c | 51 | ||||
-rw-r--r-- | arch/arm/plat-mxc/epit.c | 452 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/include/mach/devices-common.h | 9 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/epit.h | 72 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mx6.h | 5 |
10 files changed, 456 insertions, 167 deletions
diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c index c69b4609d3f3..016e5dcf0ec5 100644 --- a/arch/arm/mach-mx6/clock.c +++ b/arch/arm/mach-mx6/clock.c @@ -4799,6 +4799,26 @@ static struct clk pwm_clk[] = { }, }; +static struct clk epit_clk[] = { + { + __INIT_CLK_DEBUG(epit_clk_0) + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(epit_clk_1) + .parent = &ipg_perclk, + .id = 1, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; static int _clk_sata_enable(struct clk *clk) { unsigned int reg; @@ -5409,6 +5429,8 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm_clk[1]), _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm_clk[2]), _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm_clk[3]), + _REGISTER_CLOCK("mxc_epit.0", NULL, epit_clk[0]), + _REGISTER_CLOCK("mxc_epit.1", NULL, epit_clk[1]), _REGISTER_CLOCK(NULL, "pcie_clk", pcie_clk[0]), _REGISTER_CLOCK(NULL, "pcie_ep_clk", pcie_ep_clk[0]), _REGISTER_CLOCK(NULL, "fec_clk", enet_clk[0]), diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index 32408ed9f9e7..f4cd579a4bb6 100755 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -95,6 +95,12 @@ config MXC_PWM help Enable support for the i.MX PWM controller(s). +config MXC_EPIT + tristate "Enable EPIT driver" + select HAVE_EPIT + help + Enable support for the i.MX EPIT 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 cf0457cb5237..3566862d654b 100755 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -14,7 +14,7 @@ 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_MXC_EPIT) += epit.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index 2e666bac3afd..7d1b6bc981ac 100755 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -84,6 +84,9 @@ config IMX_HAVE_PLATFORM_MXC_NAND config IMX_HAVE_PLATFORM_MXC_PWM bool +config IMX_HAVE_PLATFORM_MXC_EPIT + bool + config IMX_HAVE_PLATFORM_MXC_RNGA bool select ARCH_HAS_RNGA diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index af3ace4c08cc..8fa9e17ca894 100755 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI) += platform-mxc-ehci.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_MMC) += platform-mxc-mmc.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_PWM) += platform-mxc_pwm.o +obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_EPIT) += platform-mxc_epit.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RNGA) += platform-mxc_rnga.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RTC) += platform-mxc_rtc.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o diff --git a/arch/arm/plat-mxc/devices/platform-mxc_epit.c b/arch/arm/plat-mxc/devices/platform-mxc_epit.c new file mode 100644 index 000000000000..5b0f1cc4007e --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-mxc_epit.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <mach/hardware.h> +#include <mach/devices-common.h> + +#define imx_mxc_epit_data_entry_single(soc, _id, _hwid, _size) \ + { \ + .id = _id, \ + .iobase = soc ## _EPIT ## _hwid ## _BASE_ADDR, \ + .iosize = _size, \ + .irq = soc ## _INT_EPIT ## _hwid, \ + } +#define imx_mxc_epit_data_entry(soc, _id, _hwid, _size) \ + [_id] = imx_mxc_epit_data_entry_single(soc, _id, _hwid, _size) + +#ifdef CONFIG_SOC_IMX6Q +const struct imx_mxc_epit_data imx6q_mxc_epit_data[] __initconst = { +#define imx6q_mxc_epit_data_entry(_id, _hwid) \ + imx_mxc_epit_data_entry(MX6Q, _id, _hwid, SZ_16K) + imx6q_mxc_epit_data_entry(0, 1), + imx6q_mxc_epit_data_entry(1, 2), +}; +#endif /* ifdef CONFIG_SOC_IMX6Q */ + +struct platform_device *__init imx_add_mxc_epit( + const struct imx_mxc_epit_data *data) +{ + struct resource res[] = { + { + .start = data->iobase, + .end = data->iobase + data->iosize - 1, + .flags = IORESOURCE_MEM, + }, { + .start = data->irq, + .end = data->irq, + .flags = IORESOURCE_IRQ, + }, + }; + + return imx_add_platform_device("mxc_epit", data->id, + res, ARRAY_SIZE(res), NULL, 0); +} diff --git a/arch/arm/plat-mxc/epit.c b/arch/arm/plat-mxc/epit.c index d3467f818c33..96f6a6b0c5d6 100644 --- a/arch/arm/plat-mxc/epit.c +++ b/arch/arm/plat-mxc/epit.c @@ -1,225 +1,345 @@ /* - * linux/arch/arm/plat-mxc/epit.c - * - * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de> - * - * 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; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html */ - -#define EPITCR 0x00 -#define EPITSR 0x04 -#define EPITLR 0x08 -#define EPITCMPR 0x0c -#define EPITCNR 0x10 - -#define EPITCR_EN (1 << 0) -#define EPITCR_ENMOD (1 << 1) -#define EPITCR_OCIEN (1 << 2) -#define EPITCR_RLD (1 << 3) -#define EPITCR_PRESC(x) (((x) & 0xfff) << 4) -#define EPITCR_SWR (1 << 16) -#define EPITCR_IOVW (1 << 17) -#define EPITCR_DBGEN (1 << 18) -#define EPITCR_WAITEN (1 << 19) -#define EPITCR_RES (1 << 20) -#define EPITCR_STOPEN (1 << 21) -#define EPITCR_OM_DISCON (0 << 22) -#define EPITCR_OM_TOGGLE (1 << 22) -#define EPITCR_OM_CLEAR (2 << 22) -#define EPITCR_OM_SET (3 << 22) -#define EPITCR_CLKSRC_OFF (0 << 24) -#define EPITCR_CLKSRC_PERIPHERAL (1 << 24) -#define EPITCR_CLKSRC_REF_HIGH (1 << 24) -#define EPITCR_CLKSRC_REF_LOW (3 << 24) - -#define EPITSR_OCIF (1 << 0) - +#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/fsl_devices.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/clockchips.h> -#include <linux/clk.h> - #include <mach/hardware.h> #include <asm/mach/time.h> #include <mach/common.h> +#include <mach/epit.h> + +struct epit_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 id; + unsigned int irq; + int mode; + void (*cb)(void *); + void *cb_para; +}; -static struct clock_event_device clockevent_epit; -static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED; -static void __iomem *timer_base; +static DEFINE_MUTEX(epit_lock); +static LIST_HEAD(epit_list); -static inline void epit_irq_disable(void) +static inline void epit_irq_disable(struct epit_device *epit) { u32 val; - val = __raw_readl(timer_base + EPITCR); + val = readl(epit->mmio_base + EPITCR); val &= ~EPITCR_OCIEN; - __raw_writel(val, timer_base + EPITCR); + writel(val, epit->mmio_base + EPITCR); } -static inline void epit_irq_enable(void) +static inline void epit_irq_enable(struct epit_device *epit) { u32 val; - val = __raw_readl(timer_base + EPITCR); + val = readl(epit->mmio_base + EPITCR); val |= EPITCR_OCIEN; - __raw_writel(val, timer_base + EPITCR); + writel(val, epit->mmio_base + EPITCR); } -static void epit_irq_acknowledge(void) +static inline void epit_irq_acknowledge(struct epit_device *epit) { - __raw_writel(EPITSR_OCIF, timer_base + EPITSR); + writel(EPITSR_OCIF, epit->mmio_base + EPITSR); } -static int __init epit_clocksource_init(struct clk *timer_clk) +static irqreturn_t epit_timer_interrupt(int irq, void *epit) { - unsigned int c = clk_get_rate(timer_clk); - - return clocksource_mmio_init(timer_base + EPITCNR, "epit", c, 200, 32, - clocksource_mmio_readl_down); + struct epit_device *epit_dev = epit; + u32 cr = 0; + + if (epit_dev) { + /* stop EPIT timer */ + cr = readl(epit_dev->mmio_base + EPITCR); + cr &= ~(EPITCR_EN); + writel(cr, epit_dev->mmio_base + EPITCR); + /* clear EPIT interrupt flag */ + epit_irq_acknowledge(epit_dev); + if (epit_dev->cb) + epit_dev->cb(epit_dev->cb_para); + } + return IRQ_HANDLED; } -/* clock event */ - -static int epit_set_next_event(unsigned long evt, - struct clock_event_device *unused) +int epit_config(struct epit_device *epit, int mode, void *cb, void *para) { - unsigned long tcmp; - - tcmp = __raw_readl(timer_base + EPITCNR); - - __raw_writel(tcmp - evt, timer_base + EPITCMPR); + u32 cr; + unsigned int rc; + + if (epit == NULL) + return -EINVAL; + + epit->cb = cb; + epit->cb_para = para; + + /*SW Reset EPIT */ + writel(EPITCR_SWR, epit->mmio_base + EPITCR); + while (readl(epit->mmio_base + EPITCR) & EPITCR_SWR) + ; + + /* reset EPIT register */ + writel(0x0, epit->mmio_base + EPITCR); + /* clear EPIT interrupt flag */ + writel(EPITSR_OCIF, epit->mmio_base + EPITSR); + /* set EPIT mode and clk src */ + cr = (mode << 3) | EPITCR_CLKSRC_REF_HIGH; + cr |= (EPITCR_WAITEN | EPITCR_OCIEN | EPITCR_RLD); + writel(cr, epit->mmio_base + EPITCR); + /* write load counter */ + writel(0xFFFFFFFF, epit->mmio_base + EPITLR); + + epit->mode = mode; + + if (!epit->clk_enabled) { + rc = clk_enable(epit->clk); + if (!rc) + epit->clk_enabled = 1; + } + /* Enable EPIT IRQ */ + epit_irq_enable(epit); return 0; } +EXPORT_SYMBOL(epit_config); -static void epit_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +void epit_start(struct epit_device *epit, int time_ns) { - unsigned long flags; - - /* - * The timer interrupt generation is disabled at least - * for enough time to call epit_set_next_event() - */ - local_irq_save(flags); - - /* Disable interrupt in GPT module */ - epit_irq_disable(); - - if (mode != clockevent_mode) { - /* Set event time into far-far future */ - - /* Clear pending interrupt */ - epit_irq_acknowledge(); + u32 compare_count = 0; + unsigned long long int c; + unsigned int cycles, prescale; + u32 cr; + + c = clk_get_rate(epit->clk); + c = c * time_ns; + do_div(c, 1000000000); + cycles = c; + prescale = cycles / 0x10000 + 1; + cycles /= (prescale + 1); + /* select prescale */ + cr = readl(epit->mmio_base + EPITCR); + cr &= ~(EPITCR_PRESC(0xFFF)); + cr |= EPITCR_PRESC(prescale) ; + writel(cr, epit->mmio_base + EPITCR); + /* write compare count */ + if (EPIT_FREE_RUN_MODE == epit->mode) { + compare_count = (0xFFFFFFFF - cycles + 1); /* down counter */ + } else { + cr = readl(epit->mmio_base + EPITLR); + compare_count = cr - cycles + 1; } + writel(compare_count, epit->mmio_base + EPITCMPR); + /* set EPIT Timer Mode */ + cr = readl(epit->mmio_base + EPITCR); + if (EPIT_FREE_RUN_MODE == epit->mode) + cr |= EPITCR_ENMOD; + + writel(cr, epit->mmio_base + EPITCR); + /* start EPIT timer */ + cr = readl(epit->mmio_base + EPITCR); + cr |= EPITCR_EN; + writel(cr, epit->mmio_base + EPITCR); +} +EXPORT_SYMBOL(epit_start); - /* Remember timer mode */ - clockevent_mode = mode; - local_irq_restore(flags); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - printk(KERN_ERR "epit_set_mode: Periodic mode is not " - "supported for i.MX EPIT\n"); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* - * Do not put overhead of interrupt enable/disable into - * epit_set_next_event(), the core has about 4 minutes - * to call epit_set_next_event() or shutdown clock after - * mode switching - */ - local_irq_save(flags); - epit_irq_enable(); - local_irq_restore(flags); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - /* Left event sources disabled, no more interrupts appear */ - break; +void epit_stop(struct epit_device *epit) +{ + u32 cr = 0; + + epit_irq_disable(epit); + cr = readl(epit->mmio_base + EPITCR); + cr &= ~EPITCR_EN; + writel(cr, epit->mmio_base + EPITCR); + /* reset EPIT register */ + writel(EPITCR_SWR, epit->mmio_base + EPITCR); + while (readl(epit->mmio_base + EPITCR) & EPITCR_SWR) + ; + + if (epit->clk_enabled) { + clk_disable(epit->clk); + epit->clk_enabled = 0; } } +EXPORT_SYMBOL(epit_stop); -/* - * IRQ handler for the timer - */ -static irqreturn_t epit_timer_interrupt(int irq, void *dev_id) +struct epit_device *epit_request(int epit_id, const char *label) { - struct clock_event_device *evt = &clockevent_epit; - - epit_irq_acknowledge(); - - evt->event_handler(evt); + struct epit_device *epit; + int found = 0; + + mutex_lock(&epit_lock); + list_for_each_entry(epit, &epit_list, node) { + if (epit->id == epit_id) { + found = 1; + break; + } + } + if (found) { + if (epit->use_count == 0) { + epit->use_count++; + epit->label = label; + } else { + epit = ERR_PTR(-EBUSY); + } + } else { + epit = ERR_PTR(-ENOENT); + } - return IRQ_HANDLED; + mutex_unlock(&epit_lock); + return epit; } +EXPORT_SYMBOL(epit_request); -static struct irqaction epit_timer_irq = { - .name = "i.MX EPIT Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = epit_timer_interrupt, -}; - -static struct clock_event_device clockevent_epit = { - .name = "epit", - .features = CLOCK_EVT_FEAT_ONESHOT, - .shift = 32, - .set_mode = epit_set_mode, - .set_next_event = epit_set_next_event, - .rating = 200, -}; +void epit_free(struct epit_device *epit) +{ + mutex_lock(&epit_lock); + if (epit->use_count) { + epit->use_count--; + epit->label = NULL; + } else { + pr_warning("EPIT device already freed\n"); + } + mutex_unlock(&epit_lock); +} +EXPORT_SYMBOL(epit_free); -static int __init epit_clockevent_init(struct clk *timer_clk) +static int __devinit mxc_epit_probe(struct platform_device *pdev) { - unsigned int c = clk_get_rate(timer_clk); + struct epit_device *epit; + struct resource *r; + struct mxc_epit_platform_data *plat_data = pdev->dev.platform_data; + int ret = 0; + + epit = kzalloc(sizeof(struct epit_device), GFP_KERNEL); + if (epit == NULL) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + epit->clk = clk_get(&pdev->dev, "epit"); + if (IS_ERR(epit->clk)) { + ret = PTR_ERR(epit->clk); + goto err_free; + } + + epit->clk_enabled = 0; + epit->use_count = 0; + epit->id = pdev->id; + epit->pdev = pdev; + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + epit->irq = (unsigned int)(r->start); + if (!epit->irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + ret = -ENODEV; + goto err_free_clk; + } - clockevent_epit.mult = div_sc(c, NSEC_PER_SEC, - clockevent_epit.shift); - clockevent_epit.max_delta_ns = - clockevent_delta2ns(0xfffffffe, &clockevent_epit); - clockevent_epit.min_delta_ns = - clockevent_delta2ns(0x800, &clockevent_epit); + /* setup IRQ */ + if (request_irq(epit->irq, epit_timer_interrupt, IRQF_DISABLED, "epit", + (void *)epit)) { + printk(KERN_ERR "rtc: cannot register IRQ %d\n", epit->irq); + ret = -EIO; + goto err_free_clk; + } - clockevent_epit.cpumask = cpumask_of(0); + 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; + } - clockevents_register_device(&clockevent_epit); + r = request_mem_region(r->start, r->end - r->start + 1, pdev->name); + if (r == NULL) { + dev_err(&pdev->dev, "failed to request memory resource\n"); + ret = -EBUSY; + goto err_free; + } + epit->mmio_base = ioremap(r->start, r->end - r->start + 1); + if (epit->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to ioremap() registers\n"); + ret = -ENODEV; + goto err_free_mem; + } + mutex_lock(&epit_lock); + list_add_tail(&epit->node, &epit_list); + mutex_unlock(&epit_lock); + platform_set_drvdata(pdev, epit); return 0; +err_free_mem: + release_mem_region(r->start, r->end - r->start + 1); +err_free_clk: + clk_put(epit->clk); +err_free: + kfree(epit); + return ret; } -void __init epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq) +static int __devexit mxc_epit_remove(struct platform_device *pdev) { - clk_enable(timer_clk); - - timer_base = base; - - /* - * Initialise to a known state (all timers off, and timing reset) - */ - __raw_writel(0x0, timer_base + EPITCR); + struct epit_device *epit; + struct resource *r; + + epit = platform_get_drvdata(pdev); + if (epit == NULL) + return -ENODEV; + + mutex_lock(&epit_lock); + list_del(&epit->node); + mutex_unlock(&epit_lock); + + iounmap(epit->mmio_base); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(r->start, r->end - r->start + 1); + clk_put(epit->clk); + kfree(epit); + return 0; +} - __raw_writel(0xffffffff, timer_base + EPITLR); - __raw_writel(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN, - timer_base + EPITCR); +static struct platform_driver mxc_epit_driver = { + .driver = { + .name = "mxc_epit", + }, + .probe = mxc_epit_probe, + .remove = __devexit_p(mxc_epit_remove), +}; - /* init and register the timer to the framework */ - epit_clocksource_init(timer_clk); - epit_clockevent_init(timer_clk); +static int __init mxc_epit_init(void) +{ + return platform_driver_register(&mxc_epit_driver); +} +arch_initcall(mxc_epit_init); - /* Make irqs happen */ - setup_irq(irq, &epit_timer_irq); +static void __exit mxc_epit_exit(void) +{ + platform_driver_unregister(&mxc_epit_driver); } +module_exit(mxc_epit_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("Enhance PIT driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index cc6f7781c31c..7bb4c15380ac 100755 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -305,6 +305,15 @@ struct platform_device *__init imx_add_mxc_nand( const struct imx_mxc_nand_data *data, const struct mxc_nand_platform_data *pdata); +struct imx_mxc_epit_data { + int id; + resource_size_t iobase; + resource_size_t iosize; + resource_size_t irq; +}; +struct platform_device *__init imx_add_mxc_epit( + const struct imx_mxc_epit_data *data); + struct imx_mxc_pwm_data { int id; resource_size_t iobase; diff --git a/arch/arm/plat-mxc/include/mach/epit.h b/arch/arm/plat-mxc/include/mach/epit.h new file mode 100644 index 000000000000..faa01e026ee5 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/epit.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __PLAT_MXC_EPIT_H +#define __PLAT_MXC_EPIT_H + + +#define EPITCR 0x00 +#define EPITSR 0x04 +#define EPITLR 0x08 +#define EPITCMPR 0x0c +#define EPITCNR 0x10 + +#define EPITCR_EN (1 << 0) +#define EPITCR_ENMOD (1 << 1) +#define EPITCR_OCIEN (1 << 2) +#define EPITCR_RLD (1 << 3) +#define EPITCR_PRESC(x) (((x) & 0xfff) << 4) +#define EPITCR_SWR (1 << 16) +#define EPITCR_IOVW (1 << 17) +#define EPITCR_DBGEN (1 << 18) +#define EPITCR_WAITEN (1 << 19) +#define EPITCR_RES (1 << 20) +#define EPITCR_STOPEN (1 << 21) +#define EPITCR_OM_DISCON (0 << 22) +#define EPITCR_OM_TOGGLE (1 << 22) +#define EPITCR_OM_CLEAR (2 << 22) +#define EPITCR_OM_SET (3 << 22) +#define EPITCR_CLKSRC_OFF (0 << 24) +#define EPITCR_CLKSRC_PERIPHERAL (1 << 24) +#define EPITCR_CLKSRC_REF_HIGH (2 << 24) +#define EPITCR_CLKSRC_REF_LOW (3 << 24) +#define EPIT_FREE_RUN_MODE (0) +#define EPIT_SET_FORGET_MODE (1) + +#define EPITSR_OCIF (1 << 0) + + +struct epit_device; +/* + * epit_request - request a epit device + */ +struct epit_device *epit_request(int epit_id, const char *label); + +/* + * epit_free - free a epit device + */ +void epit_free(struct epit_device *epit); + +/* + * epit_config - change a epit device configuration + */ +int epit_config(struct epit_device *epit, int mode, void *cb, void *para); + +/* + * epit_start - start a epit output toggling + */ +void epit_start(struct epit_device *epit, int time_ns); +/* + * epit_stop - stop a epit output toggling + */ +void epit_stop(struct epit_device *epit); + +#endif /* __LINUX_epit_H */ diff --git a/arch/arm/plat-mxc/include/mach/mx6.h b/arch/arm/plat-mxc/include/mach/mx6.h index ba38b8a4181e..0a45c8a6d8bd 100644 --- a/arch/arm/plat-mxc/include/mach/mx6.h +++ b/arch/arm/plat-mxc/include/mach/mx6.h @@ -290,6 +290,9 @@ #define MX6Q_MIPI_DSI_BASE_ADDR MIPI_DSI_BASE_ADDR #define MX6Q_MIPI_CSI2_BASE_ADDR MIPI_CSI2_BASE_ADDR +#define MX6Q_EPIT1_BASE_ADDR EPIT1_BASE_ADDR +#define MX6Q_EPIT2_BASE_ADDR EPIT2_BASE_ADDR + /* define virtual address */ #define PERIPBASE_VIRT 0xF2000000 #define BOOT_ROM_BASE_ADDR_VIRT (PERIPBASE_VIRT + BOOT_ROM_BASE_ADDR) @@ -497,6 +500,8 @@ #define MX6Q_INT_FEC MXC_INT_ENET1 #define MX6Q_INT_DSI MXC_INT_DSI +#define MX6Q_INT_EPIT1 MXC_INT_EPIT1 +#define MX6Q_INT_EPIT2 MXC_INT_EPIT2 #define IRQ_LOCALTIMER 29 /* APBH-DMA */ |