/drivers/rtc/rtc-twl.c
C | 589 lines | 399 code | 100 blank | 90 comment | 38 complexity | e16e7d5cabfa59b339e3e1b9aa3a1865 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * rtc-twl.c -- TWL Real Time Clock interface
- *
- * Copyright (C) 2007 MontaVista Software, Inc
- * Author: Alexandre Rusev <source@mvista.com>
- *
- * 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 <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>
- #include <linux/errno.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/rtc.h>
- #include <linux/bcd.h>
- #include <linux/platform_device.h>
- #include <linux/interrupt.h>
- #include <linux/i2c/twl.h>
- /*
- * RTC block register offsets (use TWL_MODULE_RTC)
- */
- enum {
- REG_SECONDS_REG = 0,
- REG_MINUTES_REG,
- REG_HOURS_REG,
- REG_DAYS_REG,
- REG_MONTHS_REG,
- REG_YEARS_REG,
- REG_WEEKS_REG,
- REG_ALARM_SECONDS_REG,
- REG_ALARM_MINUTES_REG,
- REG_ALARM_HOURS_REG,
- REG_ALARM_DAYS_REG,
- REG_ALARM_MONTHS_REG,
- REG_ALARM_YEARS_REG,
- REG_RTC_CTRL_REG,
- REG_RTC_STATUS_REG,
- REG_RTC_INTERRUPTS_REG,
- REG_RTC_COMP_LSB_REG,
- REG_RTC_COMP_MSB_REG,
- };
- static const u8 twl4030_rtc_reg_map[] = {
- [REG_SECONDS_REG] = 0x00,
- [REG_MINUTES_REG] = 0x01,
- [REG_HOURS_REG] = 0x02,
- [REG_DAYS_REG] = 0x03,
- [REG_MONTHS_REG] = 0x04,
- [REG_YEARS_REG] = 0x05,
- [REG_WEEKS_REG] = 0x06,
- [REG_ALARM_SECONDS_REG] = 0x07,
- [REG_ALARM_MINUTES_REG] = 0x08,
- [REG_ALARM_HOURS_REG] = 0x09,
- [REG_ALARM_DAYS_REG] = 0x0A,
- [REG_ALARM_MONTHS_REG] = 0x0B,
- [REG_ALARM_YEARS_REG] = 0x0C,
- [REG_RTC_CTRL_REG] = 0x0D,
- [REG_RTC_STATUS_REG] = 0x0E,
- [REG_RTC_INTERRUPTS_REG] = 0x0F,
- [REG_RTC_COMP_LSB_REG] = 0x10,
- [REG_RTC_COMP_MSB_REG] = 0x11,
- };
- static const u8 twl6030_rtc_reg_map[] = {
- [REG_SECONDS_REG] = 0x00,
- [REG_MINUTES_REG] = 0x01,
- [REG_HOURS_REG] = 0x02,
- [REG_DAYS_REG] = 0x03,
- [REG_MONTHS_REG] = 0x04,
- [REG_YEARS_REG] = 0x05,
- [REG_WEEKS_REG] = 0x06,
- [REG_ALARM_SECONDS_REG] = 0x08,
- [REG_ALARM_MINUTES_REG] = 0x09,
- [REG_ALARM_HOURS_REG] = 0x0A,
- [REG_ALARM_DAYS_REG] = 0x0B,
- [REG_ALARM_MONTHS_REG] = 0x0C,
- [REG_ALARM_YEARS_REG] = 0x0D,
- [REG_RTC_CTRL_REG] = 0x10,
- [REG_RTC_STATUS_REG] = 0x11,
- [REG_RTC_INTERRUPTS_REG] = 0x12,
- [REG_RTC_COMP_LSB_REG] = 0x13,
- [REG_RTC_COMP_MSB_REG] = 0x14,
- };
- /* RTC_CTRL_REG bitfields */
- #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01
- #define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02
- #define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04
- #define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08
- #define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10
- #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20
- #define BIT_RTC_CTRL_REG_GET_TIME_M 0x40
- /* RTC_STATUS_REG bitfields */
- #define BIT_RTC_STATUS_REG_RUN_M 0x02
- #define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04
- #define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08
- #define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10
- #define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20
- #define BIT_RTC_STATUS_REG_ALARM_M 0x40
- #define BIT_RTC_STATUS_REG_POWER_UP_M 0x80
- /* RTC_INTERRUPTS_REG bitfields */
- #define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03
- #define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04
- #define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08
- /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
- #define ALL_TIME_REGS 6
- /*----------------------------------------------------------------------*/
- static u8 *rtc_reg_map;
- /*
- * Supports 1 byte read from TWL RTC register.
- */
- static int twl_rtc_read_u8(u8 *data, u8 reg)
- {
- int ret;
- ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
- if (ret < 0)
- pr_err("twl_rtc: Could not read TWL"
- "register %X - error %d\n", reg, ret);
- return ret;
- }
- /*
- * Supports 1 byte write to TWL RTC registers.
- */
- static int twl_rtc_write_u8(u8 data, u8 reg)
- {
- int ret;
- ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
- if (ret < 0)
- pr_err("twl_rtc: Could not write TWL"
- "register %X - error %d\n", reg, ret);
- return ret;
- }
- /*
- * 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 1/second update and/or alarm interrupts.
- */
- static int set_rtc_irq_bit(unsigned char bit)
- {
- unsigned char val;
- int ret;
- val = rtc_irq_bits | bit;
- val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
- ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
- if (ret == 0)
- rtc_irq_bits = val;
- return ret;
- }
- /*
- * Disable update and/or alarm interrupts.
- */
- static int mask_rtc_irq_bit(unsigned char bit)
- {
- unsigned char val;
- int ret;
- val = rtc_irq_bits & ~bit;
- ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
- if (ret == 0)
- rtc_irq_bits = val;
- return ret;
- }
- static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
- {
- int ret;
- 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 TWL 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 twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
- {
- unsigned char rtc_data[ALL_TIME_REGS + 1];
- int ret;
- u8 save_control;
- ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
- if (ret < 0)
- return ret;
- save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
- ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
- if (ret < 0)
- return ret;
- ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
- (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
- if (ret < 0) {
- dev_err(dev, "rtc_read_time error %d\n", ret);
- return ret;
- }