253 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs4 *5 * Copyright (C) 2013 ams AG6 * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.7 *8 * Author: Florian Lobmaier <florian.lobmaier@ams.com>9 * Author: Laxman Dewangan <ldewangan@nvidia.com>10 */11 12#include <linux/bcd.h>13#include <linux/completion.h>14#include <linux/delay.h>15#include <linux/interrupt.h>16#include <linux/ioctl.h>17#include <linux/kernel.h>18#include <linux/module.h>19#include <linux/mfd/as3722.h>20#include <linux/platform_device.h>21#include <linux/rtc.h>22#include <linux/time.h>23 24#define AS3722_RTC_START_YEAR 200025struct as3722_rtc {26 struct rtc_device *rtc;27 struct device *dev;28 struct as3722 *as3722;29 int alarm_irq;30 bool irq_enable;31};32 33static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm)34{35 rbuff[0] = bin2bcd(tm->tm_sec);36 rbuff[1] = bin2bcd(tm->tm_min);37 rbuff[2] = bin2bcd(tm->tm_hour);38 rbuff[3] = bin2bcd(tm->tm_mday);39 rbuff[4] = bin2bcd(tm->tm_mon + 1);40 rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900));41}42 43static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm)44{45 tm->tm_sec = bcd2bin(rbuff[0] & 0x7F);46 tm->tm_min = bcd2bin(rbuff[1] & 0x7F);47 tm->tm_hour = bcd2bin(rbuff[2] & 0x3F);48 tm->tm_mday = bcd2bin(rbuff[3] & 0x3F);49 tm->tm_mon = bcd2bin(rbuff[4] & 0x1F) - 1;50 tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F);51 return;52}53 54static int as3722_rtc_read_time(struct device *dev, struct rtc_time *tm)55{56 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);57 struct as3722 *as3722 = as3722_rtc->as3722;58 u8 as_time_array[6];59 int ret;60 61 ret = as3722_block_read(as3722, AS3722_RTC_SECOND_REG,62 6, as_time_array);63 if (ret < 0) {64 dev_err(dev, "RTC_SECOND reg block read failed %d\n", ret);65 return ret;66 }67 as3722_reg_to_time(as_time_array, tm);68 return 0;69}70 71static int as3722_rtc_set_time(struct device *dev, struct rtc_time *tm)72{73 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);74 struct as3722 *as3722 = as3722_rtc->as3722;75 u8 as_time_array[6];76 int ret;77 78 if (tm->tm_year < (AS3722_RTC_START_YEAR - 1900))79 return -EINVAL;80 81 as3722_time_to_reg(as_time_array, tm);82 ret = as3722_block_write(as3722, AS3722_RTC_SECOND_REG, 6,83 as_time_array);84 if (ret < 0)85 dev_err(dev, "RTC_SECOND reg block write failed %d\n", ret);86 return ret;87}88 89static int as3722_rtc_alarm_irq_enable(struct device *dev,90 unsigned int enabled)91{92 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);93 94 if (enabled && !as3722_rtc->irq_enable) {95 enable_irq(as3722_rtc->alarm_irq);96 as3722_rtc->irq_enable = true;97 } else if (!enabled && as3722_rtc->irq_enable) {98 disable_irq(as3722_rtc->alarm_irq);99 as3722_rtc->irq_enable = false;100 }101 return 0;102}103 104static int as3722_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)105{106 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);107 struct as3722 *as3722 = as3722_rtc->as3722;108 u8 as_time_array[6];109 int ret;110 111 ret = as3722_block_read(as3722, AS3722_RTC_ALARM_SECOND_REG, 6,112 as_time_array);113 if (ret < 0) {114 dev_err(dev, "RTC_ALARM_SECOND block read failed %d\n", ret);115 return ret;116 }117 118 as3722_reg_to_time(as_time_array, &alrm->time);119 return 0;120}121 122static int as3722_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)123{124 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);125 struct as3722 *as3722 = as3722_rtc->as3722;126 u8 as_time_array[6];127 int ret;128 129 if (alrm->time.tm_year < (AS3722_RTC_START_YEAR - 1900))130 return -EINVAL;131 132 ret = as3722_rtc_alarm_irq_enable(dev, 0);133 if (ret < 0) {134 dev_err(dev, "Disable RTC alarm failed\n");135 return ret;136 }137 138 as3722_time_to_reg(as_time_array, &alrm->time);139 ret = as3722_block_write(as3722, AS3722_RTC_ALARM_SECOND_REG, 6,140 as_time_array);141 if (ret < 0) {142 dev_err(dev, "RTC_ALARM_SECOND block write failed %d\n", ret);143 return ret;144 }145 146 if (alrm->enabled)147 ret = as3722_rtc_alarm_irq_enable(dev, alrm->enabled);148 return ret;149}150 151static irqreturn_t as3722_alarm_irq(int irq, void *data)152{153 struct as3722_rtc *as3722_rtc = data;154 155 rtc_update_irq(as3722_rtc->rtc, 1, RTC_IRQF | RTC_AF);156 return IRQ_HANDLED;157}158 159static const struct rtc_class_ops as3722_rtc_ops = {160 .read_time = as3722_rtc_read_time,161 .set_time = as3722_rtc_set_time,162 .read_alarm = as3722_rtc_read_alarm,163 .set_alarm = as3722_rtc_set_alarm,164 .alarm_irq_enable = as3722_rtc_alarm_irq_enable,165};166 167static int as3722_rtc_probe(struct platform_device *pdev)168{169 struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);170 struct as3722_rtc *as3722_rtc;171 int ret;172 173 as3722_rtc = devm_kzalloc(&pdev->dev, sizeof(*as3722_rtc), GFP_KERNEL);174 if (!as3722_rtc)175 return -ENOMEM;176 177 as3722_rtc->as3722 = as3722;178 as3722_rtc->dev = &pdev->dev;179 platform_set_drvdata(pdev, as3722_rtc);180 181 /* Enable the RTC to make sure it is running. */182 ret = as3722_update_bits(as3722, AS3722_RTC_CONTROL_REG,183 AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN,184 AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN);185 if (ret < 0) {186 dev_err(&pdev->dev, "RTC_CONTROL reg write failed: %d\n", ret);187 return ret;188 }189 190 device_init_wakeup(&pdev->dev, 1);191 192 as3722_rtc->rtc = devm_rtc_device_register(&pdev->dev, "as3722-rtc",193 &as3722_rtc_ops, THIS_MODULE);194 if (IS_ERR(as3722_rtc->rtc)) {195 ret = PTR_ERR(as3722_rtc->rtc);196 dev_err(&pdev->dev, "RTC register failed: %d\n", ret);197 return ret;198 }199 200 as3722_rtc->alarm_irq = platform_get_irq(pdev, 0);201 dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq);202 203 ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL,204 as3722_alarm_irq, IRQF_ONESHOT,205 "rtc-alarm", as3722_rtc);206 if (ret < 0) {207 dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",208 as3722_rtc->alarm_irq, ret);209 return ret;210 }211 disable_irq(as3722_rtc->alarm_irq);212 return 0;213}214 215#ifdef CONFIG_PM_SLEEP216static int as3722_rtc_suspend(struct device *dev)217{218 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);219 220 if (device_may_wakeup(dev))221 enable_irq_wake(as3722_rtc->alarm_irq);222 223 return 0;224}225 226static int as3722_rtc_resume(struct device *dev)227{228 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);229 230 if (device_may_wakeup(dev))231 disable_irq_wake(as3722_rtc->alarm_irq);232 return 0;233}234#endif235 236static SIMPLE_DEV_PM_OPS(as3722_rtc_pm_ops, as3722_rtc_suspend,237 as3722_rtc_resume);238 239static struct platform_driver as3722_rtc_driver = {240 .probe = as3722_rtc_probe,241 .driver = {242 .name = "as3722-rtc",243 .pm = &as3722_rtc_pm_ops,244 },245};246module_platform_driver(as3722_rtc_driver);247 248MODULE_DESCRIPTION("RTC driver for AS3722 PMICs");249MODULE_ALIAS("platform:as3722-rtc");250MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>");251MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");252MODULE_LICENSE("GPL");253