xref: /linux/drivers/rtc/rtc-rv3028.c (revision 0f7695691be617e066cd3fdbb936989d0484c048)
1e6e7376cSAlexandre Belloni // SPDX-License-Identifier: GPL-2.0
2e6e7376cSAlexandre Belloni /*
3e6e7376cSAlexandre Belloni  * RTC driver for the Micro Crystal RV3028
4e6e7376cSAlexandre Belloni  *
5e6e7376cSAlexandre Belloni  * Copyright (C) 2019 Micro Crystal SA
6e6e7376cSAlexandre Belloni  *
7e6e7376cSAlexandre Belloni  * Alexandre Belloni <alexandre.belloni@bootlin.com>
8e6e7376cSAlexandre Belloni  *
9e6e7376cSAlexandre Belloni  */
10e6e7376cSAlexandre Belloni 
11f583c341SParthiban Nallathambi #include <linux/clk-provider.h>
12e6e7376cSAlexandre Belloni #include <linux/bcd.h>
13e6e7376cSAlexandre Belloni #include <linux/bitops.h>
14e6e7376cSAlexandre Belloni #include <linux/i2c.h>
15e6e7376cSAlexandre Belloni #include <linux/interrupt.h>
16e6e7376cSAlexandre Belloni #include <linux/kernel.h>
17e6e7376cSAlexandre Belloni #include <linux/log2.h>
18e6e7376cSAlexandre Belloni #include <linux/module.h>
19e6e7376cSAlexandre Belloni #include <linux/of_device.h>
20e6e7376cSAlexandre Belloni #include <linux/regmap.h>
21e6e7376cSAlexandre Belloni #include <linux/rtc.h>
22e6e7376cSAlexandre Belloni 
23e6e7376cSAlexandre Belloni #define RV3028_SEC			0x00
24e6e7376cSAlexandre Belloni #define RV3028_MIN			0x01
25e6e7376cSAlexandre Belloni #define RV3028_HOUR			0x02
26e6e7376cSAlexandre Belloni #define RV3028_WDAY			0x03
27e6e7376cSAlexandre Belloni #define RV3028_DAY			0x04
28e6e7376cSAlexandre Belloni #define RV3028_MONTH			0x05
29e6e7376cSAlexandre Belloni #define RV3028_YEAR			0x06
30e6e7376cSAlexandre Belloni #define RV3028_ALARM_MIN		0x07
31e6e7376cSAlexandre Belloni #define RV3028_ALARM_HOUR		0x08
32e6e7376cSAlexandre Belloni #define RV3028_ALARM_DAY		0x09
33e6e7376cSAlexandre Belloni #define RV3028_STATUS			0x0E
34e6e7376cSAlexandre Belloni #define RV3028_CTRL1			0x0F
35e6e7376cSAlexandre Belloni #define RV3028_CTRL2			0x10
36e6e7376cSAlexandre Belloni #define RV3028_EVT_CTRL			0x13
37e6e7376cSAlexandre Belloni #define RV3028_TS_COUNT			0x14
38e6e7376cSAlexandre Belloni #define RV3028_TS_SEC			0x15
39e6e7376cSAlexandre Belloni #define RV3028_RAM1			0x1F
40e6e7376cSAlexandre Belloni #define RV3028_EEPROM_ADDR		0x25
41e6e7376cSAlexandre Belloni #define RV3028_EEPROM_DATA		0x26
42e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD		0x27
43e6e7376cSAlexandre Belloni #define RV3028_CLKOUT			0x35
44e6e7376cSAlexandre Belloni #define RV3028_OFFSET			0x36
45e6e7376cSAlexandre Belloni #define RV3028_BACKUP			0x37
46e6e7376cSAlexandre Belloni 
47e6e7376cSAlexandre Belloni #define RV3028_STATUS_PORF		BIT(0)
48e6e7376cSAlexandre Belloni #define RV3028_STATUS_EVF		BIT(1)
49e6e7376cSAlexandre Belloni #define RV3028_STATUS_AF		BIT(2)
50e6e7376cSAlexandre Belloni #define RV3028_STATUS_TF		BIT(3)
51e6e7376cSAlexandre Belloni #define RV3028_STATUS_UF		BIT(4)
52e6e7376cSAlexandre Belloni #define RV3028_STATUS_BSF		BIT(5)
53e6e7376cSAlexandre Belloni #define RV3028_STATUS_CLKF		BIT(6)
54e6e7376cSAlexandre Belloni #define RV3028_STATUS_EEBUSY		BIT(7)
55e6e7376cSAlexandre Belloni 
56f583c341SParthiban Nallathambi #define RV3028_CLKOUT_FD_MASK		GENMASK(2, 0)
57f583c341SParthiban Nallathambi #define RV3028_CLKOUT_PORIE		BIT(3)
58f583c341SParthiban Nallathambi #define RV3028_CLKOUT_CLKSY		BIT(6)
59f583c341SParthiban Nallathambi #define RV3028_CLKOUT_CLKOE		BIT(7)
60f583c341SParthiban Nallathambi 
61e6e7376cSAlexandre Belloni #define RV3028_CTRL1_EERD		BIT(3)
62e6e7376cSAlexandre Belloni #define RV3028_CTRL1_WADA		BIT(5)
63e6e7376cSAlexandre Belloni 
64e6e7376cSAlexandre Belloni #define RV3028_CTRL2_RESET		BIT(0)
65e6e7376cSAlexandre Belloni #define RV3028_CTRL2_12_24		BIT(1)
66e6e7376cSAlexandre Belloni #define RV3028_CTRL2_EIE		BIT(2)
67e6e7376cSAlexandre Belloni #define RV3028_CTRL2_AIE		BIT(3)
68e6e7376cSAlexandre Belloni #define RV3028_CTRL2_TIE		BIT(4)
69e6e7376cSAlexandre Belloni #define RV3028_CTRL2_UIE		BIT(5)
70e6e7376cSAlexandre Belloni #define RV3028_CTRL2_TSE		BIT(7)
71e6e7376cSAlexandre Belloni 
72e6e7376cSAlexandre Belloni #define RV3028_EVT_CTRL_TSR		BIT(2)
73e6e7376cSAlexandre Belloni 
74024e6f3dSAlexandre Belloni #define RV3028_EEPROM_CMD_UPDATE	0x11
75e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD_WRITE		0x21
76e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD_READ		0x22
77e6e7376cSAlexandre Belloni 
78e6e7376cSAlexandre Belloni #define RV3028_EEBUSY_POLL		10000
79e6e7376cSAlexandre Belloni #define RV3028_EEBUSY_TIMEOUT		100000
80e6e7376cSAlexandre Belloni 
81e6e7376cSAlexandre Belloni #define RV3028_BACKUP_TCE		BIT(5)
82e6e7376cSAlexandre Belloni #define RV3028_BACKUP_TCR_MASK		GENMASK(1,0)
83e6e7376cSAlexandre Belloni 
84e6e7376cSAlexandre Belloni #define OFFSET_STEP_PPT			953674
85e6e7376cSAlexandre Belloni 
86e6e7376cSAlexandre Belloni enum rv3028_type {
87e6e7376cSAlexandre Belloni 	rv_3028,
88e6e7376cSAlexandre Belloni };
89e6e7376cSAlexandre Belloni 
90e6e7376cSAlexandre Belloni struct rv3028_data {
91e6e7376cSAlexandre Belloni 	struct regmap *regmap;
92e6e7376cSAlexandre Belloni 	struct rtc_device *rtc;
93e6e7376cSAlexandre Belloni 	enum rv3028_type type;
94f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK
95f583c341SParthiban Nallathambi 	struct clk_hw clkout_hw;
96f583c341SParthiban Nallathambi #endif
97e6e7376cSAlexandre Belloni };
98e6e7376cSAlexandre Belloni 
99c1efae14SAlexandre Belloni static u16 rv3028_trickle_resistors[] = {3000, 5000, 9000, 15000};
100e6e7376cSAlexandre Belloni 
101e6e7376cSAlexandre Belloni static ssize_t timestamp0_store(struct device *dev,
102e6e7376cSAlexandre Belloni 				struct device_attribute *attr,
103e6e7376cSAlexandre Belloni 				const char *buf, size_t count)
104e6e7376cSAlexandre Belloni {
105e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
106e6e7376cSAlexandre Belloni 
107e6e7376cSAlexandre Belloni 	regmap_update_bits(rv3028->regmap, RV3028_EVT_CTRL, RV3028_EVT_CTRL_TSR,
108e6e7376cSAlexandre Belloni 			   RV3028_EVT_CTRL_TSR);
109e6e7376cSAlexandre Belloni 
110e6e7376cSAlexandre Belloni 	return count;
111e6e7376cSAlexandre Belloni };
112e6e7376cSAlexandre Belloni 
113e6e7376cSAlexandre Belloni static ssize_t timestamp0_show(struct device *dev,
114e6e7376cSAlexandre Belloni 			       struct device_attribute *attr, char *buf)
115e6e7376cSAlexandre Belloni {
116e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
117e6e7376cSAlexandre Belloni 	struct rtc_time tm;
118e6e7376cSAlexandre Belloni 	int ret, count;
119e6e7376cSAlexandre Belloni 	u8 date[6];
120e6e7376cSAlexandre Belloni 
121e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
122e6e7376cSAlexandre Belloni 	if (ret)
123e6e7376cSAlexandre Belloni 		return ret;
124e6e7376cSAlexandre Belloni 
125e6e7376cSAlexandre Belloni 	if (!count)
126e6e7376cSAlexandre Belloni 		return 0;
127e6e7376cSAlexandre Belloni 
128e6e7376cSAlexandre Belloni 	ret = regmap_bulk_read(rv3028->regmap, RV3028_TS_SEC, date,
129e6e7376cSAlexandre Belloni 			       sizeof(date));
130e6e7376cSAlexandre Belloni 	if (ret)
131e6e7376cSAlexandre Belloni 		return ret;
132e6e7376cSAlexandre Belloni 
133e6e7376cSAlexandre Belloni 	tm.tm_sec = bcd2bin(date[0]);
134e6e7376cSAlexandre Belloni 	tm.tm_min = bcd2bin(date[1]);
135e6e7376cSAlexandre Belloni 	tm.tm_hour = bcd2bin(date[2]);
136e6e7376cSAlexandre Belloni 	tm.tm_mday = bcd2bin(date[3]);
137e6e7376cSAlexandre Belloni 	tm.tm_mon = bcd2bin(date[4]) - 1;
138e6e7376cSAlexandre Belloni 	tm.tm_year = bcd2bin(date[5]) + 100;
139e6e7376cSAlexandre Belloni 
140e6e7376cSAlexandre Belloni 	ret = rtc_valid_tm(&tm);
141e6e7376cSAlexandre Belloni 	if (ret)
142e6e7376cSAlexandre Belloni 		return ret;
143e6e7376cSAlexandre Belloni 
144e6e7376cSAlexandre Belloni 	return sprintf(buf, "%llu\n",
145e6e7376cSAlexandre Belloni 		       (unsigned long long)rtc_tm_to_time64(&tm));
146e6e7376cSAlexandre Belloni };
147e6e7376cSAlexandre Belloni 
148e6e7376cSAlexandre Belloni static DEVICE_ATTR_RW(timestamp0);
149e6e7376cSAlexandre Belloni 
150e6e7376cSAlexandre Belloni static ssize_t timestamp0_count_show(struct device *dev,
151e6e7376cSAlexandre Belloni 				     struct device_attribute *attr, char *buf)
152e6e7376cSAlexandre Belloni {
153e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
154e6e7376cSAlexandre Belloni 	int ret, count;
155e6e7376cSAlexandre Belloni 
156e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
157e6e7376cSAlexandre Belloni 	if (ret)
158e6e7376cSAlexandre Belloni 		return ret;
159e6e7376cSAlexandre Belloni 
160e6e7376cSAlexandre Belloni 	return sprintf(buf, "%u\n", count);
161e6e7376cSAlexandre Belloni };
162e6e7376cSAlexandre Belloni 
163e6e7376cSAlexandre Belloni static DEVICE_ATTR_RO(timestamp0_count);
164e6e7376cSAlexandre Belloni 
165e6e7376cSAlexandre Belloni static struct attribute *rv3028_attrs[] = {
166e6e7376cSAlexandre Belloni 	&dev_attr_timestamp0.attr,
167e6e7376cSAlexandre Belloni 	&dev_attr_timestamp0_count.attr,
168e6e7376cSAlexandre Belloni 	NULL
169e6e7376cSAlexandre Belloni };
170e6e7376cSAlexandre Belloni 
171e6e7376cSAlexandre Belloni static const struct attribute_group rv3028_attr_group = {
172e6e7376cSAlexandre Belloni 	.attrs	= rv3028_attrs,
173e6e7376cSAlexandre Belloni };
174e6e7376cSAlexandre Belloni 
175de0ad60eSAlexandre Belloni static int rv3028_exit_eerd(struct rv3028_data *rv3028, u32 eerd)
176de0ad60eSAlexandre Belloni {
177de0ad60eSAlexandre Belloni 	if (eerd)
178de0ad60eSAlexandre Belloni 		return 0;
179de0ad60eSAlexandre Belloni 
180de0ad60eSAlexandre Belloni 	return regmap_update_bits(rv3028->regmap, RV3028_CTRL1, RV3028_CTRL1_EERD, 0);
181de0ad60eSAlexandre Belloni }
182de0ad60eSAlexandre Belloni 
183de0ad60eSAlexandre Belloni static int rv3028_enter_eerd(struct rv3028_data *rv3028, u32 *eerd)
184de0ad60eSAlexandre Belloni {
185de0ad60eSAlexandre Belloni 	u32 ctrl1, status;
186de0ad60eSAlexandre Belloni 	int ret;
187de0ad60eSAlexandre Belloni 
188de0ad60eSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_CTRL1, &ctrl1);
189de0ad60eSAlexandre Belloni 	if (ret)
190de0ad60eSAlexandre Belloni 		return ret;
191de0ad60eSAlexandre Belloni 
192de0ad60eSAlexandre Belloni 	*eerd = ctrl1 & RV3028_CTRL1_EERD;
193de0ad60eSAlexandre Belloni 	if (*eerd)
194de0ad60eSAlexandre Belloni 		return 0;
195de0ad60eSAlexandre Belloni 
196de0ad60eSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
197de0ad60eSAlexandre Belloni 				 RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
198de0ad60eSAlexandre Belloni 	if (ret)
199de0ad60eSAlexandre Belloni 		return ret;
200de0ad60eSAlexandre Belloni 
201de0ad60eSAlexandre Belloni 	ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
202de0ad60eSAlexandre Belloni 				       !(status & RV3028_STATUS_EEBUSY),
203de0ad60eSAlexandre Belloni 				       RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
204de0ad60eSAlexandre Belloni 	if (ret) {
205de0ad60eSAlexandre Belloni 		rv3028_exit_eerd(rv3028, *eerd);
206de0ad60eSAlexandre Belloni 
207de0ad60eSAlexandre Belloni 		return ret;
208de0ad60eSAlexandre Belloni 	}
209de0ad60eSAlexandre Belloni 
210de0ad60eSAlexandre Belloni 	return 0;
211de0ad60eSAlexandre Belloni }
212de0ad60eSAlexandre Belloni 
213024e6f3dSAlexandre Belloni static int rv3028_update_eeprom(struct rv3028_data *rv3028, u32 eerd)
214024e6f3dSAlexandre Belloni {
215024e6f3dSAlexandre Belloni 	u32 status;
216024e6f3dSAlexandre Belloni 	int ret;
217024e6f3dSAlexandre Belloni 
218024e6f3dSAlexandre Belloni 	ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
219024e6f3dSAlexandre Belloni 	if (ret)
220024e6f3dSAlexandre Belloni 		goto exit_eerd;
221024e6f3dSAlexandre Belloni 
222024e6f3dSAlexandre Belloni 	ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, RV3028_EEPROM_CMD_UPDATE);
223024e6f3dSAlexandre Belloni 	if (ret)
224024e6f3dSAlexandre Belloni 		goto exit_eerd;
225024e6f3dSAlexandre Belloni 
226024e6f3dSAlexandre Belloni 	usleep_range(63000, RV3028_EEBUSY_TIMEOUT);
227024e6f3dSAlexandre Belloni 
228024e6f3dSAlexandre Belloni 	ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
229024e6f3dSAlexandre Belloni 				       !(status & RV3028_STATUS_EEBUSY),
230024e6f3dSAlexandre Belloni 				       RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
231024e6f3dSAlexandre Belloni 
232024e6f3dSAlexandre Belloni exit_eerd:
233024e6f3dSAlexandre Belloni 	rv3028_exit_eerd(rv3028, eerd);
234024e6f3dSAlexandre Belloni 
235024e6f3dSAlexandre Belloni 	return ret;
236024e6f3dSAlexandre Belloni }
237024e6f3dSAlexandre Belloni 
238024e6f3dSAlexandre Belloni static int rv3028_update_cfg(struct rv3028_data *rv3028, unsigned int reg,
239024e6f3dSAlexandre Belloni 			     unsigned int mask, unsigned int val)
240024e6f3dSAlexandre Belloni {
241024e6f3dSAlexandre Belloni 	u32 eerd;
242024e6f3dSAlexandre Belloni 	int ret;
243024e6f3dSAlexandre Belloni 
244024e6f3dSAlexandre Belloni 	ret = rv3028_enter_eerd(rv3028, &eerd);
245024e6f3dSAlexandre Belloni 	if (ret)
246024e6f3dSAlexandre Belloni 		return ret;
247024e6f3dSAlexandre Belloni 
248024e6f3dSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, reg, mask, val);
249024e6f3dSAlexandre Belloni 	if (ret) {
250024e6f3dSAlexandre Belloni 		rv3028_exit_eerd(rv3028, eerd);
251024e6f3dSAlexandre Belloni 		return ret;
252024e6f3dSAlexandre Belloni 	}
253024e6f3dSAlexandre Belloni 
254024e6f3dSAlexandre Belloni 	return rv3028_update_eeprom(rv3028, eerd);
255024e6f3dSAlexandre Belloni }
256024e6f3dSAlexandre Belloni 
257e6e7376cSAlexandre Belloni static irqreturn_t rv3028_handle_irq(int irq, void *dev_id)
258e6e7376cSAlexandre Belloni {
259e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_id;
260e6e7376cSAlexandre Belloni 	unsigned long events = 0;
261e6e7376cSAlexandre Belloni 	u32 status = 0, ctrl = 0;
262e6e7376cSAlexandre Belloni 
263e6e7376cSAlexandre Belloni 	if (regmap_read(rv3028->regmap, RV3028_STATUS, &status) < 0 ||
264e6e7376cSAlexandre Belloni 	   status == 0) {
265e6e7376cSAlexandre Belloni 		return IRQ_NONE;
266e6e7376cSAlexandre Belloni 	}
267e6e7376cSAlexandre Belloni 
268e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_PORF)
269e6e7376cSAlexandre Belloni 		dev_warn(&rv3028->rtc->dev, "Voltage low, data loss detected.\n");
270e6e7376cSAlexandre Belloni 
271e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_TF) {
272e6e7376cSAlexandre Belloni 		status |= RV3028_STATUS_TF;
273e6e7376cSAlexandre Belloni 		ctrl |= RV3028_CTRL2_TIE;
274e6e7376cSAlexandre Belloni 		events |= RTC_PF;
275e6e7376cSAlexandre Belloni 	}
276e6e7376cSAlexandre Belloni 
277e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_AF) {
278e6e7376cSAlexandre Belloni 		status |= RV3028_STATUS_AF;
279e6e7376cSAlexandre Belloni 		ctrl |= RV3028_CTRL2_AIE;
280e6e7376cSAlexandre Belloni 		events |= RTC_AF;
281e6e7376cSAlexandre Belloni 	}
282e6e7376cSAlexandre Belloni 
283e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_UF) {
284e6e7376cSAlexandre Belloni 		status |= RV3028_STATUS_UF;
285e6e7376cSAlexandre Belloni 		ctrl |= RV3028_CTRL2_UIE;
286e6e7376cSAlexandre Belloni 		events |= RTC_UF;
287e6e7376cSAlexandre Belloni 	}
288e6e7376cSAlexandre Belloni 
289e6e7376cSAlexandre Belloni 	if (events) {
290e6e7376cSAlexandre Belloni 		rtc_update_irq(rv3028->rtc, 1, events);
291e6e7376cSAlexandre Belloni 		regmap_update_bits(rv3028->regmap, RV3028_STATUS, status, 0);
292e6e7376cSAlexandre Belloni 		regmap_update_bits(rv3028->regmap, RV3028_CTRL2, ctrl, 0);
293e6e7376cSAlexandre Belloni 	}
294e6e7376cSAlexandre Belloni 
295e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_EVF) {
296e6e7376cSAlexandre Belloni 		sysfs_notify(&rv3028->rtc->dev.kobj, NULL,
297e6e7376cSAlexandre Belloni 			     dev_attr_timestamp0.attr.name);
298e6e7376cSAlexandre Belloni 		dev_warn(&rv3028->rtc->dev, "event detected");
299e6e7376cSAlexandre Belloni 	}
300e6e7376cSAlexandre Belloni 
301e6e7376cSAlexandre Belloni 	return IRQ_HANDLED;
302e6e7376cSAlexandre Belloni }
303e6e7376cSAlexandre Belloni 
304e6e7376cSAlexandre Belloni static int rv3028_get_time(struct device *dev, struct rtc_time *tm)
305e6e7376cSAlexandre Belloni {
306e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
307e6e7376cSAlexandre Belloni 	u8 date[7];
308e6e7376cSAlexandre Belloni 	int ret, status;
309e6e7376cSAlexandre Belloni 
310e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
311e6e7376cSAlexandre Belloni 	if (ret < 0)
312e6e7376cSAlexandre Belloni 		return ret;
313e6e7376cSAlexandre Belloni 
314e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_PORF) {
315e6e7376cSAlexandre Belloni 		dev_warn(dev, "Voltage low, data is invalid.\n");
316e6e7376cSAlexandre Belloni 		return -EINVAL;
317e6e7376cSAlexandre Belloni 	}
318e6e7376cSAlexandre Belloni 
319e6e7376cSAlexandre Belloni 	ret = regmap_bulk_read(rv3028->regmap, RV3028_SEC, date, sizeof(date));
320e6e7376cSAlexandre Belloni 	if (ret)
321e6e7376cSAlexandre Belloni 		return ret;
322e6e7376cSAlexandre Belloni 
323e6e7376cSAlexandre Belloni 	tm->tm_sec  = bcd2bin(date[RV3028_SEC] & 0x7f);
324e6e7376cSAlexandre Belloni 	tm->tm_min  = bcd2bin(date[RV3028_MIN] & 0x7f);
325e6e7376cSAlexandre Belloni 	tm->tm_hour = bcd2bin(date[RV3028_HOUR] & 0x3f);
326e6e7376cSAlexandre Belloni 	tm->tm_wday = ilog2(date[RV3028_WDAY] & 0x7f);
327e6e7376cSAlexandre Belloni 	tm->tm_mday = bcd2bin(date[RV3028_DAY] & 0x3f);
328e6e7376cSAlexandre Belloni 	tm->tm_mon  = bcd2bin(date[RV3028_MONTH] & 0x1f) - 1;
329e6e7376cSAlexandre Belloni 	tm->tm_year = bcd2bin(date[RV3028_YEAR]) + 100;
330e6e7376cSAlexandre Belloni 
331e6e7376cSAlexandre Belloni 	return 0;
332e6e7376cSAlexandre Belloni }
333e6e7376cSAlexandre Belloni 
334e6e7376cSAlexandre Belloni static int rv3028_set_time(struct device *dev, struct rtc_time *tm)
335e6e7376cSAlexandre Belloni {
336e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
337e6e7376cSAlexandre Belloni 	u8 date[7];
338e6e7376cSAlexandre Belloni 	int ret;
339e6e7376cSAlexandre Belloni 
340e6e7376cSAlexandre Belloni 	date[RV3028_SEC]   = bin2bcd(tm->tm_sec);
341e6e7376cSAlexandre Belloni 	date[RV3028_MIN]   = bin2bcd(tm->tm_min);
342e6e7376cSAlexandre Belloni 	date[RV3028_HOUR]  = bin2bcd(tm->tm_hour);
343e6e7376cSAlexandre Belloni 	date[RV3028_WDAY]  = 1 << (tm->tm_wday);
344e6e7376cSAlexandre Belloni 	date[RV3028_DAY]   = bin2bcd(tm->tm_mday);
345e6e7376cSAlexandre Belloni 	date[RV3028_MONTH] = bin2bcd(tm->tm_mon + 1);
346e6e7376cSAlexandre Belloni 	date[RV3028_YEAR]  = bin2bcd(tm->tm_year - 100);
347e6e7376cSAlexandre Belloni 
348e6e7376cSAlexandre Belloni 	/*
349e6e7376cSAlexandre Belloni 	 * Writing to the Seconds register has the same effect as setting RESET
350e6e7376cSAlexandre Belloni 	 * bit to 1
351e6e7376cSAlexandre Belloni 	 */
352e6e7376cSAlexandre Belloni 	ret = regmap_bulk_write(rv3028->regmap, RV3028_SEC, date,
353e6e7376cSAlexandre Belloni 				sizeof(date));
354e6e7376cSAlexandre Belloni 	if (ret)
355e6e7376cSAlexandre Belloni 		return ret;
356e6e7376cSAlexandre Belloni 
357e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
358e6e7376cSAlexandre Belloni 				 RV3028_STATUS_PORF, 0);
359e6e7376cSAlexandre Belloni 
360e6e7376cSAlexandre Belloni 	return ret;
361e6e7376cSAlexandre Belloni }
362e6e7376cSAlexandre Belloni 
363e6e7376cSAlexandre Belloni static int rv3028_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
364e6e7376cSAlexandre Belloni {
365e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
366e6e7376cSAlexandre Belloni 	u8 alarmvals[3];
367e6e7376cSAlexandre Belloni 	int status, ctrl, ret;
368e6e7376cSAlexandre Belloni 
369e6e7376cSAlexandre Belloni 	ret = regmap_bulk_read(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
370e6e7376cSAlexandre Belloni 			       sizeof(alarmvals));
371e6e7376cSAlexandre Belloni 	if (ret)
372e6e7376cSAlexandre Belloni 		return ret;
373e6e7376cSAlexandre Belloni 
374e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
375e6e7376cSAlexandre Belloni 	if (ret < 0)
376e6e7376cSAlexandre Belloni 		return ret;
377e6e7376cSAlexandre Belloni 
378e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_CTRL2, &ctrl);
379e6e7376cSAlexandre Belloni 	if (ret < 0)
380e6e7376cSAlexandre Belloni 		return ret;
381e6e7376cSAlexandre Belloni 
382e6e7376cSAlexandre Belloni 	alrm->time.tm_sec  = 0;
383e6e7376cSAlexandre Belloni 	alrm->time.tm_min  = bcd2bin(alarmvals[0] & 0x7f);
384e6e7376cSAlexandre Belloni 	alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
385e6e7376cSAlexandre Belloni 	alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
386e6e7376cSAlexandre Belloni 
387e6e7376cSAlexandre Belloni 	alrm->enabled = !!(ctrl & RV3028_CTRL2_AIE);
388e6e7376cSAlexandre Belloni 	alrm->pending = (status & RV3028_STATUS_AF) && alrm->enabled;
389e6e7376cSAlexandre Belloni 
390e6e7376cSAlexandre Belloni 	return 0;
391e6e7376cSAlexandre Belloni }
392e6e7376cSAlexandre Belloni 
393e6e7376cSAlexandre Belloni static int rv3028_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
394e6e7376cSAlexandre Belloni {
395e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
396e6e7376cSAlexandre Belloni 	u8 alarmvals[3];
397e6e7376cSAlexandre Belloni 	u8 ctrl = 0;
398e6e7376cSAlexandre Belloni 	int ret;
399e6e7376cSAlexandre Belloni 
400e6e7376cSAlexandre Belloni 	/* The alarm has no seconds, round up to nearest minute */
401e6e7376cSAlexandre Belloni 	if (alrm->time.tm_sec) {
402e6e7376cSAlexandre Belloni 		time64_t alarm_time = rtc_tm_to_time64(&alrm->time);
403e6e7376cSAlexandre Belloni 
404e6e7376cSAlexandre Belloni 		alarm_time += 60 - alrm->time.tm_sec;
405e6e7376cSAlexandre Belloni 		rtc_time64_to_tm(alarm_time, &alrm->time);
406e6e7376cSAlexandre Belloni 	}
407e6e7376cSAlexandre Belloni 
408e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
409e6e7376cSAlexandre Belloni 				 RV3028_CTRL2_AIE | RV3028_CTRL2_UIE, 0);
410e6e7376cSAlexandre Belloni 	if (ret)
411e6e7376cSAlexandre Belloni 		return ret;
412e6e7376cSAlexandre Belloni 
413e6e7376cSAlexandre Belloni 	alarmvals[0] = bin2bcd(alrm->time.tm_min);
414e6e7376cSAlexandre Belloni 	alarmvals[1] = bin2bcd(alrm->time.tm_hour);
415e6e7376cSAlexandre Belloni 	alarmvals[2] = bin2bcd(alrm->time.tm_mday);
416e6e7376cSAlexandre Belloni 
417e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
418e6e7376cSAlexandre Belloni 				 RV3028_STATUS_AF, 0);
419e6e7376cSAlexandre Belloni 	if (ret)
420e6e7376cSAlexandre Belloni 		return ret;
421e6e7376cSAlexandre Belloni 
422e6e7376cSAlexandre Belloni 	ret = regmap_bulk_write(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
423e6e7376cSAlexandre Belloni 				sizeof(alarmvals));
424e6e7376cSAlexandre Belloni 	if (ret)
425e6e7376cSAlexandre Belloni 		return ret;
426e6e7376cSAlexandre Belloni 
427e6e7376cSAlexandre Belloni 	if (alrm->enabled) {
428e6e7376cSAlexandre Belloni 		if (rv3028->rtc->uie_rtctimer.enabled)
429e6e7376cSAlexandre Belloni 			ctrl |= RV3028_CTRL2_UIE;
430e6e7376cSAlexandre Belloni 		if (rv3028->rtc->aie_timer.enabled)
431e6e7376cSAlexandre Belloni 			ctrl |= RV3028_CTRL2_AIE;
432e6e7376cSAlexandre Belloni 	}
433e6e7376cSAlexandre Belloni 
434e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
435e6e7376cSAlexandre Belloni 				 RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
436e6e7376cSAlexandre Belloni 
437e6e7376cSAlexandre Belloni 	return ret;
438e6e7376cSAlexandre Belloni }
439e6e7376cSAlexandre Belloni 
440e6e7376cSAlexandre Belloni static int rv3028_alarm_irq_enable(struct device *dev, unsigned int enabled)
441e6e7376cSAlexandre Belloni {
442e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
443e6e7376cSAlexandre Belloni 	int ctrl = 0, ret;
444e6e7376cSAlexandre Belloni 
445e6e7376cSAlexandre Belloni 	if (enabled) {
446e6e7376cSAlexandre Belloni 		if (rv3028->rtc->uie_rtctimer.enabled)
447e6e7376cSAlexandre Belloni 			ctrl |= RV3028_CTRL2_UIE;
448e6e7376cSAlexandre Belloni 		if (rv3028->rtc->aie_timer.enabled)
449e6e7376cSAlexandre Belloni 			ctrl |= RV3028_CTRL2_AIE;
450e6e7376cSAlexandre Belloni 	}
451e6e7376cSAlexandre Belloni 
452e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
453e6e7376cSAlexandre Belloni 				 RV3028_STATUS_AF | RV3028_STATUS_UF, 0);
454e6e7376cSAlexandre Belloni 	if (ret)
455e6e7376cSAlexandre Belloni 		return ret;
456e6e7376cSAlexandre Belloni 
457e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
458e6e7376cSAlexandre Belloni 				 RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
459e6e7376cSAlexandre Belloni 	if (ret)
460e6e7376cSAlexandre Belloni 		return ret;
461e6e7376cSAlexandre Belloni 
462e6e7376cSAlexandre Belloni 	return 0;
463e6e7376cSAlexandre Belloni }
464e6e7376cSAlexandre Belloni 
465e6e7376cSAlexandre Belloni static int rv3028_read_offset(struct device *dev, long *offset)
466e6e7376cSAlexandre Belloni {
467e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
468e6e7376cSAlexandre Belloni 	int ret, value, steps;
469e6e7376cSAlexandre Belloni 
470e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_OFFSET, &value);
471e6e7376cSAlexandre Belloni 	if (ret < 0)
472e6e7376cSAlexandre Belloni 		return ret;
473e6e7376cSAlexandre Belloni 
474e6e7376cSAlexandre Belloni 	steps = sign_extend32(value << 1, 8);
475e6e7376cSAlexandre Belloni 
476e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
477e6e7376cSAlexandre Belloni 	if (ret < 0)
478e6e7376cSAlexandre Belloni 		return ret;
479e6e7376cSAlexandre Belloni 
480e6e7376cSAlexandre Belloni 	steps += value >> 7;
481e6e7376cSAlexandre Belloni 
482e6e7376cSAlexandre Belloni 	*offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000);
483e6e7376cSAlexandre Belloni 
484e6e7376cSAlexandre Belloni 	return 0;
485e6e7376cSAlexandre Belloni }
486e6e7376cSAlexandre Belloni 
487e6e7376cSAlexandre Belloni static int rv3028_set_offset(struct device *dev, long offset)
488e6e7376cSAlexandre Belloni {
489e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
490024e6f3dSAlexandre Belloni 	u32 eerd;
491e6e7376cSAlexandre Belloni 	int ret;
492e6e7376cSAlexandre Belloni 
493e6e7376cSAlexandre Belloni 	offset = clamp(offset, -244141L, 243187L) * 1000;
494e6e7376cSAlexandre Belloni 	offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT);
495e6e7376cSAlexandre Belloni 
496024e6f3dSAlexandre Belloni 	ret = rv3028_enter_eerd(rv3028, &eerd);
497024e6f3dSAlexandre Belloni 	if (ret)
498e6e7376cSAlexandre Belloni 		return ret;
499e6e7376cSAlexandre Belloni 
500024e6f3dSAlexandre Belloni 	ret = regmap_write(rv3028->regmap, RV3028_OFFSET, offset >> 1);
501024e6f3dSAlexandre Belloni 	if (ret < 0)
502024e6f3dSAlexandre Belloni 		goto exit_eerd;
503024e6f3dSAlexandre Belloni 
504024e6f3dSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7),
505e6e7376cSAlexandre Belloni 				 offset << 7);
506024e6f3dSAlexandre Belloni 	if (ret < 0)
507024e6f3dSAlexandre Belloni 		goto exit_eerd;
508024e6f3dSAlexandre Belloni 
509024e6f3dSAlexandre Belloni 	return rv3028_update_eeprom(rv3028, eerd);
510024e6f3dSAlexandre Belloni 
511024e6f3dSAlexandre Belloni exit_eerd:
512024e6f3dSAlexandre Belloni 	rv3028_exit_eerd(rv3028, eerd);
513024e6f3dSAlexandre Belloni 
514024e6f3dSAlexandre Belloni 	return ret;
515024e6f3dSAlexandre Belloni 
516e6e7376cSAlexandre Belloni }
517e6e7376cSAlexandre Belloni 
518e6e7376cSAlexandre Belloni static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
519e6e7376cSAlexandre Belloni {
520e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028 = dev_get_drvdata(dev);
521e6e7376cSAlexandre Belloni 	int status, ret = 0;
522e6e7376cSAlexandre Belloni 
523e6e7376cSAlexandre Belloni 	switch (cmd) {
524e6e7376cSAlexandre Belloni 	case RTC_VL_READ:
525e6e7376cSAlexandre Belloni 		ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
526e6e7376cSAlexandre Belloni 		if (ret < 0)
527e6e7376cSAlexandre Belloni 			return ret;
528e6e7376cSAlexandre Belloni 
52986e655f9SAlexandre Belloni 		status = status & RV3028_STATUS_PORF ? RTC_VL_DATA_INVALID : 0;
53086e655f9SAlexandre Belloni 		return put_user(status, (unsigned int __user *)arg);
531e6e7376cSAlexandre Belloni 
532e6e7376cSAlexandre Belloni 	default:
533e6e7376cSAlexandre Belloni 		return -ENOIOCTLCMD;
534e6e7376cSAlexandre Belloni 	}
535e6e7376cSAlexandre Belloni }
536e6e7376cSAlexandre Belloni 
537e6e7376cSAlexandre Belloni static int rv3028_nvram_write(void *priv, unsigned int offset, void *val,
538e6e7376cSAlexandre Belloni 			      size_t bytes)
539e6e7376cSAlexandre Belloni {
540e6e7376cSAlexandre Belloni 	return regmap_bulk_write(priv, RV3028_RAM1 + offset, val, bytes);
541e6e7376cSAlexandre Belloni }
542e6e7376cSAlexandre Belloni 
543e6e7376cSAlexandre Belloni static int rv3028_nvram_read(void *priv, unsigned int offset, void *val,
544e6e7376cSAlexandre Belloni 			     size_t bytes)
545e6e7376cSAlexandre Belloni {
546e6e7376cSAlexandre Belloni 	return regmap_bulk_read(priv, RV3028_RAM1 + offset, val, bytes);
547e6e7376cSAlexandre Belloni }
548e6e7376cSAlexandre Belloni 
549e6e7376cSAlexandre Belloni static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val,
550e6e7376cSAlexandre Belloni 			       size_t bytes)
551e6e7376cSAlexandre Belloni {
552de0ad60eSAlexandre Belloni 	struct rv3028_data *rv3028 = priv;
553de0ad60eSAlexandre Belloni 	u32 status, eerd;
554de0ad60eSAlexandre Belloni 	int i, ret;
555e6e7376cSAlexandre Belloni 	u8 *buf = val;
556e6e7376cSAlexandre Belloni 
557de0ad60eSAlexandre Belloni 	ret = rv3028_enter_eerd(rv3028, &eerd);
558e6e7376cSAlexandre Belloni 	if (ret)
559e6e7376cSAlexandre Belloni 		return ret;
560e6e7376cSAlexandre Belloni 
561e6e7376cSAlexandre Belloni 	for (i = 0; i < bytes; i++) {
562de0ad60eSAlexandre Belloni 		ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i);
563e6e7376cSAlexandre Belloni 		if (ret)
564e6e7376cSAlexandre Belloni 			goto restore_eerd;
565e6e7376cSAlexandre Belloni 
566de0ad60eSAlexandre Belloni 		ret = regmap_write(rv3028->regmap, RV3028_EEPROM_DATA, buf[i]);
567e6e7376cSAlexandre Belloni 		if (ret)
568e6e7376cSAlexandre Belloni 			goto restore_eerd;
569e6e7376cSAlexandre Belloni 
570de0ad60eSAlexandre Belloni 		ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
571e6e7376cSAlexandre Belloni 		if (ret)
572e6e7376cSAlexandre Belloni 			goto restore_eerd;
573e6e7376cSAlexandre Belloni 
574de0ad60eSAlexandre Belloni 		ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD,
575e6e7376cSAlexandre Belloni 				   RV3028_EEPROM_CMD_WRITE);
576e6e7376cSAlexandre Belloni 		if (ret)
577e6e7376cSAlexandre Belloni 			goto restore_eerd;
578e6e7376cSAlexandre Belloni 
579e6e7376cSAlexandre Belloni 		usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
580e6e7376cSAlexandre Belloni 
581de0ad60eSAlexandre Belloni 		ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
582e6e7376cSAlexandre Belloni 					       !(status & RV3028_STATUS_EEBUSY),
583e6e7376cSAlexandre Belloni 					       RV3028_EEBUSY_POLL,
584e6e7376cSAlexandre Belloni 					       RV3028_EEBUSY_TIMEOUT);
585e6e7376cSAlexandre Belloni 		if (ret)
586e6e7376cSAlexandre Belloni 			goto restore_eerd;
587e6e7376cSAlexandre Belloni 	}
588e6e7376cSAlexandre Belloni 
589e6e7376cSAlexandre Belloni restore_eerd:
590de0ad60eSAlexandre Belloni 	rv3028_exit_eerd(rv3028, eerd);
591e6e7376cSAlexandre Belloni 
592e6e7376cSAlexandre Belloni 	return ret;
593e6e7376cSAlexandre Belloni }
594e6e7376cSAlexandre Belloni 
595e6e7376cSAlexandre Belloni static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val,
596e6e7376cSAlexandre Belloni 			      size_t bytes)
597e6e7376cSAlexandre Belloni {
598de0ad60eSAlexandre Belloni 	struct rv3028_data *rv3028 = priv;
599de0ad60eSAlexandre Belloni 	u32 status, eerd, data;
600de0ad60eSAlexandre Belloni 	int i, ret;
601e6e7376cSAlexandre Belloni 	u8 *buf = val;
602e6e7376cSAlexandre Belloni 
603de0ad60eSAlexandre Belloni 	ret = rv3028_enter_eerd(rv3028, &eerd);
604e6e7376cSAlexandre Belloni 	if (ret)
605e6e7376cSAlexandre Belloni 		return ret;
606e6e7376cSAlexandre Belloni 
607e6e7376cSAlexandre Belloni 	for (i = 0; i < bytes; i++) {
608de0ad60eSAlexandre Belloni 		ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i);
609e6e7376cSAlexandre Belloni 		if (ret)
610e6e7376cSAlexandre Belloni 			goto restore_eerd;
611e6e7376cSAlexandre Belloni 
612de0ad60eSAlexandre Belloni 		ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
613e6e7376cSAlexandre Belloni 		if (ret)
614e6e7376cSAlexandre Belloni 			goto restore_eerd;
615e6e7376cSAlexandre Belloni 
616de0ad60eSAlexandre Belloni 		ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD,
617e6e7376cSAlexandre Belloni 				   RV3028_EEPROM_CMD_READ);
618e6e7376cSAlexandre Belloni 		if (ret)
619e6e7376cSAlexandre Belloni 			goto restore_eerd;
620e6e7376cSAlexandre Belloni 
621de0ad60eSAlexandre Belloni 		ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
622e6e7376cSAlexandre Belloni 					       !(status & RV3028_STATUS_EEBUSY),
623e6e7376cSAlexandre Belloni 					       RV3028_EEBUSY_POLL,
624e6e7376cSAlexandre Belloni 					       RV3028_EEBUSY_TIMEOUT);
625e6e7376cSAlexandre Belloni 		if (ret)
626e6e7376cSAlexandre Belloni 			goto restore_eerd;
627e6e7376cSAlexandre Belloni 
628de0ad60eSAlexandre Belloni 		ret = regmap_read(rv3028->regmap, RV3028_EEPROM_DATA, &data);
629e6e7376cSAlexandre Belloni 		if (ret)
630e6e7376cSAlexandre Belloni 			goto restore_eerd;
631e6e7376cSAlexandre Belloni 		buf[i] = data;
632e6e7376cSAlexandre Belloni 	}
633e6e7376cSAlexandre Belloni 
634e6e7376cSAlexandre Belloni restore_eerd:
635de0ad60eSAlexandre Belloni 	rv3028_exit_eerd(rv3028, eerd);
636e6e7376cSAlexandre Belloni 
637e6e7376cSAlexandre Belloni 	return ret;
638e6e7376cSAlexandre Belloni }
639e6e7376cSAlexandre Belloni 
640f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK
641f583c341SParthiban Nallathambi #define clkout_hw_to_rv3028(hw) container_of(hw, struct rv3028_data, clkout_hw)
642f583c341SParthiban Nallathambi 
643f583c341SParthiban Nallathambi static int clkout_rates[] = {
644f583c341SParthiban Nallathambi 	32768,
645f583c341SParthiban Nallathambi 	8192,
646f583c341SParthiban Nallathambi 	1024,
647f583c341SParthiban Nallathambi 	64,
648f583c341SParthiban Nallathambi 	32,
649f583c341SParthiban Nallathambi 	1,
650f583c341SParthiban Nallathambi };
651f583c341SParthiban Nallathambi 
652f583c341SParthiban Nallathambi static unsigned long rv3028_clkout_recalc_rate(struct clk_hw *hw,
653f583c341SParthiban Nallathambi 					       unsigned long parent_rate)
654f583c341SParthiban Nallathambi {
655f583c341SParthiban Nallathambi 	int clkout, ret;
656f583c341SParthiban Nallathambi 	struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
657f583c341SParthiban Nallathambi 
658f583c341SParthiban Nallathambi 	ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout);
659f583c341SParthiban Nallathambi 	if (ret < 0)
660f583c341SParthiban Nallathambi 		return 0;
661f583c341SParthiban Nallathambi 
662f583c341SParthiban Nallathambi 	clkout &= RV3028_CLKOUT_FD_MASK;
663f583c341SParthiban Nallathambi 	return clkout_rates[clkout];
664f583c341SParthiban Nallathambi }
665f583c341SParthiban Nallathambi 
666f583c341SParthiban Nallathambi static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
667f583c341SParthiban Nallathambi 				     unsigned long *prate)
668f583c341SParthiban Nallathambi {
669f583c341SParthiban Nallathambi 	int i;
670f583c341SParthiban Nallathambi 
671f583c341SParthiban Nallathambi 	for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
672f583c341SParthiban Nallathambi 		if (clkout_rates[i] <= rate)
673f583c341SParthiban Nallathambi 			return clkout_rates[i];
674f583c341SParthiban Nallathambi 
675f583c341SParthiban Nallathambi 	return 0;
676f583c341SParthiban Nallathambi }
677f583c341SParthiban Nallathambi 
678f583c341SParthiban Nallathambi static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
679f583c341SParthiban Nallathambi 				  unsigned long parent_rate)
680f583c341SParthiban Nallathambi {
681f583c341SParthiban Nallathambi 	int i, ret;
68200e8e87fSAlexandre Belloni 	u32 enabled;
683f583c341SParthiban Nallathambi 	struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
684f583c341SParthiban Nallathambi 
68500e8e87fSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &enabled);
68600e8e87fSAlexandre Belloni 	if (ret < 0)
68700e8e87fSAlexandre Belloni 		return ret;
68800e8e87fSAlexandre Belloni 
689f583c341SParthiban Nallathambi 	ret = regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0);
690f583c341SParthiban Nallathambi 	if (ret < 0)
691f583c341SParthiban Nallathambi 		return ret;
692f583c341SParthiban Nallathambi 
69300e8e87fSAlexandre Belloni 	enabled &= RV3028_CLKOUT_CLKOE;
694f583c341SParthiban Nallathambi 
69500e8e87fSAlexandre Belloni 	for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
69600e8e87fSAlexandre Belloni 		if (clkout_rates[i] == rate)
697024e6f3dSAlexandre Belloni 			return rv3028_update_cfg(rv3028, RV3028_CLKOUT, 0xff,
69800e8e87fSAlexandre Belloni 						 RV3028_CLKOUT_CLKSY | enabled | i);
699f583c341SParthiban Nallathambi 
700f583c341SParthiban Nallathambi 	return -EINVAL;
701f583c341SParthiban Nallathambi }
702f583c341SParthiban Nallathambi 
703f583c341SParthiban Nallathambi static int rv3028_clkout_prepare(struct clk_hw *hw)
704f583c341SParthiban Nallathambi {
705f583c341SParthiban Nallathambi 	struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
706f583c341SParthiban Nallathambi 
707f583c341SParthiban Nallathambi 	return regmap_write(rv3028->regmap, RV3028_CLKOUT,
708f583c341SParthiban Nallathambi 			    RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE);
709f583c341SParthiban Nallathambi }
710f583c341SParthiban Nallathambi 
711f583c341SParthiban Nallathambi static void rv3028_clkout_unprepare(struct clk_hw *hw)
712f583c341SParthiban Nallathambi {
713f583c341SParthiban Nallathambi 	struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
714f583c341SParthiban Nallathambi 
715f583c341SParthiban Nallathambi 	regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0);
716f583c341SParthiban Nallathambi 	regmap_update_bits(rv3028->regmap, RV3028_STATUS,
717f583c341SParthiban Nallathambi 			   RV3028_STATUS_CLKF, 0);
718f583c341SParthiban Nallathambi }
719f583c341SParthiban Nallathambi 
720f583c341SParthiban Nallathambi static int rv3028_clkout_is_prepared(struct clk_hw *hw)
721f583c341SParthiban Nallathambi {
722f583c341SParthiban Nallathambi 	int clkout, ret;
723f583c341SParthiban Nallathambi 	struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
724f583c341SParthiban Nallathambi 
725f583c341SParthiban Nallathambi 	ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout);
726f583c341SParthiban Nallathambi 	if (ret < 0)
727f583c341SParthiban Nallathambi 		return ret;
728f583c341SParthiban Nallathambi 
729f583c341SParthiban Nallathambi 	return !!(clkout & RV3028_CLKOUT_CLKOE);
730f583c341SParthiban Nallathambi }
731f583c341SParthiban Nallathambi 
732f583c341SParthiban Nallathambi static const struct clk_ops rv3028_clkout_ops = {
733f583c341SParthiban Nallathambi 	.prepare = rv3028_clkout_prepare,
734f583c341SParthiban Nallathambi 	.unprepare = rv3028_clkout_unprepare,
735f583c341SParthiban Nallathambi 	.is_prepared = rv3028_clkout_is_prepared,
736f583c341SParthiban Nallathambi 	.recalc_rate = rv3028_clkout_recalc_rate,
737f583c341SParthiban Nallathambi 	.round_rate = rv3028_clkout_round_rate,
738f583c341SParthiban Nallathambi 	.set_rate = rv3028_clkout_set_rate,
739f583c341SParthiban Nallathambi };
740f583c341SParthiban Nallathambi 
741f583c341SParthiban Nallathambi static int rv3028_clkout_register_clk(struct rv3028_data *rv3028,
742f583c341SParthiban Nallathambi 				      struct i2c_client *client)
743f583c341SParthiban Nallathambi {
744f583c341SParthiban Nallathambi 	int ret;
745f583c341SParthiban Nallathambi 	struct clk *clk;
746f583c341SParthiban Nallathambi 	struct clk_init_data init;
747f583c341SParthiban Nallathambi 	struct device_node *node = client->dev.of_node;
748f583c341SParthiban Nallathambi 
749f583c341SParthiban Nallathambi 	ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
750f583c341SParthiban Nallathambi 				 RV3028_STATUS_CLKF, 0);
751f583c341SParthiban Nallathambi 	if (ret < 0)
752f583c341SParthiban Nallathambi 		return ret;
753f583c341SParthiban Nallathambi 
754f583c341SParthiban Nallathambi 	init.name = "rv3028-clkout";
755f583c341SParthiban Nallathambi 	init.ops = &rv3028_clkout_ops;
756f583c341SParthiban Nallathambi 	init.flags = 0;
757f583c341SParthiban Nallathambi 	init.parent_names = NULL;
758f583c341SParthiban Nallathambi 	init.num_parents = 0;
759f583c341SParthiban Nallathambi 	rv3028->clkout_hw.init = &init;
760f583c341SParthiban Nallathambi 
761f583c341SParthiban Nallathambi 	/* optional override of the clockname */
762f583c341SParthiban Nallathambi 	of_property_read_string(node, "clock-output-names", &init.name);
763f583c341SParthiban Nallathambi 
764f583c341SParthiban Nallathambi 	/* register the clock */
765f583c341SParthiban Nallathambi 	clk = devm_clk_register(&client->dev, &rv3028->clkout_hw);
766f583c341SParthiban Nallathambi 	if (!IS_ERR(clk))
767f583c341SParthiban Nallathambi 		of_clk_add_provider(node, of_clk_src_simple_get, clk);
768f583c341SParthiban Nallathambi 
769f583c341SParthiban Nallathambi 	return 0;
770f583c341SParthiban Nallathambi }
771f583c341SParthiban Nallathambi #endif
772f583c341SParthiban Nallathambi 
773*0f769569SAlexandre Belloni static const struct rtc_class_ops rv3028_rtc_ops = {
774e6e7376cSAlexandre Belloni 	.read_time = rv3028_get_time,
775e6e7376cSAlexandre Belloni 	.set_time = rv3028_set_time,
776*0f769569SAlexandre Belloni 	.read_alarm = rv3028_get_alarm,
777*0f769569SAlexandre Belloni 	.set_alarm = rv3028_set_alarm,
778*0f769569SAlexandre Belloni 	.alarm_irq_enable = rv3028_alarm_irq_enable,
779e6e7376cSAlexandre Belloni 	.read_offset = rv3028_read_offset,
780e6e7376cSAlexandre Belloni 	.set_offset = rv3028_set_offset,
781e6e7376cSAlexandre Belloni 	.ioctl = rv3028_ioctl,
782e6e7376cSAlexandre Belloni };
783e6e7376cSAlexandre Belloni 
784e6e7376cSAlexandre Belloni static const struct regmap_config regmap_config = {
785e6e7376cSAlexandre Belloni         .reg_bits = 8,
786e6e7376cSAlexandre Belloni         .val_bits = 8,
787e6e7376cSAlexandre Belloni         .max_register = 0x37,
788e6e7376cSAlexandre Belloni };
789e6e7376cSAlexandre Belloni 
790e6e7376cSAlexandre Belloni static int rv3028_probe(struct i2c_client *client)
791e6e7376cSAlexandre Belloni {
792e6e7376cSAlexandre Belloni 	struct rv3028_data *rv3028;
793e6e7376cSAlexandre Belloni 	int ret, status;
794e6e7376cSAlexandre Belloni 	u32 ohms;
795e6e7376cSAlexandre Belloni 	struct nvmem_config nvmem_cfg = {
796e6e7376cSAlexandre Belloni 		.name = "rv3028_nvram",
797e6e7376cSAlexandre Belloni 		.word_size = 1,
798e6e7376cSAlexandre Belloni 		.stride = 1,
799e6e7376cSAlexandre Belloni 		.size = 2,
800e6e7376cSAlexandre Belloni 		.type = NVMEM_TYPE_BATTERY_BACKED,
801e6e7376cSAlexandre Belloni 		.reg_read = rv3028_nvram_read,
802e6e7376cSAlexandre Belloni 		.reg_write = rv3028_nvram_write,
803e6e7376cSAlexandre Belloni 	};
804e6e7376cSAlexandre Belloni 	struct nvmem_config eeprom_cfg = {
805e6e7376cSAlexandre Belloni 		.name = "rv3028_eeprom",
806e6e7376cSAlexandre Belloni 		.word_size = 1,
807e6e7376cSAlexandre Belloni 		.stride = 1,
808e6e7376cSAlexandre Belloni 		.size = 43,
809e6e7376cSAlexandre Belloni 		.type = NVMEM_TYPE_EEPROM,
810e6e7376cSAlexandre Belloni 		.reg_read = rv3028_eeprom_read,
811e6e7376cSAlexandre Belloni 		.reg_write = rv3028_eeprom_write,
812e6e7376cSAlexandre Belloni 	};
813e6e7376cSAlexandre Belloni 
814e6e7376cSAlexandre Belloni 	rv3028 = devm_kzalloc(&client->dev, sizeof(struct rv3028_data),
815e6e7376cSAlexandre Belloni 			      GFP_KERNEL);
816e6e7376cSAlexandre Belloni 	if (!rv3028)
817e6e7376cSAlexandre Belloni 		return -ENOMEM;
818e6e7376cSAlexandre Belloni 
819e6e7376cSAlexandre Belloni 	rv3028->regmap = devm_regmap_init_i2c(client, &regmap_config);
820c3b29bf6SChuhong Yuan 	if (IS_ERR(rv3028->regmap))
821c3b29bf6SChuhong Yuan 		return PTR_ERR(rv3028->regmap);
822e6e7376cSAlexandre Belloni 
823e6e7376cSAlexandre Belloni 	i2c_set_clientdata(client, rv3028);
824e6e7376cSAlexandre Belloni 
825e6e7376cSAlexandre Belloni 	ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
826e6e7376cSAlexandre Belloni 	if (ret < 0)
827e6e7376cSAlexandre Belloni 		return ret;
828e6e7376cSAlexandre Belloni 
829e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_PORF)
830e6e7376cSAlexandre Belloni 		dev_warn(&client->dev, "Voltage low, data loss detected.\n");
831e6e7376cSAlexandre Belloni 
832e6e7376cSAlexandre Belloni 	if (status & RV3028_STATUS_AF)
833e6e7376cSAlexandre Belloni 		dev_warn(&client->dev, "An alarm may have been missed.\n");
834e6e7376cSAlexandre Belloni 
835e6e7376cSAlexandre Belloni 	rv3028->rtc = devm_rtc_allocate_device(&client->dev);
83644c638ceSAlexandre Belloni 	if (IS_ERR(rv3028->rtc))
837e6e7376cSAlexandre Belloni 		return PTR_ERR(rv3028->rtc);
838e6e7376cSAlexandre Belloni 
839e6e7376cSAlexandre Belloni 	if (client->irq > 0) {
840e6e7376cSAlexandre Belloni 		ret = devm_request_threaded_irq(&client->dev, client->irq,
841e6e7376cSAlexandre Belloni 						NULL, rv3028_handle_irq,
842e6e7376cSAlexandre Belloni 						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
843e6e7376cSAlexandre Belloni 						"rv3028", rv3028);
844e6e7376cSAlexandre Belloni 		if (ret) {
845e6e7376cSAlexandre Belloni 			dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
846e6e7376cSAlexandre Belloni 			client->irq = 0;
847e6e7376cSAlexandre Belloni 		}
848e6e7376cSAlexandre Belloni 	}
849*0f769569SAlexandre Belloni 	if (!client->irq)
850*0f769569SAlexandre Belloni 		clear_bit(RTC_FEATURE_ALARM, rv3028->rtc->features);
851e6e7376cSAlexandre Belloni 
852e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
853e6e7376cSAlexandre Belloni 				 RV3028_CTRL1_WADA, RV3028_CTRL1_WADA);
854e6e7376cSAlexandre Belloni 	if (ret)
855e6e7376cSAlexandre Belloni 		return ret;
856e6e7376cSAlexandre Belloni 
857e6e7376cSAlexandre Belloni 	/* setup timestamping */
858e6e7376cSAlexandre Belloni 	ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
859e6e7376cSAlexandre Belloni 				 RV3028_CTRL2_EIE | RV3028_CTRL2_TSE,
860e6e7376cSAlexandre Belloni 				 RV3028_CTRL2_EIE | RV3028_CTRL2_TSE);
861e6e7376cSAlexandre Belloni 	if (ret)
862e6e7376cSAlexandre Belloni 		return ret;
863e6e7376cSAlexandre Belloni 
864e6e7376cSAlexandre Belloni 	/* setup trickle charger */
865e6e7376cSAlexandre Belloni 	if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
866e6e7376cSAlexandre Belloni 				      &ohms)) {
867e6e7376cSAlexandre Belloni 		int i;
868e6e7376cSAlexandre Belloni 
869e6e7376cSAlexandre Belloni 		for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
870e6e7376cSAlexandre Belloni 			if (ohms == rv3028_trickle_resistors[i])
871e6e7376cSAlexandre Belloni 				break;
872e6e7376cSAlexandre Belloni 
873e6e7376cSAlexandre Belloni 		if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
874024e6f3dSAlexandre Belloni 			ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE |
875024e6f3dSAlexandre Belloni 						 RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i);
876e6e7376cSAlexandre Belloni 			if (ret)
877e6e7376cSAlexandre Belloni 				return ret;
878e6e7376cSAlexandre Belloni 		} else {
879e6e7376cSAlexandre Belloni 			dev_warn(&client->dev, "invalid trickle resistor value\n");
880e6e7376cSAlexandre Belloni 		}
881e6e7376cSAlexandre Belloni 	}
882e6e7376cSAlexandre Belloni 
883e6e7376cSAlexandre Belloni 	ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
884e6e7376cSAlexandre Belloni 	if (ret)
885e6e7376cSAlexandre Belloni 		return ret;
886e6e7376cSAlexandre Belloni 
887e6e7376cSAlexandre Belloni 	rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
888e6e7376cSAlexandre Belloni 	rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099;
889e6e7376cSAlexandre Belloni 	rv3028->rtc->ops = &rv3028_rtc_ops;
890fdcfd854SBartosz Golaszewski 	ret = devm_rtc_register_device(rv3028->rtc);
891e6e7376cSAlexandre Belloni 	if (ret)
892e6e7376cSAlexandre Belloni 		return ret;
893e6e7376cSAlexandre Belloni 
894e6e7376cSAlexandre Belloni 	nvmem_cfg.priv = rv3028->regmap;
8953a905c2dSBartosz Golaszewski 	devm_rtc_nvmem_register(rv3028->rtc, &nvmem_cfg);
896de0ad60eSAlexandre Belloni 	eeprom_cfg.priv = rv3028;
8973a905c2dSBartosz Golaszewski 	devm_rtc_nvmem_register(rv3028->rtc, &eeprom_cfg);
898e6e7376cSAlexandre Belloni 
899e6e7376cSAlexandre Belloni 	rv3028->rtc->max_user_freq = 1;
900e6e7376cSAlexandre Belloni 
901f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK
902f583c341SParthiban Nallathambi 	rv3028_clkout_register_clk(rv3028, client);
903f583c341SParthiban Nallathambi #endif
904e6e7376cSAlexandre Belloni 	return 0;
905e6e7376cSAlexandre Belloni }
906e6e7376cSAlexandre Belloni 
907e6e7376cSAlexandre Belloni static const struct of_device_id rv3028_of_match[] = {
908e6e7376cSAlexandre Belloni 	{ .compatible = "microcrystal,rv3028", },
909e6e7376cSAlexandre Belloni 	{ }
910e6e7376cSAlexandre Belloni };
911e6e7376cSAlexandre Belloni MODULE_DEVICE_TABLE(of, rv3028_of_match);
912e6e7376cSAlexandre Belloni 
913e6e7376cSAlexandre Belloni static struct i2c_driver rv3028_driver = {
914e6e7376cSAlexandre Belloni 	.driver = {
915e6e7376cSAlexandre Belloni 		.name = "rtc-rv3028",
916e6e7376cSAlexandre Belloni 		.of_match_table = of_match_ptr(rv3028_of_match),
917e6e7376cSAlexandre Belloni 	},
918e6e7376cSAlexandre Belloni 	.probe_new	= rv3028_probe,
919e6e7376cSAlexandre Belloni };
920e6e7376cSAlexandre Belloni module_i2c_driver(rv3028_driver);
921e6e7376cSAlexandre Belloni 
922e6e7376cSAlexandre Belloni MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
923e6e7376cSAlexandre Belloni MODULE_DESCRIPTION("Micro Crystal RV3028 RTC driver");
924e6e7376cSAlexandre Belloni MODULE_LICENSE("GPL v2");
925