summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorKe Qinghua <qinghua.ke@freescale.com>2013-12-18 15:50:50 +0800
committerKe Qinghua <qinghua.ke@freescale.com>2013-12-18 18:05:34 +0800
commit6aa195c6f430c25f671c00b88601cc7550f5a72c (patch)
treefe50e18c1e9f7cfcc4bb82145220e7e0a47e51b6 /arch
parente3a806afa97a199f35b8f1424bdaaedcb6919216 (diff)
ENGR00292598 Enable EPIT driver
Add EPIT driver Signed-off-by: Ke Qinghua <qinghua.ke@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-mx6/clock.c22
-rwxr-xr-xarch/arm/plat-mxc/Kconfig6
-rwxr-xr-xarch/arm/plat-mxc/Makefile2
-rwxr-xr-xarch/arm/plat-mxc/devices/Kconfig3
-rwxr-xr-xarch/arm/plat-mxc/devices/Makefile1
-rw-r--r--arch/arm/plat-mxc/devices/platform-mxc_epit.c51
-rw-r--r--arch/arm/plat-mxc/epit.c452
-rwxr-xr-xarch/arm/plat-mxc/include/mach/devices-common.h9
-rw-r--r--arch/arm/plat-mxc/include/mach/epit.h72
-rw-r--r--arch/arm/plat-mxc/include/mach/mx6.h5
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 */