18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * RTC driver for the Micro Crystal RV8803
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Micro Crystal SA
68c2ecf20Sopenharmony_ci * Alexandre Belloni <alexandre.belloni@bootlin.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/bcd.h>
118c2ecf20Sopenharmony_ci#include <linux/bitops.h>
128c2ecf20Sopenharmony_ci#include <linux/log2.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/of_device.h>
188c2ecf20Sopenharmony_ci#include <linux/rtc.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define RV8803_I2C_TRY_COUNT		4
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define RV8803_SEC			0x00
238c2ecf20Sopenharmony_ci#define RV8803_MIN			0x01
248c2ecf20Sopenharmony_ci#define RV8803_HOUR			0x02
258c2ecf20Sopenharmony_ci#define RV8803_WEEK			0x03
268c2ecf20Sopenharmony_ci#define RV8803_DAY			0x04
278c2ecf20Sopenharmony_ci#define RV8803_MONTH			0x05
288c2ecf20Sopenharmony_ci#define RV8803_YEAR			0x06
298c2ecf20Sopenharmony_ci#define RV8803_RAM			0x07
308c2ecf20Sopenharmony_ci#define RV8803_ALARM_MIN		0x08
318c2ecf20Sopenharmony_ci#define RV8803_ALARM_HOUR		0x09
328c2ecf20Sopenharmony_ci#define RV8803_ALARM_WEEK_OR_DAY	0x0A
338c2ecf20Sopenharmony_ci#define RV8803_EXT			0x0D
348c2ecf20Sopenharmony_ci#define RV8803_FLAG			0x0E
358c2ecf20Sopenharmony_ci#define RV8803_CTRL			0x0F
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define RV8803_EXT_WADA			BIT(6)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define RV8803_FLAG_V1F			BIT(0)
408c2ecf20Sopenharmony_ci#define RV8803_FLAG_V2F			BIT(1)
418c2ecf20Sopenharmony_ci#define RV8803_FLAG_AF			BIT(3)
428c2ecf20Sopenharmony_ci#define RV8803_FLAG_TF			BIT(4)
438c2ecf20Sopenharmony_ci#define RV8803_FLAG_UF			BIT(5)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define RV8803_CTRL_RESET		BIT(0)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define RV8803_CTRL_EIE			BIT(2)
488c2ecf20Sopenharmony_ci#define RV8803_CTRL_AIE			BIT(3)
498c2ecf20Sopenharmony_ci#define RV8803_CTRL_TIE			BIT(4)
508c2ecf20Sopenharmony_ci#define RV8803_CTRL_UIE			BIT(5)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define RX8900_BACKUP_CTRL		0x18
538c2ecf20Sopenharmony_ci#define RX8900_FLAG_SWOFF		BIT(2)
548c2ecf20Sopenharmony_ci#define RX8900_FLAG_VDETOFF		BIT(3)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cienum rv8803_type {
578c2ecf20Sopenharmony_ci	rv_8803,
588c2ecf20Sopenharmony_ci	rx_8900
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistruct rv8803_data {
628c2ecf20Sopenharmony_ci	struct i2c_client *client;
638c2ecf20Sopenharmony_ci	struct rtc_device *rtc;
648c2ecf20Sopenharmony_ci	struct mutex flags_lock;
658c2ecf20Sopenharmony_ci	u8 ctrl;
668c2ecf20Sopenharmony_ci	enum rv8803_type type;
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int rv8803_read_reg(const struct i2c_client *client, u8 reg)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	int try = RV8803_I2C_TRY_COUNT;
728c2ecf20Sopenharmony_ci	s32 ret;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/*
758c2ecf20Sopenharmony_ci	 * There is a 61µs window during which the RTC does not acknowledge I2C
768c2ecf20Sopenharmony_ci	 * transfers. In that case, ensure that there are multiple attempts.
778c2ecf20Sopenharmony_ci	 */
788c2ecf20Sopenharmony_ci	do
798c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, reg);
808c2ecf20Sopenharmony_ci	while ((ret == -ENXIO || ret == -EIO) && --try);
818c2ecf20Sopenharmony_ci	if (ret < 0)
828c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Unable to read register 0x%02x\n", reg);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return ret;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int rv8803_read_regs(const struct i2c_client *client,
888c2ecf20Sopenharmony_ci			    u8 reg, u8 count, u8 *values)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int try = RV8803_I2C_TRY_COUNT;
918c2ecf20Sopenharmony_ci	s32 ret;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	do
948c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_i2c_block_data(client, reg, count, values);
958c2ecf20Sopenharmony_ci	while ((ret == -ENXIO || ret == -EIO) && --try);
968c2ecf20Sopenharmony_ci	if (ret != count) {
978c2ecf20Sopenharmony_ci		dev_err(&client->dev,
988c2ecf20Sopenharmony_ci			"Unable to read registers 0x%02x..0x%02x\n",
998c2ecf20Sopenharmony_ci			reg, reg + count - 1);
1008c2ecf20Sopenharmony_ci		return ret < 0 ? ret : -EIO;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int rv8803_write_reg(const struct i2c_client *client, u8 reg, u8 value)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	int try = RV8803_I2C_TRY_COUNT;
1098c2ecf20Sopenharmony_ci	s32 ret;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	do
1128c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, reg, value);
1138c2ecf20Sopenharmony_ci	while ((ret == -ENXIO || ret == -EIO) && --try);
1148c2ecf20Sopenharmony_ci	if (ret)
1158c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Unable to write register 0x%02x\n", reg);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return ret;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int rv8803_write_regs(const struct i2c_client *client,
1218c2ecf20Sopenharmony_ci			     u8 reg, u8 count, const u8 *values)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	int try = RV8803_I2C_TRY_COUNT;
1248c2ecf20Sopenharmony_ci	s32 ret;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	do
1278c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_i2c_block_data(client, reg, count,
1288c2ecf20Sopenharmony_ci						     values);
1298c2ecf20Sopenharmony_ci	while ((ret == -ENXIO || ret == -EIO) && --try);
1308c2ecf20Sopenharmony_ci	if (ret)
1318c2ecf20Sopenharmony_ci		dev_err(&client->dev,
1328c2ecf20Sopenharmony_ci			"Unable to write registers 0x%02x..0x%02x\n",
1338c2ecf20Sopenharmony_ci			reg, reg + count - 1);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return ret;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct i2c_client *client = dev_id;
1418c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803 = i2c_get_clientdata(client);
1428c2ecf20Sopenharmony_ci	unsigned long events = 0;
1438c2ecf20Sopenharmony_ci	int flags;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	mutex_lock(&rv8803->flags_lock);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	flags = rv8803_read_reg(client, RV8803_FLAG);
1488c2ecf20Sopenharmony_ci	if (flags <= 0) {
1498c2ecf20Sopenharmony_ci		mutex_unlock(&rv8803->flags_lock);
1508c2ecf20Sopenharmony_ci		return IRQ_NONE;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_V1F)
1548c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "Voltage low, temperature compensation stopped.\n");
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_V2F)
1578c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "Voltage low, data loss detected.\n");
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_TF) {
1608c2ecf20Sopenharmony_ci		flags &= ~RV8803_FLAG_TF;
1618c2ecf20Sopenharmony_ci		rv8803->ctrl &= ~RV8803_CTRL_TIE;
1628c2ecf20Sopenharmony_ci		events |= RTC_PF;
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_AF) {
1668c2ecf20Sopenharmony_ci		flags &= ~RV8803_FLAG_AF;
1678c2ecf20Sopenharmony_ci		rv8803->ctrl &= ~RV8803_CTRL_AIE;
1688c2ecf20Sopenharmony_ci		events |= RTC_AF;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_UF) {
1728c2ecf20Sopenharmony_ci		flags &= ~RV8803_FLAG_UF;
1738c2ecf20Sopenharmony_ci		rv8803->ctrl &= ~RV8803_CTRL_UIE;
1748c2ecf20Sopenharmony_ci		events |= RTC_UF;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (events) {
1788c2ecf20Sopenharmony_ci		rtc_update_irq(rv8803->rtc, 1, events);
1798c2ecf20Sopenharmony_ci		rv8803_write_reg(client, RV8803_FLAG, flags);
1808c2ecf20Sopenharmony_ci		rv8803_write_reg(rv8803->client, RV8803_CTRL, rv8803->ctrl);
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	mutex_unlock(&rv8803->flags_lock);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int rv8803_get_time(struct device *dev, struct rtc_time *tm)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803 = dev_get_drvdata(dev);
1918c2ecf20Sopenharmony_ci	u8 date1[7];
1928c2ecf20Sopenharmony_ci	u8 date2[7];
1938c2ecf20Sopenharmony_ci	u8 *date = date1;
1948c2ecf20Sopenharmony_ci	int ret, flags;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
1978c2ecf20Sopenharmony_ci	if (flags < 0)
1988c2ecf20Sopenharmony_ci		return flags;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_V2F) {
2018c2ecf20Sopenharmony_ci		dev_warn(dev, "Voltage low, data is invalid.\n");
2028c2ecf20Sopenharmony_ci		return -EINVAL;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date);
2068c2ecf20Sopenharmony_ci	if (ret)
2078c2ecf20Sopenharmony_ci		return ret;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if ((date1[RV8803_SEC] & 0x7f) == bin2bcd(59)) {
2108c2ecf20Sopenharmony_ci		ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date2);
2118c2ecf20Sopenharmony_ci		if (ret)
2128c2ecf20Sopenharmony_ci			return ret;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		if ((date2[RV8803_SEC] & 0x7f) != bin2bcd(59))
2158c2ecf20Sopenharmony_ci			date = date2;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	tm->tm_sec  = bcd2bin(date[RV8803_SEC] & 0x7f);
2198c2ecf20Sopenharmony_ci	tm->tm_min  = bcd2bin(date[RV8803_MIN] & 0x7f);
2208c2ecf20Sopenharmony_ci	tm->tm_hour = bcd2bin(date[RV8803_HOUR] & 0x3f);
2218c2ecf20Sopenharmony_ci	tm->tm_wday = ilog2(date[RV8803_WEEK] & 0x7f);
2228c2ecf20Sopenharmony_ci	tm->tm_mday = bcd2bin(date[RV8803_DAY] & 0x3f);
2238c2ecf20Sopenharmony_ci	tm->tm_mon  = bcd2bin(date[RV8803_MONTH] & 0x1f) - 1;
2248c2ecf20Sopenharmony_ci	tm->tm_year = bcd2bin(date[RV8803_YEAR]) + 100;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int rv8803_set_time(struct device *dev, struct rtc_time *tm)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803 = dev_get_drvdata(dev);
2328c2ecf20Sopenharmony_ci	u8 date[7];
2338c2ecf20Sopenharmony_ci	int ctrl, flags, ret;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	ctrl = rv8803_read_reg(rv8803->client, RV8803_CTRL);
2368c2ecf20Sopenharmony_ci	if (ctrl < 0)
2378c2ecf20Sopenharmony_ci		return ctrl;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* Stop the clock */
2408c2ecf20Sopenharmony_ci	ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
2418c2ecf20Sopenharmony_ci			       ctrl | RV8803_CTRL_RESET);
2428c2ecf20Sopenharmony_ci	if (ret)
2438c2ecf20Sopenharmony_ci		return ret;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	date[RV8803_SEC]   = bin2bcd(tm->tm_sec);
2468c2ecf20Sopenharmony_ci	date[RV8803_MIN]   = bin2bcd(tm->tm_min);
2478c2ecf20Sopenharmony_ci	date[RV8803_HOUR]  = bin2bcd(tm->tm_hour);
2488c2ecf20Sopenharmony_ci	date[RV8803_WEEK]  = 1 << (tm->tm_wday);
2498c2ecf20Sopenharmony_ci	date[RV8803_DAY]   = bin2bcd(tm->tm_mday);
2508c2ecf20Sopenharmony_ci	date[RV8803_MONTH] = bin2bcd(tm->tm_mon + 1);
2518c2ecf20Sopenharmony_ci	date[RV8803_YEAR]  = bin2bcd(tm->tm_year - 100);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	ret = rv8803_write_regs(rv8803->client, RV8803_SEC, 7, date);
2548c2ecf20Sopenharmony_ci	if (ret)
2558c2ecf20Sopenharmony_ci		return ret;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* Restart the clock */
2588c2ecf20Sopenharmony_ci	ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
2598c2ecf20Sopenharmony_ci			       ctrl & ~RV8803_CTRL_RESET);
2608c2ecf20Sopenharmony_ci	if (ret)
2618c2ecf20Sopenharmony_ci		return ret;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	mutex_lock(&rv8803->flags_lock);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
2668c2ecf20Sopenharmony_ci	if (flags < 0) {
2678c2ecf20Sopenharmony_ci		mutex_unlock(&rv8803->flags_lock);
2688c2ecf20Sopenharmony_ci		return flags;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
2728c2ecf20Sopenharmony_ci			       flags & ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F));
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	mutex_unlock(&rv8803->flags_lock);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return ret;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803 = dev_get_drvdata(dev);
2828c2ecf20Sopenharmony_ci	struct i2c_client *client = rv8803->client;
2838c2ecf20Sopenharmony_ci	u8 alarmvals[3];
2848c2ecf20Sopenharmony_ci	int flags, ret;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	ret = rv8803_read_regs(client, RV8803_ALARM_MIN, 3, alarmvals);
2878c2ecf20Sopenharmony_ci	if (ret)
2888c2ecf20Sopenharmony_ci		return ret;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	flags = rv8803_read_reg(client, RV8803_FLAG);
2918c2ecf20Sopenharmony_ci	if (flags < 0)
2928c2ecf20Sopenharmony_ci		return flags;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	alrm->time.tm_sec  = 0;
2958c2ecf20Sopenharmony_ci	alrm->time.tm_min  = bcd2bin(alarmvals[0] & 0x7f);
2968c2ecf20Sopenharmony_ci	alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
2978c2ecf20Sopenharmony_ci	alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
3008c2ecf20Sopenharmony_ci	alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return 0;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
3088c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803 = dev_get_drvdata(dev);
3098c2ecf20Sopenharmony_ci	u8 alarmvals[3];
3108c2ecf20Sopenharmony_ci	u8 ctrl[2];
3118c2ecf20Sopenharmony_ci	int ret, err;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* The alarm has no seconds, round up to nearest minute */
3148c2ecf20Sopenharmony_ci	if (alrm->time.tm_sec) {
3158c2ecf20Sopenharmony_ci		time64_t alarm_time = rtc_tm_to_time64(&alrm->time);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		alarm_time += 60 - alrm->time.tm_sec;
3188c2ecf20Sopenharmony_ci		rtc_time64_to_tm(alarm_time, &alrm->time);
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	mutex_lock(&rv8803->flags_lock);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	ret = rv8803_read_regs(client, RV8803_FLAG, 2, ctrl);
3248c2ecf20Sopenharmony_ci	if (ret) {
3258c2ecf20Sopenharmony_ci		mutex_unlock(&rv8803->flags_lock);
3268c2ecf20Sopenharmony_ci		return ret;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	alarmvals[0] = bin2bcd(alrm->time.tm_min);
3308c2ecf20Sopenharmony_ci	alarmvals[1] = bin2bcd(alrm->time.tm_hour);
3318c2ecf20Sopenharmony_ci	alarmvals[2] = bin2bcd(alrm->time.tm_mday);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (rv8803->ctrl & (RV8803_CTRL_AIE | RV8803_CTRL_UIE)) {
3348c2ecf20Sopenharmony_ci		rv8803->ctrl &= ~(RV8803_CTRL_AIE | RV8803_CTRL_UIE);
3358c2ecf20Sopenharmony_ci		err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
3368c2ecf20Sopenharmony_ci				       rv8803->ctrl);
3378c2ecf20Sopenharmony_ci		if (err) {
3388c2ecf20Sopenharmony_ci			mutex_unlock(&rv8803->flags_lock);
3398c2ecf20Sopenharmony_ci			return err;
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	ctrl[1] &= ~RV8803_FLAG_AF;
3448c2ecf20Sopenharmony_ci	err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[1]);
3458c2ecf20Sopenharmony_ci	mutex_unlock(&rv8803->flags_lock);
3468c2ecf20Sopenharmony_ci	if (err)
3478c2ecf20Sopenharmony_ci		return err;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	err = rv8803_write_regs(rv8803->client, RV8803_ALARM_MIN, 3, alarmvals);
3508c2ecf20Sopenharmony_ci	if (err)
3518c2ecf20Sopenharmony_ci		return err;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (alrm->enabled) {
3548c2ecf20Sopenharmony_ci		if (rv8803->rtc->uie_rtctimer.enabled)
3558c2ecf20Sopenharmony_ci			rv8803->ctrl |= RV8803_CTRL_UIE;
3568c2ecf20Sopenharmony_ci		if (rv8803->rtc->aie_timer.enabled)
3578c2ecf20Sopenharmony_ci			rv8803->ctrl |= RV8803_CTRL_AIE;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
3608c2ecf20Sopenharmony_ci				       rv8803->ctrl);
3618c2ecf20Sopenharmony_ci		if (err)
3628c2ecf20Sopenharmony_ci			return err;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return 0;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
3718c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803 = dev_get_drvdata(dev);
3728c2ecf20Sopenharmony_ci	int ctrl, flags, err;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	ctrl = rv8803->ctrl;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (enabled) {
3778c2ecf20Sopenharmony_ci		if (rv8803->rtc->uie_rtctimer.enabled)
3788c2ecf20Sopenharmony_ci			ctrl |= RV8803_CTRL_UIE;
3798c2ecf20Sopenharmony_ci		if (rv8803->rtc->aie_timer.enabled)
3808c2ecf20Sopenharmony_ci			ctrl |= RV8803_CTRL_AIE;
3818c2ecf20Sopenharmony_ci	} else {
3828c2ecf20Sopenharmony_ci		if (!rv8803->rtc->uie_rtctimer.enabled)
3838c2ecf20Sopenharmony_ci			ctrl &= ~RV8803_CTRL_UIE;
3848c2ecf20Sopenharmony_ci		if (!rv8803->rtc->aie_timer.enabled)
3858c2ecf20Sopenharmony_ci			ctrl &= ~RV8803_CTRL_AIE;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	mutex_lock(&rv8803->flags_lock);
3898c2ecf20Sopenharmony_ci	flags = rv8803_read_reg(client, RV8803_FLAG);
3908c2ecf20Sopenharmony_ci	if (flags < 0) {
3918c2ecf20Sopenharmony_ci		mutex_unlock(&rv8803->flags_lock);
3928c2ecf20Sopenharmony_ci		return flags;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci	flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF);
3958c2ecf20Sopenharmony_ci	err = rv8803_write_reg(client, RV8803_FLAG, flags);
3968c2ecf20Sopenharmony_ci	mutex_unlock(&rv8803->flags_lock);
3978c2ecf20Sopenharmony_ci	if (err)
3988c2ecf20Sopenharmony_ci		return err;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (ctrl != rv8803->ctrl) {
4018c2ecf20Sopenharmony_ci		rv8803->ctrl = ctrl;
4028c2ecf20Sopenharmony_ci		err = rv8803_write_reg(client, RV8803_CTRL, rv8803->ctrl);
4038c2ecf20Sopenharmony_ci		if (err)
4048c2ecf20Sopenharmony_ci			return err;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	return 0;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
4138c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803 = dev_get_drvdata(dev);
4148c2ecf20Sopenharmony_ci	unsigned int vl = 0;
4158c2ecf20Sopenharmony_ci	int flags, ret = 0;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	switch (cmd) {
4188c2ecf20Sopenharmony_ci	case RTC_VL_READ:
4198c2ecf20Sopenharmony_ci		flags = rv8803_read_reg(client, RV8803_FLAG);
4208c2ecf20Sopenharmony_ci		if (flags < 0)
4218c2ecf20Sopenharmony_ci			return flags;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		if (flags & RV8803_FLAG_V1F) {
4248c2ecf20Sopenharmony_ci			dev_warn(&client->dev, "Voltage low, temperature compensation stopped.\n");
4258c2ecf20Sopenharmony_ci			vl = RTC_VL_ACCURACY_LOW;
4268c2ecf20Sopenharmony_ci		}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		if (flags & RV8803_FLAG_V2F)
4298c2ecf20Sopenharmony_ci			vl |= RTC_VL_DATA_INVALID;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		return put_user(vl, (unsigned int __user *)arg);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	case RTC_VL_CLR:
4348c2ecf20Sopenharmony_ci		mutex_lock(&rv8803->flags_lock);
4358c2ecf20Sopenharmony_ci		flags = rv8803_read_reg(client, RV8803_FLAG);
4368c2ecf20Sopenharmony_ci		if (flags < 0) {
4378c2ecf20Sopenharmony_ci			mutex_unlock(&rv8803->flags_lock);
4388c2ecf20Sopenharmony_ci			return flags;
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		flags &= ~RV8803_FLAG_V1F;
4428c2ecf20Sopenharmony_ci		ret = rv8803_write_reg(client, RV8803_FLAG, flags);
4438c2ecf20Sopenharmony_ci		mutex_unlock(&rv8803->flags_lock);
4448c2ecf20Sopenharmony_ci		if (ret)
4458c2ecf20Sopenharmony_ci			return ret;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		return 0;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	default:
4508c2ecf20Sopenharmony_ci		return -ENOIOCTLCMD;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int rv8803_nvram_write(void *priv, unsigned int offset, void *val,
4558c2ecf20Sopenharmony_ci			      size_t bytes)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	return rv8803_write_reg(priv, RV8803_RAM, *(u8 *)val);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int rv8803_nvram_read(void *priv, unsigned int offset,
4618c2ecf20Sopenharmony_ci			     void *val, size_t bytes)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	int ret;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	ret = rv8803_read_reg(priv, RV8803_RAM);
4668c2ecf20Sopenharmony_ci	if (ret < 0)
4678c2ecf20Sopenharmony_ci		return ret;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	*(u8 *)val = ret;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic struct rtc_class_ops rv8803_rtc_ops = {
4758c2ecf20Sopenharmony_ci	.read_time = rv8803_get_time,
4768c2ecf20Sopenharmony_ci	.set_time = rv8803_set_time,
4778c2ecf20Sopenharmony_ci	.ioctl = rv8803_ioctl,
4788c2ecf20Sopenharmony_ci};
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int rx8900_trickle_charger_init(struct rv8803_data *rv8803)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct i2c_client *client = rv8803->client;
4838c2ecf20Sopenharmony_ci	struct device_node *node = client->dev.of_node;
4848c2ecf20Sopenharmony_ci	int err;
4858c2ecf20Sopenharmony_ci	u8 flags;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (!node)
4888c2ecf20Sopenharmony_ci		return 0;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (rv8803->type != rx_8900)
4918c2ecf20Sopenharmony_ci		return 0;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	err = i2c_smbus_read_byte_data(rv8803->client, RX8900_BACKUP_CTRL);
4948c2ecf20Sopenharmony_ci	if (err < 0)
4958c2ecf20Sopenharmony_ci		return err;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	flags = ~(RX8900_FLAG_VDETOFF | RX8900_FLAG_SWOFF) & (u8)err;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (of_property_read_bool(node, "epson,vdet-disable"))
5008c2ecf20Sopenharmony_ci		flags |= RX8900_FLAG_VDETOFF;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (of_property_read_bool(node, "trickle-diode-disable"))
5038c2ecf20Sopenharmony_ci		flags |= RX8900_FLAG_SWOFF;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(rv8803->client, RX8900_BACKUP_CTRL,
5068c2ecf20Sopenharmony_ci					 flags);
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int rv8803_probe(struct i2c_client *client,
5108c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
5138c2ecf20Sopenharmony_ci	struct rv8803_data *rv8803;
5148c2ecf20Sopenharmony_ci	int err, flags;
5158c2ecf20Sopenharmony_ci	struct nvmem_config nvmem_cfg = {
5168c2ecf20Sopenharmony_ci		.name = "rv8803_nvram",
5178c2ecf20Sopenharmony_ci		.word_size = 1,
5188c2ecf20Sopenharmony_ci		.stride = 1,
5198c2ecf20Sopenharmony_ci		.size = 1,
5208c2ecf20Sopenharmony_ci		.reg_read = rv8803_nvram_read,
5218c2ecf20Sopenharmony_ci		.reg_write = rv8803_nvram_write,
5228c2ecf20Sopenharmony_ci		.priv = client,
5238c2ecf20Sopenharmony_ci	};
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
5268c2ecf20Sopenharmony_ci				     I2C_FUNC_SMBUS_I2C_BLOCK)) {
5278c2ecf20Sopenharmony_ci		dev_err(&adapter->dev, "doesn't support I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK\n");
5288c2ecf20Sopenharmony_ci		return -EIO;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	rv8803 = devm_kzalloc(&client->dev, sizeof(struct rv8803_data),
5328c2ecf20Sopenharmony_ci			      GFP_KERNEL);
5338c2ecf20Sopenharmony_ci	if (!rv8803)
5348c2ecf20Sopenharmony_ci		return -ENOMEM;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	mutex_init(&rv8803->flags_lock);
5378c2ecf20Sopenharmony_ci	rv8803->client = client;
5388c2ecf20Sopenharmony_ci	if (client->dev.of_node)
5398c2ecf20Sopenharmony_ci		rv8803->type = (enum rv8803_type)
5408c2ecf20Sopenharmony_ci			of_device_get_match_data(&client->dev);
5418c2ecf20Sopenharmony_ci	else
5428c2ecf20Sopenharmony_ci		rv8803->type = id->driver_data;
5438c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, rv8803);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	flags = rv8803_read_reg(client, RV8803_FLAG);
5468c2ecf20Sopenharmony_ci	if (flags < 0)
5478c2ecf20Sopenharmony_ci		return flags;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_V1F)
5508c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "Voltage low, temperature compensation stopped.\n");
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_V2F)
5538c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "Voltage low, data loss detected.\n");
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	if (flags & RV8803_FLAG_AF)
5568c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "An alarm maybe have been missed.\n");
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	rv8803->rtc = devm_rtc_allocate_device(&client->dev);
5598c2ecf20Sopenharmony_ci	if (IS_ERR(rv8803->rtc))
5608c2ecf20Sopenharmony_ci		return PTR_ERR(rv8803->rtc);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (client->irq > 0) {
5638c2ecf20Sopenharmony_ci		err = devm_request_threaded_irq(&client->dev, client->irq,
5648c2ecf20Sopenharmony_ci						NULL, rv8803_handle_irq,
5658c2ecf20Sopenharmony_ci						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
5668c2ecf20Sopenharmony_ci						"rv8803", client);
5678c2ecf20Sopenharmony_ci		if (err) {
5688c2ecf20Sopenharmony_ci			dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
5698c2ecf20Sopenharmony_ci			client->irq = 0;
5708c2ecf20Sopenharmony_ci		} else {
5718c2ecf20Sopenharmony_ci			rv8803_rtc_ops.read_alarm = rv8803_get_alarm;
5728c2ecf20Sopenharmony_ci			rv8803_rtc_ops.set_alarm = rv8803_set_alarm;
5738c2ecf20Sopenharmony_ci			rv8803_rtc_ops.alarm_irq_enable = rv8803_alarm_irq_enable;
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
5788c2ecf20Sopenharmony_ci	if (err)
5798c2ecf20Sopenharmony_ci		return err;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	err = rx8900_trickle_charger_init(rv8803);
5828c2ecf20Sopenharmony_ci	if (err) {
5838c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed to init charger\n");
5848c2ecf20Sopenharmony_ci		return err;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	rv8803->rtc->ops = &rv8803_rtc_ops;
5888c2ecf20Sopenharmony_ci	rv8803->rtc->nvram_old_abi = true;
5898c2ecf20Sopenharmony_ci	rv8803->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
5908c2ecf20Sopenharmony_ci	rv8803->rtc->range_max = RTC_TIMESTAMP_END_2099;
5918c2ecf20Sopenharmony_ci	err = rtc_register_device(rv8803->rtc);
5928c2ecf20Sopenharmony_ci	if (err)
5938c2ecf20Sopenharmony_ci		return err;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	rtc_nvmem_register(rv8803->rtc, &nvmem_cfg);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	rv8803->rtc->max_user_freq = 1;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	return 0;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic const struct i2c_device_id rv8803_id[] = {
6038c2ecf20Sopenharmony_ci	{ "rv8803", rv_8803 },
6048c2ecf20Sopenharmony_ci	{ "rx8803", rv_8803 },
6058c2ecf20Sopenharmony_ci	{ "rx8900", rx_8900 },
6068c2ecf20Sopenharmony_ci	{ }
6078c2ecf20Sopenharmony_ci};
6088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, rv8803_id);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic const struct of_device_id rv8803_of_match[] = {
6118c2ecf20Sopenharmony_ci	{
6128c2ecf20Sopenharmony_ci		.compatible = "microcrystal,rv8803",
6138c2ecf20Sopenharmony_ci		.data = (void *)rv_8803
6148c2ecf20Sopenharmony_ci	},
6158c2ecf20Sopenharmony_ci	{
6168c2ecf20Sopenharmony_ci		.compatible = "epson,rx8803",
6178c2ecf20Sopenharmony_ci		.data = (void *)rv_8803
6188c2ecf20Sopenharmony_ci	},
6198c2ecf20Sopenharmony_ci	{
6208c2ecf20Sopenharmony_ci		.compatible = "epson,rx8900",
6218c2ecf20Sopenharmony_ci		.data = (void *)rx_8900
6228c2ecf20Sopenharmony_ci	},
6238c2ecf20Sopenharmony_ci	{ }
6248c2ecf20Sopenharmony_ci};
6258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rv8803_of_match);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_cistatic struct i2c_driver rv8803_driver = {
6288c2ecf20Sopenharmony_ci	.driver = {
6298c2ecf20Sopenharmony_ci		.name = "rtc-rv8803",
6308c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(rv8803_of_match),
6318c2ecf20Sopenharmony_ci	},
6328c2ecf20Sopenharmony_ci	.probe		= rv8803_probe,
6338c2ecf20Sopenharmony_ci	.id_table	= rv8803_id,
6348c2ecf20Sopenharmony_ci};
6358c2ecf20Sopenharmony_cimodule_i2c_driver(rv8803_driver);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
6388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Micro Crystal RV8803 RTC driver");
6398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
640