* [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
@ 2008-09-04 17:24 David Brownell
2008-09-04 17:48 ` David Brownell
2008-09-09 17:42 ` Tony Lindgren
0 siblings, 2 replies; 6+ messages in thread
From: David Brownell @ 2008-09-04 17:24 UTC (permalink / raw)
To: linux-omap
From: David Brownell <dbrownell@users.sourceforge.net>
Some rtc-twl4030 cleanup, which among other things adds up to
using about 10% less object code:
- Remove:
* broken/unfixable "periodic" IRQ support (2^N Hz)
* duplicated constants in the header file
* pointless stuff:
+ support for settable epoch
+ memset() calls
+ indirection when reading time and alarm
+ indirection when enabling irqs
* needless ifdeffery for reading irq enable register
- IRQ updates:
* group irq enable/disable utilities together
* cache irq enable register
* now disable any old alarm irq before setting alarm
- Comment updates
* fix up my copyright attribution (old omap1 code)
* more correctly describe the rtc mask/set ops
* have a single place describe the register vs tm_* differences
- Other:
* don't support "current" dates in the 20th century
* switch over to bcd2bin()/bin2bcd()
* prefer dev_err() and better messages to printk(KERN_ERR...)
* correct some KERN_WARNING messages (should have been pr_err)
* whitespace bugs
* misc
The bugs fixed here are removing "periodic" IRQ support, and
some of the messaging. Update IRQs still misbehave (two per
second, not one!), and the alarm isn't wake-enabled.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
drivers/rtc/rtc-twl4030.c | 328 +++++++++++---------------------------
include/linux/i2c/twl4030-rtc.h | 58 ------
2 files changed, 103 insertions(+), 283 deletions(-)
--- a/drivers/rtc/rtc-twl4030.c
+++ b/drivers/rtc/rtc-twl4030.c
@@ -1,7 +1,5 @@
/*
- * drivers/rtc/rtc-twl4030.c
- *
- * TWL4030 Real Time Clock interface
+ * rtc-twl4030.c -- TWL4030 Real Time Clock interface
*
* Copyright (C) 2007 MontaVista Software, Inc
* Author: Alexandre Rusev <source@mvista.com>
@@ -12,14 +10,12 @@
* Based on rtc-omap.c
* Copyright (C) 2003 MontaVista Software, Inc.
* Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
- *
* 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>
@@ -46,12 +42,6 @@
#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)
@@ -59,10 +49,9 @@ static int twl4030_rtc_read_u8(u8 *data,
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);
- }
+ if (ret < 0)
+ pr_err("twl4030_rtc: Could not read TWL4030"
+ "register %X - error %d\n", reg, ret);
return ret;
}
@@ -74,68 +63,54 @@ static int twl4030_rtc_write_u8(u8 data,
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);
- }
+ if (ret < 0)
+ pr_err("twl4030_rtc: Could not write TWL4030"
+ "register %X - error %d\n", reg, ret);
return ret;
}
/*
- * Enables timer or alarm interrupts.
+ * Cache the value for timer/alarm interrupts register; this is
+ * only changed by callers holding rtc ops lock (or resume).
+ */
+static unsigned char rtc_irq_bits;
+
+/*
+ * Enable timer and/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;
+ val = rtc_irq_bits | bit;
ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+ if (ret == 0)
+ rtc_irq_bits = val;
-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.
+ * Disable timer and/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;
+ val = rtc_irq_bits & ~bit;
ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+ if (ret == 0)
+ rtc_irq_bits = val;
-mask_irq_out:
return ret;
}
-static int twl4030_rtc_alarm_irq_set_state(struct device *dev, int enabled)
+static inline int twl4030_rtc_alarm_irq_set_state(int enabled)
{
int ret;
- /* Allow ints for RTC ALARM updates. */
if (enabled)
ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
else
@@ -144,10 +119,28 @@ static int twl4030_rtc_alarm_irq_set_sta
return ret;
}
+static inline int twl4030_rtc_irq_set_state(int enabled)
+{
+ int ret;
+
+ 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;
+}
+
/*
* Gets current TWL4030 RTC time and date parameters.
+ *
+ * The RTC's time/alarm representation is not what gmtime(3) requires
+ * Linux to use:
+ *
+ * - Months are 1..12 vs Linux 0-11
+ * - Years are 0..99 vs Linux 1900..N (we assume 21st century)
*/
-static int get_rtc_time(struct rtc_time *rtc_tm)
+static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
unsigned char rtc_data[ALL_TIME_REGS + 1];
int ret;
@@ -167,26 +160,16 @@ static int get_rtc_time(struct rtc_time
REG_SECONDS_REG, ALL_TIME_REGS);
if (ret < 0) {
- printk(KERN_ERR "twl4030_rtc: twl4030_i2c_read error.\n");
+ dev_err(dev, "rtc_read_time error %d\n", ret);
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;
- */
- rtc_tm->tm_year += (epoch - 1900);
- if (rtc_tm->tm_year <= 69)
- rtc_tm->tm_year += 100;
-
- rtc_tm->tm_mon--;
+ tm->tm_sec = bcd2bin(rtc_data[0]);
+ tm->tm_min = bcd2bin(rtc_data[1]);
+ tm->tm_hour = bcd2bin(rtc_data[2]);
+ tm->tm_mday = bcd2bin(rtc_data[3]);
+ tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
+ tm->tm_year = bcd2bin(rtc_data[5]) + 100;
return ret;
}
@@ -197,15 +180,12 @@ static int twl4030_rtc_set_time(struct d
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);
+ 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 + 1);
+ rtc_data[6] = bin2bcd(tm->tm_year - 100);
/* Stop RTC while updating the TC registers */
ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
@@ -217,11 +197,11 @@ static int twl4030_rtc_set_time(struct d
if (ret < 0)
goto out;
- /* update all the alarm registers in one shot */
+ /* update all the time 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");
+ dev_err(dev, "rtc_set_time error %d\n", ret);
goto out;
}
@@ -236,7 +216,7 @@ out:
/*
* Gets current TWL4030 RTC alarm time.
*/
-static int get_rtc_alm_time(struct rtc_time *alm_tm)
+static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
unsigned char rtc_data[ALL_TIME_REGS + 1];
int ret;
@@ -244,85 +224,21 @@ static int get_rtc_alm_time(struct rtc_t
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");
+ dev_err(dev, "rtc_read_alarm error %d\n", ret);
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;
- */
- alm_tm->tm_year += (epoch - 1900);
- if (alm_tm->tm_year <= 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.
- */
-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.
- */
- 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;
+ /* some of these fields may be wildcard/"match all" */
+ alm->time.tm_sec = bcd2bin(rtc_data[0]);
+ alm->time.tm_min = bcd2bin(rtc_data[1]);
+ alm->time.tm_hour = bcd2bin(rtc_data[2]);
+ alm->time.tm_mday = bcd2bin(rtc_data[3]);
+ alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
+ alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
- if ((rtc_interrupts_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) != 0)
+ /* report cached alarm enable state */
+ if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
alm->enabled = 1;
- else
- 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. */
- 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;
}
@@ -332,86 +248,46 @@ static int twl4030_rtc_set_alarm(struct
unsigned char alarm_data[ALL_TIME_REGS + 1];
int ret;
- /* Month range is 01..12 */
- alm->time.tm_mon++;
+ ret = twl4030_rtc_alarm_irq_set_state(0);
+ if (ret)
+ goto out;
- 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);
+ 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 + 1);
+ alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
/* 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");
+ dev_err(dev, "rtc_set_alarm error %d\n", ret);
goto out;
}
- ret = twl4030_rtc_alarm_irq_set_state(dev, alm->enabled);
+ if (alm->enabled)
+ ret = twl4030_rtc_alarm_irq_set_state(1);
out:
return ret;
}
-/*
- * We will just handle setting the frequency and make use the framework for
- * reading the periodic interupts.
- * @freq: Current periodic IRQ freq
- */
-static int twl4030_rtc_irq_set_freq(struct device *dev, int freq)
-{
- struct rtc_device *rtc = dev_get_drvdata(dev);
-
- if (freq < 0 || freq > 3)
- return -EINVAL;
-
- rtc->irq_freq = freq;
-
- /* set rtc irq freq to user defined value */
- set_rtc_irq_bit(freq);
-
- return 0;
-}
-
#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);
+ return twl4030_rtc_alarm_irq_set_state(0);
case RTC_AIE_ON:
- return twl4030_rtc_alarm_irq_set_state(dev, 1);
-
+ return twl4030_rtc_alarm_irq_set_state(1);
case RTC_UIE_OFF:
- /* Fall Through */
- case RTC_PIE_OFF:
- /* Mask ints from RTC updates. */
- return twl4030_rtc_irq_set_state(dev, 0);
+ return twl4030_rtc_irq_set_state(0);
case RTC_UIE_ON:
- /* Fall Through */
- case RTC_PIE_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;
+ return twl4030_rtc_irq_set_state(1);
- epoch = arg;
- return 0;
default:
return -ENOIOCTLCMD;
}
@@ -465,7 +341,6 @@ static struct rtc_class_ops twl4030_rtc_
.set_time = twl4030_rtc_set_time,
.read_alarm = twl4030_rtc_read_alarm,
.set_alarm = twl4030_rtc_set_alarm,
- .irq_set_freq = twl4030_rtc_irq_set_freq,
};
static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
@@ -491,9 +366,6 @@ static int __devinit twl4030_rtc_probe(s
}
- /* Set the irq freq to every second */
- rtc->irq_freq = 0;
-
platform_set_drvdata(pdev, rtc);
ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
@@ -552,6 +424,11 @@ static int __devinit twl4030_rtc_probe(s
if (ret < 0)
goto out2;
+ /* init cached IRQ enable bits */
+ ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
+ if (ret < 0)
+ goto out2;
+
return ret;
@@ -591,8 +468,8 @@ static int __devexit twl4030_rtc_remove(
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);
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
+ BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
}
#ifdef CONFIG_PM
@@ -601,8 +478,9 @@ static unsigned char irqstat;
static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
- get_rtc_irq_bit(&irqstat);
+ irqstat = rtc_irq_bits;
+ /* REVISIT alarm may need to wake us from sleep */
mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
return 0;
@@ -613,19 +491,21 @@ static int twl4030_rtc_resume(struct pla
set_rtc_irq_bit(irqstat);
return 0;
}
+
#else
#define twl4030_rtc_suspend NULL
#define twl4030_rtc_resume NULL
#endif
MODULE_ALIAS("platform:twl4030_rtc");
+
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 = {
+ .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",
},
@@ -635,15 +515,13 @@ static int __init twl4030_rtc_init(void)
{
return platform_driver_register(&twl4030rtc_driver);
}
+module_init(twl4030_rtc_init);
static void __exit twl4030_rtc_exit(void)
{
platform_driver_unregister(&twl4030rtc_driver);
}
+module_exit(twl4030_rtc_exit);
-MODULE_ALIAS("platform:twl4030_rtc");
MODULE_AUTHOR("Texas Instruments, MontaVista Software");
-MODULE_LICENSE("GPL");;
-
-module_init(twl4030_rtc_init);
-module_exit(twl4030_rtc_exit);
+MODULE_LICENSE("GPL");
--- a/include/linux/i2c/twl4030-rtc.h
+++ b/include/linux/i2c/twl4030-rtc.h
@@ -164,64 +164,6 @@
#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB (0x000)
#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB_M (0x000000FF)
-/* ALARM_DAYS_REG Fields */
-#define BIT_ALARM_DAYS_REG_ALARM_DAY1 (0x004)
-#define BIT_ALARM_DAYS_REG_ALARM_DAY1_M (0x00000030)
-/* ALARM_MONTHS_REG Fields */
-#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0 (0x000)
-#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0_M (0x0000000F)
-#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1 (0x004)
-#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1_M (0x00000010)
-/* ALARM_YEARS_REG Fields */
-#define BIT_ALARM_YEARS_REG_ALARM_YEAR0 (0x000)
-#define BIT_ALARM_YEARS_REG_ALARM_YEAR0_M (0x0000000F)
-#define BIT_ALARM_YEARS_REG_ALARM_YEAR1 (0x004)
-#define BIT_ALARM_YEARS_REG_ALARM_YEAR1_M (0x000000F0)
-/* RTC_CTRL_REG Fields */
-#define BIT_RTC_CTRL_REG_STOP_RTC (0x000)
-#define BIT_RTC_CTRL_REG_STOP_RTC_M (0x00000001)
-#define BIT_RTC_CTRL_REG_ROUND_30S (0x001)
-#define BIT_RTC_CTRL_REG_ROUND_30S_M (0x00000002)
-#define BIT_RTC_CTRL_REG_AUTO_COMP (0x002)
-#define BIT_RTC_CTRL_REG_AUTO_COMP_M (0x00000004)
-#define BIT_RTC_CTRL_REG_MODE_12_24 (0x003)
-#define BIT_RTC_CTRL_REG_MODE_12_24_M (0x00000008)
-#define BIT_RTC_CTRL_REG_TEST_MODE (0x004)
-#define BIT_RTC_CTRL_REG_TEST_MODE_M (0x00000010)
-#define BIT_RTC_CTRL_REG_SET_32_COUNTER (0x005)
-#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M (0x00000020)
-#define BIT_RTC_CTRL_REG_GET_TIME (0x006)
-#define BIT_RTC_CTRL_REG_GET_TIME_M (0x00000040)
-/* RTC_STATUS_REG Fields */
-#define BIT_RTC_STATUS_REG_RUN (0x001)
-#define BIT_RTC_STATUS_REG_RUN_M (0x00000002)
-#define BIT_RTC_STATUS_REG_1S_EVENT (0x002)
-#define BIT_RTC_STATUS_REG_1S_EVENT_M (0x00000004)
-#define BIT_RTC_STATUS_REG_1M_EVENT (0x003)
-#define BIT_RTC_STATUS_REG_1M_EVENT_M (0x00000008)
-#define BIT_RTC_STATUS_REG_1H_EVENT (0x004)
-#define BIT_RTC_STATUS_REG_1H_EVENT_M (0x00000010)
-#define BIT_RTC_STATUS_REG_1D_EVENT (0x005)
-#define BIT_RTC_STATUS_REG_1D_EVENT_M (0x00000020)
-#define BIT_RTC_STATUS_REG_ALARM (0x006)
-#define BIT_RTC_STATUS_REG_ALARM_M (0x00000040)
-#define BIT_RTC_STATUS_REG_POWER_UP (0x007)
-#define BIT_RTC_STATUS_REG_POWER_UP_M (0x00000080)
-/* RTC_INTERRUPTS_REG Fields */
-#define BIT_RTC_INTERRUPTS_REG_EVERY (0x000)
-#define BIT_RTC_INTERRUPTS_REG_EVERY_M (0x00000003)
-#define BIT_RTC_INTERRUPTS_REG_IT_TIMER (0x002)
-#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M (0x00000004)
-#define BIT_RTC_INTERRUPTS_REG_IT_ALARM (0x003)
-#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M (0x00000008)
-/* RTC_COMP_LSB_REG Fields */
-#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB (0x000)
-#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB_M (0x000000FF)
-/* RTC_COMP_MSB_REG Fields */
-#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB (0x000)
-#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB_M (0x000000FF)
-
-
struct twl4030rtc_platform_data {
int (*init)(void);
void (*exit)(void);
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
2008-09-04 17:24 [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup David Brownell
@ 2008-09-04 17:48 ` David Brownell
2008-09-05 7:24 ` Pakaravoor, Jagadeesh
2008-09-09 17:42 ` Tony Lindgren
1 sibling, 1 reply; 6+ messages in thread
From: David Brownell @ 2008-09-04 17:48 UTC (permalink / raw)
To: linux-omap
On Thursday 04 September 2008, David Brownell wrote:
> Update IRQs still misbehave (two per > second, not one!),
Someone with docs will need to sort this one out. The
appended test program will illustrate the problem; it
was sitting around to help sort out bugs in way x86
"HPET Emulation" reports update IRQs.
Output on twl4030 is like:
Read using select(2) on /dev/rtc0:
1 0.562852 (+0.358789) 0190
-3 * 0.563770 (+0.359707) 0190
-2 1.562741 (+0.358678) 0190
-6 * 1.563712 (+0.359649) 0190
-5 2.562825 (+0.358762) 0190
-9 * 2.563737 (+0.359674) 0190
-8 3.562817 (+0.358754) 0190
-12 * 3.563722 (+0.359659) 0190
-11 4.562975 (+0.358912) 0190
-15 * 4.563923 (+0.359860) 0190
-14 5.563039 (+0.358976) 0190
-18 * 5.564048 (+0.359985) 0190
^C
The "*" indicates bogus IRQ reports ... in this case it
looks like each update IRQ is reported TWICE, with the
second one being about one millisec after the first one.
Since this test waits for five consecutive non-bogus
interrupts, it never stops ...
Note that if you abort the test with an interrupt (as
shown above) you'll want the RTC framework patch from
http://groups.google.com/group/rtc-linux/msg/d18d561014a97807
to shut the update IRQs down. Or, just run "hwclock"
from util-linux-ng (not busybox!).
- Dave
/* gcc -s -Os -Wall -Wstrict-prototypes uie2.c -o uie2 */
#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
/*
* This expects the new RTC class driver framework, working with
* clocks that will often not be clones of what the PC-AT had.
* Use the command line to specify another RTC if you need one.
*/
static const char default_rtc[] = "/dev/rtc0";
int main(int argc, char **argv)
{
int i, fd, retval, irqcount = 0;
unsigned long data;
const char *rtc = default_rtc;
char *exception;
struct timeval stv, etv;
struct timezone tz;
long sec, usec, old_ticks;
switch (argc) {
case 2:
rtc = argv[1];
/* FALLTHROUGH */
case 1:
break;
default:
fprintf(stderr, "usage: uie2 [rtcdev]\n");
return 1;
}
fd = open(rtc, O_RDONLY);
if (fd == -1) {
perror(rtc);
exit(errno);
}
/* Turn on update interrupts (one per second) */
// gettimeofday(&stv, &tz);
retval = ioctl(fd, RTC_UIE_ON, 0);
if (retval == -1) {
if (errno == ENOTTY) {
fprintf(stderr, "\n...Update IRQs not supported.\n");
}
perror("RTC_UIE_ON ioctl");
exit(errno);
}
fprintf(stderr, "\nRead using select(2) on %s:\n", rtc);
fflush(stderr);
old_ticks = -1;
gettimeofday(&stv, &tz);
for (i = 1; i < 6; i++) {
struct timeval tv = { 5, 0 }; /* 5 second timeout on select */
fd_set readfds;
long new_ticks, diff;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
/* The select will wait until an RTC interrupt happens. */
retval = select(fd + 1, &readfds, NULL, NULL, &tv);
if (retval == -1) {
perror("select");
exit(errno);
}
/* This read won't block unlike the select-less case above. */
retval = read(fd, &data, sizeof(unsigned long));
if (retval == -1) {
perror("read");
exit(errno);
}
gettimeofday(&etv, &tz);
sec = etv.tv_sec - stv.tv_sec;
usec = etv.tv_usec - stv.tv_usec;
if (usec < 0) {
usec += 1000000;
sec -= 1;
} else if (usec > 1000000) {
usec -= 1000000;
sec++;
}
/* what we want to watch for is having a "one-per-second"
* update report be more imprecise than the 64 Hz default
* of the HPET rtc glue should be able to deliver...
*/
new_ticks = (sec * 1000000 + usec) / (1000000 / 64);
diff = abs(new_ticks - old_ticks);
if ((old_ticks > 0) && ((diff < 63) || (diff > 65))) {
exception = "*";
i -= 5;
} else
exception = " ";
fprintf(stderr, " %4d %s %ld.%06lu (+0.%06lu) %04lx\n",
i, exception, sec, usec, etv.tv_usec, data);
fflush(stderr);
old_ticks = new_ticks;
irqcount++;
}
/* Turn off update interrupts */
retval = ioctl(fd, RTC_UIE_OFF, 0);
if (retval == -1) {
perror("RTC_UIE_OFF ioctl");
exit(errno);
}
return 0;
}
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
2008-09-04 17:48 ` David Brownell
@ 2008-09-05 7:24 ` Pakaravoor, Jagadeesh
2008-09-05 8:09 ` David Brownell
0 siblings, 1 reply; 6+ messages in thread
From: Pakaravoor, Jagadeesh @ 2008-09-05 7:24 UTC (permalink / raw)
To: David Brownell, linux-omap@vger.kernel.org
> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of David
> Brownell
> Sent: Thursday, September 04, 2008 11:19 PM
> To: linux-omap@vger.kernel.org
> Subject: Re: [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
>
> On Thursday 04 September 2008, David Brownell wrote:
> > Update IRQs still misbehave (two per > second, not one!),
>
> Someone with docs will need to sort this one out. The
> appended test program will illustrate the problem; it
> was sitting around to help sort out bugs in way x86
> "HPET Emulation" reports update IRQs.
>
> Output on twl4030 is like:
>
> Read using select(2) on /dev/rtc0:
> 1 0.562852 (+0.358789) 0190
> -3 * 0.563770 (+0.359707) 0190
> -2 1.562741 (+0.358678) 0190
> -6 * 1.563712 (+0.359649) 0190
> -5 2.562825 (+0.358762) 0190
> -9 * 2.563737 (+0.359674) 0190
> -8 3.562817 (+0.358754) 0190
> -12 * 3.563722 (+0.359659) 0190
> -11 4.562975 (+0.358912) 0190
> -15 * 4.563923 (+0.359860) 0190
> -14 5.563039 (+0.358976) 0190
> -18 * 5.564048 (+0.359985) 0190
> ^C
>
> The "*" indicates bogus IRQ reports ... in this case it
> looks like each update IRQ is reported TWICE, with the
> second one being about one millisec after the first one.
> Since this test waits for five consecutive non-bogus
> interrupts, it never stops ...
>
David,
Could you please try with this patch?
<CUT HERE>
RTC generates an extra spurious interrupt for every actual periodic
interrupt. This is due to a problem with the RTC_IT bit of
REG_PWR_ISR1. It requires two writes or two reads (when COR is
enabled) to clear it. Since COR is enabled and one read of the same
register is done already (inside twl4030-pwrirq.c do_twl4030_pwrirq()
function), all we need is one more read.
Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
Index: linux-omap-2.6/drivers/rtc/rtc-twl4030.c
===================================================================
--- linux-omap-2.6.orig/drivers/rtc/rtc-twl4030.c 2008-09-05 12:22:23.089855991 +0530
+++ linux-omap-2.6/drivers/rtc/rtc-twl4030.c 2008-09-05 12:49:55.634939761 +0530
@@ -446,8 +446,13 @@ static irqreturn_t twl4030_rtc_interrupt
REG_RTC_STATUS_REG);
if (res)
goto out;
- res = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
- PWR_RTC_INT_CLR, REG_PWR_ISR1);
+
+ /* Clear on Read enabled. RTC_IT bit of REG_PWR_ISR1 needs
+ * 2 reads to clear the interrupt. One read is done in
+ * do_twl4030_pwrirq(). Doing the second read, to clear
+ * the bit.
+ */
+ res = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &rd_reg, REG_PWR_ISR1);
if (res)
goto out;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
2008-09-05 7:24 ` Pakaravoor, Jagadeesh
@ 2008-09-05 8:09 ` David Brownell
2008-09-05 9:27 ` Pakaravoor, Jagadeesh
0 siblings, 1 reply; 6+ messages in thread
From: David Brownell @ 2008-09-05 8:09 UTC (permalink / raw)
To: Pakaravoor, Jagadeesh; +Cc: linux-omap@vger.kernel.org
On Friday 05 September 2008, Pakaravoor, Jagadeesh wrote:
> RTC generates an extra spurious interrupt for every actual periodic
> interrupt. This is due to a problem with the RTC_IT bit of
> REG_PWR_ISR1. It requires two writes or two reads (when COR is
> enabled) to clear it. Since COR is enabled and one read of the same
> register is done already (inside twl4030-pwrirq.c do_twl4030_pwrirq()
> function), all we need is one more read.
>
> Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
Yes, that seems to make the 1/second update IRQs work right.
Thanks!
Were alarm IRQs having the same problem, just not as noticably?
The two other technical issues I know about with this driver
also relate to IRQs:
- Is it really true that alarm and update IRQs are
mutually exclusive? Unusual if so ...
+ if exclusive, then don't let both be enabled
at the same time (the way it now does)!
+ else, update irq handler so the comment is
correct, and so the code stops assuming
it's alarm -or- update irqs ... it should
be possible to report *both* events at once.
- Are there any reasons alarm IRQs wouldn't be able
to wake the system from sleep states (STR etc)?
If not, then need to update suspend() to leave
the alarm active (yes?) and do various other stuff
related to driver model wakeup flags; rtc-omap.c
can be an example. (Except for leaving update
IRQs active...)
The wakeup stuff will let programs like rtcwake work,
and enable the /sys/class/rtc/rtc0/wakealarm file.
It's better to have that stuff work than not, even
if OMAP power management uses states like STR very
differently than most other Linuxes.
- Dave
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
2008-09-05 8:09 ` David Brownell
@ 2008-09-05 9:27 ` Pakaravoor, Jagadeesh
0 siblings, 0 replies; 6+ messages in thread
From: Pakaravoor, Jagadeesh @ 2008-09-05 9:27 UTC (permalink / raw)
To: David Brownell; +Cc: linux-omap@vger.kernel.org
> -----Original Message-----
> From: David Brownell [mailto:david-b@pacbell.net]
> Sent: Friday, September 05, 2008 1:40 PM
> To: Pakaravoor, Jagadeesh
> Cc: linux-omap@vger.kernel.org
> Subject: Re: [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
>
> On Friday 05 September 2008, Pakaravoor, Jagadeesh wrote:
> > RTC generates an extra spurious interrupt for every actual periodic
> > interrupt. This is due to a problem with the RTC_IT bit of
> > REG_PWR_ISR1. It requires two writes or two reads (when COR is
> > enabled) to clear it. Since COR is enabled and one read of the same
> > register is done already (inside twl4030-pwrirq.c do_twl4030_pwrirq()
> > function), all we need is one more read.
> >
> > Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
>
> Yes, that seems to make the 1/second update IRQs work right.
> Thanks!
>
> Were alarm IRQs having the same problem, just not as noticably?
>
> The two other technical issues I know about with this driver
> also relate to IRQs:
>
> - Is it really true that alarm and update IRQs are
> mutually exclusive? Unusual if so ...
>
> + if exclusive, then don't let both be enabled
> at the same time (the way it now does)!
>
> + else, update irq handler so the comment is
> correct, and so the code stops assuming
> it's alarm -or- update irqs ... it should
> be possible to report *both* events at once.
>
> - Are there any reasons alarm IRQs wouldn't be able
> to wake the system from sleep states (STR etc)?
>
> If not, then need to update suspend() to leave
> the alarm active (yes?) and do various other stuff
> related to driver model wakeup flags; rtc-omap.c
> can be an example. (Except for leaving update
> IRQs active...)
>
> The wakeup stuff will let programs like rtcwake work,
> and enable the /sys/class/rtc/rtc0/wakealarm file.
> It's better to have that stuff work than not, even
> if OMAP power management uses states like STR very
> differently than most other Linuxes.
>
> - Dave
>
Dave,
Sorry that I'll be able to take a look into it only in a week's time, since I am going on a vacation from today.
-Jagadeesh
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup
2008-09-04 17:24 [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup David Brownell
2008-09-04 17:48 ` David Brownell
@ 2008-09-09 17:42 ` Tony Lindgren
1 sibling, 0 replies; 6+ messages in thread
From: Tony Lindgren @ 2008-09-09 17:42 UTC (permalink / raw)
To: David Brownell; +Cc: linux-omap
* David Brownell <david-b@pacbell.net> [080904 10:25]:
> From: David Brownell <dbrownell@users.sourceforge.net>
>
> Some rtc-twl4030 cleanup, which among other things adds up to
> using about 10% less object code:
>
> - Remove:
> * broken/unfixable "periodic" IRQ support (2^N Hz)
> * duplicated constants in the header file
> * pointless stuff:
> + support for settable epoch
> + memset() calls
> + indirection when reading time and alarm
> + indirection when enabling irqs
> * needless ifdeffery for reading irq enable register
> - IRQ updates:
> * group irq enable/disable utilities together
> * cache irq enable register
> * now disable any old alarm irq before setting alarm
> - Comment updates
> * fix up my copyright attribution (old omap1 code)
> * more correctly describe the rtc mask/set ops
> * have a single place describe the register vs tm_* differences
> - Other:
> * don't support "current" dates in the 20th century
> * switch over to bcd2bin()/bin2bcd()
> * prefer dev_err() and better messages to printk(KERN_ERR...)
> * correct some KERN_WARNING messages (should have been pr_err)
> * whitespace bugs
> * misc
>
> The bugs fixed here are removing "periodic" IRQ support, and
> some of the messaging. Update IRQs still misbehave (two per
> second, not one!), and the alarm isn't wake-enabled.
Pushing today.
Tony
>
> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
> ---
> drivers/rtc/rtc-twl4030.c | 328 +++++++++++---------------------------
> include/linux/i2c/twl4030-rtc.h | 58 ------
> 2 files changed, 103 insertions(+), 283 deletions(-)
>
> --- a/drivers/rtc/rtc-twl4030.c
> +++ b/drivers/rtc/rtc-twl4030.c
> @@ -1,7 +1,5 @@
> /*
> - * drivers/rtc/rtc-twl4030.c
> - *
> - * TWL4030 Real Time Clock interface
> + * rtc-twl4030.c -- TWL4030 Real Time Clock interface
> *
> * Copyright (C) 2007 MontaVista Software, Inc
> * Author: Alexandre Rusev <source@mvista.com>
> @@ -12,14 +10,12 @@
> * Based on rtc-omap.c
> * Copyright (C) 2003 MontaVista Software, Inc.
> * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
> - *
> * 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>
> @@ -46,12 +42,6 @@
> #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)
> @@ -59,10 +49,9 @@ static int twl4030_rtc_read_u8(u8 *data,
> 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);
> - }
> + if (ret < 0)
> + pr_err("twl4030_rtc: Could not read TWL4030"
> + "register %X - error %d\n", reg, ret);
> return ret;
> }
>
> @@ -74,68 +63,54 @@ static int twl4030_rtc_write_u8(u8 data,
> 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);
> - }
> + if (ret < 0)
> + pr_err("twl4030_rtc: Could not write TWL4030"
> + "register %X - error %d\n", reg, ret);
> return ret;
> }
>
> /*
> - * Enables timer or alarm interrupts.
> + * Cache the value for timer/alarm interrupts register; this is
> + * only changed by callers holding rtc ops lock (or resume).
> + */
> +static unsigned char rtc_irq_bits;
> +
> +/*
> + * Enable timer and/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;
> + val = rtc_irq_bits | bit;
> ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
> + if (ret == 0)
> + rtc_irq_bits = val;
>
> -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.
> + * Disable timer and/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;
> + val = rtc_irq_bits & ~bit;
> ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
> + if (ret == 0)
> + rtc_irq_bits = val;
>
> -mask_irq_out:
> return ret;
> }
>
> -static int twl4030_rtc_alarm_irq_set_state(struct device *dev, int enabled)
> +static inline int twl4030_rtc_alarm_irq_set_state(int enabled)
> {
> int ret;
>
> - /* Allow ints for RTC ALARM updates. */
> if (enabled)
> ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
> else
> @@ -144,10 +119,28 @@ static int twl4030_rtc_alarm_irq_set_sta
> return ret;
> }
>
> +static inline int twl4030_rtc_irq_set_state(int enabled)
> +{
> + int ret;
> +
> + 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;
> +}
> +
> /*
> * Gets current TWL4030 RTC time and date parameters.
> + *
> + * The RTC's time/alarm representation is not what gmtime(3) requires
> + * Linux to use:
> + *
> + * - Months are 1..12 vs Linux 0-11
> + * - Years are 0..99 vs Linux 1900..N (we assume 21st century)
> */
> -static int get_rtc_time(struct rtc_time *rtc_tm)
> +static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm)
> {
> unsigned char rtc_data[ALL_TIME_REGS + 1];
> int ret;
> @@ -167,26 +160,16 @@ static int get_rtc_time(struct rtc_time
> REG_SECONDS_REG, ALL_TIME_REGS);
>
> if (ret < 0) {
> - printk(KERN_ERR "twl4030_rtc: twl4030_i2c_read error.\n");
> + dev_err(dev, "rtc_read_time error %d\n", ret);
> 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;
> - */
> - rtc_tm->tm_year += (epoch - 1900);
> - if (rtc_tm->tm_year <= 69)
> - rtc_tm->tm_year += 100;
> -
> - rtc_tm->tm_mon--;
> + tm->tm_sec = bcd2bin(rtc_data[0]);
> + tm->tm_min = bcd2bin(rtc_data[1]);
> + tm->tm_hour = bcd2bin(rtc_data[2]);
> + tm->tm_mday = bcd2bin(rtc_data[3]);
> + tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
> + tm->tm_year = bcd2bin(rtc_data[5]) + 100;
>
> return ret;
> }
> @@ -197,15 +180,12 @@ static int twl4030_rtc_set_time(struct d
> 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);
> + 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 + 1);
> + rtc_data[6] = bin2bcd(tm->tm_year - 100);
>
> /* Stop RTC while updating the TC registers */
> ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
> @@ -217,11 +197,11 @@ static int twl4030_rtc_set_time(struct d
> if (ret < 0)
> goto out;
>
> - /* update all the alarm registers in one shot */
> + /* update all the time 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");
> + dev_err(dev, "rtc_set_time error %d\n", ret);
> goto out;
> }
>
> @@ -236,7 +216,7 @@ out:
> /*
> * Gets current TWL4030 RTC alarm time.
> */
> -static int get_rtc_alm_time(struct rtc_time *alm_tm)
> +static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
> {
> unsigned char rtc_data[ALL_TIME_REGS + 1];
> int ret;
> @@ -244,85 +224,21 @@ static int get_rtc_alm_time(struct rtc_t
> 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");
> + dev_err(dev, "rtc_read_alarm error %d\n", ret);
> 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;
> - */
> - alm_tm->tm_year += (epoch - 1900);
> - if (alm_tm->tm_year <= 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.
> - */
> -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.
> - */
> - 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;
> + /* some of these fields may be wildcard/"match all" */
> + alm->time.tm_sec = bcd2bin(rtc_data[0]);
> + alm->time.tm_min = bcd2bin(rtc_data[1]);
> + alm->time.tm_hour = bcd2bin(rtc_data[2]);
> + alm->time.tm_mday = bcd2bin(rtc_data[3]);
> + alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
> + alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
>
> - if ((rtc_interrupts_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) != 0)
> + /* report cached alarm enable state */
> + if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
> alm->enabled = 1;
> - else
> - 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. */
> - 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;
> }
> @@ -332,86 +248,46 @@ static int twl4030_rtc_set_alarm(struct
> unsigned char alarm_data[ALL_TIME_REGS + 1];
> int ret;
>
> - /* Month range is 01..12 */
> - alm->time.tm_mon++;
> + ret = twl4030_rtc_alarm_irq_set_state(0);
> + if (ret)
> + goto out;
>
> - 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);
> + 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 + 1);
> + alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
>
> /* 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");
> + dev_err(dev, "rtc_set_alarm error %d\n", ret);
> goto out;
> }
>
> - ret = twl4030_rtc_alarm_irq_set_state(dev, alm->enabled);
> + if (alm->enabled)
> + ret = twl4030_rtc_alarm_irq_set_state(1);
> out:
> return ret;
> }
>
> -/*
> - * We will just handle setting the frequency and make use the framework for
> - * reading the periodic interupts.
> - * @freq: Current periodic IRQ freq
> - */
> -static int twl4030_rtc_irq_set_freq(struct device *dev, int freq)
> -{
> - struct rtc_device *rtc = dev_get_drvdata(dev);
> -
> - if (freq < 0 || freq > 3)
> - return -EINVAL;
> -
> - rtc->irq_freq = freq;
> -
> - /* set rtc irq freq to user defined value */
> - set_rtc_irq_bit(freq);
> -
> - return 0;
> -}
> -
> #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);
> + return twl4030_rtc_alarm_irq_set_state(0);
> case RTC_AIE_ON:
> - return twl4030_rtc_alarm_irq_set_state(dev, 1);
> -
> + return twl4030_rtc_alarm_irq_set_state(1);
> case RTC_UIE_OFF:
> - /* Fall Through */
> - case RTC_PIE_OFF:
> - /* Mask ints from RTC updates. */
> - return twl4030_rtc_irq_set_state(dev, 0);
> + return twl4030_rtc_irq_set_state(0);
> case RTC_UIE_ON:
> - /* Fall Through */
> - case RTC_PIE_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;
> + return twl4030_rtc_irq_set_state(1);
>
> - epoch = arg;
> - return 0;
> default:
> return -ENOIOCTLCMD;
> }
> @@ -465,7 +341,6 @@ static struct rtc_class_ops twl4030_rtc_
> .set_time = twl4030_rtc_set_time,
> .read_alarm = twl4030_rtc_read_alarm,
> .set_alarm = twl4030_rtc_set_alarm,
> - .irq_set_freq = twl4030_rtc_irq_set_freq,
> };
>
> static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
> @@ -491,9 +366,6 @@ static int __devinit twl4030_rtc_probe(s
>
> }
>
> - /* Set the irq freq to every second */
> - rtc->irq_freq = 0;
> -
> platform_set_drvdata(pdev, rtc);
>
> ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
> @@ -552,6 +424,11 @@ static int __devinit twl4030_rtc_probe(s
> if (ret < 0)
> goto out2;
>
> + /* init cached IRQ enable bits */
> + ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
> + if (ret < 0)
> + goto out2;
> +
> return ret;
>
>
> @@ -591,8 +468,8 @@ static int __devexit twl4030_rtc_remove(
>
> 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);
> + mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
> + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
> }
>
> #ifdef CONFIG_PM
> @@ -601,8 +478,9 @@ static unsigned char irqstat;
>
> static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> {
> - get_rtc_irq_bit(&irqstat);
> + irqstat = rtc_irq_bits;
>
> + /* REVISIT alarm may need to wake us from sleep */
> mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
> BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
> return 0;
> @@ -613,19 +491,21 @@ static int twl4030_rtc_resume(struct pla
> set_rtc_irq_bit(irqstat);
> return 0;
> }
> +
> #else
> #define twl4030_rtc_suspend NULL
> #define twl4030_rtc_resume NULL
> #endif
>
> MODULE_ALIAS("platform:twl4030_rtc");
> +
> 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 = {
> + .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",
> },
> @@ -635,15 +515,13 @@ static int __init twl4030_rtc_init(void)
> {
> return platform_driver_register(&twl4030rtc_driver);
> }
> +module_init(twl4030_rtc_init);
>
> static void __exit twl4030_rtc_exit(void)
> {
> platform_driver_unregister(&twl4030rtc_driver);
> }
> +module_exit(twl4030_rtc_exit);
>
> -MODULE_ALIAS("platform:twl4030_rtc");
> MODULE_AUTHOR("Texas Instruments, MontaVista Software");
> -MODULE_LICENSE("GPL");;
> -
> -module_init(twl4030_rtc_init);
> -module_exit(twl4030_rtc_exit);
> +MODULE_LICENSE("GPL");
> --- a/include/linux/i2c/twl4030-rtc.h
> +++ b/include/linux/i2c/twl4030-rtc.h
> @@ -164,64 +164,6 @@
> #define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB (0x000)
> #define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB_M (0x000000FF)
>
> -/* ALARM_DAYS_REG Fields */
> -#define BIT_ALARM_DAYS_REG_ALARM_DAY1 (0x004)
> -#define BIT_ALARM_DAYS_REG_ALARM_DAY1_M (0x00000030)
> -/* ALARM_MONTHS_REG Fields */
> -#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0 (0x000)
> -#define BIT_ALARM_MONTHS_REG_ALARM_MONTH0_M (0x0000000F)
> -#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1 (0x004)
> -#define BIT_ALARM_MONTHS_REG_ALARM_MONTH1_M (0x00000010)
> -/* ALARM_YEARS_REG Fields */
> -#define BIT_ALARM_YEARS_REG_ALARM_YEAR0 (0x000)
> -#define BIT_ALARM_YEARS_REG_ALARM_YEAR0_M (0x0000000F)
> -#define BIT_ALARM_YEARS_REG_ALARM_YEAR1 (0x004)
> -#define BIT_ALARM_YEARS_REG_ALARM_YEAR1_M (0x000000F0)
> -/* RTC_CTRL_REG Fields */
> -#define BIT_RTC_CTRL_REG_STOP_RTC (0x000)
> -#define BIT_RTC_CTRL_REG_STOP_RTC_M (0x00000001)
> -#define BIT_RTC_CTRL_REG_ROUND_30S (0x001)
> -#define BIT_RTC_CTRL_REG_ROUND_30S_M (0x00000002)
> -#define BIT_RTC_CTRL_REG_AUTO_COMP (0x002)
> -#define BIT_RTC_CTRL_REG_AUTO_COMP_M (0x00000004)
> -#define BIT_RTC_CTRL_REG_MODE_12_24 (0x003)
> -#define BIT_RTC_CTRL_REG_MODE_12_24_M (0x00000008)
> -#define BIT_RTC_CTRL_REG_TEST_MODE (0x004)
> -#define BIT_RTC_CTRL_REG_TEST_MODE_M (0x00000010)
> -#define BIT_RTC_CTRL_REG_SET_32_COUNTER (0x005)
> -#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M (0x00000020)
> -#define BIT_RTC_CTRL_REG_GET_TIME (0x006)
> -#define BIT_RTC_CTRL_REG_GET_TIME_M (0x00000040)
> -/* RTC_STATUS_REG Fields */
> -#define BIT_RTC_STATUS_REG_RUN (0x001)
> -#define BIT_RTC_STATUS_REG_RUN_M (0x00000002)
> -#define BIT_RTC_STATUS_REG_1S_EVENT (0x002)
> -#define BIT_RTC_STATUS_REG_1S_EVENT_M (0x00000004)
> -#define BIT_RTC_STATUS_REG_1M_EVENT (0x003)
> -#define BIT_RTC_STATUS_REG_1M_EVENT_M (0x00000008)
> -#define BIT_RTC_STATUS_REG_1H_EVENT (0x004)
> -#define BIT_RTC_STATUS_REG_1H_EVENT_M (0x00000010)
> -#define BIT_RTC_STATUS_REG_1D_EVENT (0x005)
> -#define BIT_RTC_STATUS_REG_1D_EVENT_M (0x00000020)
> -#define BIT_RTC_STATUS_REG_ALARM (0x006)
> -#define BIT_RTC_STATUS_REG_ALARM_M (0x00000040)
> -#define BIT_RTC_STATUS_REG_POWER_UP (0x007)
> -#define BIT_RTC_STATUS_REG_POWER_UP_M (0x00000080)
> -/* RTC_INTERRUPTS_REG Fields */
> -#define BIT_RTC_INTERRUPTS_REG_EVERY (0x000)
> -#define BIT_RTC_INTERRUPTS_REG_EVERY_M (0x00000003)
> -#define BIT_RTC_INTERRUPTS_REG_IT_TIMER (0x002)
> -#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M (0x00000004)
> -#define BIT_RTC_INTERRUPTS_REG_IT_ALARM (0x003)
> -#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M (0x00000008)
> -/* RTC_COMP_LSB_REG Fields */
> -#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB (0x000)
> -#define BIT_RTC_COMP_LSB_REG_RTC_COMP_LSB_M (0x000000FF)
> -/* RTC_COMP_MSB_REG Fields */
> -#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB (0x000)
> -#define BIT_RTC_COMP_MSB_REG_RTC_COMP_MSB_M (0x000000FF)
> -
> -
> struct twl4030rtc_platform_data {
> int (*init)(void);
> void (*exit)(void);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-09-09 17:42 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-04 17:24 [patch 2.6.27-rc5-omap1] rtc-twl4030 cleanup David Brownell
2008-09-04 17:48 ` David Brownell
2008-09-05 7:24 ` Pakaravoor, Jagadeesh
2008-09-05 8:09 ` David Brownell
2008-09-05 9:27 ` Pakaravoor, Jagadeesh
2008-09-09 17:42 ` Tony Lindgren
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox