1fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* 2fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * RTC driver for Maxim MAX77686 3fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * 4fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * Copyright (C) 2012 Samsung Electronics Co.Ltd 5fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * 6fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * based on rtc-max8997.c 7fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * 8fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * This program is free software; you can redistribute it and/or modify it 9fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * under the terms of the GNU General Public License as published by the 10fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * Free Software Foundation; either version 2 of the License, or (at your 11fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * option) any later version. 12fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * 13fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee */ 14fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 15fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/slab.h> 16fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/rtc.h> 17fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/delay.h> 18fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/mutex.h> 19fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/module.h> 20fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/platform_device.h> 21fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/mfd/max77686-private.h> 22fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/irqdomain.h> 23fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/regmap.h> 24fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 25fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Control Register */ 26fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define BCD_EN_SHIFT 0 27ac60bf31210f7b388ea2c1de62ef573a45f49a0fJingoo Han#define BCD_EN_MASK (1 << BCD_EN_SHIFT) 28fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define MODEL24_SHIFT 1 29fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define MODEL24_MASK (1 << MODEL24_SHIFT) 30fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Update Register1 */ 31fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_UDR_SHIFT 0 32fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) 33fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_RBUDR_SHIFT 4 34fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) 35fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Hour register */ 36fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define HOUR_PM_SHIFT 6 37fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) 38fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Alarm Enable */ 39fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define ALARM_ENABLE_SHIFT 7 40fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) 41fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 42fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define MAX77686_RTC_UPDATE_DELAY 16 43fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 44fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeenum { 45fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_SEC = 0, 46fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_MIN, 47fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_HOUR, 48fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_WEEKDAY, 49fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_MONTH, 50fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_YEAR, 51fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_DATE, 52fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee RTC_NR_TIME 53fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}; 54fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 55fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestruct max77686_rtc_info { 56fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct device *dev; 57fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_dev *max77686; 58fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct i2c_client *rtc; 59fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct rtc_device *rtc_dev; 60fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct mutex lock; 61fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 62fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct regmap *regmap; 63fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 64fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int virq; 65fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int rtc_24hr_mode; 66fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}; 67fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 68fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeenum MAX77686_RTC_OP { 69fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_RTC_WRITE, 70fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_RTC_READ, 71fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}; 72fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 73fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, 74fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int rtc_24hr_mode) 75fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 76fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_sec = data[RTC_SEC] & 0x7f; 77fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_min = data[RTC_MIN] & 0x7f; 78fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (rtc_24hr_mode) 79fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_hour = data[RTC_HOUR] & 0x1f; 80fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee else { 81fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_hour = data[RTC_HOUR] & 0x0f; 82fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (data[RTC_HOUR] & HOUR_PM_MASK) 83fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_hour += 12; 84fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 85fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 86a20cd88e20e59ce11ebca84fac769654193c51e0Javier Martinez Canillas /* Only a single bit is set in data[], so fls() would be equivalent */ 87a20cd88e20e59ce11ebca84fac769654193c51e0Javier Martinez Canillas tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1; 88fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_mday = data[RTC_DATE] & 0x1f; 89fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; 90fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; 91fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_yday = 0; 92fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee tm->tm_isdst = 0; 93fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 94fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 95fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) 96fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 97fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_SEC] = tm->tm_sec; 98fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_MIN] = tm->tm_min; 99fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_HOUR] = tm->tm_hour; 100fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_WEEKDAY] = 1 << tm->tm_wday; 101fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_DATE] = tm->tm_mday; 102fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_MONTH] = tm->tm_mon + 1; 103cdf5f4ac63785e48d93137566d003d6c839b1259Sachin Kamat data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; 104fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 105fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (tm->tm_year < 100) { 106fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee pr_warn("%s: MAX77686 RTC cannot handle the year %d." 107fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); 108fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return -EINVAL; 109fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 110fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return 0; 111fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 112fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 113fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_update(struct max77686_rtc_info *info, 114fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee enum MAX77686_RTC_OP op) 115fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 116fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret; 117fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee unsigned int data; 118fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 119fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (op == MAX77686_RTC_WRITE) 120fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data = 1 << RTC_UDR_SHIFT; 121fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee else 122fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data = 1 << RTC_RBUDR_SHIFT; 123fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 124fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_update_bits(info->max77686->rtc_regmap, 125fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_RTC_UPDATE0, data, data); 126fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 127fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", 128fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, ret, data); 129fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee else { 130fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee /* Minimum 16ms delay required before RTC update. */ 131fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee msleep(MAX77686_RTC_UPDATE_DELAY); 132fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 133fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 134fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 135fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 136fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 137fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) 138fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 139fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_rtc_info *info = dev_get_drvdata(dev); 140fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee u8 data[RTC_NR_TIME]; 141fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret; 142fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 143fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_lock(&info->lock); 144fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 145fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_READ); 146fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 147fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 148fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 149fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_read(info->max77686->rtc_regmap, 150fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_RTC_SEC, data, RTC_NR_TIME); 151fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 152fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); 153fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 154fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 155fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 156fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); 157fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 158fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = rtc_valid_tm(tm); 159fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 160fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout: 161fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_unlock(&info->lock); 162fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 163fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 164fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 165fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) 166fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 167fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_rtc_info *info = dev_get_drvdata(dev); 168fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee u8 data[RTC_NR_TIME]; 169fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret; 170fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 171fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_tm_to_data(tm, data); 172fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 173fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 174fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 175fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_lock(&info->lock); 176fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 177fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_write(info->max77686->rtc_regmap, 178fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_RTC_SEC, data, RTC_NR_TIME); 179fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 180fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, 181fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret); 182fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 183fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 184fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 185fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); 186fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 187fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout: 188fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_unlock(&info->lock); 189fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 190fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 191fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 192fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 193fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 194fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_rtc_info *info = dev_get_drvdata(dev); 195fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee u8 data[RTC_NR_TIME]; 196fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee unsigned int val; 197fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int i, ret; 198fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 199fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_lock(&info->lock); 200fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 201fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_READ); 202fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 203fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 204fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 205fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_read(info->max77686->rtc_regmap, 206fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_ALARM1_SEC, data, RTC_NR_TIME); 207fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 208fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", 209fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, __LINE__, ret); 210fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 211fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 212fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 213fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); 214fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 215fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee alrm->enabled = 0; 216fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee for (i = 0; i < RTC_NR_TIME; i++) { 217fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (data[i] & ALARM_ENABLE_MASK) { 218fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee alrm->enabled = 1; 219fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee break; 220fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 221fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 222fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 223fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee alrm->pending = 0; 2241748cbf7f7c464593232cde914f5a103181a83b5Sangjung Woo ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val); 225fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 2261748cbf7f7c464593232cde914f5a103181a83b5Sangjung Woo dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n", 227fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, __LINE__, ret); 228fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 229fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 230fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 231fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (val & (1 << 4)) /* RTCA1 */ 232fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee alrm->pending = 1; 233fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 234fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout: 235fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_unlock(&info->lock); 236fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return 0; 237fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 238fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 239fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) 240fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 241fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee u8 data[RTC_NR_TIME]; 242fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret, i; 243fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct rtc_time tm; 244fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 245fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (!mutex_is_locked(&info->lock)) 246fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_warn(info->dev, "%s: should have mutex locked\n", __func__); 247fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 248fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_READ); 249fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 250fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 251fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 252fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_read(info->max77686->rtc_regmap, 253fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_ALARM1_SEC, data, RTC_NR_TIME); 254fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 255fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", 256fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, ret); 257fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 258fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 259fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 260fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); 261fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 262fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee for (i = 0; i < RTC_NR_TIME; i++) 263fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[i] &= ~ALARM_ENABLE_MASK; 264fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 265fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_write(info->max77686->rtc_regmap, 266fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_ALARM1_SEC, data, RTC_NR_TIME); 267fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 268fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", 269fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, ret); 270fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 271fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 272fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 273fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); 274fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout: 275fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 276fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 277fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 278fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_start_alarm(struct max77686_rtc_info *info) 279fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 280fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee u8 data[RTC_NR_TIME]; 281fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret; 282fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct rtc_time tm; 283fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 284fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (!mutex_is_locked(&info->lock)) 285fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_warn(info->dev, "%s: should have mutex locked\n", __func__); 286fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 287fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_READ); 288fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 289fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 290fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 291fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_read(info->max77686->rtc_regmap, 292fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_ALARM1_SEC, data, RTC_NR_TIME); 293fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 294fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", 295fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, ret); 296fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 297fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 298fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 299fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); 300fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 301fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); 302fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); 303fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); 304fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; 305fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (data[RTC_MONTH] & 0xf) 306fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); 307fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (data[RTC_YEAR] & 0x7f) 308fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); 309fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (data[RTC_DATE] & 0x1f) 310fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); 311fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 312fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_write(info->max77686->rtc_regmap, 313fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_ALARM1_SEC, data, RTC_NR_TIME); 314fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 315fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", 316fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, ret); 317fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 318fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 319fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 320fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); 321fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout: 322fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 323fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 324fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 325fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 326fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 327fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_rtc_info *info = dev_get_drvdata(dev); 328fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee u8 data[RTC_NR_TIME]; 329fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret; 330fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 331fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_tm_to_data(&alrm->time, data); 332fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 333fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 334fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 335fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_lock(&info->lock); 336fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 337fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_stop_alarm(info); 338fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 339fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 340fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 341fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_write(info->max77686->rtc_regmap, 342fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee MAX77686_ALARM1_SEC, data, RTC_NR_TIME); 343fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 344fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 345fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", 346fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, ret); 347fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 348fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 349fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 350fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); 351fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) 352fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto out; 353fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 354fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (alrm->enabled) 355fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_start_alarm(info); 356fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout: 357fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_unlock(&info->lock); 358fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 359fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 360fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 361fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_alarm_irq_enable(struct device *dev, 362fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee unsigned int enabled) 363fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 364fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_rtc_info *info = dev_get_drvdata(dev); 365fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret; 366fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 367fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_lock(&info->lock); 368fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (enabled) 369fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_start_alarm(info); 370fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee else 371fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_stop_alarm(info); 372fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_unlock(&info->lock); 373fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 374fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 375fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 376fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 377fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic irqreturn_t max77686_rtc_alarm_irq(int irq, void *data) 378fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 379fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_rtc_info *info = data; 380fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 381fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); 382fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 383fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); 384fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 385fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return IRQ_HANDLED; 386fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 387fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 388fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic const struct rtc_class_ops max77686_rtc_ops = { 389fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .read_time = max77686_rtc_read_time, 390fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .set_time = max77686_rtc_set_time, 391fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .read_alarm = max77686_rtc_read_alarm, 392fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .set_alarm = max77686_rtc_set_alarm, 393fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .alarm_irq_enable = max77686_rtc_alarm_irq_enable, 394fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}; 395fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 396fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_init_reg(struct max77686_rtc_info *info) 397fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 398fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee u8 data[2]; 399fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee int ret; 400fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 401fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee /* Set RTC control register : Binary mode, 24hour mdoe */ 402fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); 403fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); 404fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 405fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee info->rtc_24hr_mode = 1; 406fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 407fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2); 408fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 409fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", 410fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee __func__, ret); 411fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 412fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 413fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 414fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); 415fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 416fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 417fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 418fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_probe(struct platform_device *pdev) 419fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{ 420fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); 421fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee struct max77686_rtc_info *info; 4226f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas int ret; 423fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 4243cebeb53d921c2079be0f1bf20f8cae68c20ecc0Jingoo Han dev_info(&pdev->dev, "%s\n", __func__); 425fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 4260f64f853fc622a0b0c7ab255f8605ae40aa45d84Jingoo Han info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info), 4270f64f853fc622a0b0c7ab255f8605ae40aa45d84Jingoo Han GFP_KERNEL); 428fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (!info) 429fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return -ENOMEM; 430fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 431fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee mutex_init(&info->lock); 432fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee info->dev = &pdev->dev; 433fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee info->max77686 = max77686; 434fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee info->rtc = max77686->rtc; 4356f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas 436fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee platform_set_drvdata(pdev, info); 437fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 438fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = max77686_rtc_init_reg(info); 439fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 440fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret < 0) { 441fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); 442fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto err_rtc; 443fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 444fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 445fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee device_init_wakeup(&pdev->dev, 1); 446fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 447f56950ec3a8dc093db724bf1c1611a12c85fb260Jingoo Han info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc", 448f56950ec3a8dc093db724bf1c1611a12c85fb260Jingoo Han &max77686_rtc_ops, THIS_MODULE); 449fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 450fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (IS_ERR(info->rtc_dev)) { 451fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = PTR_ERR(info->rtc_dev); 452fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); 453fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee if (ret == 0) 454fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee ret = -EINVAL; 455fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto err_rtc; 456fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee } 4576f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas 4581745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas if (!max77686->rtc_irq_data) { 4591745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas ret = -EINVAL; 4601745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__); 4611745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas goto err_rtc; 4621745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas } 4631745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas 4646f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas info->virq = regmap_irq_get_virq(max77686->rtc_irq_data, 4656f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas MAX77686_RTCIRQ_RTCA1); 4666f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas if (!info->virq) { 467ad819039f1aa5c5179ecdfb035ed2864d93e741eSachin Kamat ret = -ENXIO; 468fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee goto err_rtc; 469ad819039f1aa5c5179ecdfb035ed2864d93e741eSachin Kamat } 470fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 4716f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, 4726f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas max77686_rtc_alarm_irq, 0, "rtc-alarm1", info); 473ad819039f1aa5c5179ecdfb035ed2864d93e741eSachin Kamat if (ret < 0) 474fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", 475fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee info->virq, ret); 476fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 477fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeerr_rtc: 478fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee return ret; 479fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee} 480fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 481e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson#ifdef CONFIG_PM_SLEEP 482e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Andersonstatic int max77686_rtc_suspend(struct device *dev) 483e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson{ 484e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson if (device_may_wakeup(dev)) { 485e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson struct max77686_rtc_info *info = dev_get_drvdata(dev); 486e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson 487e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson return enable_irq_wake(info->virq); 488e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson } 489e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson 490e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson return 0; 491e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson} 492e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson 493e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Andersonstatic int max77686_rtc_resume(struct device *dev) 494e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson{ 495e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson if (device_may_wakeup(dev)) { 496e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson struct max77686_rtc_info *info = dev_get_drvdata(dev); 497e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson 498e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson return disable_irq_wake(info->virq); 499e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson } 500e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson 501e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson return 0; 502e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson} 503e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson#endif 504e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson 505e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Andersonstatic SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, 506e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson max77686_rtc_suspend, max77686_rtc_resume); 507e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson 508fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic const struct platform_device_id rtc_id[] = { 509fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee { "max77686-rtc", 0 }, 510fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee {}, 511fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}; 512fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 513fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic struct platform_driver max77686_rtc_driver = { 514fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .driver = { 515fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .name = "max77686-rtc", 516fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .owner = THIS_MODULE, 517e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson .pm = &max77686_rtc_pm_ops, 518fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee }, 519fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .probe = max77686_rtc_probe, 520fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee .id_table = rtc_id, 521fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}; 522fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 5230c58ff587738c25e4402a51df6575230e7f099e1Jingoo Hanmodule_platform_driver(max77686_rtc_driver); 524fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee 525fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa LeeMODULE_DESCRIPTION("Maxim MAX77686 RTC driver"); 526f5b1d3c5d022aeb994f94ed3372102e057925c6aJingoo HanMODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>"); 527fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa LeeMODULE_LICENSE("GPL"); 528