diff options
author | Hirufmi Yagi <yagi@lineo.co.jp> | 2012-07-02 15:18:31 +0900 |
---|---|---|
committer | Justin Waters <justin.waters@timesys.com> | 2012-07-03 17:15:31 -0400 |
commit | 7a66fb115ea0b388558d204fe8e353ae6d964af3 (patch) | |
tree | 5d219ae3237ee1198dfcb8d2f5c17b310bcbc97e | |
parent | 6f09f2ffe5a9cdac5f3dd00682437063785ff8e0 (diff) |
Add: timers
-rw-r--r-- | arch/arm/mach-mvf/board-twr_vf600.c | 92 | ||||
-rw-r--r-- | drivers/char/Kconfig | 18 | ||||
-rw-r--r-- | drivers/char/Makefile | 4 | ||||
-rw-r--r-- | drivers/char/ftimer.c | 395 | ||||
-rw-r--r-- | drivers/char/ftimer.h | 59 | ||||
-rw-r--r-- | drivers/char/ftimer_reg.h | 339 | ||||
-rw-r--r-- | drivers/char/lptimer.c | 349 | ||||
-rw-r--r-- | drivers/char/lptimer.h | 77 | ||||
-rw-r--r-- | drivers/char/lptimer_reg.h | 33 | ||||
-rw-r--r-- | drivers/char/mvf_timer_master.c | 113 | ||||
-rw-r--r-- | drivers/char/pitimer.c | 323 | ||||
-rw-r--r-- | drivers/char/pitimer.h | 40 | ||||
-rw-r--r-- | drivers/char/pitimer_reg.h | 37 |
13 files changed, 1879 insertions, 0 deletions
diff --git a/arch/arm/mach-mvf/board-twr_vf600.c b/arch/arm/mach-mvf/board-twr_vf600.c index c8c68e72a2ed..f7ac6863c242 100644 --- a/arch/arm/mach-mvf/board-twr_vf600.c +++ b/arch/arm/mach-mvf/board-twr_vf600.c @@ -257,6 +257,94 @@ static struct platform_device edma_device = { .resource = edma_resources, }; + +// +// Timer resources +// +// pit +static struct resource pit_resources[] = { + [0] = { + .start = MVF_PIT_BASE_ADDR, + .end = MVF_PIT_BASE_ADDR + 0x1000, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_PIT, + .end = MXC_INT_PIT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pit_device = { + .name = "mvf-pit", + .id = 0, + .num_resources = 2, + .resource = pit_resources, +}; + +// ftm 0 +static struct resource ftm0_resources[] = { + [0] = { + .start = MVF_FTM0_BASE_ADDR, + .end = MVF_FTM0_BASE_ADDR + 0x1000, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_FTM0, + .end = MXC_INT_FTM0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ftm0_device = { + .name = "mvf-ftm", + .id = 0, + .num_resources = 2, + .resource = ftm0_resources, +}; + +// ftm 1 +static struct resource ftm1_resources[] = { + [0] = { + .start = MVF_FTM1_BASE_ADDR, + .end = MVF_FTM1_BASE_ADDR + 0x1000, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_FTM1, + .end = MXC_INT_FTM1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ftm1_device = { + .name = "mvf-ftm", + .id = 1, + .num_resources = 2, + .resource = ftm1_resources, +}; + +// pit +static struct resource lpt_resources[] = { + [0] = { + .start = MVF_LPTMR_BASE_ADDR, + .end = MVF_LPTMR_BASE_ADDR + 0x1000, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_LP_TIMER0, + .end = MXC_INT_LP_TIMER0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device lpt_device = { + .name = "mvf-lpt", + .id = 0, + .num_resources = 2, + .resource = lpt_resources, +}; + static void twr_vf600_suspend_enter(void) { /* suspend preparation */ @@ -301,6 +389,10 @@ static void __init twr_vf600_init(void) mvf_init_fec(fec_data); platform_device_register(&edma_device); + platform_device_register(&pit_device); + platform_device_register(&ftm0_device); + platform_device_register(&ftm1_device); + platform_device_register(&lpt_device); vf600_add_android_device_buttons(); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 125645af6e80..15e7af6c024d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -644,5 +644,23 @@ config MXS_VIIM help Support for access to MXS Virtual IIM device, most people should say N here. +config FTM + bool "Flex Timer Module support" + depends on SOC_VF6XX + help + Support Flex Timer Module. + +config LPTMR + bool "Low Power Timer Module support" + depends on SOC_VF6XX + help + Support Low Power Timer Module. + +config PIT + bool "Periodic Interrupt Timer Module support" + depends on SOC_VF6XX + help + Support Periodic Interrupt Timer Module. + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 813845aec98e..d312faeda3b3 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -65,5 +65,9 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o obj-$(CONFIG_MXC_IIM) += mxc_iim.o obj-$(CONFIG_MXS_VIIM) += mxs_viim.o +obj-$(CONFIG_FTM) += ftimer.o +obj-$(CONFIG_LPTMR) += lptimer.o +obj-$(CONFIG_PIT) += pitimer.o + obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o diff --git a/drivers/char/ftimer.c b/drivers/char/ftimer.c new file mode 100644 index 000000000000..88a31997ef8f --- /dev/null +++ b/drivers/char/ftimer.c @@ -0,0 +1,395 @@ +/* + * drivers/char/ftimer.c + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> +#include <linux/platform_device.h> +#include <linux/poll.h> +#include <mach/clock.h> +#include "ftimer_reg.h" +#include "ftimer.h" + +// define for timer master +#define TIMER_MASTER_MAX_TIMER 2 +#define TIMER_MASTER_ENUM_AVAILABLE FMT_AVAILABLE_CHANNEL +#define TIMER_MASTER_ENUM_MAXCHANNEL FMT1 +#include "mvf_timer_master.c" + + +//////////////////////////////////////////////////////////////// + +#define FTM_DRIVER_NAME "ftm" + +struct mvf_ftm_dev { + struct clk *clk; + void __iomem *membase; + int irq; + unsigned long configured; + unsigned long refer_ch; + void (*event_handler)(int); +}; + +void ftm_module_enable( void __iomem *membase) +{ + unsigned long val; + + val = readl(membase + FTM_MODE_OFFSET); + if (!( val & FTM_MODE_FTMEN)){ + val |= ( FTM_MODE_FTMEN | FTM_MODE_INIT); + writel(val, membase + FTM_MODE_OFFSET); + } +} + +void ftm_module_disable( void __iomem *membase) +{ + unsigned long val; + + val = readl(membase + FTM_MODE_OFFSET); + val &= ~FTM_MODE_FTMEN; + writel(val, membase + FTM_MODE_OFFSET); +} + + +void ftm_write_protect_on( void __iomem *membase) +{ + unsigned long val; + + val = readl(membase + FTM_FMS_OFFSET); + if ( !(val & FTM_FMS_WPEN)){ + val |= FTM_FMS_WPEN; + writel(val, membase + FTM_FMS_OFFSET); + } +} + +void ftm_write_protect_off( void __iomem *membase) +{ + unsigned long val,val2; + + val = readl(membase + FTM_MODE_OFFSET); + val2 = readl(membase + FTM_FMS_OFFSET); + if ( val2 & FTM_FMS_WPEN){ + val |= FTM_MODE_WPDIS; + writel(val, membase + FTM_MODE_OFFSET); + } + +} + +static int in_ftm_timer_stop( struct mvf_ftm_dev *timedevptr) +{ + void __iomem *membase; + unsigned long val; + + membase = timedevptr->membase; + + val = readl(membase + FTM_SC_OFFSET); + val &= ~FTM_SC_TOIE; + + // interrupt disable + writel( val, membase + FTM_SC_OFFSET); + + return 0; +} + +static int in_ftm_timer_start( struct mvf_ftm_dev *timedevptr) +{ + void __iomem *membase; + unsigned long val; + int ret; + + membase = timedevptr->membase; + + ret = 0; + + if ( timedevptr->configured){ + // read sc reg + val = readl(membase + FTM_SC_OFFSET); + val |= FTM_SC_TOIE; + + // clear counter + writel(0, membase + FTM_CNT_OFFSET); + + // interrupt enable + writel( val, membase + FTM_SC_OFFSET); + }else{ + ret = -EAGAIN; + } + + return ret; +} + +static irqreturn_t ftm_int_handler(int irq, void *dev_id) +{ + struct mvf_ftm_dev *timedevptr = dev_id; + unsigned long val; + irqreturn_t iret; + + iret = IRQ_HANDLED; + + val = readl( timedevptr->membase + FTM_SC_OFFSET); + if (val & FTM_SC_TOF){ + + if ( timedevptr->event_handler){ + (*timedevptr->event_handler)( timedevptr->refer_ch); + } + val &= ~FTM_SC_TOF; + writel( val, timedevptr->membase + FTM_SC_OFFSET); + }else{ + iret = IRQ_NONE; + } + + return iret; + +} + +int ftm_enable_timer( int timer_handle) +{ + struct platform_device *pdev; + struct mvf_ftm_dev *timedevptr; + + if ( !timer_master_is_opened(timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + return in_ftm_timer_start( timedevptr); +} +EXPORT_SYMBOL( ftm_enable_timer); + +int ftm_disable_timer( int timer_handle) +{ + struct platform_device *pdev; + struct mvf_ftm_dev *timedevptr; + + if ( !timer_master_is_opened(timer_handle)){ + return -EAGAIN; + } + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + + return in_ftm_timer_stop( timedevptr); +} +EXPORT_SYMBOL(ftm_disable_timer); + + +int ftm_alloc_timer( ftm_channel ch) +{ + return timer_master_alloc_timer(ch); +} +EXPORT_SYMBOL(ftm_alloc_timer); + +int ftm_free_timer (int timer_handle) +{ + if ( !ftm_disable_timer( timer_handle)){ + return timer_master_free( timer_handle); + } + + return -EAGAIN; +} +EXPORT_SYMBOL(ftm_free_timer); + +int ftm_read_counter( int timer_handle, unsigned long *counter) +{ + struct platform_device *pdev; + struct mvf_ftm_dev *timedevptr; + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + // 16bit timer + *counter = readl( timedevptr->membase + FTM_CNT_OFFSET) & 0x0000ffff; + + return 0; +} +EXPORT_SYMBOL(ftm_read_counter); + +int ftm_param_set( int timer_handle, struct mvf_ftm_request *req, void (*event_handler)(int)) +{ + void __iomem *membase; + struct platform_device *pdev; + struct mvf_ftm_dev *timedevptr; + unsigned long val; + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + membase = timedevptr->membase; + if ( req == NULL){ + printk( KERN_ERR"FTM param error \n"); + return -EINVAL; + } + + if( req->clocksource > FTM_PARAM_CLK_EXTERNAL){ + printk( KERN_ERR"FTM clock source setting error\n"); + return -EINVAL; + } + + if( req->divider > FTM_PARAM_DIV_BY_128){ + printk( KERN_ERR"FTM clock divider error\n"); + return -EINVAL; + } + + // WP off + ftm_write_protect_off( membase); + + // enable ip + ftm_module_enable( membase); + + // set clksrc and divider. IE is OFF. + val = (req->clocksource << 3) | req->divider; + writel(val, membase + FTM_SC_OFFSET); + + // counter initial value(=reset value) + writel(req->start, membase + FTM_CNTIN_OFFSET); + // modulo value(=max count) + writel(req->end, membase + FTM_MOD_OFFSET); + + timedevptr->event_handler = event_handler; + timedevptr->refer_ch = timer_handle; + + timedevptr->configured++; + // check 32bit cyclic + if( timedevptr->configured == 0){ + timedevptr->configured++; + } + + ftm_write_protect_on( membase); + + return 0; +} +EXPORT_SYMBOL(ftm_param_set); + +static __devinit +int ftm_probe(struct platform_device *pdev) +{ + int size; + int result; + struct resource *ftm_membase, *ftm_irq; + struct mvf_ftm_dev *timedevptr; + + ftm_membase = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ftm_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!ftm_irq || !ftm_membase){ + printk(KERN_WARNING"FTM resource allocation failed\n"); + return -ENODEV; + } + + timedevptr = kzalloc(sizeof(struct mvf_ftm_dev), GFP_KERNEL); + if (!timedevptr) { + printk(KERN_WARNING"FTM malloc fail.\n"); + return -ENOMEM; + } + + if ( pdev->id == 0){ + timedevptr->clk = clk_get(&pdev->dev, "ftm0_clk"); + }else{ + timedevptr->clk = clk_get(&pdev->dev, "ftm1_clk"); + } + if ( IS_ERR( timedevptr->clk )) { + dev_err(&pdev->dev, "Could not get FTM %d clock \n",pdev->id ); + return PTR_ERR( timedevptr->clk); + } + clk_enable( timedevptr->clk); + + size = ftm_membase->end - ftm_membase->start + 1; + timedevptr->membase = ioremap(ftm_membase->start, size); + if (!timedevptr->membase){ + printk(KERN_WARNING"FTM ioremap failed.\n"); + return -ENOMEM; + } + timedevptr->irq = ftm_irq->start; + + result = request_irq(timedevptr->irq, ftm_int_handler, 0, FTM_DRIVER_NAME, timedevptr); + if (result < 0) { + printk(KERN_WARNING"FTM Error %d can't get irq.\n", result); + return result; + } + + platform_set_drvdata(pdev, timedevptr); + + timer_master_register_platform(pdev); + + return 0; +} + +static int __devexit ftm_remove(struct platform_device *pdev) +{ + struct mvf_ftm_dev *timedevptr; + + timedevptr = platform_get_drvdata(pdev); + + // disable all + writel( 0, timedevptr->membase + FTM_SC_OFFSET); + in_ftm_timer_stop( timedevptr); + clk_disable( timedevptr->clk); + kfree( timedevptr); + + return 0; +} + +static struct platform_driver ftm_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "mvf-ftm", + }, + .probe = ftm_probe, + .remove = ftm_remove, +}; + +static int __init ftm_plat_dev_init(void) +{ + return platform_driver_register(&ftm_driver); +} + +static void __exit ftm_plat_dev_cleanup(void) +{ + platform_driver_unregister(&ftm_driver); +} + +module_init(ftm_plat_dev_init); +module_exit(ftm_plat_dev_cleanup); diff --git a/drivers/char/ftimer.h b/drivers/char/ftimer.h new file mode 100644 index 000000000000..7ee985a1b476 --- /dev/null +++ b/drivers/char/ftimer.h @@ -0,0 +1,59 @@ +/* + * drivers/char/ftimer.h + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +struct mvf_ftm_request{ + unsigned long clocksource; + unsigned long divider; + unsigned short start; + unsigned short end; +}; + +typedef enum { + FMT0, + FMT1, + FMT_AVAILABLE_CHANNEL +} ftm_channel; + + +// clock source +#define FTM_PARAM_CLK_NOCLOCK 0x00 +#define FTM_PARAM_CLK_SYSTEMCLOCK 0x01 +#define FTM_PARAM_CLK_FIXEDFREQ 0x02 +#define FTM_PARAM_CLK_EXTERNAL 0x03 + +// divider +#define FTM_PARAM_DIV_BY_1 0x00 +#define FTM_PARAM_DIV_BY_2 0x01 +#define FTM_PARAM_DIV_BY_4 0x02 +#define FTM_PARAM_DIV_BY_8 0x03 +#define FTM_PARAM_DIV_BY_16 0x04 +#define FTM_PARAM_DIV_BY_32 0x05 +#define FTM_PARAM_DIV_BY_64 0x06 +#define FTM_PARAM_DIV_BY_128 0x07 + +int ftm_alloc_timer( ftm_channel ch); +int ftm_free_timer( int timer_handle); +int ftm_enable_timer( int timer_handle); +int ftm_disable_timer( int timer_handle); +int ftm_read_counter( int timer_handle, unsigned long *counter); +int ftm_param_set( int timer_handle, struct mvf_ftm_request *req, void (*event_handler)(int)); + diff --git a/drivers/char/ftimer_reg.h b/drivers/char/ftimer_reg.h new file mode 100644 index 000000000000..8bc139b228b9 --- /dev/null +++ b/drivers/char/ftimer_reg.h @@ -0,0 +1,339 @@ +/* + * drivers/char/ftimer_reg.h + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * based on NuttX RTOS (http://nuttx.sourceforge.net/) + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _FTM_H +#define _FTM_H + +#define FTM_SC_OFFSET 0x0000 /* Status and Control */ +#define FTM_CNT_OFFSET 0x0004 /* Counter */ +#define FTM_MOD_OFFSET 0x0008 /* Modulo */ + +#define FTM_CSC_OFFSET(n) (0x000c+((n)<<3) /* Channel (n) Status and Control */ +#define FTM_CV_OFFSET(n) (0x0010+((n)<<3) /* Channel (n) Value */ +#define FTM_C0SC_OFFSET 0x000c /* Channel 0 Status and Control */ +#define FTM_C0V_OFFSET 0x0010 /* Channel 0 Value */ +#define FTM_C1SC_OFFSET 0x0014 /* Channel 1 Status and Control */ +#define FTM_C1V_OFFSET 0x0018 /* Channel 1 Value */ +#define FTM_C2SC_OFFSET 0x001c /* Channel 2 Status and Control */ +#define FTM_C2V_OFFSET 0x0020 /* Channel 2 Value */ +#define FTM_C3SC_OFFSET 0x0024 /* Channel 3 Status and Control */ +#define FTM_C3V_OFFSET 0x0028 /* Channel 3 Value */ +#define FTM_C4SC_OFFSET 0x002c /* Channel 4 Status and Control */ +#define FTM_C4V_OFFSET 0x0030 /* Channel 4 Value */ +#define FTM_C5SC_OFFSET 0x0034 /* Channel 5 Status and Control */ +#define FTM_C5V_OFFSET 0x0038 /* Channel 5 Value */ +#define FTM_C6SC_OFFSET 0x003c /* Channel 6 Status and Control */ +#define FTM_C6V_OFFSET 0x0040 /* Channel 6 Value */ +#define FTM_C7SC_OFFSET 0x0044 /* Channel 7 Status and Control */ +#define FTM_C7V_OFFSET 0x0048 /* Channel 7 Value */ + +#define FTM_CNTIN_OFFSET 0x004c /* Counter Initial Value */ +#define FTM_STATUS_OFFSET 0x0050 /* Capture and Compare Status */ +#define FTM_MODE_OFFSET 0x0054 /* Features Mode Selection */ +#define FTM_SYNC_OFFSET 0x0058 /* Synchronization */ +#define FTM_OUTINIT_OFFSET 0x005c /* Initial State for Channels Output */ +#define FTM_OUTMASK_OFFSET 0x0060 /* Output Mask */ +#define FTM_COMBINE_OFFSET 0x0064 /* Function for Linked Channels */ +#define FTM_DEADTIME_OFFSET 0x0068 /* Deadtime Insertion Control */ +#define FTM_EXTTRIG_OFFSET 0x006c /* FTM External Trigger */ +#define FTM_POL_OFFSET 0x0070 /* Channels Polarity */ +#define FTM_FMS_OFFSET 0x0074 /* Fault Mode Status */ +#define FTM_FILTER_OFFSET 0x0078 /* Input Capture Filter Control */ +#define FTM_FLTCTRL_OFFSET 0x007c /* Fault Control */ +#define FTM_QDCTRL_OFFSET 0x0080 /* Quadrature Decoder Control and Status */ +#define FTM_CONF_OFFSET 0x0084 /* Configuration */ +#define FTM_FLTPOL_OFFSET 0x0088 /* FTM Fault Input Polarity */ +#define FTM_SYNCONF_OFFSET 0x008c /* Synchronization Configuration */ +#define FTM_INVCTRL_OFFSET 0x0090 /* FTM Inverting Control */ +#define FTM_SWOCTRL_OFFSET 0x0094 /* FTM Software Output Control */ +#define FTM_PWMLOAD_OFFSET 0x0098 /* FTM PWM Load */ + +#define FTM_SC_PS_SHIFT (0) /* Bits 0-2: Prescale Factor Selection */ +#define FTM_SC_PS_MASK (7 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_1 (0 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_2 (1 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_4 (2 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_8 (3 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_16 (4 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_32 (5 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_64 (6 << FTM_SC_PS_SHIFT) +# define FTM_SC_PS_128 (7 << FTM_SC_PS_SHIFT) +#define FTM_SC_CLKS_SHIFT (3) /* Bits 3-4: Clock Source Selection */ +#define FTM_SC_CLKS_MASK (3 << FTM_SC_CLKS_SHIFT) +# define FTM_SC_CLKS_NONE (0 << FTM_SC_CLKS_SHIFT) /* No clock selected */ +# define FTM_SC_CLKS_SYSCLK (1 << FTM_SC_CLKS_SHIFT) /* System clock */ +# define FTM_SC_CLKS_FIXED (2 << FTM_SC_CLKS_SHIFT) /* Fixed frequency clock */ +# define FTM_SC_CLKS_EXTCLK (3 << FTM_SC_CLKS_SHIFT) /* External clock */ +#define FTM_SC_CPWMS (1 << 5) /* Bit 5: Center-aligned PWM Select */ +#define FTM_SC_TOIE (1 << 6) /* Bit 6: Timer Overflow Interrupt Enable */ +#define FTM_SC_TOF (1 << 7) /* Bit 7: Timer Overflow Flag */ + /* Bits 8-31: Reserved */ + +#define FTM_CNT_SHIFT (0) /* Bits 0-15: Counter value */ +#define FTM_CNT_MASK (0xffff << FTM_CNT_SHIFT) + /* Bits 16-31: Reserved */ + + +#define FTM_MOD_SHIFT (0) /* Bits 0-15: Modulo value */ +#define FTM_MOD_MASK (0xffff << FTM_MOD_SHIFT) + /* Bits 16-31: Reserved */ + +#define FTM_CSC_DMA (1 << 0) /* Bit 0: DMA Enable */ + /* Bit 1: Reserved */ +#define FTM_CSC_ELSA (1 << 2) /* Bit 2: Edge or Level Select */ +#define FTM_CSC_ELSB (1 << 3) /* Bit 3: Edge or Level Select */ +#define FTM_CSC_MSA (1 << 4) /* Bit 4: Channel Mode Select */ +#define FTM_CSC_MSB (1 << 5) /* Bit 5: Channel Mode Select */ +#define FTM_CSC_CHIE (1 << 6) /* Bit 6: Channel Interrupt Enable */ +#define FTM_CSC_CHF (1 << 7) /* Bit 7: Channel Flag */ + +#define FTM_CV_SHIFT (0) /* Bits 0-15: Channel Value */ +#define FTM_CV_MASK (0xffff << FTM_CV_SHIFT) + /* Bits 16-31: Reserved */ + +#define FTM_CNTIN_SHIFT (0) /* Bits 0-15: Initial Value of the FTM Counter */ +#define FTM_CNTIN_MASK (0xffff << FTM_CNTIN_SHIFT) + /* Bits 16-31: Reserved */ + +#define FTM_STATUS(n) (1 << (n)) /* Channel (n) Flag, n=0..7 */ + /* Bits 8-31: Reserved */ +#define FTM_MODE_FTMEN (1 << 0) /* Bit 0: FTM Enable */ +#define FTM_MODE_INIT (1 << 1) /* Bit 1: Initialize the Channels Output */ +#define FTM_MODE_WPDIS (1 << 2) /* Bit 2: Write Protection Disable */ +#define FTM_MODE_PWMSYNC (1 << 3) /* Bit 3: PWM Synchronization Mode */ +#define FTM_MODE_CAPTEST (1 << 4) /* Bit 4: Capture Test Mode Enable */ +#define FTM_MODE_FAULTM_SHIFT (5) /* Bits 5-6: Fault Control Mode */ +#define FTM_MODE_FAULTM_MASK (3 << FTM_MODE_FAULTM_SHIFT) +# define FTM_MODE_FAULTM_DISABLED (0 << FTM_MODE_FAULTM_SHIFT) /* Disabled */ +# define FTM_MODE_FAULTM_EVEN (1 << FTM_MODE_FAULTM_SHIFT) /* Enable even channels, manual fault clearing */ +# define FTM_MODE_FAULTM_MANUAL (2 << FTM_MODE_FAULTM_SHIFT) /* Enable all channels, manual fault clearing */ +# define FTM_MODE_FAULTM_AUTO (3 << FTM_MODE_FAULTM_SHIFT) /* Enable all channels, automatic fault clearing */ +#define FTM_MODE_FAULTIE (1 << 7) /* Bit 7: Fault Interrupt Enable */ + /* Bits 8-31: Reserved */ +/* Synchronization */ + +#define FTM_SYNC_CNTMIN (1 << 0) /* Bit 0: Minimum loading point enable */ +#define FTM_SYNC_CNTMAX (1 << 1) /* Bit 1: Maximum loading point enable */ +#define FTM_SYNC_REINIT (1 << 2) /* Bit 2: FTM Counter Reinitialization by Synchron */ +#define FTM_SYNC_SYNCHOM (1 << 3) /* Bit 3: Output Mask Synchronization */ +#define FTM_SYNC_TRIG0 (1 << 4) /* Bit 4: PWM Synchronization Hardware Trigger 0 */ +#define FTM_SYNC_TRIG1 (1 << 5) /* Bit 5: PWM Synchronization Hardware Trigger 1 */ +#define FTM_SYNC_TRIG2 (1 << 6) /* Bit 6: PWM Synchronization Hardware Trigger 2 */ +#define FTM_SYNC_SWSYNC (1 << 7) /* Bit 7: PWM Synchronization Software Trigger */ + /* Bits 8-31: Reserved */ +/* Initial State for Channels Output */ + +#define FTM_OUTINIT(n) (1 << (n)) /* Channel (n) Output Initialization Value, n=0..7 */ + /* Bits 8-31: Reserved */ +/* Output Mask */ + +#define FTM_OUTMASK(n) (1 << (n)) /* Channel (n) Output Mask, n=0..7 */ + /* Bits 8-31: Reserved */ +/* Function for Linked Channels */ + +#define FTM_COMBINE_COMBINE0 (1 << 0) /* Bit 0: Combine Channels for n = 0 */ +#define FTM_COMBINE_COMP0 (1 << 1) /* Bit 1: Complement of Channel (n) for n = 0 */ +#define FTM_COMBINE_DECAPEN0 (1 << 2) /* Bit 2: Dual Edge Capture Mode Enable for n = 0 */ +#define FTM_COMBINE_DECAP0 (1 << 3) /* Bit 3: Dual Edge Capture Mode Captures for n = 0 */ +#define FTM_COMBINE_DTEN0 (1 << 4) /* Bit 4: Deadtime Enable for n = 0 */ +#define FTM_COMBINE_SYNCEN0 (1 << 5) /* Bit 5: Synchronization Enable for n = 0 */ +#define FTM_COMBINE_FAULTEN0 (1 << 6) /* Bit 6: Fault Control Enable for n = 0 */ + /* Bit 7: Reserved */ +#define FTM_COMBINE_COMBINE1 (1 << 8) /* Bit 8: Combine Channels for n = 2 */ +#define FTM_COMBINE_COMP1 (1 << 9) /* Bit 9: Complement of Channel (n) for n = 2 */ +#define FTM_COMBINE_DECAPEN1 (1 << 10) /* Bit 10: Dual Edge Capture Mode Enable for n = 2 */ +#define FTM_COMBINE_DECAP1 (1 << 11) /* Bit 11: Dual Edge Capture Mode Captures for n = 2 */ +#define FTM_COMBINE_DTEN1 (1 << 12) /* Bit 12: Deadtime Enable for n = 2 */ +#define FTM_COMBINE_SYNCEN1 (1 << 13) /* Bit 13: Synchronization Enable for n = 2 */ +#define FTM_COMBINE_FAULTEN1 (1 << 14) /* Bit 14: Fault Control Enable for n = 2 */ + /* Bit 15: Reserved */ +#define FTM_COMBINE_COMBINE2 (1 << 16) /* Bit 16: Combine Channels for n = 4 */ +#define FTM_COMBINE_COMP2 (1 << 17) /* Bit 17: Complement of Channel (n) for n = 4 */ +#define FTM_COMBINE_DECAPEN2 (1 << 18) /* Bit 18: Dual Edge Capture Mode Enable for n = 4 */ +#define FTM_COMBINE_DECAP2 (1 << 19) /* Bit 19: Dual Edge Capture Mode Captures for n = 4 */ +#define FTM_COMBINE_DTEN2 (1 << 20) /* Bit 20: Deadtime Enable for n = 4 */ +#define FTM_COMBINE_SYNCEN2 (1 << 21) /* Bit 21: Synchronization Enable for n = 4 */ +#define FTM_COMBINE_FAULTEN2 (1 << 22) /* Bit 22: Fault Control Enable for n = 4 */ + /* Bit 23: Reserved */ +#define FTM_COMBINE_COMBINE3 (1 << 24) /* Bit 24: Combine Channels for n = 6 */ +#define FTM_COMBINE_COMP3 (1 << 25) /* Bit 25: Complement of Channel (n) for n = 6 */ +#define FTM_COMBINE_DECAPEN3 (1 << 26) /* Bit 26: Dual Edge Capture Mode Enable for n = 6 */ +#define FTM_COMBINE_DECAP3 (1 << 27) /* Bit 27: Dual Edge Capture Mode Captures for n = 6 */ +#define FTM_COMBINE_DTEN3 (1 << 28) /* Bit 28: Deadtime Enable for n = 6 */ +#define FTM_COMBINE_SYNCEN3 (1 << 29) /* Bit 29: Synchronization Enable for n = 6 */ +#define FTM_COMBINE_FAULTEN3 (1 << 30) /* Bit 30: Fault Control Enable for n = 6 */ + /* Bit 31: Reserved */ +/* Deadtime Insertion Control */ + +#define FTM_DEADTIME_DTVAL_SHIFT (0) /* Bits 0-5: Deadtime Value */ +#define FTM_DEADTIME_DTVAL_MASK (63 << FTM_DEADTIME_DTVAL_SHIFT) +#define FTM_DEADTIME_DTPS_SHIFT (6) /* Bits 6-7: Deadtime Prescaler Value */ +#define FTM_DEADTIME_DTPS_MASK (3 << FTM_DEADTIME_DTPS_SHIFT) +# define FTM_DEADTIME_DTPS_DIV1 (0 << FTM_DEADTIME_DTPS_SHIFT) +# define FTM_DEADTIME_DTPS_DIV4 (2 << FTM_DEADTIME_DTPS_SHIFT) +# define FTM_DEADTIME_DTPS_DIV16 (3 << FTM_DEADTIME_DTPS_SHIFT) + /* Bits 8-31: Reserved */ +/* FTM External Trigger */ + +#define FTM_EXTTRIG_CH2TRIG (1 << 0) /* Bit 0: Channel 2 Trigger Enable */ +#define FTM_EXTTRIG_CH3TRIG (1 << 1) /* Bit 1: Channel 3 Trigger Enable */ +#define FTM_EXTTRIG_CH4TRIG (1 << 2) /* Bit 2: Channel 4 Trigger Enable */ +#define FTM_EXTTRIG_CH5TRIG (1 << 3) /* Bit 3: Channel 5 Trigger Enable */ +#define FTM_EXTTRIG_CH0TRIG (1 << 4) /* Bit 4: Channel 0 Trigger Enable */ +#define FTM_EXTTRIG_CH1TRIG (1 << 5) /* Bit 5: Channel 1 Trigger Enable */ +#define FTM_EXTTRIG_INITTRIGEN (1 << 6) /* Bit 6: Initialization Trigger Enable */ +#define FTM_EXTTRIG_TRIGF (1 << 7) /* Bit 7: Channel Trigger Flag */ + /* Bits 8-31: Reserved */ +/* Channels Polarity */ + +#define FTM_POL(n) (1 << (n)) /* Channel (n) Polarity, n=0..7 */ + /* Bits 8-31: Reserved */ + +/* Fault Mode Status */ + +#define FTM_FMS_FAULTF0 (1 << 0) /* Bit 0: Fault Detection Flag 0 */ +#define FTM_FMS_FAULTF1 (1 << 1) /* Bit 1: Fault Detection Flag 1 */ +#define FTM_FMS_FAULTF2 (1 << 2) /* Bit 2: Fault Detection Flag 2 */ +#define FTM_FMS_FAULTF3 (1 << 3) /* Bit 3: Fault Detection Flag 3 */ + /* Bit 4: Reserved */ +#define FTM_FMS_FAULTIN (1 << 5) /* Bit 5: Fault Inputs */ +#define FTM_FMS_WPEN (1 << 6) /* Bit 6: Write Protection Enable */ +#define FTM_FMS_FAULTF (1 << 7) /* Bit 7: Fault Detection Flag */ + /* Bits 8-31: Reserved */ +/* Input Capture Filter Control */ + +#define FTM_FILTER_CH0FVAL_SHIFT (0) /* Bits 0-3: Channel 0 Input Filter */ +#define FTM_FILTER_CH0FVAL_MASK (15 << FTM_FILTER_CH0FVAL_SHIFT) +#define FTM_FILTER_CH1FVAL_SHIFT (4) /* Bits 4-7: Channel 1 Input Filter */ +#define FTM_FILTER_CH1FVAL_MASK (15 << FTM_FILTER_CH1FVAL_SHIFT) +#define FTM_FILTER_CH2FVAL_SHIFT (8) /* Bits 8-11: Channel 2 Input Filter */ +#define FTM_FILTER_CH2FVAL_MASK (15 << FTM_FILTER_CH2FVAL_SHIFT) +#define FTM_FILTER_CH3FVAL_SHIFT (12) /* Bits 12-15: Channel 3 Input Filter */ +#define FTM_FILTER_CH3FVAL_MASK (15 << FTM_FILTER_CH3FVAL_SHIFT) + /* Bits 16-31: Reserved */ +/* Fault Control */ + +#define FTM_FLTCTRL_FAULT0EN (1 << 0) /* Bit 0: Fault Input 0 Enable */ +#define FTM_FLTCTRL_FAULT1EN (1 << 1) /* Bit 1: Fault Input 1 Enable */ +#define FTM_FLTCTRL_FAULT2EN (1 << 2) /* Bit 2: Fault Input 2 Enable */ +#define FTM_FLTCTRL_FAULT3EN (1 << 3) /* Bit 3: Fault Input 3 Enable */ +#define FTM_FLTCTRL_FFLTR0EN (1 << 4) /* Bit 4: Fault Input 0 Filter Enable */ +#define FTM_FLTCTRL_FFLTR1EN (1 << 5) /* Bit 5: Fault Input 1 Filter Enable */ +#define FTM_FLTCTRL_FFLTR2EN (1 << 6) /* Bit 6: Fault Input 2 Filter Enable */ +#define FTM_FLTCTRL_FFLTR3EN (1 << 7) /* Bit 7: Fault Input 3 Filter Enable */ +#define FTM_FLTCTRL_FFVAL_SHIFT (8) /* Bits 8-11: Fault Input Filter */ +#define FTM_FLTCTRL_FFVAL_MASK (15 << FTM_FLTCTRL_FFVAL_SHIFT) + /* Bits 12-31: Reserved */ +/* Quadrature Decoder Control and Status */ + +#define FTM_QDCTRL_QUADEN (1 << 0) /* Bit 0: Quadrature Decoder Mode Enable */ +#define FTM_QDCTRL_TOFDIR (1 << 1) /* Bit 1: Timer Overflow Direction in Quadrature Decoder Mode */ +#define FTM_QDCTRL_QUADIR (1 << 2) /* Bit 2: FTM Counter Direction in Quadrature Decoder Mode */ +#define FTM_QDCTRL_QUADMODE (1 << 3) /* Bit 3: Quadrature Decoder Mode */ +#define FTM_QDCTRL_PHBPOL (1 << 4) /* Bit 4: Phase B Input Polarity */ +#define FTM_QDCTRL_PHAPOL (1 << 5) /* Bit 5: Phase A Input Polarity */ +#define FTM_QDCTRL_PHBFLTREN (1 << 6) /* Bit 6: Phase B Input Filter Enable */ +#define FTM_QDCTRL_PHAFLTREN (1 << 7) /* Bit 7: Phase A Input Filter Enable */ + /* Bits 8-31: Reserved */ +/* Configuration */ + +#define FTM_CONF_NUMTOF_SHIFT (0) /* Bits 0-4: TOF Frequency */ +#define FTM_CONF_NUMTOF_MASK (31 << FTM_CONF_NUMTOF_SHIFT) + /* Bit 5: Reserved */ +#define FTM_CONF_BDMMODE_SHIFT (6) /* Bits 6-7: BDM Mode */ +#define FTM_CONF_BDMMODE_MASK (3 << FTM_CONF_BDMMODE_SHIFT) + /* Bit 8: Reserved */ +#define FTM_CONF_GTBEEN (1 << 9) /* Bit 9: Global time base enable */ +#define FTM_CONF_GTBEOUT (1 << 10) /* Bit 10: Global time base output */ + /* Bits 11-31: Reserved */ +/* FTM Fault Input Polarity */ + +#define FTM_FLTPOL_FLT0POL (1 << 0) /* Bit 0: Fault Input 0 Polarity */ +#define FTM_FLTPOL_FLT1POL (1 << 1) /* Bit 1: Fault Input 1 Polarity */ +#define FTM_FLTPOL_FLT2POL (1 << 2) /* Bit 2: Fault Input 2 Polarity */ +#define FTM_FLTPOL_FLT3POL (1 << 3) /* Bit 3: Fault Input 3 Polarity */ + /* Bits 4-31: Reserved */ +/* Synchronization Configuration */ + +#define FTM_SYNCONF_HWTRIGMODE (1 << 0) /* Bit 0: Hardware Trigger Mode */ + /* Bit 1: Reserved */ +#define FTM_SYNCONF_CNTINC (1 << 2) /* Bit 2: CNTIN register synchronization */ + /* Bit 3: Reserved */ +#define FTM_SYNCONF_INVC (1 << 4) /* Bit 4: INVCTRL register synchronization */ +#define FTM_SYNCONF_SWOC (1 << 5) /* Bit 5: SWOCTRL register synchronization */ + /* Bit 6: Reserved */ +#define FTM_SYNCONF_SYNCMODE (1 << 7) /* Bit 7: Synchronization Mode */ +#define FTM_SYNCONF_SWRSTCNT (1 << 8) /* Bit 8: FTM counter synchronization (S/W) */ +#define FTM_SYNCONF_SWWRBUF (1 << 9) /* Bit 9: MOD, CNTIN, and CV registers synchronization (S/W) */ +#define FTM_SYNCONF_SWOM (1 << 10) /* Bit 10: Output mask synchronization (S/W) */ +#define FTM_SYNCONF_SWINVC (1 << 11) /* Bit 11: Inverting control synchronization (S/W) */ +#define FTM_SYNCONF_SWSOC (1 << 12) /* Bit 12: Software output control synchronization (S/W) */ + /* Bits 13-15: Reserved */ +#define FTM_SYNCONF_HWRSTCNT (1 << 16) /* Bit 16: FTM counter synchronization (H/W) */ +#define FTM_SYNCONF_HWWRBUF (1 << 17) /* Bit 17: MOD, CNTIN, and CV registers synchronization (H/W) */ +#define FTM_SYNCONF_HWOM (1 << 18) /* Bit 18: Output mask synchronization (H/W) */ +#define FTM_SYNCONF_HWINVC (1 << 19) /* Bit 19: Inverting control synchronization (H/W) */ +#define FTM_SYNCONF_HWSOC (1 << 20) /* Bit 20: Software output control synchronization (H/W) */ + /* Bits 21-31: Reserved */ +/* FTM Inverting Control */ + +#define FTM_INVCTRL_INV0EN (1 << 0) /* Bit 0: Pair Channels 0 Inverting Enable */ +#define FTM_INVCTRL_INV1EN (1 << 1) /* Bit 1: Pair Channels 1 Inverting Enable */ +#define FTM_INVCTRL_INV2EN (1 << 2) /* Bit 2: Pair Channels 2 Inverting Enable */ +#define FTM_INVCTRL_INV3EN (1 << 3) /* Bit 3: Pair Channels 3 Inverting Enable */ + /* Bits 4-31: Reserved */ +/* FTM Software Output Control */ + +//#define FTM_SWOCTRL_CH7OC(n) (1 << (n)) /* Bits 0-7: Channel (n) Software Output Control Enable */ +#define FTM_SWOCTRL_CH0OC (1 << 0) /* Bit 0: Channel 0 Software Output Control Enable */ +#define FTM_SWOCTRL_CH1OC (1 << 1) /* Bit 1: Channel 1 Software Output Control Enable */ +#define FTM_SWOCTRL_CH2OC (1 << 2) /* Bit 2: Channel 2 Software Output Control Enable */ +#define FTM_SWOCTRL_CH3OC (1 << 3) /* Bit 3: Channel 3 Software Output Control Enable */ +#define FTM_SWOCTRL_CH4OC (1 << 4) /* Bit 4: Channel 4 Software Output Control Enable */ +#define FTM_SWOCTRL_CH5OC (1 << 5) /* Bit 5: Channel 5 Software Output Control Enable */ +#define FTM_SWOCTRL_CH6OC (1 << 6) /* Bit 6: Channel 6 Software Output Control Enable */ +#define FTM_SWOCTRL_CH7OC (1 << 7) /* Bit 7: Channel 7 Software Output Control Enable */ +#define FTM_SWOCTRL_CHOCV(n) (1 << ((n)+8)) /* Bits 8-15: Channel (n) Software Output Control Value */ +#define FTM_SWOCTRL_CH0OCV (1 << 8) /* Bit 8: Channel 0 Software Output Control Value */ +#define FTM_SWOCTRL_CH1OCV (1 << 9) /* Bit 9: Channel 1 Software Output Control Value */ +#define FTM_SWOCTRL_CH2OCV (1 << 10) /* Bit 10: Channel 2 Software Output Control Value */ +#define FTM_SWOCTRL_CH3OCV (1 << 11) /* Bit 11: Channel 3 Software Output Control Value */ +#define FTM_SWOCTRL_CH4OCV (1 << 12) /* Bit 12: Channel 4 Software Output Control Value */ +#define FTM_SWOCTRL_CH5OCV (1 << 13) /* Bit 13: Channel 5 Software Output Control Value */ +#define FTM_SWOCTRL_CH6OCV (1 << 14) /* Bit 14: Channel 6 Software Output Control Value */ +#define FTM_SWOCTRL_CH7OCV (1 << 15) /* Bit 15: Channel 7 Software Output Control Value */ + /* Bits 16-31: Reserved */ +/* FTM PWM Load */ + +//#define FTM_PWMLOAD_CH7SEL(n) (1 << (n)) /* Bits 0-7: Channel (n) Select */ +#define FTM_PWMLOAD_CH0SEL (1 << 0) /* Bit 0: Channel 0 Select */ +#define FTM_PWMLOAD_CH1SEL (1 << 1) /* Bit 1: Channel 1 Select */ +#define FTM_PWMLOAD_CH2SEL (1 << 2) /* Bit 2: Channel 2 Select */ +#define FTM_PWMLOAD_CH3SEL (1 << 3) /* Bit 3: Channel 3 Select */ +#define FTM_PWMLOAD_CH4SEL (1 << 4) /* Bit 4: Channel 4 Select */ +#define FTM_PWMLOAD_CH5SEL (1 << 5) /* Bit 5: Channel 5 Select */ +#define FTM_PWMLOAD_CH6SEL (1 << 6) /* Bit 6: Channel 6 Select */ +#define FTM_PWMLOAD_CH7SEL (1 << 7) /* Bit 7: Channel 7 Select */ + /* Bit 8: Reserved */ +#define FTM_PWMLOAD_LDOK (1 << 9) /* Bit 9: Load Enable */ + /* Bits 10-31: Reserved */ +#endif diff --git a/drivers/char/lptimer.c b/drivers/char/lptimer.c new file mode 100644 index 000000000000..3203580beda1 --- /dev/null +++ b/drivers/char/lptimer.c @@ -0,0 +1,349 @@ +/* + * drivers/char/lptimer.c + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> +#include <linux/platform_device.h> +#include <linux/poll.h> +#include <mach/clock.h> +#include "lptimer_reg.h" +#include "lptimer.h" + +// define for timer master +#define TIMER_MASTER_MAX_TIMER 1 +#define TIMER_MASTER_ENUM_AVAILABLE 1 +#define TIMER_MASTER_ENUM_MAXCHANNEL 1 +#include "mvf_timer_master.c" + +//////////////////////////////////////////////////////////////// + +#define LPT_DRIVER_NAME "lpt" + +struct mvf_lpt_dev { + void __iomem *membase; + int irq; + unsigned long configured; + void (*event_handler)(void); + struct clk *clk; +}; + + +static irqreturn_t lpt_int_handler(int irq, void *dev_id) +{ + struct mvf_lpt_dev *timedevptr = dev_id; + unsigned long val; + irqreturn_t iret; + + iret = IRQ_HANDLED; + + val = readl( timedevptr->membase + LPTMR_CSR_OFFSET); + if (val & LPTMR_CSR_TCF){ + + if ( timedevptr->event_handler){ + (*timedevptr->event_handler)(); + } + // clear 1 write. + writel( val, timedevptr->membase + LPTMR_CSR_OFFSET); + }else{ + iret = IRQ_NONE; + } + + return iret; + +} + +int lpt_enable_timer( int timer_handle) +{ + struct platform_device *pdev; + struct mvf_lpt_dev *timedevptr; + void __iomem *membase; + unsigned long val; + + if ( !timer_master_is_opened(timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + if ( !timedevptr->configured){ + return -EAGAIN; + } + + membase = timedevptr->membase; + + // When TEN is set,the LPTMR is enabled. + // While writing 1 to this field, CSR[5:1] + // must not be altered. + val = readl(membase + LPTMR_CSR_OFFSET); + val |= ( LPTMR_CSR_TEN|LPTMR_CSR_TIE); + writel( val, membase + LPTMR_CSR_TEN); + + return 0; +} +EXPORT_SYMBOL(lpt_enable_timer); + +int lpt_disable_timer( int timer_handle) +{ + struct platform_device *pdev; + struct mvf_lpt_dev *timedevptr; + void __iomem *membase; + unsigned long val; + + if ( !timer_master_is_opened(timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + if ( !timedevptr->configured){ + return -EAGAIN; + } + + membase = timedevptr->membase; + + // When TEN is clear, it resets the LPTMR internal logic, + // including the CNR and TCF. + val = readl(membase + LPTMR_CSR_OFFSET); + val &= ~LPTMR_CSR_TEN; + writel( val, membase + LPTMR_CSR_TEN); + + return 0; +} +EXPORT_SYMBOL(lpt_disable_timer); + +int lpt_alloc_timer( void) +{ + return timer_master_alloc_timer(0); +} +EXPORT_SYMBOL(lpt_alloc_timer); + +int lpt_free_timer( int timer_handle) +{ + if ( !lpt_disable_timer( timer_handle)){ + return timer_master_free( timer_handle); + } + + return -EAGAIN; +} +EXPORT_SYMBOL( lpt_free_timer); + +int lpt_read_counter( int timer_handle, unsigned long *counter) +{ + struct platform_device *pdev; + struct mvf_lpt_dev *timedevptr; + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + // 16bit timer + *counter = readl( timedevptr->membase + LPTMR_CNR_OFFSET) & 0x0000ffff; + + return 0; +} +EXPORT_SYMBOL( lpt_read_counter); + +int lpt_param_set( int timer_handle, struct mvf_lpt_request *req, void (*event_handler)(void)) +{ + void __iomem *membase; + struct platform_device *pdev; + struct mvf_lpt_dev *timedevptr; + unsigned long val; + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + membase = timedevptr->membase; + if ( req == NULL){ + printk( KERN_ERR"lptmr param error \n"); + return -EINVAL; + } + + if( req->timer_mode > LPT_PARAM_TM_PULSECOUNTER){ + printk( KERN_ERR"lptmr clock mode setting error\n"); + return -EINVAL; + } + + if( req->pulse_pin_polarity > LPT_PARAM_PPP_ACTIVELOW){ + printk( KERN_ERR"lptmr clock pin polarity error\n"); + return -EINVAL; + } + + if( req->pulse_pin_select > LPT_PARAM_PPS_INPUT3){ + printk( KERN_ERR"lptmr clock pin polarity error\n"); + return -EINVAL; + } + + if( req->prs_clock_sel > LPT_PARAM_PCS_CLOCK3){ + printk( KERN_ERR"lptmr clock select error\n"); + return -EINVAL; + } + + if( req->prs_bypass > LPT_PARAM_PB_GF_BYPASS){ + printk( KERN_ERR"lptmr clock bypass error\n"); + return -EINVAL; + } + + + if( req->prs_value > LPT_PARAM_PV_DIV65536_RISE32768){ + printk( KERN_ERR"lptmr clock bypass error\n"); + return -EINVAL; + } + + if( req->compare_value > 0x0000ffff){ + printk( KERN_ERR"lptmr clock compare value over 16bit\n"); + } + + + // clear all param + writel( 0, membase + LPTMR_CSR_OFFSET); + + // CSR : TMS(1) TPP(3) TPS(4-5) + val = ( req->timer_mode << 1) | ( req->pulse_pin_polarity << 3) | ( req->pulse_pin_select << 4); + writel( val, membase + LPTMR_CSR_OFFSET); + + // PSR : PCS(0) PBYP(2) PRESCALE(3-6) + val = ( req->prs_clock_sel) | ( req->prs_bypass << 2) | ( req->prs_value << 3); + writel( val, membase + LPTMR_PSR_OFFSET); + + // compare + writel( req->compare_value, membase + LPTMR_CMR_OFFSET); + + timedevptr->event_handler = event_handler; + timedevptr->configured++; + // check 32bit cyclic + if( timedevptr->configured ==0){ + timedevptr->configured++; + } + + + return 0; +} +EXPORT_SYMBOL( lpt_param_set); + +static __devinit +int lpt_probe(struct platform_device *pdev) +{ + int size; + int result; + struct resource *lptmr_membase, *lptmr_irq; + struct mvf_lpt_dev *timedevptr; + + lptmr_membase = platform_get_resource(pdev, IORESOURCE_MEM, 1); + lptmr_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!lptmr_irq || !lptmr_membase){ + printk(KERN_WARNING"lptmr resource allocation failed\n"); + return -ENODEV; + } + + timedevptr = kzalloc(sizeof(struct mvf_lpt_dev), GFP_KERNEL); + if (!timedevptr) { + printk(KERN_WARNING"lptmr malloc fail.\n"); + return -ENOMEM; + } + timedevptr->clk = clk_get(&pdev->dev, "lptmr_clk"); + if ( IS_ERR( timedevptr->clk )) { + dev_err(&pdev->dev, "Could not low power timer clk\n"); + return PTR_ERR( timedevptr->clk); + } + clk_enable( timedevptr->clk); + + size = lptmr_membase->end - lptmr_membase->start + 1; + timedevptr->membase = ioremap(lptmr_membase->start, size); + if (!timedevptr->membase){ + printk(KERN_WARNING"lptmr ioremap failed.\n"); + return -ENOMEM; + } + timedevptr->irq = lptmr_irq->start; + + result = request_irq(timedevptr->irq, lpt_int_handler, 0, LPT_DRIVER_NAME, timedevptr); + if (result < 0) { + printk(KERN_WARNING"lptmr Error %d can't get irq.\n", result); + return result; + } + + platform_set_drvdata(pdev, timedevptr); + + timer_master_register_platform(pdev); + + return 0; +} + +static int __devexit lpt_remove(struct platform_device *pdev) +{ + struct mvf_lpt_dev *timedevptr; + + timedevptr = platform_get_drvdata(pdev); + + // disable all + lpt_disable_timer( 0); + clk_disable( timedevptr->clk); + kfree( timedevptr); + return 0; +} + +static struct platform_driver lpt_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "mvf-lpt", + }, + .probe = lpt_probe, + .remove = lpt_remove, +}; + +static int __init lpt_plat_dev_init(void) +{ + return platform_driver_register(&lpt_driver); +} + +static void __exit lpt_plat_dev_cleanup(void) +{ + platform_driver_unregister(&lpt_driver); +} + +module_init(lpt_plat_dev_init); +module_exit(lpt_plat_dev_cleanup); diff --git a/drivers/char/lptimer.h b/drivers/char/lptimer.h new file mode 100644 index 000000000000..e04a60df0a1d --- /dev/null +++ b/drivers/char/lptimer.h @@ -0,0 +1,77 @@ +/* + * drivers/char/lptimer.h + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +struct mvf_lpt_request{ + unsigned long compare_value; + unsigned short timer_mode; + + unsigned short pulse_pin_polarity; + unsigned short pulse_pin_select; + + unsigned short prs_clock_sel; + unsigned short prs_bypass; + unsigned short prs_value; +}; + + +#define LPT_PARAM_TM_TIMECOUNTER 0 +#define LPT_PARAM_TM_PULSECOUNTER 1 + +#define LPT_PARAM_PPP_ACTIVEHIGH 0 +#define LPT_PARAM_PPP_ACTIVELOW 1 + +#define LPT_PARAM_PPS_INPUT0 0 +#define LPT_PARAM_PPS_INPUT1 1 +#define LPT_PARAM_PPS_INPUT2 2 +#define LPT_PARAM_PPS_INPUT3 3 + + +#define LPT_PARAM_PCS_CLOCK0 0 +#define LPT_PARAM_PCS_CLOCK1 1 +#define LPT_PARAM_PCS_CLOCK2 2 +#define LPT_PARAM_PCS_CLOCK3 3 + +#define LPT_PARAM_PB_GF_ENABLE 0 +#define LPT_PARAM_PB_GF_BYPASS 1 + +#define LPT_PARAM_PV_DIV2_NA 0 +#define LPT_PARAM_PV_DIV4_RISE2 1 +#define LPT_PARAM_PV_DIV8_RISE4 2 +#define LPT_PARAM_PV_DIV16_RISE8 3 +#define LPT_PARAM_PV_DIV32_RISE16 4 +#define LPT_PARAM_PV_DIV64_RISE32 5 +#define LPT_PARAM_PV_DIV128_RISE64 6 +#define LPT_PARAM_PV_DIV256_RISE128 7 +#define LPT_PARAM_PV_DIV512_RISE256 8 +#define LPT_PARAM_PV_DIV1024_RISE512 9 +#define LPT_PARAM_PV_DIV2048_RISE1024 10 +#define LPT_PARAM_PV_DIV4096_RISE2048 11 +#define LPT_PARAM_PV_DIV8192_RISE4096 12 +#define LPT_PARAM_PV_DIV16384_RISE8192 13 +#define LPT_PARAM_PV_DIV32768_RISE16384 14 +#define LPT_PARAM_PV_DIV65536_RISE32768 15 + +int lpt_alloc_timer( void); +int lpt_free_timer(int timer_handle); +int lpt_enable_timer( int timer_handle); +int lpt_disable_timer( int timer_handle); +int lpt_read_counter(int timer_handle, unsigned long *counter); +int lpt_param_set( int timer_handle, struct mvf_lpt_request *req, void (*event_handler)(void)); diff --git a/drivers/char/lptimer_reg.h b/drivers/char/lptimer_reg.h new file mode 100644 index 000000000000..fc78e2708266 --- /dev/null +++ b/drivers/char/lptimer_reg.h @@ -0,0 +1,33 @@ +/* + * drivers/char/lptimer_reg.h + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define LPTMR_CSR_OFFSET 0x0000 +#define LPTMR_CSR_TEN 0x01 +#define LPTMR_CSR_TMS 0x02 +#define LPTMR_CSR_TFC 0x04 +#define LPTMR_CSR_TPP 0x08 +#define LPTMR_CSR_TIE 0x40 +#define LPTMR_CSR_TCF 0x80 + + +#define LPTMR_PSR_OFFSET 0x0004 +#define LPTMR_CMR_OFFSET 0x0008 +#define LPTMR_CNR_OFFSET 0x000C + diff --git a/drivers/char/mvf_timer_master.c b/drivers/char/mvf_timer_master.c new file mode 100644 index 000000000000..56d134d499be --- /dev/null +++ b/drivers/char/mvf_timer_master.c @@ -0,0 +1,113 @@ +/* + * drivers/char/mvf_timer_master.c + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +struct timer_master_control{ + int probe_cnt; + int is_opened[ TIMER_MASTER_MAX_TIMER]; +#define TIMER_AVAILABLE 0 +#define TIMER_BUSY 1 + struct platform_device *plat_timerdev[ TIMER_MASTER_MAX_TIMER]; +}; + +static struct timer_master_control master_control; + +static int timer_master_is_valid_handle(int index) +{ + int val; + + val = 0; + // error check + if ( index > TIMER_MASTER_ENUM_AVAILABLE) val = -EINVAL; + + return val; +} + +static int timer_master_is_opened(int index) +{ + int ret; + + ret = timer_master_is_valid_handle(index); + if ( ret < 0) return ret; + + return master_control.is_opened[index]; +} + +#if 0 +static int timer_master_set_eventhandler( int timer_handle, void (*event_handler)(void)) +{ + master_control.event_handler[ timer_handle] = event_handler; + return 0; +} +#endif + + +static struct platform_device *timer_master_get_pdev(int index) +{ + return master_control.plat_timerdev[ index]; +} + +static void timer_master_register_platform(struct platform_device *plat) +{ + int index = master_control.probe_cnt; + + if (master_control.probe_cnt >= TIMER_MASTER_MAX_TIMER){ + printk(KERN_WARNING"Timer regist count overflow\n"); + }else{ + master_control.plat_timerdev[ index] = plat; + master_control.probe_cnt++; + } +} + +static int timer_master_alloc_timer( int index) +{ + int i,ret; + + ret = timer_master_is_valid_handle( index); + if ( ret < 0) return ret; + + ret = -EBUSY; + if ( index == TIMER_MASTER_ENUM_AVAILABLE){ + for ( i = 0; i < TIMER_MASTER_MAX_TIMER; i ++){ + if ( master_control.is_opened[ i] == TIMER_AVAILABLE){ + master_control.is_opened[ i] = TIMER_BUSY; + ret = i; + } + } + }else + if ( master_control.is_opened[ index] == TIMER_AVAILABLE){ + master_control.is_opened[ index] = TIMER_BUSY; + ret = index; + } + + return ret; +} + +static int timer_master_free(int index) +{ + int ret; + + ret = timer_master_is_valid_handle(index); + if ( ret < 0) return ret; + + master_control.is_opened[ index] = TIMER_AVAILABLE; + + return 0; +} + diff --git a/drivers/char/pitimer.c b/drivers/char/pitimer.c new file mode 100644 index 000000000000..b83da781e76c --- /dev/null +++ b/drivers/char/pitimer.c @@ -0,0 +1,323 @@ +/* + * drivers/char/pitimer.c + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> +#include <linux/platform_device.h> +#include <linux/poll.h> +#include <mach/clock.h> +#include "pitimer_reg.h" +#include "pitimer.h" + +// define for timer master +#define TIMER_MASTER_MAX_TIMER 8 +#define TIMER_MASTER_ENUM_AVAILABLE PIT_AVAILABLE_CHANNEL +#define TIMER_MASTER_ENUM_MAXCHANNEL PIT7 +#include "mvf_timer_master.c" + + +// define for pit +#define PIT_MAXCHANNEL 8 + +//////////////////////////////////////////////////////////////// + +#define PIT_DRIVER_NAME "pit" + +struct mvf_pit_dev { + void __iomem *membase; + int irq; + unsigned long configured[ PIT_MAXCHANNEL]; + unsigned long refer_ch[ PIT_MAXCHANNEL]; + void (*event_handler[ PIT_MAXCHANNEL])(int); + struct clk *clk; +}; + + +static irqreturn_t pit_int_handler(int irq, void *dev_id) +{ + struct mvf_pit_dev *timedevptr = dev_id; + unsigned long val; + irqreturn_t iret; + int i; + + iret = IRQ_NONE; + + for ( i = 0; i < PIT_MAXCHANNEL; i ++){ + if ( timedevptr->configured[ i]){ + val = readl( timedevptr->membase + PIT_TFLG_OFFSET( i)); + if ( val & PIT_TFLG_TIF){ + (*timedevptr->event_handler[i])( timedevptr->refer_ch[ i]); + } + // ack + writel( val, timedevptr->membase + PIT_TFLG_OFFSET( i)); + iret = IRQ_HANDLED; + } + } + + return iret; + +} + +int pit_enable_timer( int timer_handle) +{ + struct platform_device *pdev; + struct mvf_pit_dev *timedevptr; + void __iomem *membase; + unsigned long val; + int i; + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + i = timer_handle % PIT_MAXCHANNEL; + + if ( !timedevptr->configured[ i]){ + return -EAGAIN; + } + + membase = timedevptr->membase; + + writel( PIT_TFLG_TIF, timedevptr->membase + PIT_TFLG_OFFSET( i)); + val = PIT_TCTR_TEN | PIT_TCTR_TIE; + writel( val, membase + PIT_TCTRL_OFFSET( i)); + + return 0; +} +EXPORT_SYMBOL(pit_enable_timer); + +int pit_disable_timer( int timer_handle) +{ + int i; + struct platform_device *pdev; + struct mvf_pit_dev *timedevptr; + void __iomem *membase; + + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev( timer_handle); + timedevptr = platform_get_drvdata( pdev); + + i = timer_handle % PIT_MAXCHANNEL; + if ( !timedevptr->configured[ i]){ + return -EAGAIN; + } + + membase = timedevptr->membase; + + writel( 0, membase + PIT_TCTRL_OFFSET( i)); + + return 0; +} +EXPORT_SYMBOL(pit_disable_timer); + +int pit_alloc_timer( pit_channel ch) +{ + return timer_master_alloc_timer( ch); +} +EXPORT_SYMBOL(pit_alloc_timer); + +int pit_free_timer( int timer_handle) +{ + if ( !pit_disable_timer( timer_handle)){ + return timer_master_free( timer_handle); + } + + return -EAGAIN; +} +EXPORT_SYMBOL( pit_free_timer); + +int pit_read_counter( int timer_handle, unsigned long *counter) +{ + struct platform_device *pdev; + struct mvf_pit_dev *timedevptr; + int i; + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + i = timer_handle % PIT_MAXCHANNEL; + + // 33bit timer + *counter = readl( timedevptr->membase + PIT_CVAL_OFFSET(i)); + + return 0; +} +EXPORT_SYMBOL( pit_read_counter); + +int pit_param_set( int timer_handle, unsigned long load_val, void (*event_handler)(int)) +{ + int i; + void __iomem *membase; + struct platform_device *pdev; + struct mvf_pit_dev *timedevptr; + + + if ( !timer_master_is_opened( timer_handle)){ + return -EAGAIN; + } + + pdev = timer_master_get_pdev(timer_handle); + timedevptr = platform_get_drvdata(pdev); + + membase = timedevptr->membase; + i = timer_handle % PIT_MAXCHANNEL; + + writel( load_val, membase + PIT_LDVAL_OFFSET(i)); + + timedevptr->refer_ch[ i] = timer_handle; + timedevptr->event_handler[ i] = event_handler; + + timedevptr->configured[ i]++; + // check 32bit cyclic + if( timedevptr->configured[ i] == 0){ + timedevptr->configured[ i]++; + } + + + return 0; +} +EXPORT_SYMBOL( pit_param_set); + +static __devinit +int pit_probe(struct platform_device *pdev) +{ + int size; + int result; + int i; + unsigned long val; + struct resource *pit_membase, *pit_irq; + struct mvf_pit_dev *timedevptr; + + pit_membase = platform_get_resource(pdev, IORESOURCE_MEM, 1); + pit_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!pit_irq || !pit_membase){ + printk(KERN_WARNING"PIT resource allocation failed\n"); + return -ENODEV; + } + + timedevptr = kzalloc(sizeof(struct mvf_pit_dev), GFP_KERNEL); + if (!timedevptr) { + printk(KERN_WARNING"PIT malloc fail.\n"); + return -ENOMEM; + } + timedevptr->clk = clk_get(&pdev->dev, "pit_clk"); + if ( IS_ERR( timedevptr->clk )) { + dev_err(&pdev->dev, "Could not pit clk\n"); + return PTR_ERR( timedevptr->clk); + } + clk_enable( timedevptr->clk); + + size = pit_membase->end - pit_membase->start + 1; + timedevptr->membase = ioremap(pit_membase->start, size); + if (!timedevptr->membase){ + printk(KERN_WARNING"PIT ioremap failed.\n"); + return -ENOMEM; + } + timedevptr->irq = pit_irq->start; + + result = request_irq(timedevptr->irq, pit_int_handler, 0, PIT_DRIVER_NAME, timedevptr); + if (result < 0) { + printk(KERN_WARNING"PIT Error %d can't get irq.\n", result); + return result; + } + + platform_set_drvdata(pdev, timedevptr); + + // for each channel + for ( i = 0; i < TIMER_MASTER_MAX_TIMER; i ++){ + timer_master_register_platform( pdev); + } + + val = readl( timedevptr->membase + PIT_MCR_OFFSET); + if( (val & PIT_MCR_MDIS)){ + // timer clock start + writel( 0, timedevptr->membase + PIT_MCR_OFFSET); + }else{ + // assume PIT 0 is kernel system tick + pit_alloc_timer( PIT0); + printk(KERN_WARNING"Maybe PIT0 is system tick\n"); + } + + return 0; +} + +static int __devexit pit_remove(struct platform_device *pdev) +{ + struct mvf_pit_dev *timedevptr; + + timedevptr = platform_get_drvdata(pdev); + + // disable all + pit_disable_timer( 0); + clk_disable( timedevptr->clk); + kfree( timedevptr); + + return 0; +} + +static struct platform_driver pit_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "mvf-pit", + }, + .probe = pit_probe, + .remove = pit_remove, +}; + +static int __init pit_plat_dev_init(void) +{ + return platform_driver_register(&pit_driver); +} + +static void __exit pit_plat_dev_cleanup(void) +{ + platform_driver_unregister(&pit_driver); +} + +module_init(pit_plat_dev_init); +module_exit(pit_plat_dev_cleanup); diff --git a/drivers/char/pitimer.h b/drivers/char/pitimer.h new file mode 100644 index 000000000000..0e1c22c0dd49 --- /dev/null +++ b/drivers/char/pitimer.h @@ -0,0 +1,40 @@ +/* + * drivers/char/pitimer.h + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +typedef enum { + PIT0, + PIT1, + PIT2, + PIT3, + PIT4, + PIT5, + PIT6, + PIT7, + PIT_AVAILABLE_CHANNEL +} pit_channel; + + +int pit_alloc_timer( pit_channel ch); +int pit_free_timer(int timer_handle); +int pit_enable_timer( int timer_handle); +int pit_disable_timer( int timer_handle); +int pit_read_counter(int timer_handle, unsigned long *counter); +int pit_param_set( int timer_handle, unsigned long load_val, void (*event_handler)(int)); diff --git a/drivers/char/pitimer_reg.h b/drivers/char/pitimer_reg.h new file mode 100644 index 000000000000..4f9aae4d6513 --- /dev/null +++ b/drivers/char/pitimer_reg.h @@ -0,0 +1,37 @@ +/* + * drivers/char/pitimer_reg.h + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define PIT_MCR_OFFSET 0x00 +#define PIT_MCR_FRZ 0x01 +#define PIT_MCR_MDIS 0x02 + +#define PIT_LTMR64H_OFFSET 0x04 +#define PIT_LTMR64L_OFFSET 0x08 + + +#define PIT_LDVAL_OFFSET(x) ( ( x * 0x10) + 0x100) +#define PIT_CVAL_OFFSET(x) ( ( x * 0x10) + 0x104) +#define PIT_TCTRL_OFFSET(x) ( ( x * 0x10) + 0x108) +#define PIT_TCTR_TEN 0x01 +#define PIT_TCTR_TIE 0x02 +#define PIT_TCTR_CHN 0x04 + +#define PIT_TFLG_OFFSET(x) ( ( x * 0x10) + 0x10c) +#define PIT_TFLG_TIF 0x01 |