18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2007-2009 ST-Ericsson AB
48c2ecf20Sopenharmony_ci * RTC clock driver for the AB3100 Analog Baseband Chip
58c2ecf20Sopenharmony_ci * Author: Linus Walleij <linus.walleij@stericsson.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
118c2ecf20Sopenharmony_ci#include <linux/rtc.h>
128c2ecf20Sopenharmony_ci#include <linux/mfd/abx500.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* Clock rate in Hz */
158c2ecf20Sopenharmony_ci#define AB3100_RTC_CLOCK_RATE	32768
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * The AB3100 RTC registers. These are the same for
198c2ecf20Sopenharmony_ci * AB3000 and AB3100.
208c2ecf20Sopenharmony_ci * Control register:
218c2ecf20Sopenharmony_ci * Bit 0: RTC Monitor cleared=0, active=1, if you set it
228c2ecf20Sopenharmony_ci *        to 1 it remains active until RTC power is lost.
238c2ecf20Sopenharmony_ci * Bit 1: 32 kHz Oscillator, 0 = on, 1 = bypass
248c2ecf20Sopenharmony_ci * Bit 2: Alarm on, 0 = off, 1 = on
258c2ecf20Sopenharmony_ci * Bit 3: 32 kHz buffer disabling, 0 = enabled, 1 = disabled
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci#define AB3100_RTC		0x53
288c2ecf20Sopenharmony_ci/* default setting, buffer disabled, alarm on */
298c2ecf20Sopenharmony_ci#define RTC_SETTING		0x30
308c2ecf20Sopenharmony_ci/* Alarm when AL0-AL3 == TI0-TI3  */
318c2ecf20Sopenharmony_ci#define AB3100_AL0		0x56
328c2ecf20Sopenharmony_ci#define AB3100_AL1		0x57
338c2ecf20Sopenharmony_ci#define AB3100_AL2		0x58
348c2ecf20Sopenharmony_ci#define AB3100_AL3		0x59
358c2ecf20Sopenharmony_ci/* This 48-bit register that counts up at 32768 Hz */
368c2ecf20Sopenharmony_ci#define AB3100_TI0		0x5a
378c2ecf20Sopenharmony_ci#define AB3100_TI1		0x5b
388c2ecf20Sopenharmony_ci#define AB3100_TI2		0x5c
398c2ecf20Sopenharmony_ci#define AB3100_TI3		0x5d
408c2ecf20Sopenharmony_ci#define AB3100_TI4		0x5e
418c2ecf20Sopenharmony_ci#define AB3100_TI5		0x5f
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * RTC clock functions and device struct declaration
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_cistatic int ab3100_rtc_set_time(struct device *dev, struct rtc_time *tm)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2,
498c2ecf20Sopenharmony_ci		     AB3100_TI3, AB3100_TI4, AB3100_TI5};
508c2ecf20Sopenharmony_ci	unsigned char buf[6];
518c2ecf20Sopenharmony_ci	u64 hw_counter = rtc_tm_to_time64(tm) * AB3100_RTC_CLOCK_RATE * 2;
528c2ecf20Sopenharmony_ci	int err = 0;
538c2ecf20Sopenharmony_ci	int i;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	buf[0] = (hw_counter) & 0xFF;
568c2ecf20Sopenharmony_ci	buf[1] = (hw_counter >> 8) & 0xFF;
578c2ecf20Sopenharmony_ci	buf[2] = (hw_counter >> 16) & 0xFF;
588c2ecf20Sopenharmony_ci	buf[3] = (hw_counter >> 24) & 0xFF;
598c2ecf20Sopenharmony_ci	buf[4] = (hw_counter >> 32) & 0xFF;
608c2ecf20Sopenharmony_ci	buf[5] = (hw_counter >> 40) & 0xFF;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
638c2ecf20Sopenharmony_ci		err = abx500_set_register_interruptible(dev, 0,
648c2ecf20Sopenharmony_ci							regs[i], buf[i]);
658c2ecf20Sopenharmony_ci		if (err)
668c2ecf20Sopenharmony_ci			return err;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* Set the flag to mark that the clock is now set */
708c2ecf20Sopenharmony_ci	return abx500_mask_and_set_register_interruptible(dev, 0,
718c2ecf20Sopenharmony_ci							  AB3100_RTC,
728c2ecf20Sopenharmony_ci							  0x01, 0x01);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	time64_t time;
798c2ecf20Sopenharmony_ci	u8 rtcval;
808c2ecf20Sopenharmony_ci	int err;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	err = abx500_get_register_interruptible(dev, 0,
838c2ecf20Sopenharmony_ci						AB3100_RTC, &rtcval);
848c2ecf20Sopenharmony_ci	if (err)
858c2ecf20Sopenharmony_ci		return err;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (!(rtcval & 0x01)) {
888c2ecf20Sopenharmony_ci		dev_info(dev, "clock not set (lost power)");
898c2ecf20Sopenharmony_ci		return -EINVAL;
908c2ecf20Sopenharmony_ci	} else {
918c2ecf20Sopenharmony_ci		u64 hw_counter;
928c2ecf20Sopenharmony_ci		u8 buf[6];
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		/* Read out time registers */
958c2ecf20Sopenharmony_ci		err = abx500_get_register_page_interruptible(dev, 0,
968c2ecf20Sopenharmony_ci							     AB3100_TI0,
978c2ecf20Sopenharmony_ci							     buf, 6);
988c2ecf20Sopenharmony_ci		if (err != 0)
998c2ecf20Sopenharmony_ci			return err;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		hw_counter = ((u64) buf[5] << 40) | ((u64) buf[4] << 32) |
1028c2ecf20Sopenharmony_ci			((u64) buf[3] << 24) | ((u64) buf[2] << 16) |
1038c2ecf20Sopenharmony_ci			((u64) buf[1] << 8) | (u64) buf[0];
1048c2ecf20Sopenharmony_ci		time = hw_counter / (u64) (AB3100_RTC_CLOCK_RATE * 2);
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	rtc_time64_to_tm(time, tm);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return 0;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	time64_t time;
1158c2ecf20Sopenharmony_ci	u64 hw_counter;
1168c2ecf20Sopenharmony_ci	u8 buf[6];
1178c2ecf20Sopenharmony_ci	u8 rtcval;
1188c2ecf20Sopenharmony_ci	int err;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/* Figure out if alarm is enabled or not */
1218c2ecf20Sopenharmony_ci	err = abx500_get_register_interruptible(dev, 0,
1228c2ecf20Sopenharmony_ci						AB3100_RTC, &rtcval);
1238c2ecf20Sopenharmony_ci	if (err)
1248c2ecf20Sopenharmony_ci		return err;
1258c2ecf20Sopenharmony_ci	if (rtcval & 0x04)
1268c2ecf20Sopenharmony_ci		alarm->enabled = 1;
1278c2ecf20Sopenharmony_ci	else
1288c2ecf20Sopenharmony_ci		alarm->enabled = 0;
1298c2ecf20Sopenharmony_ci	/* No idea how this could be represented */
1308c2ecf20Sopenharmony_ci	alarm->pending = 0;
1318c2ecf20Sopenharmony_ci	/* Read out alarm registers, only 4 bytes */
1328c2ecf20Sopenharmony_ci	err = abx500_get_register_page_interruptible(dev, 0,
1338c2ecf20Sopenharmony_ci						     AB3100_AL0, buf, 4);
1348c2ecf20Sopenharmony_ci	if (err)
1358c2ecf20Sopenharmony_ci		return err;
1368c2ecf20Sopenharmony_ci	hw_counter = ((u64) buf[3] << 40) | ((u64) buf[2] << 32) |
1378c2ecf20Sopenharmony_ci		((u64) buf[1] << 24) | ((u64) buf[0] << 16);
1388c2ecf20Sopenharmony_ci	time = hw_counter / (u64) (AB3100_RTC_CLOCK_RATE * 2);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	rtc_time64_to_tm(time, &alarm->time);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return rtc_valid_tm(&alarm->time);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	u8 regs[] = {AB3100_AL0, AB3100_AL1, AB3100_AL2, AB3100_AL3};
1488c2ecf20Sopenharmony_ci	unsigned char buf[4];
1498c2ecf20Sopenharmony_ci	time64_t secs;
1508c2ecf20Sopenharmony_ci	u64 hw_counter;
1518c2ecf20Sopenharmony_ci	int err;
1528c2ecf20Sopenharmony_ci	int i;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	secs = rtc_tm_to_time64(&alarm->time);
1558c2ecf20Sopenharmony_ci	hw_counter = secs * AB3100_RTC_CLOCK_RATE * 2;
1568c2ecf20Sopenharmony_ci	buf[0] = (hw_counter >> 16) & 0xFF;
1578c2ecf20Sopenharmony_ci	buf[1] = (hw_counter >> 24) & 0xFF;
1588c2ecf20Sopenharmony_ci	buf[2] = (hw_counter >> 32) & 0xFF;
1598c2ecf20Sopenharmony_ci	buf[3] = (hw_counter >> 40) & 0xFF;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Set the alarm */
1628c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
1638c2ecf20Sopenharmony_ci		err = abx500_set_register_interruptible(dev, 0,
1648c2ecf20Sopenharmony_ci							regs[i], buf[i]);
1658c2ecf20Sopenharmony_ci		if (err)
1668c2ecf20Sopenharmony_ci			return err;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci	/* Then enable the alarm */
1698c2ecf20Sopenharmony_ci	return abx500_mask_and_set_register_interruptible(dev, 0,
1708c2ecf20Sopenharmony_ci							  AB3100_RTC, (1 << 2),
1718c2ecf20Sopenharmony_ci							  alarm->enabled << 2);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	/*
1778c2ecf20Sopenharmony_ci	 * It's not possible to enable/disable the alarm IRQ for this RTC.
1788c2ecf20Sopenharmony_ci	 * It does not actually trigger any IRQ: instead its only function is
1798c2ecf20Sopenharmony_ci	 * to power up the system, if it wasn't on. This will manifest as
1808c2ecf20Sopenharmony_ci	 * a "power up cause" in the AB3100 power driver (battery charging etc)
1818c2ecf20Sopenharmony_ci	 * and need to be handled there instead.
1828c2ecf20Sopenharmony_ci	 */
1838c2ecf20Sopenharmony_ci	if (enabled)
1848c2ecf20Sopenharmony_ci		return abx500_mask_and_set_register_interruptible(dev, 0,
1858c2ecf20Sopenharmony_ci						    AB3100_RTC, (1 << 2),
1868c2ecf20Sopenharmony_ci						    1 << 2);
1878c2ecf20Sopenharmony_ci	else
1888c2ecf20Sopenharmony_ci		return abx500_mask_and_set_register_interruptible(dev, 0,
1898c2ecf20Sopenharmony_ci						    AB3100_RTC, (1 << 2),
1908c2ecf20Sopenharmony_ci						    0);
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic const struct rtc_class_ops ab3100_rtc_ops = {
1948c2ecf20Sopenharmony_ci	.read_time	= ab3100_rtc_read_time,
1958c2ecf20Sopenharmony_ci	.set_time	= ab3100_rtc_set_time,
1968c2ecf20Sopenharmony_ci	.read_alarm	= ab3100_rtc_read_alarm,
1978c2ecf20Sopenharmony_ci	.set_alarm	= ab3100_rtc_set_alarm,
1988c2ecf20Sopenharmony_ci	.alarm_irq_enable = ab3100_rtc_irq_enable,
1998c2ecf20Sopenharmony_ci};
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic int __init ab3100_rtc_probe(struct platform_device *pdev)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	int err;
2048c2ecf20Sopenharmony_ci	u8 regval;
2058c2ecf20Sopenharmony_ci	struct rtc_device *rtc;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* The first RTC register needs special treatment */
2088c2ecf20Sopenharmony_ci	err = abx500_get_register_interruptible(&pdev->dev, 0,
2098c2ecf20Sopenharmony_ci						AB3100_RTC, &regval);
2108c2ecf20Sopenharmony_ci	if (err) {
2118c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "unable to read RTC register\n");
2128c2ecf20Sopenharmony_ci		return -ENODEV;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if ((regval & 0xFE) != RTC_SETTING) {
2168c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "not default value in RTC reg 0x%x\n",
2178c2ecf20Sopenharmony_ci			 regval);
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if ((regval & 1) == 0) {
2218c2ecf20Sopenharmony_ci		/*
2228c2ecf20Sopenharmony_ci		 * Set bit to detect power loss.
2238c2ecf20Sopenharmony_ci		 * This bit remains until RTC power is lost.
2248c2ecf20Sopenharmony_ci		 */
2258c2ecf20Sopenharmony_ci		regval = 1 | RTC_SETTING;
2268c2ecf20Sopenharmony_ci		err = abx500_set_register_interruptible(&pdev->dev, 0,
2278c2ecf20Sopenharmony_ci							AB3100_RTC, regval);
2288c2ecf20Sopenharmony_ci		/* Ignore any error on this write */
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	rtc = devm_rtc_allocate_device(&pdev->dev);
2328c2ecf20Sopenharmony_ci	if (IS_ERR(rtc))
2338c2ecf20Sopenharmony_ci		return PTR_ERR(rtc);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	rtc->ops = &ab3100_rtc_ops;
2368c2ecf20Sopenharmony_ci	/* 48bit counter at (AB3100_RTC_CLOCK_RATE * 2) */
2378c2ecf20Sopenharmony_ci	rtc->range_max = U32_MAX;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, rtc);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return rtc_register_device(rtc);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic struct platform_driver ab3100_rtc_driver = {
2458c2ecf20Sopenharmony_ci	.driver = {
2468c2ecf20Sopenharmony_ci		.name = "ab3100-rtc",
2478c2ecf20Sopenharmony_ci	},
2488c2ecf20Sopenharmony_ci};
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cimodule_platform_driver_probe(ab3100_rtc_driver, ab3100_rtc_probe);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
2538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AB3100 RTC Driver");
2548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
255