1b07682b6SSantosh Shilimkar /* 2ef3b7d0dSBalaji T K * rtc-twl.c -- TWL Real Time Clock interface 3b07682b6SSantosh Shilimkar * 4b07682b6SSantosh Shilimkar * Copyright (C) 2007 MontaVista Software, Inc 5b07682b6SSantosh Shilimkar * Author: Alexandre Rusev <source@mvista.com> 6b07682b6SSantosh Shilimkar * 7b07682b6SSantosh Shilimkar * Based on original TI driver twl4030-rtc.c 8b07682b6SSantosh Shilimkar * Copyright (C) 2006 Texas Instruments, Inc. 9b07682b6SSantosh Shilimkar * 10b07682b6SSantosh Shilimkar * Based on rtc-omap.c 11b07682b6SSantosh Shilimkar * Copyright (C) 2003 MontaVista Software, Inc. 12b07682b6SSantosh Shilimkar * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com> 13b07682b6SSantosh Shilimkar * Copyright (C) 2006 David Brownell 14b07682b6SSantosh Shilimkar * 15b07682b6SSantosh Shilimkar * This program is free software; you can redistribute it and/or 16b07682b6SSantosh Shilimkar * modify it under the terms of the GNU General Public License 17b07682b6SSantosh Shilimkar * as published by the Free Software Foundation; either version 18b07682b6SSantosh Shilimkar * 2 of the License, or (at your option) any later version. 19b07682b6SSantosh Shilimkar */ 20b07682b6SSantosh Shilimkar 21a737e835SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22a737e835SJoe Perches 23b07682b6SSantosh Shilimkar #include <linux/kernel.h> 24b07682b6SSantosh Shilimkar #include <linux/errno.h> 25b07682b6SSantosh Shilimkar #include <linux/init.h> 26b07682b6SSantosh Shilimkar #include <linux/module.h> 27b07682b6SSantosh Shilimkar #include <linux/types.h> 28b07682b6SSantosh Shilimkar #include <linux/rtc.h> 29b07682b6SSantosh Shilimkar #include <linux/bcd.h> 30b07682b6SSantosh Shilimkar #include <linux/platform_device.h> 31b07682b6SSantosh Shilimkar #include <linux/interrupt.h> 32c8a6046eSSachin Kamat #include <linux/of.h> 33b07682b6SSantosh Shilimkar 34b07682b6SSantosh Shilimkar #include <linux/i2c/twl.h> 35b07682b6SSantosh Shilimkar 36b07682b6SSantosh Shilimkar 37b07682b6SSantosh Shilimkar /* 38b07682b6SSantosh Shilimkar * RTC block register offsets (use TWL_MODULE_RTC) 39b07682b6SSantosh Shilimkar */ 40a6b49ffdSBalaji T K enum { 41a6b49ffdSBalaji T K REG_SECONDS_REG = 0, 42a6b49ffdSBalaji T K REG_MINUTES_REG, 43a6b49ffdSBalaji T K REG_HOURS_REG, 44a6b49ffdSBalaji T K REG_DAYS_REG, 45a6b49ffdSBalaji T K REG_MONTHS_REG, 46a6b49ffdSBalaji T K REG_YEARS_REG, 47a6b49ffdSBalaji T K REG_WEEKS_REG, 48b07682b6SSantosh Shilimkar 49a6b49ffdSBalaji T K REG_ALARM_SECONDS_REG, 50a6b49ffdSBalaji T K REG_ALARM_MINUTES_REG, 51a6b49ffdSBalaji T K REG_ALARM_HOURS_REG, 52a6b49ffdSBalaji T K REG_ALARM_DAYS_REG, 53a6b49ffdSBalaji T K REG_ALARM_MONTHS_REG, 54a6b49ffdSBalaji T K REG_ALARM_YEARS_REG, 55b07682b6SSantosh Shilimkar 56a6b49ffdSBalaji T K REG_RTC_CTRL_REG, 57a6b49ffdSBalaji T K REG_RTC_STATUS_REG, 58a6b49ffdSBalaji T K REG_RTC_INTERRUPTS_REG, 59b07682b6SSantosh Shilimkar 60a6b49ffdSBalaji T K REG_RTC_COMP_LSB_REG, 61a6b49ffdSBalaji T K REG_RTC_COMP_MSB_REG, 62a6b49ffdSBalaji T K }; 632e84067bSTobias Klauser static const u8 twl4030_rtc_reg_map[] = { 64a6b49ffdSBalaji T K [REG_SECONDS_REG] = 0x00, 65a6b49ffdSBalaji T K [REG_MINUTES_REG] = 0x01, 66a6b49ffdSBalaji T K [REG_HOURS_REG] = 0x02, 67a6b49ffdSBalaji T K [REG_DAYS_REG] = 0x03, 68a6b49ffdSBalaji T K [REG_MONTHS_REG] = 0x04, 69a6b49ffdSBalaji T K [REG_YEARS_REG] = 0x05, 70a6b49ffdSBalaji T K [REG_WEEKS_REG] = 0x06, 71a6b49ffdSBalaji T K 72a6b49ffdSBalaji T K [REG_ALARM_SECONDS_REG] = 0x07, 73a6b49ffdSBalaji T K [REG_ALARM_MINUTES_REG] = 0x08, 74a6b49ffdSBalaji T K [REG_ALARM_HOURS_REG] = 0x09, 75a6b49ffdSBalaji T K [REG_ALARM_DAYS_REG] = 0x0A, 76a6b49ffdSBalaji T K [REG_ALARM_MONTHS_REG] = 0x0B, 77a6b49ffdSBalaji T K [REG_ALARM_YEARS_REG] = 0x0C, 78a6b49ffdSBalaji T K 79a6b49ffdSBalaji T K [REG_RTC_CTRL_REG] = 0x0D, 80a6b49ffdSBalaji T K [REG_RTC_STATUS_REG] = 0x0E, 81a6b49ffdSBalaji T K [REG_RTC_INTERRUPTS_REG] = 0x0F, 82a6b49ffdSBalaji T K 83a6b49ffdSBalaji T K [REG_RTC_COMP_LSB_REG] = 0x10, 84a6b49ffdSBalaji T K [REG_RTC_COMP_MSB_REG] = 0x11, 85a6b49ffdSBalaji T K }; 862e84067bSTobias Klauser static const u8 twl6030_rtc_reg_map[] = { 87a6b49ffdSBalaji T K [REG_SECONDS_REG] = 0x00, 88a6b49ffdSBalaji T K [REG_MINUTES_REG] = 0x01, 89a6b49ffdSBalaji T K [REG_HOURS_REG] = 0x02, 90a6b49ffdSBalaji T K [REG_DAYS_REG] = 0x03, 91a6b49ffdSBalaji T K [REG_MONTHS_REG] = 0x04, 92a6b49ffdSBalaji T K [REG_YEARS_REG] = 0x05, 93a6b49ffdSBalaji T K [REG_WEEKS_REG] = 0x06, 94a6b49ffdSBalaji T K 95a6b49ffdSBalaji T K [REG_ALARM_SECONDS_REG] = 0x08, 96a6b49ffdSBalaji T K [REG_ALARM_MINUTES_REG] = 0x09, 97a6b49ffdSBalaji T K [REG_ALARM_HOURS_REG] = 0x0A, 98a6b49ffdSBalaji T K [REG_ALARM_DAYS_REG] = 0x0B, 99a6b49ffdSBalaji T K [REG_ALARM_MONTHS_REG] = 0x0C, 100a6b49ffdSBalaji T K [REG_ALARM_YEARS_REG] = 0x0D, 101a6b49ffdSBalaji T K 102a6b49ffdSBalaji T K [REG_RTC_CTRL_REG] = 0x10, 103a6b49ffdSBalaji T K [REG_RTC_STATUS_REG] = 0x11, 104a6b49ffdSBalaji T K [REG_RTC_INTERRUPTS_REG] = 0x12, 105a6b49ffdSBalaji T K 106a6b49ffdSBalaji T K [REG_RTC_COMP_LSB_REG] = 0x13, 107a6b49ffdSBalaji T K [REG_RTC_COMP_MSB_REG] = 0x14, 108a6b49ffdSBalaji T K }; 109b07682b6SSantosh Shilimkar 110b07682b6SSantosh Shilimkar /* RTC_CTRL_REG bitfields */ 111b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 112b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02 113b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04 114b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08 115b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10 116b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20 117b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_GET_TIME_M 0x40 118f3ec434cSKonstantin Shlyakhovoy #define BIT_RTC_CTRL_REG_RTC_V_OPT 0x80 119b07682b6SSantosh Shilimkar 120b07682b6SSantosh Shilimkar /* RTC_STATUS_REG bitfields */ 121b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_RUN_M 0x02 122b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04 123b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08 124b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10 125b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20 126b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_ALARM_M 0x40 127b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_POWER_UP_M 0x80 128b07682b6SSantosh Shilimkar 129b07682b6SSantosh Shilimkar /* RTC_INTERRUPTS_REG bitfields */ 130b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03 131b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04 132b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08 133b07682b6SSantosh Shilimkar 134b07682b6SSantosh Shilimkar 135b07682b6SSantosh Shilimkar /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */ 136b07682b6SSantosh Shilimkar #define ALL_TIME_REGS 6 137b07682b6SSantosh Shilimkar 138b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 139a6b49ffdSBalaji T K static u8 *rtc_reg_map; 140b07682b6SSantosh Shilimkar 141b07682b6SSantosh Shilimkar /* 142ef3b7d0dSBalaji T K * Supports 1 byte read from TWL RTC register. 143b07682b6SSantosh Shilimkar */ 144ef3b7d0dSBalaji T K static int twl_rtc_read_u8(u8 *data, u8 reg) 145b07682b6SSantosh Shilimkar { 146b07682b6SSantosh Shilimkar int ret; 147b07682b6SSantosh Shilimkar 148a6b49ffdSBalaji T K ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); 149b07682b6SSantosh Shilimkar if (ret < 0) 150a737e835SJoe Perches pr_err("Could not read TWL register %X - error %d\n", reg, ret); 151b07682b6SSantosh Shilimkar return ret; 152b07682b6SSantosh Shilimkar } 153b07682b6SSantosh Shilimkar 154b07682b6SSantosh Shilimkar /* 155ef3b7d0dSBalaji T K * Supports 1 byte write to TWL RTC registers. 156b07682b6SSantosh Shilimkar */ 157ef3b7d0dSBalaji T K static int twl_rtc_write_u8(u8 data, u8 reg) 158b07682b6SSantosh Shilimkar { 159b07682b6SSantosh Shilimkar int ret; 160b07682b6SSantosh Shilimkar 161a6b49ffdSBalaji T K ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); 162b07682b6SSantosh Shilimkar if (ret < 0) 163a737e835SJoe Perches pr_err("Could not write TWL register %X - error %d\n", 164a737e835SJoe Perches reg, ret); 165b07682b6SSantosh Shilimkar return ret; 166b07682b6SSantosh Shilimkar } 167b07682b6SSantosh Shilimkar 168b07682b6SSantosh Shilimkar /* 169b07682b6SSantosh Shilimkar * Cache the value for timer/alarm interrupts register; this is 170b07682b6SSantosh Shilimkar * only changed by callers holding rtc ops lock (or resume). 171b07682b6SSantosh Shilimkar */ 172b07682b6SSantosh Shilimkar static unsigned char rtc_irq_bits; 173b07682b6SSantosh Shilimkar 174b07682b6SSantosh Shilimkar /* 175b07682b6SSantosh Shilimkar * Enable 1/second update and/or alarm interrupts. 176b07682b6SSantosh Shilimkar */ 177b07682b6SSantosh Shilimkar static int set_rtc_irq_bit(unsigned char bit) 178b07682b6SSantosh Shilimkar { 179b07682b6SSantosh Shilimkar unsigned char val; 180b07682b6SSantosh Shilimkar int ret; 181b07682b6SSantosh Shilimkar 182ce9f6506SVenu Byravarasu /* if the bit is set, return from here */ 183ce9f6506SVenu Byravarasu if (rtc_irq_bits & bit) 184ce9f6506SVenu Byravarasu return 0; 185ce9f6506SVenu Byravarasu 186b07682b6SSantosh Shilimkar val = rtc_irq_bits | bit; 187b07682b6SSantosh Shilimkar val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; 188ef3b7d0dSBalaji T K ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); 189b07682b6SSantosh Shilimkar if (ret == 0) 190b07682b6SSantosh Shilimkar rtc_irq_bits = val; 191b07682b6SSantosh Shilimkar 192b07682b6SSantosh Shilimkar return ret; 193b07682b6SSantosh Shilimkar } 194b07682b6SSantosh Shilimkar 195b07682b6SSantosh Shilimkar /* 196b07682b6SSantosh Shilimkar * Disable update and/or alarm interrupts. 197b07682b6SSantosh Shilimkar */ 198b07682b6SSantosh Shilimkar static int mask_rtc_irq_bit(unsigned char bit) 199b07682b6SSantosh Shilimkar { 200b07682b6SSantosh Shilimkar unsigned char val; 201b07682b6SSantosh Shilimkar int ret; 202b07682b6SSantosh Shilimkar 203ce9f6506SVenu Byravarasu /* if the bit is clear, return from here */ 204ce9f6506SVenu Byravarasu if (!(rtc_irq_bits & bit)) 205ce9f6506SVenu Byravarasu return 0; 206ce9f6506SVenu Byravarasu 207b07682b6SSantosh Shilimkar val = rtc_irq_bits & ~bit; 208ef3b7d0dSBalaji T K ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); 209b07682b6SSantosh Shilimkar if (ret == 0) 210b07682b6SSantosh Shilimkar rtc_irq_bits = val; 211b07682b6SSantosh Shilimkar 212b07682b6SSantosh Shilimkar return ret; 213b07682b6SSantosh Shilimkar } 214b07682b6SSantosh Shilimkar 215ef3b7d0dSBalaji T K static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) 216b07682b6SSantosh Shilimkar { 217ae845894SKevin Hilman struct platform_device *pdev = to_platform_device(dev); 218ae845894SKevin Hilman int irq = platform_get_irq(pdev, 0); 219ae845894SKevin Hilman static bool twl_rtc_wake_enabled; 220b07682b6SSantosh Shilimkar int ret; 221b07682b6SSantosh Shilimkar 222ae845894SKevin Hilman if (enabled) { 223b07682b6SSantosh Shilimkar ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); 224ae845894SKevin Hilman if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) { 225ae845894SKevin Hilman enable_irq_wake(irq); 226ae845894SKevin Hilman twl_rtc_wake_enabled = true; 227ae845894SKevin Hilman } 228ae845894SKevin Hilman } else { 229b07682b6SSantosh Shilimkar ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); 230ae845894SKevin Hilman if (twl_rtc_wake_enabled) { 231ae845894SKevin Hilman disable_irq_wake(irq); 232ae845894SKevin Hilman twl_rtc_wake_enabled = false; 233ae845894SKevin Hilman } 234ae845894SKevin Hilman } 235b07682b6SSantosh Shilimkar 236b07682b6SSantosh Shilimkar return ret; 237b07682b6SSantosh Shilimkar } 238b07682b6SSantosh Shilimkar 239b07682b6SSantosh Shilimkar /* 240ef3b7d0dSBalaji T K * Gets current TWL RTC time and date parameters. 241b07682b6SSantosh Shilimkar * 242b07682b6SSantosh Shilimkar * The RTC's time/alarm representation is not what gmtime(3) requires 243b07682b6SSantosh Shilimkar * Linux to use: 244b07682b6SSantosh Shilimkar * 245b07682b6SSantosh Shilimkar * - Months are 1..12 vs Linux 0-11 246b07682b6SSantosh Shilimkar * - Years are 0..99 vs Linux 1900..N (we assume 21st century) 247b07682b6SSantosh Shilimkar */ 248ef3b7d0dSBalaji T K static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) 249b07682b6SSantosh Shilimkar { 25014591d88SPeter Ujfalusi unsigned char rtc_data[ALL_TIME_REGS]; 251b07682b6SSantosh Shilimkar int ret; 252b07682b6SSantosh Shilimkar u8 save_control; 253f3ec434cSKonstantin Shlyakhovoy u8 rtc_control; 254b07682b6SSantosh Shilimkar 255ef3b7d0dSBalaji T K ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); 256f3ec434cSKonstantin Shlyakhovoy if (ret < 0) { 257f3ec434cSKonstantin Shlyakhovoy dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret); 258b07682b6SSantosh Shilimkar return ret; 259f3ec434cSKonstantin Shlyakhovoy } 260f3ec434cSKonstantin Shlyakhovoy /* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */ 261f3ec434cSKonstantin Shlyakhovoy if (twl_class_is_6030()) { 262f3ec434cSKonstantin Shlyakhovoy if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) { 263f3ec434cSKonstantin Shlyakhovoy save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M; 264ef3b7d0dSBalaji T K ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); 265f3ec434cSKonstantin Shlyakhovoy if (ret < 0) { 266f3ec434cSKonstantin Shlyakhovoy dev_err(dev, "%s clr GET_TIME, error %d\n", 267f3ec434cSKonstantin Shlyakhovoy __func__, ret); 268b07682b6SSantosh Shilimkar return ret; 269f3ec434cSKonstantin Shlyakhovoy } 270f3ec434cSKonstantin Shlyakhovoy } 271f3ec434cSKonstantin Shlyakhovoy } 272f3ec434cSKonstantin Shlyakhovoy 273f3ec434cSKonstantin Shlyakhovoy /* Copy RTC counting registers to static registers or latches */ 274f3ec434cSKonstantin Shlyakhovoy rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M; 275f3ec434cSKonstantin Shlyakhovoy 276f3ec434cSKonstantin Shlyakhovoy /* for twl6030/32 enable read access to static shadowed registers */ 277f3ec434cSKonstantin Shlyakhovoy if (twl_class_is_6030()) 278f3ec434cSKonstantin Shlyakhovoy rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT; 279f3ec434cSKonstantin Shlyakhovoy 280f3ec434cSKonstantin Shlyakhovoy ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG); 281f3ec434cSKonstantin Shlyakhovoy if (ret < 0) { 282f3ec434cSKonstantin Shlyakhovoy dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret); 283f3ec434cSKonstantin Shlyakhovoy return ret; 284f3ec434cSKonstantin Shlyakhovoy } 285b07682b6SSantosh Shilimkar 286ef3b7d0dSBalaji T K ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, 287a6b49ffdSBalaji T K (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); 288b07682b6SSantosh Shilimkar 289b07682b6SSantosh Shilimkar if (ret < 0) { 290f3ec434cSKonstantin Shlyakhovoy dev_err(dev, "%s: reading data, error %d\n", __func__, ret); 291b07682b6SSantosh Shilimkar return ret; 292b07682b6SSantosh Shilimkar } 293b07682b6SSantosh Shilimkar 294f3ec434cSKonstantin Shlyakhovoy /* for twl6030 restore original state of rtc control register */ 295f3ec434cSKonstantin Shlyakhovoy if (twl_class_is_6030()) { 296f3ec434cSKonstantin Shlyakhovoy ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); 297f3ec434cSKonstantin Shlyakhovoy if (ret < 0) { 298f3ec434cSKonstantin Shlyakhovoy dev_err(dev, "%s: restore CTRL_REG, error %d\n", 299f3ec434cSKonstantin Shlyakhovoy __func__, ret); 300f3ec434cSKonstantin Shlyakhovoy return ret; 301f3ec434cSKonstantin Shlyakhovoy } 302f3ec434cSKonstantin Shlyakhovoy } 303f3ec434cSKonstantin Shlyakhovoy 304b07682b6SSantosh Shilimkar tm->tm_sec = bcd2bin(rtc_data[0]); 305b07682b6SSantosh Shilimkar tm->tm_min = bcd2bin(rtc_data[1]); 306b07682b6SSantosh Shilimkar tm->tm_hour = bcd2bin(rtc_data[2]); 307b07682b6SSantosh Shilimkar tm->tm_mday = bcd2bin(rtc_data[3]); 308b07682b6SSantosh Shilimkar tm->tm_mon = bcd2bin(rtc_data[4]) - 1; 309b07682b6SSantosh Shilimkar tm->tm_year = bcd2bin(rtc_data[5]) + 100; 310b07682b6SSantosh Shilimkar 311b07682b6SSantosh Shilimkar return ret; 312b07682b6SSantosh Shilimkar } 313b07682b6SSantosh Shilimkar 314ef3b7d0dSBalaji T K static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) 315b07682b6SSantosh Shilimkar { 316b07682b6SSantosh Shilimkar unsigned char save_control; 31714591d88SPeter Ujfalusi unsigned char rtc_data[ALL_TIME_REGS]; 318b07682b6SSantosh Shilimkar int ret; 319b07682b6SSantosh Shilimkar 32014591d88SPeter Ujfalusi rtc_data[0] = bin2bcd(tm->tm_sec); 32114591d88SPeter Ujfalusi rtc_data[1] = bin2bcd(tm->tm_min); 32214591d88SPeter Ujfalusi rtc_data[2] = bin2bcd(tm->tm_hour); 32314591d88SPeter Ujfalusi rtc_data[3] = bin2bcd(tm->tm_mday); 32414591d88SPeter Ujfalusi rtc_data[4] = bin2bcd(tm->tm_mon + 1); 32514591d88SPeter Ujfalusi rtc_data[5] = bin2bcd(tm->tm_year - 100); 326b07682b6SSantosh Shilimkar 327b07682b6SSantosh Shilimkar /* Stop RTC while updating the TC registers */ 328ef3b7d0dSBalaji T K ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); 329b07682b6SSantosh Shilimkar if (ret < 0) 330b07682b6SSantosh Shilimkar goto out; 331b07682b6SSantosh Shilimkar 332b07682b6SSantosh Shilimkar save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; 3338f6b0dd3SJesper Juhl ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); 334b07682b6SSantosh Shilimkar if (ret < 0) 335b07682b6SSantosh Shilimkar goto out; 336b07682b6SSantosh Shilimkar 337b07682b6SSantosh Shilimkar /* update all the time registers in one shot */ 338ef3b7d0dSBalaji T K ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data, 339a6b49ffdSBalaji T K (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); 340b07682b6SSantosh Shilimkar if (ret < 0) { 341b07682b6SSantosh Shilimkar dev_err(dev, "rtc_set_time error %d\n", ret); 342b07682b6SSantosh Shilimkar goto out; 343b07682b6SSantosh Shilimkar } 344b07682b6SSantosh Shilimkar 345b07682b6SSantosh Shilimkar /* Start back RTC */ 346b07682b6SSantosh Shilimkar save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; 347ef3b7d0dSBalaji T K ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); 348b07682b6SSantosh Shilimkar 349b07682b6SSantosh Shilimkar out: 350b07682b6SSantosh Shilimkar return ret; 351b07682b6SSantosh Shilimkar } 352b07682b6SSantosh Shilimkar 353b07682b6SSantosh Shilimkar /* 354ef3b7d0dSBalaji T K * Gets current TWL RTC alarm time. 355b07682b6SSantosh Shilimkar */ 356ef3b7d0dSBalaji T K static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) 357b07682b6SSantosh Shilimkar { 35814591d88SPeter Ujfalusi unsigned char rtc_data[ALL_TIME_REGS]; 359b07682b6SSantosh Shilimkar int ret; 360b07682b6SSantosh Shilimkar 361ef3b7d0dSBalaji T K ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, 362a6b49ffdSBalaji T K (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); 363b07682b6SSantosh Shilimkar if (ret < 0) { 364b07682b6SSantosh Shilimkar dev_err(dev, "rtc_read_alarm error %d\n", ret); 365b07682b6SSantosh Shilimkar return ret; 366b07682b6SSantosh Shilimkar } 367b07682b6SSantosh Shilimkar 368b07682b6SSantosh Shilimkar /* some of these fields may be wildcard/"match all" */ 369b07682b6SSantosh Shilimkar alm->time.tm_sec = bcd2bin(rtc_data[0]); 370b07682b6SSantosh Shilimkar alm->time.tm_min = bcd2bin(rtc_data[1]); 371b07682b6SSantosh Shilimkar alm->time.tm_hour = bcd2bin(rtc_data[2]); 372b07682b6SSantosh Shilimkar alm->time.tm_mday = bcd2bin(rtc_data[3]); 373b07682b6SSantosh Shilimkar alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1; 374b07682b6SSantosh Shilimkar alm->time.tm_year = bcd2bin(rtc_data[5]) + 100; 375b07682b6SSantosh Shilimkar 376b07682b6SSantosh Shilimkar /* report cached alarm enable state */ 377b07682b6SSantosh Shilimkar if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) 378b07682b6SSantosh Shilimkar alm->enabled = 1; 379b07682b6SSantosh Shilimkar 380b07682b6SSantosh Shilimkar return ret; 381b07682b6SSantosh Shilimkar } 382b07682b6SSantosh Shilimkar 383ef3b7d0dSBalaji T K static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) 384b07682b6SSantosh Shilimkar { 38514591d88SPeter Ujfalusi unsigned char alarm_data[ALL_TIME_REGS]; 386b07682b6SSantosh Shilimkar int ret; 387b07682b6SSantosh Shilimkar 388ef3b7d0dSBalaji T K ret = twl_rtc_alarm_irq_enable(dev, 0); 389b07682b6SSantosh Shilimkar if (ret) 390b07682b6SSantosh Shilimkar goto out; 391b07682b6SSantosh Shilimkar 39214591d88SPeter Ujfalusi alarm_data[0] = bin2bcd(alm->time.tm_sec); 39314591d88SPeter Ujfalusi alarm_data[1] = bin2bcd(alm->time.tm_min); 39414591d88SPeter Ujfalusi alarm_data[2] = bin2bcd(alm->time.tm_hour); 39514591d88SPeter Ujfalusi alarm_data[3] = bin2bcd(alm->time.tm_mday); 39614591d88SPeter Ujfalusi alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); 39714591d88SPeter Ujfalusi alarm_data[5] = bin2bcd(alm->time.tm_year - 100); 398b07682b6SSantosh Shilimkar 399b07682b6SSantosh Shilimkar /* update all the alarm registers in one shot */ 400ef3b7d0dSBalaji T K ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, 401a6b49ffdSBalaji T K (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); 402b07682b6SSantosh Shilimkar if (ret) { 403b07682b6SSantosh Shilimkar dev_err(dev, "rtc_set_alarm error %d\n", ret); 404b07682b6SSantosh Shilimkar goto out; 405b07682b6SSantosh Shilimkar } 406b07682b6SSantosh Shilimkar 407b07682b6SSantosh Shilimkar if (alm->enabled) 408ef3b7d0dSBalaji T K ret = twl_rtc_alarm_irq_enable(dev, 1); 409b07682b6SSantosh Shilimkar out: 410b07682b6SSantosh Shilimkar return ret; 411b07682b6SSantosh Shilimkar } 412b07682b6SSantosh Shilimkar 413ef3b7d0dSBalaji T K static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) 414b07682b6SSantosh Shilimkar { 4152778ebccSVenu Byravarasu unsigned long events; 416b07682b6SSantosh Shilimkar int ret = IRQ_NONE; 417b07682b6SSantosh Shilimkar int res; 418b07682b6SSantosh Shilimkar u8 rd_reg; 419b07682b6SSantosh Shilimkar 420ef3b7d0dSBalaji T K res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); 421b07682b6SSantosh Shilimkar if (res) 422b07682b6SSantosh Shilimkar goto out; 423b07682b6SSantosh Shilimkar /* 424b07682b6SSantosh Shilimkar * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG. 425b07682b6SSantosh Shilimkar * only one (ALARM or RTC) interrupt source may be enabled 426b07682b6SSantosh Shilimkar * at time, we also could check our results 427b07682b6SSantosh Shilimkar * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] 428b07682b6SSantosh Shilimkar */ 429b07682b6SSantosh Shilimkar if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) 4302778ebccSVenu Byravarasu events = RTC_IRQF | RTC_AF; 431b07682b6SSantosh Shilimkar else 4322778ebccSVenu Byravarasu events = RTC_IRQF | RTC_PF; 433b07682b6SSantosh Shilimkar 43494a339d0SVenu Byravarasu res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M, 435b07682b6SSantosh Shilimkar REG_RTC_STATUS_REG); 436b07682b6SSantosh Shilimkar if (res) 437b07682b6SSantosh Shilimkar goto out; 438b07682b6SSantosh Shilimkar 439a6b49ffdSBalaji T K if (twl_class_is_4030()) { 440b07682b6SSantosh Shilimkar /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 441b07682b6SSantosh Shilimkar * needs 2 reads to clear the interrupt. One read is done in 442ef3b7d0dSBalaji T K * do_twl_pwrirq(). Doing the second read, to clear 443b07682b6SSantosh Shilimkar * the bit. 444b07682b6SSantosh Shilimkar * 445b07682b6SSantosh Shilimkar * FIXME the reason PWR_ISR1 needs an extra read is that 446b07682b6SSantosh Shilimkar * RTC_IF retriggered until we cleared REG_ALARM_M above. 447b07682b6SSantosh Shilimkar * But re-reading like this is a bad hack; by doing so we 448b07682b6SSantosh Shilimkar * risk wrongly clearing status for some other IRQ (losing 449b07682b6SSantosh Shilimkar * the interrupt). Be smarter about handling RTC_UF ... 450b07682b6SSantosh Shilimkar */ 451fc7b92fcSBalaji T K res = twl_i2c_read_u8(TWL4030_MODULE_INT, 452b07682b6SSantosh Shilimkar &rd_reg, TWL4030_INT_PWR_ISR1); 453b07682b6SSantosh Shilimkar if (res) 454b07682b6SSantosh Shilimkar goto out; 455a6b49ffdSBalaji T K } 456b07682b6SSantosh Shilimkar 457b07682b6SSantosh Shilimkar /* Notify RTC core on event */ 458b07682b6SSantosh Shilimkar rtc_update_irq(rtc, 1, events); 459b07682b6SSantosh Shilimkar 460b07682b6SSantosh Shilimkar ret = IRQ_HANDLED; 461b07682b6SSantosh Shilimkar out: 462b07682b6SSantosh Shilimkar return ret; 463b07682b6SSantosh Shilimkar } 464b07682b6SSantosh Shilimkar 46534c7b3acSJulia Lawall static const struct rtc_class_ops twl_rtc_ops = { 466ef3b7d0dSBalaji T K .read_time = twl_rtc_read_time, 467ef3b7d0dSBalaji T K .set_time = twl_rtc_set_time, 468ef3b7d0dSBalaji T K .read_alarm = twl_rtc_read_alarm, 469ef3b7d0dSBalaji T K .set_alarm = twl_rtc_set_alarm, 470ef3b7d0dSBalaji T K .alarm_irq_enable = twl_rtc_alarm_irq_enable, 471b07682b6SSantosh Shilimkar }; 472b07682b6SSantosh Shilimkar 473b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/ 474b07682b6SSantosh Shilimkar 4755a167f45SGreg Kroah-Hartman static int twl_rtc_probe(struct platform_device *pdev) 476b07682b6SSantosh Shilimkar { 477b07682b6SSantosh Shilimkar struct rtc_device *rtc; 4787e72c686STodd Poynor int ret = -EINVAL; 479b07682b6SSantosh Shilimkar int irq = platform_get_irq(pdev, 0); 480b07682b6SSantosh Shilimkar u8 rd_reg; 481b07682b6SSantosh Shilimkar 482b07682b6SSantosh Shilimkar if (irq <= 0) 483f53eeb85SJingoo Han return ret; 484b07682b6SSantosh Shilimkar 485d3869ff6SPeter Ujfalusi /* Initialize the register map */ 486d3869ff6SPeter Ujfalusi if (twl_class_is_4030()) 487d3869ff6SPeter Ujfalusi rtc_reg_map = (u8 *)twl4030_rtc_reg_map; 488d3869ff6SPeter Ujfalusi else 489d3869ff6SPeter Ujfalusi rtc_reg_map = (u8 *)twl6030_rtc_reg_map; 490d3869ff6SPeter Ujfalusi 491ef3b7d0dSBalaji T K ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); 492b07682b6SSantosh Shilimkar if (ret < 0) 493f53eeb85SJingoo Han return ret; 494b07682b6SSantosh Shilimkar 495b07682b6SSantosh Shilimkar if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) 496b07682b6SSantosh Shilimkar dev_warn(&pdev->dev, "Power up reset detected.\n"); 497b07682b6SSantosh Shilimkar 498b07682b6SSantosh Shilimkar if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) 499b07682b6SSantosh Shilimkar dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); 500b07682b6SSantosh Shilimkar 501b07682b6SSantosh Shilimkar /* Clear RTC Power up reset and pending alarm interrupts */ 502ef3b7d0dSBalaji T K ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); 503b07682b6SSantosh Shilimkar if (ret < 0) 504f53eeb85SJingoo Han return ret; 505b07682b6SSantosh Shilimkar 506a6b49ffdSBalaji T K if (twl_class_is_6030()) { 507a6b49ffdSBalaji T K twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, 508a6b49ffdSBalaji T K REG_INT_MSK_LINE_A); 509a6b49ffdSBalaji T K twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, 510a6b49ffdSBalaji T K REG_INT_MSK_STS_A); 511a6b49ffdSBalaji T K } 512a6b49ffdSBalaji T K 513f7439bcbSVenu Byravarasu dev_info(&pdev->dev, "Enabling TWL-RTC\n"); 514f7439bcbSVenu Byravarasu ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG); 515b07682b6SSantosh Shilimkar if (ret < 0) 516f53eeb85SJingoo Han return ret; 517b07682b6SSantosh Shilimkar 5188dcebaa9SKevin Hilman /* ensure interrupts are disabled, bootloaders can be strange */ 5198dcebaa9SKevin Hilman ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); 5208dcebaa9SKevin Hilman if (ret < 0) 5218dcebaa9SKevin Hilman dev_warn(&pdev->dev, "unable to disable interrupt\n"); 5228dcebaa9SKevin Hilman 523b07682b6SSantosh Shilimkar /* init cached IRQ enable bits */ 524ef3b7d0dSBalaji T K ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); 525b07682b6SSantosh Shilimkar if (ret < 0) 526f53eeb85SJingoo Han return ret; 527b07682b6SSantosh Shilimkar 528b99b94b5SGrygorii Strashko device_init_wakeup(&pdev->dev, 1); 529b99b94b5SGrygorii Strashko 530f53eeb85SJingoo Han rtc = devm_rtc_device_register(&pdev->dev, pdev->name, 531f53eeb85SJingoo Han &twl_rtc_ops, THIS_MODULE); 5327e72c686STodd Poynor if (IS_ERR(rtc)) { 5337e72c686STodd Poynor dev_err(&pdev->dev, "can't register RTC device, err %ld\n", 5347e72c686STodd Poynor PTR_ERR(rtc)); 535f53eeb85SJingoo Han return PTR_ERR(rtc); 5367e72c686STodd Poynor } 5377e72c686STodd Poynor 538f53eeb85SJingoo Han ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 539f53eeb85SJingoo Han twl_rtc_interrupt, 5406b91bf1aSKevin Hilman IRQF_TRIGGER_RISING | IRQF_ONESHOT, 5417e72c686STodd Poynor dev_name(&rtc->dev), rtc); 5427e72c686STodd Poynor if (ret < 0) { 5437e72c686STodd Poynor dev_err(&pdev->dev, "IRQ is not free.\n"); 544f53eeb85SJingoo Han return ret; 5457e72c686STodd Poynor } 5467e72c686STodd Poynor 5477e72c686STodd Poynor platform_set_drvdata(pdev, rtc); 5487e72c686STodd Poynor return 0; 549b07682b6SSantosh Shilimkar } 550b07682b6SSantosh Shilimkar 551b07682b6SSantosh Shilimkar /* 552ef3b7d0dSBalaji T K * Disable all TWL RTC module interrupts. 553b07682b6SSantosh Shilimkar * Sets status flag to free. 554b07682b6SSantosh Shilimkar */ 5555a167f45SGreg Kroah-Hartman static int twl_rtc_remove(struct platform_device *pdev) 556b07682b6SSantosh Shilimkar { 557b07682b6SSantosh Shilimkar /* leave rtc running, but disable irqs */ 558b07682b6SSantosh Shilimkar mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); 559b07682b6SSantosh Shilimkar mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); 560a6b49ffdSBalaji T K if (twl_class_is_6030()) { 561a6b49ffdSBalaji T K twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, 562a6b49ffdSBalaji T K REG_INT_MSK_LINE_A); 563a6b49ffdSBalaji T K twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, 564a6b49ffdSBalaji T K REG_INT_MSK_STS_A); 565a6b49ffdSBalaji T K } 566a6b49ffdSBalaji T K 567b07682b6SSantosh Shilimkar return 0; 568b07682b6SSantosh Shilimkar } 569b07682b6SSantosh Shilimkar 570ef3b7d0dSBalaji T K static void twl_rtc_shutdown(struct platform_device *pdev) 571b07682b6SSantosh Shilimkar { 572b07682b6SSantosh Shilimkar /* mask timer interrupts, but leave alarm interrupts on to enable 573b07682b6SSantosh Shilimkar power-on when alarm is triggered */ 574b07682b6SSantosh Shilimkar mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); 575b07682b6SSantosh Shilimkar } 576b07682b6SSantosh Shilimkar 577b9d8c460SJingoo Han #ifdef CONFIG_PM_SLEEP 578b07682b6SSantosh Shilimkar static unsigned char irqstat; 579b07682b6SSantosh Shilimkar 580b9d8c460SJingoo Han static int twl_rtc_suspend(struct device *dev) 581b07682b6SSantosh Shilimkar { 582b07682b6SSantosh Shilimkar irqstat = rtc_irq_bits; 583b07682b6SSantosh Shilimkar 584b07682b6SSantosh Shilimkar mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); 585b07682b6SSantosh Shilimkar return 0; 586b07682b6SSantosh Shilimkar } 587b07682b6SSantosh Shilimkar 588b9d8c460SJingoo Han static int twl_rtc_resume(struct device *dev) 589b07682b6SSantosh Shilimkar { 590b07682b6SSantosh Shilimkar set_rtc_irq_bit(irqstat); 591b07682b6SSantosh Shilimkar return 0; 592b07682b6SSantosh Shilimkar } 593b07682b6SSantosh Shilimkar #endif 594b07682b6SSantosh Shilimkar 595b9d8c460SJingoo Han static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume); 596b9d8c460SJingoo Han 597c8a6046eSSachin Kamat #ifdef CONFIG_OF 598948170f8SBenoit Cousson static const struct of_device_id twl_rtc_of_match[] = { 599948170f8SBenoit Cousson {.compatible = "ti,twl4030-rtc", }, 600948170f8SBenoit Cousson { }, 601948170f8SBenoit Cousson }; 602948170f8SBenoit Cousson MODULE_DEVICE_TABLE(of, twl_rtc_of_match); 603c8a6046eSSachin Kamat #endif 604c8a6046eSSachin Kamat 605ef3b7d0dSBalaji T K MODULE_ALIAS("platform:twl_rtc"); 606b07682b6SSantosh Shilimkar 607b07682b6SSantosh Shilimkar static struct platform_driver twl4030rtc_driver = { 608ef3b7d0dSBalaji T K .probe = twl_rtc_probe, 6095a167f45SGreg Kroah-Hartman .remove = twl_rtc_remove, 610ef3b7d0dSBalaji T K .shutdown = twl_rtc_shutdown, 611b07682b6SSantosh Shilimkar .driver = { 612ef3b7d0dSBalaji T K .name = "twl_rtc", 613b9d8c460SJingoo Han .pm = &twl_rtc_pm_ops, 614c8a6046eSSachin Kamat .of_match_table = of_match_ptr(twl_rtc_of_match), 615b07682b6SSantosh Shilimkar }, 616b07682b6SSantosh Shilimkar }; 617b07682b6SSantosh Shilimkar 6185ee67484SPeter Ujfalusi module_platform_driver(twl4030rtc_driver); 619b07682b6SSantosh Shilimkar 620b07682b6SSantosh Shilimkar MODULE_AUTHOR("Texas Instruments, MontaVista Software"); 621b07682b6SSantosh Shilimkar MODULE_LICENSE("GPL"); 622