363 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * rtc-palmas.c -- Palmas Real Time Clock driver.4 5 * RTC driver for TI Palma series devices like TPS65913,6 * TPS65914 power management IC.7 *8 * Copyright (c) 2012, NVIDIA Corporation.9 *10 * Author: Laxman Dewangan <ldewangan@nvidia.com>11 */12 13#include <linux/bcd.h>14#include <linux/errno.h>15#include <linux/init.h>16#include <linux/interrupt.h>17#include <linux/kernel.h>18#include <linux/mfd/palmas.h>19#include <linux/module.h>20#include <linux/of.h>21#include <linux/rtc.h>22#include <linux/types.h>23#include <linux/platform_device.h>24#include <linux/pm.h>25 26struct palmas_rtc {27 struct rtc_device *rtc;28 struct device *dev;29 unsigned int irq;30};31 32/* Total number of RTC registers needed to set time*/33#define PALMAS_NUM_TIME_REGS (PALMAS_YEARS_REG - PALMAS_SECONDS_REG + 1)34 35static int palmas_rtc_read_time(struct device *dev, struct rtc_time *tm)36{37 unsigned char rtc_data[PALMAS_NUM_TIME_REGS];38 struct palmas *palmas = dev_get_drvdata(dev->parent);39 int ret;40 41 /* Copy RTC counting registers to static registers or latches */42 ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,43 PALMAS_RTC_CTRL_REG_GET_TIME, PALMAS_RTC_CTRL_REG_GET_TIME);44 if (ret < 0) {45 dev_err(dev, "RTC CTRL reg update failed, err: %d\n", ret);46 return ret;47 }48 49 ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,50 rtc_data, PALMAS_NUM_TIME_REGS);51 if (ret < 0) {52 dev_err(dev, "RTC_SECONDS reg read failed, err = %d\n", ret);53 return ret;54 }55 56 tm->tm_sec = bcd2bin(rtc_data[0]);57 tm->tm_min = bcd2bin(rtc_data[1]);58 tm->tm_hour = bcd2bin(rtc_data[2]);59 tm->tm_mday = bcd2bin(rtc_data[3]);60 tm->tm_mon = bcd2bin(rtc_data[4]) - 1;61 tm->tm_year = bcd2bin(rtc_data[5]) + 100;62 63 return ret;64}65 66static int palmas_rtc_set_time(struct device *dev, struct rtc_time *tm)67{68 unsigned char rtc_data[PALMAS_NUM_TIME_REGS];69 struct palmas *palmas = dev_get_drvdata(dev->parent);70 int ret;71 72 rtc_data[0] = bin2bcd(tm->tm_sec);73 rtc_data[1] = bin2bcd(tm->tm_min);74 rtc_data[2] = bin2bcd(tm->tm_hour);75 rtc_data[3] = bin2bcd(tm->tm_mday);76 rtc_data[4] = bin2bcd(tm->tm_mon + 1);77 rtc_data[5] = bin2bcd(tm->tm_year - 100);78 79 /* Stop RTC while updating the RTC time registers */80 ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,81 PALMAS_RTC_CTRL_REG_STOP_RTC, 0);82 if (ret < 0) {83 dev_err(dev, "RTC stop failed, err = %d\n", ret);84 return ret;85 }86 87 ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,88 rtc_data, PALMAS_NUM_TIME_REGS);89 if (ret < 0) {90 dev_err(dev, "RTC_SECONDS reg write failed, err = %d\n", ret);91 return ret;92 }93 94 /* Start back RTC */95 ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,96 PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC);97 if (ret < 0)98 dev_err(dev, "RTC start failed, err = %d\n", ret);99 return ret;100}101 102static int palmas_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)103{104 struct palmas *palmas = dev_get_drvdata(dev->parent);105 u8 val;106 107 val = enabled ? PALMAS_RTC_INTERRUPTS_REG_IT_ALARM : 0;108 return palmas_write(palmas, PALMAS_RTC_BASE,109 PALMAS_RTC_INTERRUPTS_REG, val);110}111 112static int palmas_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)113{114 unsigned char alarm_data[PALMAS_NUM_TIME_REGS];115 u32 int_val;116 struct palmas *palmas = dev_get_drvdata(dev->parent);117 int ret;118 119 ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE,120 PALMAS_ALARM_SECONDS_REG,121 alarm_data, PALMAS_NUM_TIME_REGS);122 if (ret < 0) {123 dev_err(dev, "RTC_ALARM_SECONDS read failed, err = %d\n", ret);124 return ret;125 }126 127 alm->time.tm_sec = bcd2bin(alarm_data[0]);128 alm->time.tm_min = bcd2bin(alarm_data[1]);129 alm->time.tm_hour = bcd2bin(alarm_data[2]);130 alm->time.tm_mday = bcd2bin(alarm_data[3]);131 alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;132 alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;133 134 ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG,135 &int_val);136 if (ret < 0) {137 dev_err(dev, "RTC_INTERRUPTS reg read failed, err = %d\n", ret);138 return ret;139 }140 141 if (int_val & PALMAS_RTC_INTERRUPTS_REG_IT_ALARM)142 alm->enabled = 1;143 return ret;144}145 146static int palmas_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)147{148 unsigned char alarm_data[PALMAS_NUM_TIME_REGS];149 struct palmas *palmas = dev_get_drvdata(dev->parent);150 int ret;151 152 ret = palmas_rtc_alarm_irq_enable(dev, 0);153 if (ret < 0) {154 dev_err(dev, "Disable RTC alarm failed\n");155 return ret;156 }157 158 alarm_data[0] = bin2bcd(alm->time.tm_sec);159 alarm_data[1] = bin2bcd(alm->time.tm_min);160 alarm_data[2] = bin2bcd(alm->time.tm_hour);161 alarm_data[3] = bin2bcd(alm->time.tm_mday);162 alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);163 alarm_data[5] = bin2bcd(alm->time.tm_year - 100);164 165 ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE,166 PALMAS_ALARM_SECONDS_REG, alarm_data, PALMAS_NUM_TIME_REGS);167 if (ret < 0) {168 dev_err(dev, "ALARM_SECONDS_REG write failed, err = %d\n", ret);169 return ret;170 }171 172 if (alm->enabled)173 ret = palmas_rtc_alarm_irq_enable(dev, 1);174 return ret;175}176 177static int palmas_clear_interrupts(struct device *dev)178{179 struct palmas *palmas = dev_get_drvdata(dev->parent);180 unsigned int rtc_reg;181 int ret;182 183 ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,184 &rtc_reg);185 if (ret < 0) {186 dev_err(dev, "RTC_STATUS read failed, err = %d\n", ret);187 return ret;188 }189 190 ret = palmas_write(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,191 rtc_reg);192 if (ret < 0) {193 dev_err(dev, "RTC_STATUS write failed, err = %d\n", ret);194 return ret;195 }196 return 0;197}198 199static irqreturn_t palmas_rtc_interrupt(int irq, void *context)200{201 struct palmas_rtc *palmas_rtc = context;202 struct device *dev = palmas_rtc->dev;203 int ret;204 205 ret = palmas_clear_interrupts(dev);206 if (ret < 0) {207 dev_err(dev, "RTC interrupt clear failed, err = %d\n", ret);208 return IRQ_NONE;209 }210 211 rtc_update_irq(palmas_rtc->rtc, 1, RTC_IRQF | RTC_AF);212 return IRQ_HANDLED;213}214 215static const struct rtc_class_ops palmas_rtc_ops = {216 .read_time = palmas_rtc_read_time,217 .set_time = palmas_rtc_set_time,218 .read_alarm = palmas_rtc_read_alarm,219 .set_alarm = palmas_rtc_set_alarm,220 .alarm_irq_enable = palmas_rtc_alarm_irq_enable,221};222 223static int palmas_rtc_probe(struct platform_device *pdev)224{225 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);226 struct palmas_rtc *palmas_rtc = NULL;227 int ret;228 bool enable_bb_charging = false;229 bool high_bb_charging = false;230 231 if (pdev->dev.of_node) {232 enable_bb_charging = of_property_read_bool(pdev->dev.of_node,233 "ti,backup-battery-chargeable");234 high_bb_charging = of_property_read_bool(pdev->dev.of_node,235 "ti,backup-battery-charge-high-current");236 }237 238 palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc),239 GFP_KERNEL);240 if (!palmas_rtc)241 return -ENOMEM;242 243 /* Clear pending interrupts */244 ret = palmas_clear_interrupts(&pdev->dev);245 if (ret < 0) {246 dev_err(&pdev->dev, "clear RTC int failed, err = %d\n", ret);247 return ret;248 }249 250 palmas_rtc->dev = &pdev->dev;251 platform_set_drvdata(pdev, palmas_rtc);252 253 if (enable_bb_charging) {254 unsigned reg = PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG;255 256 if (high_bb_charging)257 reg = 0;258 259 ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,260 PALMAS_BACKUP_BATTERY_CTRL,261 PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG, reg);262 if (ret < 0) {263 dev_err(&pdev->dev,264 "BACKUP_BATTERY_CTRL update failed, %d\n", ret);265 return ret;266 }267 268 ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,269 PALMAS_BACKUP_BATTERY_CTRL,270 PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN,271 PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN);272 if (ret < 0) {273 dev_err(&pdev->dev,274 "BACKUP_BATTERY_CTRL update failed, %d\n", ret);275 return ret;276 }277 }278 279 /* Start RTC */280 ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,281 PALMAS_RTC_CTRL_REG_STOP_RTC,282 PALMAS_RTC_CTRL_REG_STOP_RTC);283 if (ret < 0) {284 dev_err(&pdev->dev, "RTC_CTRL write failed, err = %d\n", ret);285 return ret;286 }287 288 palmas_rtc->irq = platform_get_irq(pdev, 0);289 290 device_init_wakeup(&pdev->dev, 1);291 palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,292 &palmas_rtc_ops, THIS_MODULE);293 if (IS_ERR(palmas_rtc->rtc)) {294 ret = PTR_ERR(palmas_rtc->rtc);295 dev_err(&pdev->dev, "RTC register failed, err = %d\n", ret);296 return ret;297 }298 299 ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL,300 palmas_rtc_interrupt,301 IRQF_TRIGGER_LOW | IRQF_ONESHOT,302 dev_name(&pdev->dev), palmas_rtc);303 if (ret < 0) {304 dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);305 return ret;306 }307 308 return 0;309}310 311static void palmas_rtc_remove(struct platform_device *pdev)312{313 palmas_rtc_alarm_irq_enable(&pdev->dev, 0);314}315 316#ifdef CONFIG_PM_SLEEP317static int palmas_rtc_suspend(struct device *dev)318{319 struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);320 321 if (device_may_wakeup(dev))322 enable_irq_wake(palmas_rtc->irq);323 return 0;324}325 326static int palmas_rtc_resume(struct device *dev)327{328 struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);329 330 if (device_may_wakeup(dev))331 disable_irq_wake(palmas_rtc->irq);332 return 0;333}334#endif335 336static SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend,337 palmas_rtc_resume);338 339#ifdef CONFIG_OF340static const struct of_device_id of_palmas_rtc_match[] = {341 { .compatible = "ti,palmas-rtc"},342 { },343};344MODULE_DEVICE_TABLE(of, of_palmas_rtc_match);345#endif346 347static struct platform_driver palmas_rtc_driver = {348 .probe = palmas_rtc_probe,349 .remove_new = palmas_rtc_remove,350 .driver = {351 .name = "palmas-rtc",352 .pm = &palmas_rtc_pm_ops,353 .of_match_table = of_match_ptr(of_palmas_rtc_match),354 },355};356 357module_platform_driver(palmas_rtc_driver);358 359MODULE_ALIAS("platform:palmas_rtc");360MODULE_DESCRIPTION("TI PALMAS series RTC driver");361MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");362MODULE_LICENSE("GPL v2");363