19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
290829c08SVenu Byravarasu /*
390829c08SVenu Byravarasu * rtc-rc5t583.c -- RICOH RC5T583 Real Time Clock
490829c08SVenu Byravarasu *
590829c08SVenu Byravarasu * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
690829c08SVenu Byravarasu * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
79952f691SThomas Gleixner */
890829c08SVenu Byravarasu
990829c08SVenu Byravarasu #include <linux/kernel.h>
1090829c08SVenu Byravarasu #include <linux/errno.h>
1190829c08SVenu Byravarasu #include <linux/init.h>
1290829c08SVenu Byravarasu #include <linux/module.h>
1390829c08SVenu Byravarasu #include <linux/types.h>
1490829c08SVenu Byravarasu #include <linux/rtc.h>
1590829c08SVenu Byravarasu #include <linux/bcd.h>
1690829c08SVenu Byravarasu #include <linux/platform_device.h>
1790829c08SVenu Byravarasu #include <linux/interrupt.h>
1890829c08SVenu Byravarasu #include <linux/mfd/rc5t583.h>
1990829c08SVenu Byravarasu
2090829c08SVenu Byravarasu struct rc5t583_rtc {
2190829c08SVenu Byravarasu struct rtc_device *rtc;
2290829c08SVenu Byravarasu /* To store the list of enabled interrupts, during system suspend */
2390829c08SVenu Byravarasu u32 irqen;
2490829c08SVenu Byravarasu };
2590829c08SVenu Byravarasu
2690829c08SVenu Byravarasu /* Total number of RTC registers needed to set time*/
2790829c08SVenu Byravarasu #define NUM_TIME_REGS (RC5T583_RTC_YEAR - RC5T583_RTC_SEC + 1)
2890829c08SVenu Byravarasu
2990829c08SVenu Byravarasu /* Total number of RTC registers needed to set Y-Alarm*/
3090829c08SVenu Byravarasu #define NUM_YAL_REGS (RC5T583_RTC_AY_YEAR - RC5T583_RTC_AY_MIN + 1)
3190829c08SVenu Byravarasu
3290829c08SVenu Byravarasu /* Set Y-Alarm interrupt */
3390829c08SVenu Byravarasu #define SET_YAL BIT(5)
3490829c08SVenu Byravarasu
3590829c08SVenu Byravarasu /* Get Y-Alarm interrupt status*/
3690829c08SVenu Byravarasu #define GET_YAL_STATUS BIT(3)
3790829c08SVenu Byravarasu
rc5t583_rtc_alarm_irq_enable(struct device * dev,unsigned enabled)3890829c08SVenu Byravarasu static int rc5t583_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
3990829c08SVenu Byravarasu {
4090829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
4190829c08SVenu Byravarasu u8 val;
4290829c08SVenu Byravarasu
4390829c08SVenu Byravarasu /* Set Y-Alarm, based on 'enabled' */
4490829c08SVenu Byravarasu val = enabled ? SET_YAL : 0;
4590829c08SVenu Byravarasu
4690829c08SVenu Byravarasu return regmap_update_bits(rc5t583->regmap, RC5T583_RTC_CTL1, SET_YAL,
4790829c08SVenu Byravarasu val);
4890829c08SVenu Byravarasu }
4990829c08SVenu Byravarasu
5090829c08SVenu Byravarasu /*
5190829c08SVenu Byravarasu * Gets current rc5t583 RTC time and date parameters.
5290829c08SVenu Byravarasu *
5390829c08SVenu Byravarasu * The RTC's time/alarm representation is not what gmtime(3) requires
5490829c08SVenu Byravarasu * Linux to use:
5590829c08SVenu Byravarasu *
5690829c08SVenu Byravarasu * - Months are 1..12 vs Linux 0-11
5790829c08SVenu Byravarasu * - Years are 0..99 vs Linux 1900..N (we assume 21st century)
5890829c08SVenu Byravarasu */
rc5t583_rtc_read_time(struct device * dev,struct rtc_time * tm)5990829c08SVenu Byravarasu static int rc5t583_rtc_read_time(struct device *dev, struct rtc_time *tm)
6090829c08SVenu Byravarasu {
6190829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
6290829c08SVenu Byravarasu u8 rtc_data[NUM_TIME_REGS];
6390829c08SVenu Byravarasu int ret;
6490829c08SVenu Byravarasu
6590829c08SVenu Byravarasu ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
6690829c08SVenu Byravarasu NUM_TIME_REGS);
6790829c08SVenu Byravarasu if (ret < 0) {
6890829c08SVenu Byravarasu dev_err(dev, "RTC read time failed with err:%d\n", ret);
6990829c08SVenu Byravarasu return ret;
7090829c08SVenu Byravarasu }
7190829c08SVenu Byravarasu
7290829c08SVenu Byravarasu tm->tm_sec = bcd2bin(rtc_data[0]);
7390829c08SVenu Byravarasu tm->tm_min = bcd2bin(rtc_data[1]);
7490829c08SVenu Byravarasu tm->tm_hour = bcd2bin(rtc_data[2]);
7590829c08SVenu Byravarasu tm->tm_wday = bcd2bin(rtc_data[3]);
7690829c08SVenu Byravarasu tm->tm_mday = bcd2bin(rtc_data[4]);
7790829c08SVenu Byravarasu tm->tm_mon = bcd2bin(rtc_data[5]) - 1;
7890829c08SVenu Byravarasu tm->tm_year = bcd2bin(rtc_data[6]) + 100;
7990829c08SVenu Byravarasu
8090829c08SVenu Byravarasu return ret;
8190829c08SVenu Byravarasu }
8290829c08SVenu Byravarasu
rc5t583_rtc_set_time(struct device * dev,struct rtc_time * tm)8390829c08SVenu Byravarasu static int rc5t583_rtc_set_time(struct device *dev, struct rtc_time *tm)
8490829c08SVenu Byravarasu {
8590829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
8690829c08SVenu Byravarasu unsigned char rtc_data[NUM_TIME_REGS];
8790829c08SVenu Byravarasu int ret;
8890829c08SVenu Byravarasu
8990829c08SVenu Byravarasu rtc_data[0] = bin2bcd(tm->tm_sec);
9090829c08SVenu Byravarasu rtc_data[1] = bin2bcd(tm->tm_min);
9190829c08SVenu Byravarasu rtc_data[2] = bin2bcd(tm->tm_hour);
9290829c08SVenu Byravarasu rtc_data[3] = bin2bcd(tm->tm_wday);
9390829c08SVenu Byravarasu rtc_data[4] = bin2bcd(tm->tm_mday);
9490829c08SVenu Byravarasu rtc_data[5] = bin2bcd(tm->tm_mon + 1);
9590829c08SVenu Byravarasu rtc_data[6] = bin2bcd(tm->tm_year - 100);
9690829c08SVenu Byravarasu
9790829c08SVenu Byravarasu ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
9890829c08SVenu Byravarasu NUM_TIME_REGS);
9990829c08SVenu Byravarasu if (ret < 0) {
10090829c08SVenu Byravarasu dev_err(dev, "RTC set time failed with error %d\n", ret);
10190829c08SVenu Byravarasu return ret;
10290829c08SVenu Byravarasu }
10390829c08SVenu Byravarasu
10490829c08SVenu Byravarasu return ret;
10590829c08SVenu Byravarasu }
10690829c08SVenu Byravarasu
rc5t583_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alm)10790829c08SVenu Byravarasu static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
10890829c08SVenu Byravarasu {
10990829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
11090829c08SVenu Byravarasu unsigned char alarm_data[NUM_YAL_REGS];
11190829c08SVenu Byravarasu u32 interrupt_enable;
11290829c08SVenu Byravarasu int ret;
11390829c08SVenu Byravarasu
11490829c08SVenu Byravarasu ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
11590829c08SVenu Byravarasu NUM_YAL_REGS);
11690829c08SVenu Byravarasu if (ret < 0) {
11790829c08SVenu Byravarasu dev_err(dev, "rtc_read_alarm error %d\n", ret);
11890829c08SVenu Byravarasu return ret;
11990829c08SVenu Byravarasu }
12090829c08SVenu Byravarasu
121d2c92705SUwe Kleine-König alm->time.tm_sec = 0;
12290829c08SVenu Byravarasu alm->time.tm_min = bcd2bin(alarm_data[0]);
12390829c08SVenu Byravarasu alm->time.tm_hour = bcd2bin(alarm_data[1]);
12490829c08SVenu Byravarasu alm->time.tm_mday = bcd2bin(alarm_data[2]);
12590829c08SVenu Byravarasu alm->time.tm_mon = bcd2bin(alarm_data[3]) - 1;
12690829c08SVenu Byravarasu alm->time.tm_year = bcd2bin(alarm_data[4]) + 100;
12790829c08SVenu Byravarasu
12890829c08SVenu Byravarasu ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1, &interrupt_enable);
12990829c08SVenu Byravarasu if (ret < 0)
13090829c08SVenu Byravarasu return ret;
13190829c08SVenu Byravarasu
13290829c08SVenu Byravarasu /* check if YALE is set */
13390829c08SVenu Byravarasu if (interrupt_enable & SET_YAL)
13490829c08SVenu Byravarasu alm->enabled = 1;
13590829c08SVenu Byravarasu
13690829c08SVenu Byravarasu return ret;
13790829c08SVenu Byravarasu }
13890829c08SVenu Byravarasu
rc5t583_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alm)13990829c08SVenu Byravarasu static int rc5t583_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
14090829c08SVenu Byravarasu {
14190829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
14290829c08SVenu Byravarasu unsigned char alarm_data[NUM_YAL_REGS];
14390829c08SVenu Byravarasu int ret;
14490829c08SVenu Byravarasu
14590829c08SVenu Byravarasu ret = rc5t583_rtc_alarm_irq_enable(dev, 0);
14690829c08SVenu Byravarasu if (ret)
14790829c08SVenu Byravarasu return ret;
14890829c08SVenu Byravarasu
14990829c08SVenu Byravarasu alarm_data[0] = bin2bcd(alm->time.tm_min);
15090829c08SVenu Byravarasu alarm_data[1] = bin2bcd(alm->time.tm_hour);
15190829c08SVenu Byravarasu alarm_data[2] = bin2bcd(alm->time.tm_mday);
15290829c08SVenu Byravarasu alarm_data[3] = bin2bcd(alm->time.tm_mon + 1);
15390829c08SVenu Byravarasu alarm_data[4] = bin2bcd(alm->time.tm_year - 100);
15490829c08SVenu Byravarasu
15590829c08SVenu Byravarasu ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
15690829c08SVenu Byravarasu NUM_YAL_REGS);
15790829c08SVenu Byravarasu if (ret) {
15890829c08SVenu Byravarasu dev_err(dev, "rtc_set_alarm error %d\n", ret);
15990829c08SVenu Byravarasu return ret;
16090829c08SVenu Byravarasu }
16190829c08SVenu Byravarasu
16290829c08SVenu Byravarasu if (alm->enabled)
16390829c08SVenu Byravarasu ret = rc5t583_rtc_alarm_irq_enable(dev, 1);
16490829c08SVenu Byravarasu
16590829c08SVenu Byravarasu return ret;
16690829c08SVenu Byravarasu }
16790829c08SVenu Byravarasu
rc5t583_rtc_interrupt(int irq,void * rtc)16890829c08SVenu Byravarasu static irqreturn_t rc5t583_rtc_interrupt(int irq, void *rtc)
16990829c08SVenu Byravarasu {
17090829c08SVenu Byravarasu struct device *dev = rtc;
17190829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
17290829c08SVenu Byravarasu struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
17390829c08SVenu Byravarasu unsigned long events = 0;
17490829c08SVenu Byravarasu int ret;
17590829c08SVenu Byravarasu u32 rtc_reg;
17690829c08SVenu Byravarasu
17790829c08SVenu Byravarasu ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL2, &rtc_reg);
17890829c08SVenu Byravarasu if (ret < 0)
17990829c08SVenu Byravarasu return IRQ_NONE;
18090829c08SVenu Byravarasu
18190829c08SVenu Byravarasu if (rtc_reg & GET_YAL_STATUS) {
18290829c08SVenu Byravarasu events = RTC_IRQF | RTC_AF;
18390829c08SVenu Byravarasu /* clear pending Y-alarm interrupt bit */
18490829c08SVenu Byravarasu rtc_reg &= ~GET_YAL_STATUS;
18590829c08SVenu Byravarasu }
18690829c08SVenu Byravarasu
18790829c08SVenu Byravarasu ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, rtc_reg);
18890829c08SVenu Byravarasu if (ret)
18990829c08SVenu Byravarasu return IRQ_NONE;
19090829c08SVenu Byravarasu
19190829c08SVenu Byravarasu /* Notify RTC core on event */
19290829c08SVenu Byravarasu rtc_update_irq(rc5t583_rtc->rtc, 1, events);
19390829c08SVenu Byravarasu
19490829c08SVenu Byravarasu return IRQ_HANDLED;
19590829c08SVenu Byravarasu }
19690829c08SVenu Byravarasu
19790829c08SVenu Byravarasu static const struct rtc_class_ops rc5t583_rtc_ops = {
19890829c08SVenu Byravarasu .read_time = rc5t583_rtc_read_time,
19990829c08SVenu Byravarasu .set_time = rc5t583_rtc_set_time,
20090829c08SVenu Byravarasu .read_alarm = rc5t583_rtc_read_alarm,
20190829c08SVenu Byravarasu .set_alarm = rc5t583_rtc_set_alarm,
20290829c08SVenu Byravarasu .alarm_irq_enable = rc5t583_rtc_alarm_irq_enable,
20390829c08SVenu Byravarasu };
20490829c08SVenu Byravarasu
rc5t583_rtc_probe(struct platform_device * pdev)2055a167f45SGreg Kroah-Hartman static int rc5t583_rtc_probe(struct platform_device *pdev)
20690829c08SVenu Byravarasu {
20790829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
20890829c08SVenu Byravarasu struct rc5t583_rtc *ricoh_rtc;
20990829c08SVenu Byravarasu struct rc5t583_platform_data *pmic_plat_data;
21090829c08SVenu Byravarasu int ret;
21190829c08SVenu Byravarasu int irq;
21290829c08SVenu Byravarasu
21390829c08SVenu Byravarasu ricoh_rtc = devm_kzalloc(&pdev->dev, sizeof(struct rc5t583_rtc),
21490829c08SVenu Byravarasu GFP_KERNEL);
21590829c08SVenu Byravarasu if (!ricoh_rtc)
21690829c08SVenu Byravarasu return -ENOMEM;
21790829c08SVenu Byravarasu
21890829c08SVenu Byravarasu platform_set_drvdata(pdev, ricoh_rtc);
21990829c08SVenu Byravarasu
22090829c08SVenu Byravarasu /* Clear pending interrupts */
22190829c08SVenu Byravarasu ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, 0);
22290829c08SVenu Byravarasu if (ret < 0)
22390829c08SVenu Byravarasu return ret;
22490829c08SVenu Byravarasu
22590829c08SVenu Byravarasu /* clear RTC Adjust register */
22690829c08SVenu Byravarasu ret = regmap_write(rc5t583->regmap, RC5T583_RTC_ADJ, 0);
22790829c08SVenu Byravarasu if (ret < 0) {
22890829c08SVenu Byravarasu dev_err(&pdev->dev, "unable to program rtc_adjust reg\n");
22990829c08SVenu Byravarasu return -EBUSY;
23090829c08SVenu Byravarasu }
23190829c08SVenu Byravarasu
23290829c08SVenu Byravarasu pmic_plat_data = dev_get_platdata(rc5t583->dev);
23390829c08SVenu Byravarasu irq = pmic_plat_data->irq_base;
23490829c08SVenu Byravarasu if (irq <= 0) {
23590829c08SVenu Byravarasu dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
23690829c08SVenu Byravarasu irq);
23790829c08SVenu Byravarasu return ret;
23890829c08SVenu Byravarasu }
23990829c08SVenu Byravarasu
24090829c08SVenu Byravarasu irq += RC5T583_IRQ_YALE;
24190829c08SVenu Byravarasu ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
24290829c08SVenu Byravarasu rc5t583_rtc_interrupt, IRQF_TRIGGER_LOW,
24390829c08SVenu Byravarasu "rtc-rc5t583", &pdev->dev);
24490829c08SVenu Byravarasu if (ret < 0) {
24590829c08SVenu Byravarasu dev_err(&pdev->dev, "IRQ is not free.\n");
24690829c08SVenu Byravarasu return ret;
24790829c08SVenu Byravarasu }
24890829c08SVenu Byravarasu device_init_wakeup(&pdev->dev, 1);
24990829c08SVenu Byravarasu
2508b7980dbSJingoo Han ricoh_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
25190829c08SVenu Byravarasu &rc5t583_rtc_ops, THIS_MODULE);
25290829c08SVenu Byravarasu if (IS_ERR(ricoh_rtc->rtc)) {
25390829c08SVenu Byravarasu ret = PTR_ERR(ricoh_rtc->rtc);
25490829c08SVenu Byravarasu dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
25590829c08SVenu Byravarasu return ret;
25690829c08SVenu Byravarasu }
25790829c08SVenu Byravarasu
25890829c08SVenu Byravarasu return 0;
25990829c08SVenu Byravarasu }
26090829c08SVenu Byravarasu
26190829c08SVenu Byravarasu /*
26290829c08SVenu Byravarasu * Disable rc5t583 RTC interrupts.
26390829c08SVenu Byravarasu * Sets status flag to free.
26490829c08SVenu Byravarasu */
rc5t583_rtc_remove(struct platform_device * pdev)265*ade527ddSUwe Kleine-König static void rc5t583_rtc_remove(struct platform_device *pdev)
26690829c08SVenu Byravarasu {
267e1c2f989SJingoo Han struct rc5t583_rtc *rc5t583_rtc = platform_get_drvdata(pdev);
26890829c08SVenu Byravarasu
26990829c08SVenu Byravarasu rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0);
27090829c08SVenu Byravarasu }
27190829c08SVenu Byravarasu
27290829c08SVenu Byravarasu #ifdef CONFIG_PM_SLEEP
rc5t583_rtc_suspend(struct device * dev)27390829c08SVenu Byravarasu static int rc5t583_rtc_suspend(struct device *dev)
27490829c08SVenu Byravarasu {
27590829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
27690829c08SVenu Byravarasu struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
27790829c08SVenu Byravarasu int ret;
27890829c08SVenu Byravarasu
27990829c08SVenu Byravarasu /* Store current list of enabled interrupts*/
28090829c08SVenu Byravarasu ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1,
28190829c08SVenu Byravarasu &rc5t583_rtc->irqen);
28290829c08SVenu Byravarasu return ret;
28390829c08SVenu Byravarasu }
28490829c08SVenu Byravarasu
rc5t583_rtc_resume(struct device * dev)28590829c08SVenu Byravarasu static int rc5t583_rtc_resume(struct device *dev)
28690829c08SVenu Byravarasu {
28790829c08SVenu Byravarasu struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
28890829c08SVenu Byravarasu struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
28990829c08SVenu Byravarasu
29090829c08SVenu Byravarasu /* Restore list of enabled interrupts before suspend */
29190829c08SVenu Byravarasu return regmap_write(rc5t583->regmap, RC5T583_RTC_CTL1,
29290829c08SVenu Byravarasu rc5t583_rtc->irqen);
29390829c08SVenu Byravarasu }
29490829c08SVenu Byravarasu #endif
29590829c08SVenu Byravarasu
29629756a52SJingoo Han static SIMPLE_DEV_PM_OPS(rc5t583_rtc_pm_ops, rc5t583_rtc_suspend,
29729756a52SJingoo Han rc5t583_rtc_resume);
29829756a52SJingoo Han
29990829c08SVenu Byravarasu static struct platform_driver rc5t583_rtc_driver = {
30090829c08SVenu Byravarasu .probe = rc5t583_rtc_probe,
301*ade527ddSUwe Kleine-König .remove_new = rc5t583_rtc_remove,
30290829c08SVenu Byravarasu .driver = {
30390829c08SVenu Byravarasu .name = "rtc-rc5t583",
30429756a52SJingoo Han .pm = &rc5t583_rtc_pm_ops,
30590829c08SVenu Byravarasu },
30690829c08SVenu Byravarasu };
30790829c08SVenu Byravarasu
30890829c08SVenu Byravarasu module_platform_driver(rc5t583_rtc_driver);
30990829c08SVenu Byravarasu MODULE_ALIAS("platform:rtc-rc5t583");
31090829c08SVenu Byravarasu MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
31190829c08SVenu Byravarasu MODULE_LICENSE("GPL v2");
312