// SPDX-License-Identifier: GPL-2.0+//// Copyright (c) 2013-2014 Samsung Electronics Co., Ltd// http://www.samsung.com//// Copyright (C) 2013 Google, Inc #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h>#include <linux/i2c.h>#include <linux/bcd.h>#include <linux/reboot.h>#include <linux/regmap.h>#include <linux/rtc.h>#include <linux/platform_device.h>#include <linux/mfd/samsung/core.h>#include <linux/mfd/samsung/rtc.h>#include <linux/mfd/samsung/s2mps14.h> /* * Maximum number of retries for checking changes in UDR field * of S5M_RTC_UDR_CON register (to limit possible endless loop). * * After writing to RTC registers (setting time or alarm) read the UDR field * in S5M_RTC_UDR_CON register. UDR is auto-cleared when data have * been transferred. */#define UDR_READ_RETRY_CNT 5 enum { RTC_SEC = 0, RTC_MIN, RTC_HOUR, RTC_WEEKDAY, RTC_DATE, RTC_MONTH, RTC_YEAR1, RTC_YEAR2, /* Make sure this is always the last enum name. */ RTC_MAX_NUM_TIME_REGS}; /* * Registers used by the driver which are different between chipsets. * * Operations like read time and write alarm/time require updating * specific fields in UDR register. These fields usually are auto-cleared * (with some exceptions). * * Table of operations per device: * * Device | Write time | Read time | Write alarm * ================================================= * S5M8767 | UDR + TIME | | UDR * S2MPG10 | WUDR | RUDR | AUDR * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR * S2MPS13 | WUDR | RUDR | WUDR + AUDR * S2MPS15 | WUDR | RUDR | AUDR */struct s5m_rtc_reg_config { /* Number of registers used for setting time/alarm0/alarm1 */ unsigned int regs_count; /* First register for time, seconds */ unsigned int time; /* RTC control register */ unsigned int ctrl; /* First register for alarm 0, seconds */ unsigned int alarm0; /* First register for alarm 1, seconds */ unsigned int alarm1; /* * Register for update flag (UDR). Typically setting UDR field to 1 * will enable update of time or alarm register. Then it will be * auto-cleared after successful update. */ unsigned int udr_update; /* Auto-cleared mask in UDR field for writing time and alarm */ unsigned int autoclear_udr_mask; /* * Masks in UDR field for time and alarm operations. * The read time mask can be 0. Rest should not. */ unsigned int read_time_udr_mask; unsigned int write_time_udr_mask; unsigned int write_alarm_udr_mask;}; /* Register map for S5M8767 */static const struct s5m_rtc_reg_config s5m_rtc_regs = { .regs_count = 8, .time = S5M_RTC_SEC, .ctrl = S5M_ALARM1_CONF, .alarm0 = S5M_ALARM0_SEC, .alarm1 = S5M_ALARM1_SEC, .udr_update = S5M_RTC_UDR_CON, .autoclear_udr_mask = S5M_RTC_UDR_MASK, .read_time_udr_mask = 0, /* Not needed */ .write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK, .write_alarm_udr_mask = S5M_RTC_UDR_MASK,}; /* Register map for S2MPG10 */static const struct s5m_rtc_reg_config s2mpg10_rtc_regs = { .regs_count = 7, .time = S2MPG10_RTC_SEC, .ctrl = S2MPG10_RTC_CTRL, .alarm0 = S2MPG10_RTC_A0SEC, .alarm1 = S2MPG10_RTC_A1SEC, .udr_update = S2MPG10_RTC_UPDATE, .autoclear_udr_mask = S2MPS15_RTC_WUDR_MASK | S2MPS15_RTC_AUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK,}; /* Register map for S2MPS13 */static const struct s5m_rtc_reg_config s2mps13_rtc_regs = { .regs_count = 7, .time = S2MPS_RTC_SEC, .ctrl = S2MPS_RTC_CTRL, .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK,}; /* Register map for S2MPS11/14 */static const struct s5m_rtc_reg_config s2mps14_rtc_regs = { .regs_count = 7, .time = S2MPS_RTC_SEC, .ctrl = S2MPS_RTC_CTRL, .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK,}; /* * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits * are swapped. */static const struct s5m_rtc_reg_config s2mps15_rtc_regs = { .regs_count = 7, .time = S2MPS_RTC_SEC, .ctrl = S2MPS_RTC_CTRL, .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK,}; struct s5m_rtc_info { struct device *dev; struct sec_pmic_dev *s5m87xx; struct regmap *regmap; struct rtc_device *rtc_dev; int irq; enum sec_device_type device_type; int rtc_24hr_mode; const struct s5m_rtc_reg_config *regs;}; static const struct regmap_config s5m_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S5M_RTC_REG_MAX,}; static const struct regmap_config s2mps14_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPS_RTC_REG_MAX,}; static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, int rtc_24hr_mode){ tm->tm_sec = data[RTC_SEC] & 0x7f; tm->tm_min = data[RTC_MIN] & 0x7f; if (rtc_24hr_mode) { tm->tm_hour = data[RTC_HOUR] & 0x1f; } else { tm->tm_hour = data[RTC_HOUR] & 0x0f; if (data[RTC_HOUR] & HOUR_PM_MASK) tm->tm_hour += 12; } tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f); tm->tm_mday = data[RTC_DATE] & 0x1f; tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100; tm->tm_yday = 0; tm->tm_isdst = 0;} static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data){ data[RTC_SEC] = tm->tm_sec; data[RTC_MIN] = tm->tm_min; if (tm->tm_hour >= 12) data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK; else data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK; data[RTC_WEEKDAY] = 1 << tm->tm_wday; data[RTC_DATE] = tm->tm_mday; data[RTC_MONTH] = tm->tm_mon + 1; data[RTC_YEAR1] = tm->tm_year - 100; return 0;} /* * Read RTC_UDR_CON register and wait till UDR field is cleared. * This indicates that time/alarm update ended. */static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info){ int ret, retry = UDR_READ_RETRY_CNT; unsigned int data; do { ret = regmap_read(info->regmap, info->regs->udr_update, &data); } while (--retry && (data & info->regs->autoclear_udr_mask) && !ret); if (!retry) dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); return ret;} static int s5m_check_pending_alarm_interrupt(struct s5m_rtc_info *info, struct rtc_wkalrm *alarm){ int ret; unsigned int val; switch (info->device_type) { case S5M8767X: ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); val &= S5M_ALARM0_STATUS; break; case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, &val); val &= S2MPS_ALARM0_STATUS; break; default: return -EINVAL; } if (ret < 0) return ret; if (val) alarm->pending = 1; else alarm->pending = 0; return 0;} static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info){ int ret; ret = regmap_set_bits(info->regmap, info->regs->udr_update, info->regs->write_time_udr_mask); if (ret < 0) { dev_err(info->dev, "failed to write update reg(%d)\n", ret); return ret; } ret = s5m8767_wait_for_udr_update(info); return ret;} static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info){ int ret; unsigned int udr_mask; udr_mask = info->regs->write_alarm_udr_mask; switch (info->device_type) { case S5M8767X: udr_mask |= S5M_RTC_TIME_EN_MASK; break; case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: /* No exceptions needed */ break; default: return -EINVAL; } ret = regmap_update_bits(info->regmap, info->regs->udr_update, udr_mask, info->regs->write_alarm_udr_mask); if (ret < 0) { dev_err(info->dev, "%s: fail to write update reg(%d)\n", __func__, ret); return ret; } ret = s5m8767_wait_for_udr_update(info); /* On S2MPS13 the AUDR is not auto-cleared */ if (info->device_type == S2MPS13X) regmap_clear_bits(info->regmap, info->regs->udr_update, S2MPS13_RTC_AUDR_MASK); return ret;} static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm){ struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; int ret; if (info->regs->read_time_udr_mask) { ret = regmap_set_bits(info->regmap, info->regs->udr_update, info->regs->read_time_udr_mask); if (ret) { dev_err(dev, "Failed to prepare registers for time reading: %d\n", ret); return ret; } } ret = regmap_bulk_read(info->regmap, info->regs->time, data, info->regs->regs_count); if (ret < 0) return ret; switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); break; default: return -EINVAL; } dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); return 0;} static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm){ struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; int ret = 0; switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: ret = s5m8767_tm_to_data(tm, data); break; default: return -EINVAL; } if (ret < 0) return ret; dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); ret = regmap_raw_write(info->regmap, info->regs->time, data, info->regs->regs_count); if (ret < 0) return ret; ret = s5m8767_rtc_set_time_reg(info); return ret;} static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm){ struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; int ret, i; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); alrm->enabled = 0; for (i = 0; i < info->regs->regs_count; i++) { if (data[i] & ALARM_ENABLE_MASK) { alrm->enabled = 1; break; } } break; default: return -EINVAL; } dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday); return s5m_check_pending_alarm_interrupt(info, alrm);} static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info){ u8 data[RTC_MAX_NUM_TIME_REGS]; int ret, i; struct rtc_time tm; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: for (i = 0; i < info->regs->regs_count; i++) data[i] &= ~ALARM_ENABLE_MASK; ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; ret = s5m8767_rtc_set_alarm_reg(info); break; default: return -EINVAL; } return ret;} static int s5m_rtc_start_alarm(struct s5m_rtc_info *info){ int ret; u8 data[RTC_MAX_NUM_TIME_REGS]; struct rtc_time tm; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: data[RTC_SEC] |= ALARM_ENABLE_MASK; data[RTC_MIN] |= ALARM_ENABLE_MASK;Lines 1–500 of 833. Load more
// SPDX-License-Identifier: GPL-2.0+ // // Copyright (c) 2013-2014 Samsung Electronics Co., Ltd // http://www.samsung.com // // Copyright (C) 2013 Google, Inc #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/i2c.h> #include <linux/bcd.h> #include <linux/reboot.h> #include <linux/regmap.h> #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/rtc.h> #include <linux/mfd/samsung/s2mps14.h> /* * Maximum number of retries for checking changes in UDR field * of S5M_RTC_UDR_CON register (to limit possible endless loop). * * After writing to RTC registers (setting time or alarm) read the UDR field * in S5M_RTC_UDR_CON register. UDR is auto-cleared when data have * been transferred. */ #define UDR_READ_RETRY_CNT 5 enum { RTC_SEC = 0, RTC_MIN, RTC_HOUR, RTC_WEEKDAY, RTC_DATE, RTC_MONTH, RTC_YEAR1, RTC_YEAR2, /* Make sure this is always the last enum name. */ RTC_MAX_NUM_TIME_REGS }; /* * Registers used by the driver which are different between chipsets. * * Operations like read time and write alarm/time require updating * specific fields in UDR register. These fields usually are auto-cleared * (with some exceptions). * * Table of operations per device: * * Device | Write time | Read time | Write alarm * ================================================= * S5M8767 | UDR + TIME | | UDR * S2MPG10 | WUDR | RUDR | AUDR * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR * S2MPS13 | WUDR | RUDR | WUDR + AUDR * S2MPS15 | WUDR | RUDR | AUDR */ struct s5m_rtc_reg_config { /* Number of registers used for setting time/alarm0/alarm1 */ unsigned int regs_count; /* First register for time, seconds */ unsigned int time; /* RTC control register */ unsigned int ctrl; /* First register for alarm 0, seconds */ unsigned int alarm0; /* First register for alarm 1, seconds */ unsigned int alarm1; /* * Register for update flag (UDR). Typically setting UDR field to 1 * will enable update of time or alarm register. Then it will be * auto-cleared after successful update. */ unsigned int udr_update; /* Auto-cleared mask in UDR field for writing time and alarm */ unsigned int autoclear_udr_mask; /* * Masks in UDR field for time and alarm operations. * The read time mask can be 0. Rest should not. */ unsigned int read_time_udr_mask; unsigned int write_time_udr_mask; unsigned int write_alarm_udr_mask; }; /* Register map for S5M8767 */ static const struct s5m_rtc_reg_config s5m_rtc_regs = { .regs_count = 8, .time = S5M_RTC_SEC, .ctrl = S5M_ALARM1_CONF, .alarm0 = S5M_ALARM0_SEC, .alarm1 = S5M_ALARM1_SEC, .udr_update = S5M_RTC_UDR_CON, .autoclear_udr_mask = S5M_RTC_UDR_MASK, .read_time_udr_mask = 0, /* Not needed */ .write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK, .write_alarm_udr_mask = S5M_RTC_UDR_MASK, }; /* Register map for S2MPG10 */ static const struct s5m_rtc_reg_config s2mpg10_rtc_regs = { .regs_count = 7, .time = S2MPG10_RTC_SEC, .ctrl = S2MPG10_RTC_CTRL, .alarm0 = S2MPG10_RTC_A0SEC, .alarm1 = S2MPG10_RTC_A1SEC, .udr_update = S2MPG10_RTC_UPDATE, .autoclear_udr_mask = S2MPS15_RTC_WUDR_MASK | S2MPS15_RTC_AUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK, }; /* Register map for S2MPS13 */ static const struct s5m_rtc_reg_config s2mps13_rtc_regs = { .regs_count = 7, .time = S2MPS_RTC_SEC, .ctrl = S2MPS_RTC_CTRL, .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK, }; /* Register map for S2MPS11/14 */ static const struct s5m_rtc_reg_config s2mps14_rtc_regs = { .regs_count = 7, .time = S2MPS_RTC_SEC, .ctrl = S2MPS_RTC_CTRL, .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK, }; /* * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits * are swapped. */ static const struct s5m_rtc_reg_config s2mps15_rtc_regs = { .regs_count = 7, .time = S2MPS_RTC_SEC, .ctrl = S2MPS_RTC_CTRL, .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK, .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK, }; struct s5m_rtc_info { struct device *dev; struct sec_pmic_dev *s5m87xx; struct regmap *regmap; struct rtc_device *rtc_dev; int irq; enum sec_device_type device_type; int rtc_24hr_mode; const struct s5m_rtc_reg_config *regs; }; static const struct regmap_config s5m_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S5M_RTC_REG_MAX, }; static const struct regmap_config s2mps14_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = S2MPS_RTC_REG_MAX, }; static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, int rtc_24hr_mode) { tm->tm_sec = data[RTC_SEC] & 0x7f; tm->tm_min = data[RTC_MIN] & 0x7f; if (rtc_24hr_mode) { tm->tm_hour = data[RTC_HOUR] & 0x1f; } else { tm->tm_hour = data[RTC_HOUR] & 0x0f; if (data[RTC_HOUR] & HOUR_PM_MASK) tm->tm_hour += 12; } tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f); tm->tm_mday = data[RTC_DATE] & 0x1f; tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100; tm->tm_yday = 0; tm->tm_isdst = 0; } static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) { data[RTC_SEC] = tm->tm_sec; data[RTC_MIN] = tm->tm_min; if (tm->tm_hour >= 12) data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK; else data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK; data[RTC_WEEKDAY] = 1 << tm->tm_wday; data[RTC_DATE] = tm->tm_mday; data[RTC_MONTH] = tm->tm_mon + 1; data[RTC_YEAR1] = tm->tm_year - 100; return 0; } /* * Read RTC_UDR_CON register and wait till UDR field is cleared. * This indicates that time/alarm update ended. */ static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) { int ret, retry = UDR_READ_RETRY_CNT; unsigned int data; do { ret = regmap_read(info->regmap, info->regs->udr_update, &data); } while (--retry && (data & info->regs->autoclear_udr_mask) && !ret); if (!retry) dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); return ret; } static int s5m_check_pending_alarm_interrupt(struct s5m_rtc_info *info, struct rtc_wkalrm *alarm) { int ret; unsigned int val; switch (info->device_type) { case S5M8767X: ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); val &= S5M_ALARM0_STATUS; break; case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, &val); val &= S2MPS_ALARM0_STATUS; break; default: return -EINVAL; } if (ret < 0) return ret; if (val) alarm->pending = 1; else alarm->pending = 0; return 0; } static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) { int ret; ret = regmap_set_bits(info->regmap, info->regs->udr_update, info->regs->write_time_udr_mask); if (ret < 0) { dev_err(info->dev, "failed to write update reg(%d)\n", ret); return ret; } ret = s5m8767_wait_for_udr_update(info); return ret; } static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) { int ret; unsigned int udr_mask; udr_mask = info->regs->write_alarm_udr_mask; switch (info->device_type) { case S5M8767X: udr_mask |= S5M_RTC_TIME_EN_MASK; break; case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: /* No exceptions needed */ break; default: return -EINVAL; } ret = regmap_update_bits(info->regmap, info->regs->udr_update, udr_mask, info->regs->write_alarm_udr_mask); if (ret < 0) { dev_err(info->dev, "%s: fail to write update reg(%d)\n", __func__, ret); return ret; } ret = s5m8767_wait_for_udr_update(info); /* On S2MPS13 the AUDR is not auto-cleared */ if (info->device_type == S2MPS13X) regmap_clear_bits(info->regmap, info->regs->udr_update, S2MPS13_RTC_AUDR_MASK); return ret; } static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; int ret; if (info->regs->read_time_udr_mask) { ret = regmap_set_bits(info->regmap, info->regs->udr_update, info->regs->read_time_udr_mask); if (ret) { dev_err(dev, "Failed to prepare registers for time reading: %d\n", ret); return ret; } } ret = regmap_bulk_read(info->regmap, info->regs->time, data, info->regs->regs_count); if (ret < 0) return ret; switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); break; default: return -EINVAL; } dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); return 0; } static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; int ret = 0; switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: ret = s5m8767_tm_to_data(tm, data); break; default: return -EINVAL; } if (ret < 0) return ret; dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); ret = regmap_raw_write(info->regmap, info->regs->time, data, info->regs->regs_count); if (ret < 0) return ret; ret = s5m8767_rtc_set_time_reg(info); return ret; } static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; int ret, i; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); alrm->enabled = 0; for (i = 0; i < info->regs->regs_count; i++) { if (data[i] & ALARM_ENABLE_MASK) { alrm->enabled = 1; break; } } break; default: return -EINVAL; } dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday); return s5m_check_pending_alarm_interrupt(info, alrm); } static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) { u8 data[RTC_MAX_NUM_TIME_REGS]; int ret, i; struct rtc_time tm; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: for (i = 0; i < info->regs->regs_count; i++) data[i] &= ~ALARM_ENABLE_MASK; ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; ret = s5m8767_rtc_set_alarm_reg(info); break; default: return -EINVAL; } return ret; } static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) { int ret; u8 data[RTC_MAX_NUM_TIME_REGS]; struct rtc_time tm; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, info->regs->regs_count); if (ret < 0) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8767X: case S2MPG10: case S2MPS15X: case S2MPS14X: case S2MPS13X: data[RTC_SEC] |= ALARM_ENABLE_MASK; data[RTC_MIN] |= ALARM_ENABLE_MASK;