18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for Epson's RTC module RX-8025 SA/NB
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2005 by Digi International Inc.
88c2ecf20Sopenharmony_ci * All rights reserved.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Modified by fengjh at rising.com.cn
118c2ecf20Sopenharmony_ci * <lm-sensors@lm-sensors.org>
128c2ecf20Sopenharmony_ci * 2006.11
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Code cleanup by Sergei Poselenov, <sposelenov@emcraft.com>
158c2ecf20Sopenharmony_ci * Converted to new style by Wolfgang Grandegger <wg@grandegger.com>
168c2ecf20Sopenharmony_ci * Alarm and periodic interrupt added by Dmitry Rakhchev <rda@emcraft.com>
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci#include <linux/bcd.h>
198c2ecf20Sopenharmony_ci#include <linux/bitops.h>
208c2ecf20Sopenharmony_ci#include <linux/i2c.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/module.h>
238c2ecf20Sopenharmony_ci#include <linux/rtc.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Register definitions */
268c2ecf20Sopenharmony_ci#define RX8025_REG_SEC		0x00
278c2ecf20Sopenharmony_ci#define RX8025_REG_MIN		0x01
288c2ecf20Sopenharmony_ci#define RX8025_REG_HOUR		0x02
298c2ecf20Sopenharmony_ci#define RX8025_REG_WDAY		0x03
308c2ecf20Sopenharmony_ci#define RX8025_REG_MDAY		0x04
318c2ecf20Sopenharmony_ci#define RX8025_REG_MONTH	0x05
328c2ecf20Sopenharmony_ci#define RX8025_REG_YEAR		0x06
338c2ecf20Sopenharmony_ci#define RX8025_REG_DIGOFF	0x07
348c2ecf20Sopenharmony_ci#define RX8025_REG_ALWMIN	0x08
358c2ecf20Sopenharmony_ci#define RX8025_REG_ALWHOUR	0x09
368c2ecf20Sopenharmony_ci#define RX8025_REG_ALWWDAY	0x0a
378c2ecf20Sopenharmony_ci#define RX8025_REG_ALDMIN	0x0b
388c2ecf20Sopenharmony_ci#define RX8025_REG_ALDHOUR	0x0c
398c2ecf20Sopenharmony_ci/* 0x0d is reserved */
408c2ecf20Sopenharmony_ci#define RX8025_REG_CTRL1	0x0e
418c2ecf20Sopenharmony_ci#define RX8025_REG_CTRL2	0x0f
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL1_CT	(7 << 0)
448c2ecf20Sopenharmony_ci/* 1 Hz periodic level irq */
458c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL1_CT_1HZ	4
468c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL1_TEST	BIT(3)
478c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL1_1224	BIT(5)
488c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL1_DALE	BIT(6)
498c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL1_WALE	BIT(7)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL2_DAFG	BIT(0)
528c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL2_WAFG	BIT(1)
538c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL2_CTFG	BIT(2)
548c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL2_PON	BIT(4)
558c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL2_XST	BIT(5)
568c2ecf20Sopenharmony_ci#define RX8025_BIT_CTRL2_VDET	BIT(6)
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* Clock precision adjustment */
598c2ecf20Sopenharmony_ci#define RX8025_ADJ_RESOLUTION	3050 /* in ppb */
608c2ecf20Sopenharmony_ci#define RX8025_ADJ_DATA_MAX	62
618c2ecf20Sopenharmony_ci#define RX8025_ADJ_DATA_MIN	-62
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic const struct i2c_device_id rx8025_id[] = {
648c2ecf20Sopenharmony_ci	{ "rx8025", 0 },
658c2ecf20Sopenharmony_ci	{ }
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, rx8025_id);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct rx8025_data {
708c2ecf20Sopenharmony_ci	struct rtc_device *rtc;
718c2ecf20Sopenharmony_ci	u8 ctrl1;
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic s32 rx8025_read_reg(const struct i2c_client *client, u8 number)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	return i2c_smbus_read_byte_data(client, number << 4);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int rx8025_read_regs(const struct i2c_client *client,
808c2ecf20Sopenharmony_ci			    u8 number, u8 length, u8 *values)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	int ret = i2c_smbus_read_i2c_block_data(client, number << 4, length,
838c2ecf20Sopenharmony_ci						values);
848c2ecf20Sopenharmony_ci	if (ret != length)
858c2ecf20Sopenharmony_ci		return ret < 0 ? ret : -EIO;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return 0;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic s32 rx8025_write_reg(const struct i2c_client *client, u8 number,
918c2ecf20Sopenharmony_ci			    u8 value)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(client, number << 4, value);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic s32 rx8025_write_regs(const struct i2c_client *client,
978c2ecf20Sopenharmony_ci			     u8 number, u8 length, const u8 *values)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	return i2c_smbus_write_i2c_block_data(client, number << 4,
1008c2ecf20Sopenharmony_ci					      length, values);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int rx8025_check_validity(struct device *dev)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
1068c2ecf20Sopenharmony_ci	int ctrl2;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2);
1098c2ecf20Sopenharmony_ci	if (ctrl2 < 0)
1108c2ecf20Sopenharmony_ci		return ctrl2;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (ctrl2 & RX8025_BIT_CTRL2_VDET)
1138c2ecf20Sopenharmony_ci		dev_warn(dev, "power voltage drop detected\n");
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (ctrl2 & RX8025_BIT_CTRL2_PON) {
1168c2ecf20Sopenharmony_ci		dev_warn(dev, "power-on reset detected, date is invalid\n");
1178c2ecf20Sopenharmony_ci		return -EINVAL;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (!(ctrl2 & RX8025_BIT_CTRL2_XST)) {
1218c2ecf20Sopenharmony_ci		dev_warn(dev, "crystal stopped, date is invalid\n");
1228c2ecf20Sopenharmony_ci		return -EINVAL;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	return 0;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic int rx8025_reset_validity(struct i2c_client *client)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (ctrl2 < 0)
1338c2ecf20Sopenharmony_ci		return ctrl2;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return rx8025_write_reg(client, RX8025_REG_CTRL2,
1388c2ecf20Sopenharmony_ci				ctrl2 | RX8025_BIT_CTRL2_XST);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct i2c_client *client = dev_id;
1448c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025 = i2c_get_clientdata(client);
1458c2ecf20Sopenharmony_ci	struct mutex *lock = &rx8025->rtc->ops_lock;
1468c2ecf20Sopenharmony_ci	int status;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	mutex_lock(lock);
1498c2ecf20Sopenharmony_ci	status = rx8025_read_reg(client, RX8025_REG_CTRL2);
1508c2ecf20Sopenharmony_ci	if (status < 0)
1518c2ecf20Sopenharmony_ci		goto out;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (!(status & RX8025_BIT_CTRL2_XST))
1548c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "Oscillation stop was detected,"
1558c2ecf20Sopenharmony_ci			 "you may have to readjust the clock\n");
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (status & RX8025_BIT_CTRL2_CTFG) {
1588c2ecf20Sopenharmony_ci		/* periodic */
1598c2ecf20Sopenharmony_ci		status &= ~RX8025_BIT_CTRL2_CTFG;
1608c2ecf20Sopenharmony_ci		rtc_update_irq(rx8025->rtc, 1, RTC_PF | RTC_IRQF);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (status & RX8025_BIT_CTRL2_DAFG) {
1648c2ecf20Sopenharmony_ci		/* alarm */
1658c2ecf20Sopenharmony_ci		status &= RX8025_BIT_CTRL2_DAFG;
1668c2ecf20Sopenharmony_ci		if (rx8025_write_reg(client, RX8025_REG_CTRL1,
1678c2ecf20Sopenharmony_ci				     rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE))
1688c2ecf20Sopenharmony_ci			goto out;
1698c2ecf20Sopenharmony_ci		rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ciout:
1738c2ecf20Sopenharmony_ci	mutex_unlock(lock);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int rx8025_get_time(struct device *dev, struct rtc_time *dt)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
1818c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025 = dev_get_drvdata(dev);
1828c2ecf20Sopenharmony_ci	u8 date[7];
1838c2ecf20Sopenharmony_ci	int err;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	err = rx8025_check_validity(dev);
1868c2ecf20Sopenharmony_ci	if (err)
1878c2ecf20Sopenharmony_ci		return err;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	err = rx8025_read_regs(client, RX8025_REG_SEC, 7, date);
1908c2ecf20Sopenharmony_ci	if (err)
1918c2ecf20Sopenharmony_ci		return err;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: read %7ph\n", __func__, date);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	dt->tm_sec = bcd2bin(date[RX8025_REG_SEC] & 0x7f);
1968c2ecf20Sopenharmony_ci	dt->tm_min = bcd2bin(date[RX8025_REG_MIN] & 0x7f);
1978c2ecf20Sopenharmony_ci	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)
1988c2ecf20Sopenharmony_ci		dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x3f);
1998c2ecf20Sopenharmony_ci	else
2008c2ecf20Sopenharmony_ci		dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x1f) % 12
2018c2ecf20Sopenharmony_ci			+ (date[RX8025_REG_HOUR] & 0x20 ? 12 : 0);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f);
2048c2ecf20Sopenharmony_ci	dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1;
2058c2ecf20Sopenharmony_ci	dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: date %ptRr\n", __func__, dt);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic int rx8025_set_time(struct device *dev, struct rtc_time *dt)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
2158c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025 = dev_get_drvdata(dev);
2168c2ecf20Sopenharmony_ci	u8 date[7];
2178c2ecf20Sopenharmony_ci	int ret;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if ((dt->tm_year < 100) || (dt->tm_year > 199))
2208c2ecf20Sopenharmony_ci		return -EINVAL;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/*
2238c2ecf20Sopenharmony_ci	 * Here the read-only bits are written as "0".  I'm not sure if that
2248c2ecf20Sopenharmony_ci	 * is sound.
2258c2ecf20Sopenharmony_ci	 */
2268c2ecf20Sopenharmony_ci	date[RX8025_REG_SEC] = bin2bcd(dt->tm_sec);
2278c2ecf20Sopenharmony_ci	date[RX8025_REG_MIN] = bin2bcd(dt->tm_min);
2288c2ecf20Sopenharmony_ci	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)
2298c2ecf20Sopenharmony_ci		date[RX8025_REG_HOUR] = bin2bcd(dt->tm_hour);
2308c2ecf20Sopenharmony_ci	else
2318c2ecf20Sopenharmony_ci		date[RX8025_REG_HOUR] = (dt->tm_hour >= 12 ? 0x20 : 0)
2328c2ecf20Sopenharmony_ci			| bin2bcd((dt->tm_hour + 11) % 12 + 1);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday);
2358c2ecf20Sopenharmony_ci	date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday);
2368c2ecf20Sopenharmony_ci	date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1);
2378c2ecf20Sopenharmony_ci	date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: write %7ph\n", __func__, date);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	ret = rx8025_write_regs(client, RX8025_REG_SEC, 7, date);
2428c2ecf20Sopenharmony_ci	if (ret < 0)
2438c2ecf20Sopenharmony_ci		return ret;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return rx8025_reset_validity(client);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int rx8025_init_client(struct i2c_client *client)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025 = i2c_get_clientdata(client);
2518c2ecf20Sopenharmony_ci	u8 ctrl[2], ctrl2;
2528c2ecf20Sopenharmony_ci	int need_clear = 0;
2538c2ecf20Sopenharmony_ci	int err;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	err = rx8025_read_regs(client, RX8025_REG_CTRL1, 2, ctrl);
2568c2ecf20Sopenharmony_ci	if (err)
2578c2ecf20Sopenharmony_ci		goto out;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* Keep test bit zero ! */
2608c2ecf20Sopenharmony_ci	rx8025->ctrl1 = ctrl[0] & ~RX8025_BIT_CTRL1_TEST;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) {
2638c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "Alarm was detected\n");
2648c2ecf20Sopenharmony_ci		need_clear = 1;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (ctrl[1] & RX8025_BIT_CTRL2_CTFG)
2688c2ecf20Sopenharmony_ci		need_clear = 1;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (need_clear) {
2718c2ecf20Sopenharmony_ci		ctrl2 = ctrl[1];
2728c2ecf20Sopenharmony_ci		ctrl2 &= ~(RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG |
2738c2ecf20Sopenharmony_ci			   RX8025_BIT_CTRL2_DAFG);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		err = rx8025_write_reg(client, RX8025_REG_CTRL2, ctrl2);
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ciout:
2788c2ecf20Sopenharmony_ci	return err;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/* Alarm support */
2828c2ecf20Sopenharmony_cistatic int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
2858c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025 = dev_get_drvdata(dev);
2868c2ecf20Sopenharmony_ci	u8 ald[2];
2878c2ecf20Sopenharmony_ci	int ctrl2, err;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (client->irq <= 0)
2908c2ecf20Sopenharmony_ci		return -EINVAL;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	err = rx8025_read_regs(client, RX8025_REG_ALDMIN, 2, ald);
2938c2ecf20Sopenharmony_ci	if (err)
2948c2ecf20Sopenharmony_ci		return err;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2);
2978c2ecf20Sopenharmony_ci	if (ctrl2 < 0)
2988c2ecf20Sopenharmony_ci		return ctrl2;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: read alarm 0x%02x 0x%02x ctrl2 %02x\n",
3018c2ecf20Sopenharmony_ci		__func__, ald[0], ald[1], ctrl2);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* Hardware alarms precision is 1 minute! */
3048c2ecf20Sopenharmony_ci	t->time.tm_sec = 0;
3058c2ecf20Sopenharmony_ci	t->time.tm_min = bcd2bin(ald[0] & 0x7f);
3068c2ecf20Sopenharmony_ci	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)
3078c2ecf20Sopenharmony_ci		t->time.tm_hour = bcd2bin(ald[1] & 0x3f);
3088c2ecf20Sopenharmony_ci	else
3098c2ecf20Sopenharmony_ci		t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12
3108c2ecf20Sopenharmony_ci			+ (ald[1] & 0x20 ? 12 : 0);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: date: %ptRr\n", __func__, &t->time);
3138c2ecf20Sopenharmony_ci	t->enabled = !!(rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE);
3148c2ecf20Sopenharmony_ci	t->pending = (ctrl2 & RX8025_BIT_CTRL2_DAFG) && t->enabled;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return err;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
3228c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025 = dev_get_drvdata(dev);
3238c2ecf20Sopenharmony_ci	u8 ald[2];
3248c2ecf20Sopenharmony_ci	int err;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (client->irq <= 0)
3278c2ecf20Sopenharmony_ci		return -EINVAL;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * Hardware alarm precision is 1 minute!
3318c2ecf20Sopenharmony_ci	 * round up to nearest minute
3328c2ecf20Sopenharmony_ci	 */
3338c2ecf20Sopenharmony_ci	if (t->time.tm_sec) {
3348c2ecf20Sopenharmony_ci		time64_t alarm_time = rtc_tm_to_time64(&t->time);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		alarm_time += 60 - t->time.tm_sec;
3378c2ecf20Sopenharmony_ci		rtc_time64_to_tm(alarm_time, &t->time);
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	ald[0] = bin2bcd(t->time.tm_min);
3418c2ecf20Sopenharmony_ci	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)
3428c2ecf20Sopenharmony_ci		ald[1] = bin2bcd(t->time.tm_hour);
3438c2ecf20Sopenharmony_ci	else
3448c2ecf20Sopenharmony_ci		ald[1] = (t->time.tm_hour >= 12 ? 0x20 : 0)
3458c2ecf20Sopenharmony_ci			| bin2bcd((t->time.tm_hour + 11) % 12 + 1);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: write 0x%02x 0x%02x\n", __func__, ald[0], ald[1]);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE) {
3508c2ecf20Sopenharmony_ci		rx8025->ctrl1 &= ~RX8025_BIT_CTRL1_DALE;
3518c2ecf20Sopenharmony_ci		err = rx8025_write_reg(client, RX8025_REG_CTRL1,
3528c2ecf20Sopenharmony_ci				       rx8025->ctrl1);
3538c2ecf20Sopenharmony_ci		if (err)
3548c2ecf20Sopenharmony_ci			return err;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci	err = rx8025_write_regs(client, RX8025_REG_ALDMIN, 2, ald);
3578c2ecf20Sopenharmony_ci	if (err)
3588c2ecf20Sopenharmony_ci		return err;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (t->enabled) {
3618c2ecf20Sopenharmony_ci		rx8025->ctrl1 |= RX8025_BIT_CTRL1_DALE;
3628c2ecf20Sopenharmony_ci		err = rx8025_write_reg(client, RX8025_REG_CTRL1,
3638c2ecf20Sopenharmony_ci				       rx8025->ctrl1);
3648c2ecf20Sopenharmony_ci		if (err)
3658c2ecf20Sopenharmony_ci			return err;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	return 0;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
3748c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025 = dev_get_drvdata(dev);
3758c2ecf20Sopenharmony_ci	u8 ctrl1;
3768c2ecf20Sopenharmony_ci	int err;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	ctrl1 = rx8025->ctrl1;
3798c2ecf20Sopenharmony_ci	if (enabled)
3808c2ecf20Sopenharmony_ci		ctrl1 |= RX8025_BIT_CTRL1_DALE;
3818c2ecf20Sopenharmony_ci	else
3828c2ecf20Sopenharmony_ci		ctrl1 &= ~RX8025_BIT_CTRL1_DALE;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (ctrl1 != rx8025->ctrl1) {
3858c2ecf20Sopenharmony_ci		rx8025->ctrl1 = ctrl1;
3868c2ecf20Sopenharmony_ci		err = rx8025_write_reg(client, RX8025_REG_CTRL1,
3878c2ecf20Sopenharmony_ci				       rx8025->ctrl1);
3888c2ecf20Sopenharmony_ci		if (err)
3898c2ecf20Sopenharmony_ci			return err;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci	return 0;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic const struct rtc_class_ops rx8025_rtc_ops = {
3958c2ecf20Sopenharmony_ci	.read_time = rx8025_get_time,
3968c2ecf20Sopenharmony_ci	.set_time = rx8025_set_time,
3978c2ecf20Sopenharmony_ci	.read_alarm = rx8025_read_alarm,
3988c2ecf20Sopenharmony_ci	.set_alarm = rx8025_set_alarm,
3998c2ecf20Sopenharmony_ci	.alarm_irq_enable = rx8025_alarm_irq_enable,
4008c2ecf20Sopenharmony_ci};
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci/*
4038c2ecf20Sopenharmony_ci * Clock precision adjustment support
4048c2ecf20Sopenharmony_ci *
4058c2ecf20Sopenharmony_ci * According to the RX8025 SA/NB application manual the frequency and
4068c2ecf20Sopenharmony_ci * temperature characteristics can be approximated using the following
4078c2ecf20Sopenharmony_ci * equation:
4088c2ecf20Sopenharmony_ci *
4098c2ecf20Sopenharmony_ci *   df = a * (ut - t)**2
4108c2ecf20Sopenharmony_ci *
4118c2ecf20Sopenharmony_ci *   df: Frequency deviation in any temperature
4128c2ecf20Sopenharmony_ci *   a : Coefficient = (-35 +-5) * 10**-9
4138c2ecf20Sopenharmony_ci *   ut: Ultimate temperature in degree = +25 +-5 degree
4148c2ecf20Sopenharmony_ci *   t : Any temperature in degree
4158c2ecf20Sopenharmony_ci *
4168c2ecf20Sopenharmony_ci * Note that the clock adjustment in ppb must be entered (which is
4178c2ecf20Sopenharmony_ci * the negative value of the deviation).
4188c2ecf20Sopenharmony_ci */
4198c2ecf20Sopenharmony_cistatic int rx8025_get_clock_adjust(struct device *dev, int *adj)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
4228c2ecf20Sopenharmony_ci	int digoff;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	digoff = rx8025_read_reg(client, RX8025_REG_DIGOFF);
4258c2ecf20Sopenharmony_ci	if (digoff < 0)
4268c2ecf20Sopenharmony_ci		return digoff;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	*adj = digoff >= 64 ? digoff - 128 : digoff;
4298c2ecf20Sopenharmony_ci	if (*adj > 0)
4308c2ecf20Sopenharmony_ci		(*adj)--;
4318c2ecf20Sopenharmony_ci	*adj *= -RX8025_ADJ_RESOLUTION;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int rx8025_set_clock_adjust(struct device *dev, int adj)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
4398c2ecf20Sopenharmony_ci	u8 digoff;
4408c2ecf20Sopenharmony_ci	int err;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	adj /= -RX8025_ADJ_RESOLUTION;
4438c2ecf20Sopenharmony_ci	if (adj > RX8025_ADJ_DATA_MAX)
4448c2ecf20Sopenharmony_ci		adj = RX8025_ADJ_DATA_MAX;
4458c2ecf20Sopenharmony_ci	else if (adj < RX8025_ADJ_DATA_MIN)
4468c2ecf20Sopenharmony_ci		adj = RX8025_ADJ_DATA_MIN;
4478c2ecf20Sopenharmony_ci	else if (adj > 0)
4488c2ecf20Sopenharmony_ci		adj++;
4498c2ecf20Sopenharmony_ci	else if (adj < 0)
4508c2ecf20Sopenharmony_ci		adj += 128;
4518c2ecf20Sopenharmony_ci	digoff = adj;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	err = rx8025_write_reg(client, RX8025_REG_DIGOFF, digoff);
4548c2ecf20Sopenharmony_ci	if (err)
4558c2ecf20Sopenharmony_ci		return err;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: write 0x%02x\n", __func__, digoff);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	return 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic ssize_t rx8025_sysfs_show_clock_adjust(struct device *dev,
4638c2ecf20Sopenharmony_ci					      struct device_attribute *attr,
4648c2ecf20Sopenharmony_ci					      char *buf)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	int err, adj;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	err = rx8025_get_clock_adjust(dev, &adj);
4698c2ecf20Sopenharmony_ci	if (err)
4708c2ecf20Sopenharmony_ci		return err;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", adj);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic ssize_t rx8025_sysfs_store_clock_adjust(struct device *dev,
4768c2ecf20Sopenharmony_ci					       struct device_attribute *attr,
4778c2ecf20Sopenharmony_ci					       const char *buf, size_t count)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	int adj, err;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (sscanf(buf, "%i", &adj) != 1)
4828c2ecf20Sopenharmony_ci		return -EINVAL;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	err = rx8025_set_clock_adjust(dev, adj);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return err ? err : count;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic DEVICE_ATTR(clock_adjust_ppb, S_IRUGO | S_IWUSR,
4908c2ecf20Sopenharmony_ci		   rx8025_sysfs_show_clock_adjust,
4918c2ecf20Sopenharmony_ci		   rx8025_sysfs_store_clock_adjust);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int rx8025_sysfs_register(struct device *dev)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	return device_create_file(dev, &dev_attr_clock_adjust_ppb);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic void rx8025_sysfs_unregister(struct device *dev)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	device_remove_file(dev, &dev_attr_clock_adjust_ppb);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int rx8025_probe(struct i2c_client *client,
5048c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
5078c2ecf20Sopenharmony_ci	struct rx8025_data *rx8025;
5088c2ecf20Sopenharmony_ci	int err = 0;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
5118c2ecf20Sopenharmony_ci				     | I2C_FUNC_SMBUS_I2C_BLOCK)) {
5128c2ecf20Sopenharmony_ci		dev_err(&adapter->dev,
5138c2ecf20Sopenharmony_ci			"doesn't support required functionality\n");
5148c2ecf20Sopenharmony_ci		return -EIO;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);
5188c2ecf20Sopenharmony_ci	if (!rx8025)
5198c2ecf20Sopenharmony_ci		return -ENOMEM;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, rx8025);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	err = rx8025_init_client(client);
5248c2ecf20Sopenharmony_ci	if (err)
5258c2ecf20Sopenharmony_ci		return err;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	rx8025->rtc = devm_rtc_device_register(&client->dev, client->name,
5288c2ecf20Sopenharmony_ci					  &rx8025_rtc_ops, THIS_MODULE);
5298c2ecf20Sopenharmony_ci	if (IS_ERR(rx8025->rtc)) {
5308c2ecf20Sopenharmony_ci		dev_err(&client->dev, "unable to register the class device\n");
5318c2ecf20Sopenharmony_ci		return PTR_ERR(rx8025->rtc);
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (client->irq > 0) {
5358c2ecf20Sopenharmony_ci		dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
5368c2ecf20Sopenharmony_ci		err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
5378c2ecf20Sopenharmony_ci						rx8025_handle_irq,
5388c2ecf20Sopenharmony_ci						IRQF_ONESHOT,
5398c2ecf20Sopenharmony_ci						"rx8025", client);
5408c2ecf20Sopenharmony_ci		if (err) {
5418c2ecf20Sopenharmony_ci			dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
5428c2ecf20Sopenharmony_ci			client->irq = 0;
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	rx8025->rtc->max_user_freq = 1;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	/* the rx8025 alarm only supports a minute accuracy */
5498c2ecf20Sopenharmony_ci	rx8025->rtc->uie_unsupported = 1;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	err = rx8025_sysfs_register(&client->dev);
5528c2ecf20Sopenharmony_ci	return err;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cistatic int rx8025_remove(struct i2c_client *client)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	rx8025_sysfs_unregister(&client->dev);
5588c2ecf20Sopenharmony_ci	return 0;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic struct i2c_driver rx8025_driver = {
5628c2ecf20Sopenharmony_ci	.driver = {
5638c2ecf20Sopenharmony_ci		.name = "rtc-rx8025",
5648c2ecf20Sopenharmony_ci	},
5658c2ecf20Sopenharmony_ci	.probe		= rx8025_probe,
5668c2ecf20Sopenharmony_ci	.remove		= rx8025_remove,
5678c2ecf20Sopenharmony_ci	.id_table	= rx8025_id,
5688c2ecf20Sopenharmony_ci};
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cimodule_i2c_driver(rx8025_driver);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
5738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RX-8025 SA/NB RTC driver");
5748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
575