ARM: OMAP2: TWL4030 RTC driver
Subsystems (4)
PATCH 1/1 ARM: OMAP2: TWL4030 RTC driver
This patch adds TWL4030 Real-Time Clock support for OMAP2430.
---
arch/arm/mach-omap2/board-2430sdp.c | 42 ++ drivers/rtc/Kconfig | 7 drivers/rtc/Makefile | 1 drivers/rtc/rtc-twl4030.c | 636 +++++++++++++++++++++++++++++++ include/asm-arm/arch-omap/twl4030-rtc.h | 230 +++++++++++ 5 files changed, 916 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/board-2430sdp.c +42 -0
@@ -38,6 +38,7 @@#include <asm/arch/keypad.h> #include <asm/arch/gpmc.h> #include <asm/arch/mcspi.h> +#include <asm/arch/twl4030-rtc.h> #include <asm/io.h>
@@ -50,6 +51,8 @@* that driver is used for the touchscreen. */ #define TS_GPIO 24 +#define TWL4030_MSECURE_GPIO 118 +static struct mtd_partition sdp2430_partitions[] = {/* bootloader (U-Boot, etc) in first sector */ {
@@ -183,11 +186,50 @@ static struct platform_device sdp2430_kp }, }; +static int twl4030_rtc_init (void ) +{ +int ret =0 ; + + ret =omap_request_gpio (TWL4030_MSECURE_GPIO ); +if (ret <0 ) { +printk (KERN_ERR "twl4030_rtc_init: can't reserve GPIO:%d !\n" , +TWL4030_MSECURE_GPIO ); + goto out; + } +/* TWL4030 will be in secure mode if msecure line from OMAP is low. +* Make msecure line high in order to change the TWL4030 RTC time +* and calender registers. +*/ +omap_set_gpio_direction (TWL4030_MSECURE_GPIO ,0 );/*dir out */ +omap_set_gpio_dataout (TWL4030_MSECURE_GPIO ,1 ); +out: +return ret; +} + +static void twl4030_rtc_exit (void ) +{ +omap_free_gpio (TWL4030_MSECURE_GPIO ); +} + +static struct twl4030rtc_platform_data sdp2430_twl4030rtc_data = { + .init = &twl4030_rtc_init, + .exit = &twl4030_rtc_exit, +}; + +static struct platform_device sdp2430_twl4030rtc_device = { + .name ="twl4030_rtc" , + .id =-1 , + .dev = { + .platform_data = &sdp2430_twl4030rtc_data, + }, +}; +static struct platform_device *sdp2430_devices[]__initdata = { &sdp2430_smc91x_device, &sdp2430_flash_device, &sdp2430_kp_device, &sdp2430_lcd_device, + &sdp2430_twl4030rtc_device, };static void ads7846_dev_init (void )
drivers/rtc/Kconfig +7 -0
@@ -121,6 +121,13 @@ config RTC_DRV_TEST comment "I2C RTC drivers" depends on RTC_CLASS +config RTC_DRV_OMAP2430_TWL4030 + tristate "OMAP243X TWL4030 Real Time Clock" + depends on RTC_CLASS && TWL4030_CORE + help + Support for TWL4030 companion chip internal RTC on OMAP2 SDP2430 board + + config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" depends on RTC_CLASS && I2C
drivers/rtc/Makefile +1 -0
@@ -41,3 +41,4 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o +obj-$(CONFIG_RTC_DRV_OMAP2430_TWL4030) += rtc-twl4030.o
drivers/rtc/rtc-twl4030.c new file +636 -0
636 lines not on this page · raw message
include/asm-arm/arch-omap/twl4030-rtc.h new file +230 -0
230 lines not on this page · raw message
Quoted 41 lines · Dmitry Krivoschekov
This patch adds TWL4030 Real-Time Clock support for OMAP2430.
Signed-off-by Dmitry Krivoschekov <[email protected]>---
arch/arm/mach-omap2/board-2430sdp.c | 42 ++ drivers/rtc/Kconfig | 7 drivers/rtc/Makefile | 1 drivers/rtc/rtc-twl4030.c | 636 +++++++++++++++++++++++++++++++ include/asm-arm/arch-omap/twl4030-rtc.h | 230 +++++++++++ 5 files changed, 916 insertions(+), 0 deletions(-)arch/arm/mach-omap2/board-2430sdp.c +7
-0@@ -38,6 +38,7 @@#include <asm/arch/keypad.h> #include <asm/arch/gpmc.h> #include <asm/arch/mcspi.h> +#include <asm/arch/twl4030-rtc.h> #include <asm/io.h> @@ -50,6 +51,8 @@* that driver is used for the touchscreen. */ #define TS_GPIO 24 +#define TWL4030_MSECURE_GPIO 118 +static struct mtd_partition sdp2430_partitions[] = {/* bootloader (U-Boot, etc) in first sector */ {@@ -183,11 +186,50 @@ static struct platform_device sdp2430_kp }, }; +static int twl4030_rtc_init (void ) +{ +int ret =0 ; +
arch/arm/mach-omap2/board-2430sdp.c static struct platform_device sdp2430_kp · line 202
Quoted 10 lines
arch/arm/mach-omap2/board-2430sdp.c +10
-0+ ret =omap_request_gpio (TWL4030_MSECURE_GPIO ); +if (ret <0 ) { +printk (KERN_ERR "twl4030_rtc_init: can't reserve GPIO:%d !\n" , +TWL4030_MSECURE_GPIO ); + goto out; + } +/* TWL4030 will be in secure mode if msecure line from OMAP is low. +* Make msecure line high in order to change the TWL4030 RTC time +* and calender registers. +*/
cosmetic changes required. Above multi-line comment block should look like this:
Quoted 45 lines
arch/arm/mach-omap2/board-2430sdp.c +30
-0+/* +* TWL4030 will be in secure mode if msecure line from OMAP is low. +* Make msecure line high in order to change the TWL4030 RTC time +* and calender registers. +*/ +omap_set_gpio_direction (TWL4030_MSECURE_GPIO ,0 );/*dir out */ +omap_set_gpio_dataout (TWL4030_MSECURE_GPIO ,1 ); +out: +return ret; +} + +static void twl4030_rtc_exit (void ) +{ +omap_free_gpio (TWL4030_MSECURE_GPIO ); +} + +static struct twl4030rtc_platform_data sdp2430_twl4030rtc_data = { + .init = &twl4030_rtc_init, + .exit = &twl4030_rtc_exit, +}; + +static struct platform_device sdp2430_twl4030rtc_device = { + .name ="twl4030_rtc" , + .id =-1 , + .dev = { + .platform_data = &sdp2430_twl4030rtc_data, + }, +}; +static struct platform_device *sdp2430_devices[]__initdata = { &sdp2430_smc91x_device, &sdp2430_flash_device, &sdp2430_kp_device, &sdp2430_lcd_device, + &sdp2430_twl4030rtc_device, };static void ads7846_dev_init (void )drivers/rtc/Kconfig +0
-0
drivers/rtc/Kconfig config RTC_DRV_TEST · line 129
Quoted 9 lines
drivers/rtc/Kconfig +6
-0@@ -121,6 +121,13 @@ config RTC_DRV_TEST comment "I2C RTC drivers" depends on RTC_CLASS +config RTC_DRV_OMAP2430_TWL4030 + tristate "OMAP243X TWL4030 Real Time Clock" + depends on RTC_CLASS && TWL4030_CORE + help + Support for TWL4030 companion chip internal RTC on OMAP2 SDP2430 board +
This driver should work on other boards having TWL4030 chip, so make help text more generic please. It is better if you don't have OMAP2430 in RTC_DRV_OMAP2430_TWL4030
Quoted 19 lines
drivers/rtc/Kconfig +1
-0+ config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" depends on RTC_CLASS && I2Cdrivers/rtc/Makefile +1
-0@@ -41,3 +41,4 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o +obj-$(CONFIG_RTC_DRV_OMAP2430_TWL4030) += rtc-twl4030.odrivers/rtc/rtc-twl4030.c new file +0
-0
drivers/rtc/rtc-twl4030.c line 5
Quoted 5 lines
drivers/rtc/rtc-twl4030.c new file +5
-0@@ -0,0 +1,636 @@ +/* +* drivers/rtc/rtc-twl4030.c +* +* TWL4030 Real Time Clock interface for Linux +*
I think this whole driver will work for Linux only. So no need to mention explicit "for Linux".
Quoted 122 lines
drivers/rtc/rtc-twl4030.c new file +122
-0+* Copyright (C) 2007 MontaVista Software, Inc +* Author: Alexandre Rusev <[email protected]> +* +* Based on original TI driver twl4030-rtc.c +* Copyright (C) 2006 Texas Instruments, Inc. +* +* Based on rtc-omap.c +* Copyright (C) 2003 MontaVista Software, Inc. +* Author: George G. Davis <[email protected]> or <[email protected]> +* +* Copyright (C) 2006 David Brownell +* +* 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. +* +*/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/device.h> + +#include <asm/io.h> +#include <asm/mach/time.h> +#include <asm/system.h> +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/arch/twl4030.h> +#include <asm/arch/twl4030-rtc.h> + +#define ALL_TIME_REGS 6 + +/* +* If this driver ever becomes modularised, it will be really nice +* to make the epoch retain its value across module reload... +*/ +static int epoch =1900 ;/* year corresponding to 0x00 */ + +/* +* Supports 1 byte read from TWL4030 RTC register. +*/ +static int twl4030_rtc_read_u8 (u8 * data,u8 reg) +{ +int ret; + + ret =twl4030_i2c_read_u8 (TWL4030_MODULE_RTC , data, reg); +if (ret <0 ) { +printk (KERN_WARNING "twl4030_rtc: Could not read TWL4030" +"register %X - returned %d[%x]\n" , reg, ret, ret); + } +return ret; +} + +/* +* Supports 1 byte write to TWL4030 RTC registers. +*/ +static int twl4030_rtc_write_u8 (u8 data,u8 reg) +{ +int ret; + + ret =twl4030_i2c_write_u8 (TWL4030_MODULE_RTC , data, reg); +if (ret <0 ) { +printk (KERN_WARNING "twl4030_rtc: Could not write TWL4030" +"register %X - returned %d[%x]\n" , reg, ret, ret); + } +return ret; +} + +/* +* Enables timer or alarm interrupts. +*/ +static int set_rtc_irq_bit (unsigned char bit) +{ +unsigned char val; +int ret; + + ret =twl4030_rtc_read_u8 (&val,REG_RTC_INTERRUPTS_REG ); +if (ret <0 ) + goto set_irq_out; + + val |= bit; + ret =twl4030_rtc_write_u8 (val,REG_RTC_INTERRUPTS_REG ); + +set_irq_out: +return ret; +} + +#ifdef CONFIG_PM +/* +* Read timer or alarm interrupts register. +*/ +static int get_rtc_irq_bit (unsigned char *val) +{ +int ret; + + ret =twl4030_rtc_read_u8 (val,REG_RTC_INTERRUPTS_REG ); +return ret; +} +#endif +/* +* Disables timer or alarm interrupts. +*/ +static int mask_rtc_irq_bit (unsigned char bit) +{ +unsigned char val; +int ret; + + ret =twl4030_rtc_read_u8 (&val,REG_RTC_INTERRUPTS_REG ); +if (ret <0 ) + goto mask_irq_out; + + val &= ~bit;
drivers/rtc/rtc-twl4030.c line 137
Quoted 10 lines
drivers/rtc/rtc-twl4030.c new file +10
-0+ ret =twl4030_rtc_write_u8 (val,REG_RTC_INTERRUPTS_REG ); + +mask_irq_out: +return ret; +} + +static int twl4030_rtc_alarm_irq_set_state (struct device *dev,int enabled) +{ +int ret; +/* Allow ints for RTC ALARM updates. */
one empty line between above sentences please.
Quoted 142 lines
drivers/rtc/rtc-twl4030.c new file +142
-0+if (enabled) + ret =set_rtc_irq_bit (BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ); +else + ret =mask_rtc_irq_bit (BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ); + +return ret; +} + +/* +* Gets current TWL4030 RTC time and date parameters. +*/ +static int get_rtc_time (struct rtc_time *rtc_tm) +{ +unsigned char rtc_data[ALL_TIME_REGS +1 ]; +int ret; +u8 save_control; + + ret =twl4030_rtc_read_u8 (&save_control,REG_RTC_CTRL_REG ); +if (ret <0 ) +return ret; + + save_control |=BIT_RTC_CTRL_REG_GET_TIME_M ; + + ret =twl4030_rtc_write_u8 (save_control,REG_RTC_CTRL_REG ); +if (ret <0 ) +return ret; + + ret =twl4030_i2c_read (TWL4030_MODULE_RTC , rtc_data, +REG_SECONDS_REG ,ALL_TIME_REGS ); + +if (ret <0 ) { +printk (KERN_ERR "twl4030_rtc: twl4030_i2c_read error.\n" ); +return ret; + } + + rtc_tm->tm_sec =BCD2BIN (rtc_data[0 ]); + rtc_tm->tm_min =BCD2BIN (rtc_data[1 ]); + rtc_tm->tm_hour =BCD2BIN (rtc_data[2 ]); + rtc_tm->tm_mday =BCD2BIN (rtc_data[3 ]); + rtc_tm->tm_mon =BCD2BIN (rtc_data[4 ]); + rtc_tm->tm_year =BCD2BIN (rtc_data[5 ]); + +/* +* Account for differences between how the RTC uses the values +* and how they are defined in a struct rtc_time; +*/ +if ((rtc_tm->tm_year += (epoch -1900 )) <=69 ) + rtc_tm->tm_year +=100 ; + + rtc_tm->tm_mon--; + +return ret; +} + +static int twl4030_rtc_set_time (struct device *dev,struct rtc_time *tm) +{ +unsigned char save_control; +unsigned char rtc_data[ALL_TIME_REGS +1 ]; +int ret; + +/* Month range is 01..12 */ + tm->tm_mon++; + + rtc_data[1 ] =BIN2BCD (tm->tm_sec); + rtc_data[2 ] =BIN2BCD (tm->tm_min); + rtc_data[3 ] =BIN2BCD (tm->tm_hour); + rtc_data[4 ] =BIN2BCD (tm->tm_mday); + rtc_data[5 ] =BIN2BCD (tm->tm_mon); + rtc_data[6 ] =BIN2BCD (tm->tm_year); + +/* Stop RTC while updating the TC registers */ + ret =twl4030_rtc_read_u8 (&save_control,REG_RTC_CTRL_REG ); +if (ret <0 ) + goto out; + + save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M ; +twl4030_rtc_write_u8 (save_control,REG_RTC_CTRL_REG ); +if (ret <0 ) + goto out; + +/* update all the alarm registers in one shot */ + ret =twl4030_i2c_write (TWL4030_MODULE_RTC , rtc_data, +REG_SECONDS_REG ,ALL_TIME_REGS ); +if (ret <0 ) { +printk (KERN_ERR "twl4030: twl4030_i2c_write error.\n" ); + goto out; + } + +/* Start back RTC */ + save_control |=BIT_RTC_CTRL_REG_STOP_RTC_M ; + ret =twl4030_rtc_write_u8 (save_control,REG_RTC_CTRL_REG ); + +out: +return ret; +} + +/* +* Gets current TWL4030 RTC alarm time. +*/ +static int get_rtc_alm_time (struct rtc_time *alm_tm) +{ +unsigned char rtc_data[ALL_TIME_REGS +1 ]; +int ret; + + ret =twl4030_i2c_read (TWL4030_MODULE_RTC , rtc_data, +REG_ALARM_SECONDS_REG ,ALL_TIME_REGS ); +if (ret <0 ) { +printk (KERN_ERR "twl4030_rtc: twl4030_i2c_read error.\n" ); +return ret; + } + + alm_tm->tm_sec =BCD2BIN (rtc_data[0 ]); + alm_tm->tm_min =BCD2BIN (rtc_data[1 ]); + alm_tm->tm_hour =BCD2BIN (rtc_data[2 ]); + alm_tm->tm_mday =BCD2BIN (rtc_data[3 ]); + alm_tm->tm_mon =BCD2BIN (rtc_data[4 ]); + alm_tm->tm_year =BCD2BIN (rtc_data[5 ]); + +/* +* Account for differences between how the RTC uses the values +* and how they are defined in a struct rtc_time; +*/ +if ((alm_tm->tm_year += (epoch -1900 )) <=69 ) + alm_tm->tm_year +=100 ; + + alm_tm->tm_mon--; + +return ret; +} + +static int twl4030_rtc_read_time (struct device *dev,struct rtc_time *tm) +{ +int ret; + +memset (tm,0 ,sizeof (struct rtc_time )); + ret =get_rtc_time (tm); + +return ret; +} + +/* +* Gets current TWL4030 RTC alarm time.
drivers/rtc/rtc-twl4030.c line 289
Quoted 10 lines
drivers/rtc/rtc-twl4030.c new file +10
-0+*/ +static int twl4030_rtc_read_alarm (struct device *dev,struct rtc_wkalrm *alm) +{ +int ret; +u8 rtc_interrupts_reg =0 ; +/* +* This returns a struct rtc_time. Reading >= 0xc0 +* means "don't care" or "match all". Only the tm_hour, +* tm_min, and tm_sec values are filled in. +*/
one empty line between above sentences please.
Quoted 17 lines
drivers/rtc/rtc-twl4030.c new file +17
-0+memset (&alm->time,0 ,sizeof (struct rtc_time )); + ret =get_rtc_alm_time (&alm->time); + +if (ret) + goto out; + +/* Check alarm enabled flag state */ + ret = + ret |twl4030_i2c_read_u8 (TWL4030_MODULE_RTC , &rtc_interrupts_reg, +REG_RTC_INTERRUPTS_REG ); + +if (ret) + goto out; + +if ((rtc_interrupts_reg &BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ) !=0 ) + alm->enabled =1 ; +else
drivers/rtc/rtc-twl4030.c line 316
Quoted 10 lines
drivers/rtc/rtc-twl4030.c new file +10
-0+ alm->enabled =0 ; + +out: +return ret; +} + +static int twl4030_rtc_irq_set_state (struct device *dev,int enabled) +{ +int ret; +/* Allow ints for RTC updates. */
one empty line between above sentences please.
Quoted 293 lines
drivers/rtc/rtc-twl4030.c new file +293
-0+if (enabled) + ret =set_rtc_irq_bit (BIT_RTC_INTERRUPTS_REG_IT_TIMER_M ); +else + ret =mask_rtc_irq_bit (BIT_RTC_INTERRUPTS_REG_IT_TIMER_M ); + +return ret; +} + +static int twl4030_rtc_set_alarm (struct device *dev,struct rtc_wkalrm *alm) +{ +unsigned char alarm_data[ALL_TIME_REGS +1 ]; +int ret; + +/* Month range is 01..12 */ + alm->time.tm_mon++; + + alarm_data[1 ] =BIN2BCD (alm->time.tm_sec); + alarm_data[2 ] =BIN2BCD (alm->time.tm_min); + alarm_data[3 ] =BIN2BCD (alm->time.tm_hour); + alarm_data[4 ] =BIN2BCD (alm->time.tm_mday); + alarm_data[5 ] =BIN2BCD (alm->time.tm_mon); + alarm_data[6 ] =BIN2BCD (alm->time.tm_year); + +/* update all the alarm registers in one shot */ + ret =twl4030_i2c_write (TWL4030_MODULE_RTC , alarm_data, +REG_ALARM_SECONDS_REG ,ALL_TIME_REGS ); +if (ret) { +printk (KERN_ERR "twl4030: twl4030_i2c_write error.\n" ); + goto out; + } + + ret =twl4030_rtc_alarm_irq_set_state (dev, alm->enabled); +out: +return ret; +} + +#ifdef CONFIG_RTC_INTF_DEV + +static int twl4030_rtc_ioctl (struct device *dev,unsigned int cmd, +unsigned long arg) +{ + +switch (cmd) { +case RTC_AIE_OFF : +return twl4030_rtc_alarm_irq_set_state (dev,0 ); +case RTC_AIE_ON : +return twl4030_rtc_alarm_irq_set_state (dev,1 ); +case RTC_UIE_OFF : +/* Mask ints from RTC updates. */ +return twl4030_rtc_irq_set_state (dev,0 ); +case RTC_UIE_ON : +/* Allow ints for RTC updates. */ +return twl4030_rtc_irq_set_state (dev,1 ); +case RTC_EPOCH_READ : +return put_user (epoch, (unsigned long *)arg); +case RTC_EPOCH_SET : +/* +* There were no RTC clocks before 1900. +*/ +if (arg <1900 ) +return -EINVAL ; + +if (!capable (CAP_SYS_TIME )) +return -EACCES ; + + epoch = arg; +return 0 ; +default : +return -ENOIOCTLCMD ; + } +} + +#else +#define omap_rtc_ioctl NULL +#endif + +static irqreturn_t twl4030_rtc_interrupt (int irq,void *rtc) +{ +unsigned long events =0 ; +int ret =IRQ_NONE ; +int res; +u8 rd_reg; + +/* clear the RTC interrupt in TWL4030 power module */ + res =twl4030_i2c_read_u8 (TWL4030_MODULE_INT , &rd_reg,REG_PWR_ISR1 ); +if (res) + goto out; + +/* Check if interrupt is sourced by RTC */ +if (!(rd_reg &PWR_RTC_INT_CLR )) + goto out; + + rd_reg |=PWR_RTC_INT_CLR ; + res =twl4030_i2c_write_u8 (TWL4030_MODULE_INT , rd_reg,REG_PWR_ISR1 ); +if (res) + goto out; + + res =twl4030_rtc_read_u8 (&rd_reg,REG_RTC_STATUS_REG ); +if (res) + goto out; +/* +* Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG. +* only one (ALARM or RTC) interrupt source may be enabled +* at time, we also could check our results +* by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] +*/ +if (rd_reg &BIT_RTC_STATUS_REG_ALARM_M ) + events |=RTC_IRQF |RTC_AF ; +else + events |=RTC_IRQF |RTC_UF ; + + res =twl4030_rtc_write_u8 (rd_reg |BIT_RTC_STATUS_REG_ALARM_M , +REG_RTC_STATUS_REG ); +if (res) + goto out; +/* +* Workaround for strange behaviour with T2. Need to write into ISR +* register one more time to clear the interrupt. Otherwise, the same +* RTC event generates 2 interrupts in a row. +* (no errata document available) +*/ + res =twl4030_i2c_read_u8 (TWL4030_MODULE_INT , &rd_reg,REG_PWR_ISR1 ); +if (res) + goto out; + + rd_reg |=PWR_RTC_INT_CLR ; + res =twl4030_i2c_write_u8 (TWL4030_MODULE_INT , rd_reg,REG_PWR_ISR1 ); +if (res) + goto out; + +/* Notify RTC core on event */ +rtc_update_irq (rtc,1 , events); + + ret =IRQ_HANDLED ; +out: +return ret; +} + +static struct rtc_class_ops twl4030_rtc_ops = { + .ioctl = twl4030_rtc_ioctl, + .read_time = twl4030_rtc_read_time, + .set_time = twl4030_rtc_set_time, + .read_alarm = twl4030_rtc_read_alarm, + .set_alarm = twl4030_rtc_set_alarm, +}; + +static int __devinit twl4030_rtc_probe (struct platform_device *pdev) +{ +struct twl4030rtc_platform_data *pdata = pdev->dev.platform_data; +struct rtc_device *rtc; +int ret =0 ; +u8 rd_reg; + +if (pdata !=NULL && pdata->init !=NULL ) { + ret = pdata->init (); +if (ret <0 ) + goto out; + } + + rtc =rtc_device_register (pdev->name, + &pdev->dev, &twl4030_rtc_ops,THIS_MODULE ); +if (IS_ERR (rtc)) { + ret = -EINVAL ; +dev_err (&pdev->dev,"can't register RTC device, err %ld\n" , +PTR_ERR (rtc)); + goto out0; + + } + +platform_set_drvdata (pdev, rtc); + + ret =twl4030_rtc_read_u8 (&rd_reg,REG_RTC_STATUS_REG ); + +if (ret <0 ) + goto out1; + +if (rd_reg &BIT_RTC_STATUS_REG_POWER_UP_M ) +dev_warn (&pdev->dev,"Power up reset detected.\n" ); + +if (rd_reg &BIT_RTC_STATUS_REG_ALARM_M ) +dev_warn (&pdev->dev,"Pending Alarm interrupt detected.\n" ); + +/* Clear RTC Power up reset and pending alarm interrupts */ + ret =twl4030_rtc_write_u8 (rd_reg,REG_RTC_STATUS_REG ); +if (ret <0 ) + goto out1; + + ret =request_irq (TWL4030_MODIRQ_PWR , twl4030_rtc_interrupt, +IRQF_DISABLED |IRQF_SHARED , rtc->dev.bus_id, rtc); +if (ret <0 ) { +dev_err (&pdev->dev,"IRQ is not free.\n" ); + goto out1; + } + +/* Check RTC module status, Enable if it is off */ + ret =twl4030_rtc_read_u8 (&rd_reg,REG_RTC_CTRL_REG ); +if (ret <0 ) + goto out2; + +if (!(rd_reg &BIT_RTC_CTRL_REG_STOP_RTC_M )) { +dev_info (&pdev->dev,"Enabling TWL4030-RTC.\n" ); + rd_reg =BIT_RTC_CTRL_REG_STOP_RTC_M ; + ret =twl4030_rtc_write_u8 (rd_reg,REG_RTC_CTRL_REG ); +if (ret <0 ) + goto out2; + } + + ret =twl4030_i2c_read_u8 (TWL4030_MODULE_INT , &rd_reg,REG_PWR_IMR1 ); +if (ret <0 ) + goto out2; + + rd_reg &=PWR_RTC_IT_UNMASK ; +/* MASK PWR - we will need this */ + ret =twl4030_i2c_write_u8 (TWL4030_MODULE_INT , rd_reg,REG_PWR_IMR1 ); +if (ret <0 ) + goto out2; + + ret =twl4030_i2c_read_u8 (TWL4030_MODULE_INT , &rd_reg,REG_PWR_EDR1 ); +if (ret <0 ) + goto out2; + +/* Rising edge detection enabled, needed for RTC alarm */ + rd_reg |=0x80 ; + ret =twl4030_i2c_write_u8 (TWL4030_MODULE_INT , rd_reg,REG_PWR_EDR1 ); +if (ret <0 ) + goto out2; + +return ret; + + +out2: +free_irq (TWL4030_MODIRQ_PWR , rtc); +out1: +rtc_device_unregister (rtc); +out0: +if (pdata !=NULL && pdata->exit !=NULL ) + pdata->exit (); +out: +return ret; +} + +/* +* Disable all TWL4030 RTC module interrupts. +* Sets status flag to free. +*/ +static int __devexit twl4030_rtc_remove(struct platform_device *pdev) +{ +/* leave rtc running, but disable irqs */ +struct twl4030rtc_platform_data *pdata = pdev->dev.platform_data; +struct rtc_device *rtc =platform_get_drvdata (pdev); + +mask_rtc_irq_bit (BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ); +mask_rtc_irq_bit (BIT_RTC_INTERRUPTS_REG_IT_TIMER_M ); + +free_irq (TWL4030_MODIRQ_PWR , rtc); + +if (pdata !=NULL && pdata->exit !=NULL ) + pdata->exit (); + +rtc_device_unregister (rtc); +return 0 ; +} + +static void twl4030_rtc_shutdown (struct platform_device *pdev) +{ +twl4030_rtc_alarm_irq_set_state (&pdev->dev,0 ); +twl4030_rtc_irq_set_state (&pdev->dev,0 ); +} + +#ifdef CONFIG_PM + +static unsigned char irqstat =0 ; + +static int twl4030_rtc_suspend (struct platform_device *pdev,pm_message_t state) +{ +get_rtc_irq_bit (&irqstat); + +mask_rtc_irq_bit (BIT_RTC_INTERRUPTS_REG_IT_TIMER_M | +BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ); +return 0 ; +} + +static int twl4030_rtc_resume (struct platform_device *pdev) +{ +set_rtc_irq_bit (irqstat); +return 0 ; +} +#else +#define twl4030_rtc_suspend NULL +#define twl4030_rtc_resume NULL +#endif + +MODULE_ALIAS ("twl4030_rtc" );
drivers/rtc/rtc-twl4030.c line 619
Quoted 10 lines
drivers/rtc/rtc-twl4030.c new file +10
-0+static struct platform_driver twl4030rtc_driver = { + .probe = twl4030_rtc_probe, + .remove =__devexit_p (twl4030_rtc_remove), + .shutdown = twl4030_rtc_shutdown, + .suspend = twl4030_rtc_suspend, + .resume = twl4030_rtc_resume, + .driver = { + .owner =THIS_MODULE , + .name ="twl4030_rtc" , + },
indentation problem?
Quoted 17 lines
drivers/rtc/rtc-twl4030.c new file +17
-0+}; + +static int __init twl4030_rtc_init (void ) +{ +return platform_driver_register (&twl4030rtc_driver); +} + +static void __exit twl4030_rtc_exit(void) +{ +platform_driver_unregister (&twl4030rtc_driver); +} + +MODULE_AUTHOR ("Texas Instruments, MontaVista Software" ); +MODULE_LICENSE ("GPL" );; + +module_init (twl4030_rtc_init); +module_exit (twl4030_rtc_exit);
Signature · 1 line
--Trilok Soni
Hello Trilok,
thanks for the review.
Quoted 12 lines · Trilok Soni
Quoted 8 lines
drivers/rtc/Kconfig +5
-0+config RTC_DRV_OMAP2430_TWL4030 + tristate "OMAP243X TWL4030 Real Time Clock" + depends on RTC_CLASS && TWL4030_CORE + help + Support for TWL4030 companion chip internal RTC on OMAP2SDP2430 board
+This driver should work on other boards having TWL4030 chip, so make help text more generic please. It is better if you don't have OMAP2430 in
RTC_DRV_OMAP2430_TWL4030
Agreed. We should avoid sticking to a particular board in general. This issue, as well as codestyle issues you found, will be fixed.
Regards,
Dmitry