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>
13018d959bSAlexandre Belloni #include <linux/bitfield.h>
14e6e7376cSAlexandre Belloni #include <linux/bitops.h>
15e6e7376cSAlexandre Belloni #include <linux/i2c.h>
16e6e7376cSAlexandre Belloni #include <linux/interrupt.h>
17e6e7376cSAlexandre Belloni #include <linux/kernel.h>
18e6e7376cSAlexandre Belloni #include <linux/log2.h>
19e6e7376cSAlexandre Belloni #include <linux/module.h>
20*48144c28SRob Herring #include <linux/of.h>
21e6e7376cSAlexandre Belloni #include <linux/regmap.h>
22e6e7376cSAlexandre Belloni #include <linux/rtc.h>
23e6e7376cSAlexandre Belloni
24e6e7376cSAlexandre Belloni #define RV3028_SEC 0x00
25e6e7376cSAlexandre Belloni #define RV3028_MIN 0x01
26e6e7376cSAlexandre Belloni #define RV3028_HOUR 0x02
27e6e7376cSAlexandre Belloni #define RV3028_WDAY 0x03
28e6e7376cSAlexandre Belloni #define RV3028_DAY 0x04
29e6e7376cSAlexandre Belloni #define RV3028_MONTH 0x05
30e6e7376cSAlexandre Belloni #define RV3028_YEAR 0x06
31e6e7376cSAlexandre Belloni #define RV3028_ALARM_MIN 0x07
32e6e7376cSAlexandre Belloni #define RV3028_ALARM_HOUR 0x08
33e6e7376cSAlexandre Belloni #define RV3028_ALARM_DAY 0x09
34e6e7376cSAlexandre Belloni #define RV3028_STATUS 0x0E
35e6e7376cSAlexandre Belloni #define RV3028_CTRL1 0x0F
36e6e7376cSAlexandre Belloni #define RV3028_CTRL2 0x10
37e6e7376cSAlexandre Belloni #define RV3028_EVT_CTRL 0x13
38e6e7376cSAlexandre Belloni #define RV3028_TS_COUNT 0x14
39e6e7376cSAlexandre Belloni #define RV3028_TS_SEC 0x15
40e6e7376cSAlexandre Belloni #define RV3028_RAM1 0x1F
41e6e7376cSAlexandre Belloni #define RV3028_EEPROM_ADDR 0x25
42e6e7376cSAlexandre Belloni #define RV3028_EEPROM_DATA 0x26
43e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD 0x27
44e6e7376cSAlexandre Belloni #define RV3028_CLKOUT 0x35
45e6e7376cSAlexandre Belloni #define RV3028_OFFSET 0x36
46e6e7376cSAlexandre Belloni #define RV3028_BACKUP 0x37
47e6e7376cSAlexandre Belloni
48e6e7376cSAlexandre Belloni #define RV3028_STATUS_PORF BIT(0)
49e6e7376cSAlexandre Belloni #define RV3028_STATUS_EVF BIT(1)
50e6e7376cSAlexandre Belloni #define RV3028_STATUS_AF BIT(2)
51e6e7376cSAlexandre Belloni #define RV3028_STATUS_TF BIT(3)
52e6e7376cSAlexandre Belloni #define RV3028_STATUS_UF BIT(4)
53e6e7376cSAlexandre Belloni #define RV3028_STATUS_BSF BIT(5)
54e6e7376cSAlexandre Belloni #define RV3028_STATUS_CLKF BIT(6)
55e6e7376cSAlexandre Belloni #define RV3028_STATUS_EEBUSY BIT(7)
56e6e7376cSAlexandre Belloni
57f583c341SParthiban Nallathambi #define RV3028_CLKOUT_FD_MASK GENMASK(2, 0)
58f583c341SParthiban Nallathambi #define RV3028_CLKOUT_PORIE BIT(3)
59f583c341SParthiban Nallathambi #define RV3028_CLKOUT_CLKSY BIT(6)
60f583c341SParthiban Nallathambi #define RV3028_CLKOUT_CLKOE BIT(7)
61f583c341SParthiban Nallathambi
62e6e7376cSAlexandre Belloni #define RV3028_CTRL1_EERD BIT(3)
63e6e7376cSAlexandre Belloni #define RV3028_CTRL1_WADA BIT(5)
64e6e7376cSAlexandre Belloni
65e6e7376cSAlexandre Belloni #define RV3028_CTRL2_RESET BIT(0)
66e6e7376cSAlexandre Belloni #define RV3028_CTRL2_12_24 BIT(1)
67e6e7376cSAlexandre Belloni #define RV3028_CTRL2_EIE BIT(2)
68e6e7376cSAlexandre Belloni #define RV3028_CTRL2_AIE BIT(3)
69e6e7376cSAlexandre Belloni #define RV3028_CTRL2_TIE BIT(4)
70e6e7376cSAlexandre Belloni #define RV3028_CTRL2_UIE BIT(5)
71e6e7376cSAlexandre Belloni #define RV3028_CTRL2_TSE BIT(7)
72e6e7376cSAlexandre Belloni
73e6e7376cSAlexandre Belloni #define RV3028_EVT_CTRL_TSR BIT(2)
74e6e7376cSAlexandre Belloni
75024e6f3dSAlexandre Belloni #define RV3028_EEPROM_CMD_UPDATE 0x11
76e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD_WRITE 0x21
77e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD_READ 0x22
78e6e7376cSAlexandre Belloni
79e6e7376cSAlexandre Belloni #define RV3028_EEBUSY_POLL 10000
80e6e7376cSAlexandre Belloni #define RV3028_EEBUSY_TIMEOUT 100000
81e6e7376cSAlexandre Belloni
82e6e7376cSAlexandre Belloni #define RV3028_BACKUP_TCE BIT(5)
83e6e7376cSAlexandre Belloni #define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
84018d959bSAlexandre Belloni #define RV3028_BACKUP_BSM GENMASK(3,2)
85018d959bSAlexandre Belloni
86018d959bSAlexandre Belloni #define RV3028_BACKUP_BSM_DSM 0x1
87018d959bSAlexandre Belloni #define RV3028_BACKUP_BSM_LSM 0x3
88e6e7376cSAlexandre Belloni
89e6e7376cSAlexandre Belloni #define OFFSET_STEP_PPT 953674
90e6e7376cSAlexandre Belloni
91e6e7376cSAlexandre Belloni enum rv3028_type {
92e6e7376cSAlexandre Belloni rv_3028,
93e6e7376cSAlexandre Belloni };
94e6e7376cSAlexandre Belloni
95e6e7376cSAlexandre Belloni struct rv3028_data {
96e6e7376cSAlexandre Belloni struct regmap *regmap;
97e6e7376cSAlexandre Belloni struct rtc_device *rtc;
98e6e7376cSAlexandre Belloni enum rv3028_type type;
99f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK
100f583c341SParthiban Nallathambi struct clk_hw clkout_hw;
101f583c341SParthiban Nallathambi #endif
102e6e7376cSAlexandre Belloni };
103e6e7376cSAlexandre Belloni
104c1efae14SAlexandre Belloni static u16 rv3028_trickle_resistors[] = {3000, 5000, 9000, 15000};
105e6e7376cSAlexandre Belloni
timestamp0_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)106e6e7376cSAlexandre Belloni static ssize_t timestamp0_store(struct device *dev,
107e6e7376cSAlexandre Belloni struct device_attribute *attr,
108e6e7376cSAlexandre Belloni const char *buf, size_t count)
109e6e7376cSAlexandre Belloni {
110e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
111e6e7376cSAlexandre Belloni
112e6e7376cSAlexandre Belloni regmap_update_bits(rv3028->regmap, RV3028_EVT_CTRL, RV3028_EVT_CTRL_TSR,
113e6e7376cSAlexandre Belloni RV3028_EVT_CTRL_TSR);
114e6e7376cSAlexandre Belloni
115e6e7376cSAlexandre Belloni return count;
116e6e7376cSAlexandre Belloni };
117e6e7376cSAlexandre Belloni
timestamp0_show(struct device * dev,struct device_attribute * attr,char * buf)118e6e7376cSAlexandre Belloni static ssize_t timestamp0_show(struct device *dev,
119e6e7376cSAlexandre Belloni struct device_attribute *attr, char *buf)
120e6e7376cSAlexandre Belloni {
121e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
122e6e7376cSAlexandre Belloni struct rtc_time tm;
123e6e7376cSAlexandre Belloni int ret, count;
124e6e7376cSAlexandre Belloni u8 date[6];
125e6e7376cSAlexandre Belloni
126e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
127e6e7376cSAlexandre Belloni if (ret)
128e6e7376cSAlexandre Belloni return ret;
129e6e7376cSAlexandre Belloni
130e6e7376cSAlexandre Belloni if (!count)
131e6e7376cSAlexandre Belloni return 0;
132e6e7376cSAlexandre Belloni
133e6e7376cSAlexandre Belloni ret = regmap_bulk_read(rv3028->regmap, RV3028_TS_SEC, date,
134e6e7376cSAlexandre Belloni sizeof(date));
135e6e7376cSAlexandre Belloni if (ret)
136e6e7376cSAlexandre Belloni return ret;
137e6e7376cSAlexandre Belloni
138e6e7376cSAlexandre Belloni tm.tm_sec = bcd2bin(date[0]);
139e6e7376cSAlexandre Belloni tm.tm_min = bcd2bin(date[1]);
140e6e7376cSAlexandre Belloni tm.tm_hour = bcd2bin(date[2]);
141e6e7376cSAlexandre Belloni tm.tm_mday = bcd2bin(date[3]);
142e6e7376cSAlexandre Belloni tm.tm_mon = bcd2bin(date[4]) - 1;
143e6e7376cSAlexandre Belloni tm.tm_year = bcd2bin(date[5]) + 100;
144e6e7376cSAlexandre Belloni
145e6e7376cSAlexandre Belloni ret = rtc_valid_tm(&tm);
146e6e7376cSAlexandre Belloni if (ret)
147e6e7376cSAlexandre Belloni return ret;
148e6e7376cSAlexandre Belloni
149e6e7376cSAlexandre Belloni return sprintf(buf, "%llu\n",
150e6e7376cSAlexandre Belloni (unsigned long long)rtc_tm_to_time64(&tm));
151e6e7376cSAlexandre Belloni };
152e6e7376cSAlexandre Belloni
153e6e7376cSAlexandre Belloni static DEVICE_ATTR_RW(timestamp0);
154e6e7376cSAlexandre Belloni
timestamp0_count_show(struct device * dev,struct device_attribute * attr,char * buf)155e6e7376cSAlexandre Belloni static ssize_t timestamp0_count_show(struct device *dev,
156e6e7376cSAlexandre Belloni struct device_attribute *attr, char *buf)
157e6e7376cSAlexandre Belloni {
158e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
159e6e7376cSAlexandre Belloni int ret, count;
160e6e7376cSAlexandre Belloni
161e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
162e6e7376cSAlexandre Belloni if (ret)
163e6e7376cSAlexandre Belloni return ret;
164e6e7376cSAlexandre Belloni
165e6e7376cSAlexandre Belloni return sprintf(buf, "%u\n", count);
166e6e7376cSAlexandre Belloni };
167e6e7376cSAlexandre Belloni
168e6e7376cSAlexandre Belloni static DEVICE_ATTR_RO(timestamp0_count);
169e6e7376cSAlexandre Belloni
170e6e7376cSAlexandre Belloni static struct attribute *rv3028_attrs[] = {
171e6e7376cSAlexandre Belloni &dev_attr_timestamp0.attr,
172e6e7376cSAlexandre Belloni &dev_attr_timestamp0_count.attr,
173e6e7376cSAlexandre Belloni NULL
174e6e7376cSAlexandre Belloni };
175e6e7376cSAlexandre Belloni
176e6e7376cSAlexandre Belloni static const struct attribute_group rv3028_attr_group = {
177e6e7376cSAlexandre Belloni .attrs = rv3028_attrs,
178e6e7376cSAlexandre Belloni };
179e6e7376cSAlexandre Belloni
rv3028_exit_eerd(struct rv3028_data * rv3028,u32 eerd)180de0ad60eSAlexandre Belloni static int rv3028_exit_eerd(struct rv3028_data *rv3028, u32 eerd)
181de0ad60eSAlexandre Belloni {
182de0ad60eSAlexandre Belloni if (eerd)
183de0ad60eSAlexandre Belloni return 0;
184de0ad60eSAlexandre Belloni
185de0ad60eSAlexandre Belloni return regmap_update_bits(rv3028->regmap, RV3028_CTRL1, RV3028_CTRL1_EERD, 0);
186de0ad60eSAlexandre Belloni }
187de0ad60eSAlexandre Belloni
rv3028_enter_eerd(struct rv3028_data * rv3028,u32 * eerd)188de0ad60eSAlexandre Belloni static int rv3028_enter_eerd(struct rv3028_data *rv3028, u32 *eerd)
189de0ad60eSAlexandre Belloni {
190de0ad60eSAlexandre Belloni u32 ctrl1, status;
191de0ad60eSAlexandre Belloni int ret;
192de0ad60eSAlexandre Belloni
193de0ad60eSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_CTRL1, &ctrl1);
194de0ad60eSAlexandre Belloni if (ret)
195de0ad60eSAlexandre Belloni return ret;
196de0ad60eSAlexandre Belloni
197de0ad60eSAlexandre Belloni *eerd = ctrl1 & RV3028_CTRL1_EERD;
198de0ad60eSAlexandre Belloni if (*eerd)
199de0ad60eSAlexandre Belloni return 0;
200de0ad60eSAlexandre Belloni
201de0ad60eSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
202de0ad60eSAlexandre Belloni RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
203de0ad60eSAlexandre Belloni if (ret)
204de0ad60eSAlexandre Belloni return ret;
205de0ad60eSAlexandre Belloni
206de0ad60eSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
207de0ad60eSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY),
208de0ad60eSAlexandre Belloni RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
209de0ad60eSAlexandre Belloni if (ret) {
210de0ad60eSAlexandre Belloni rv3028_exit_eerd(rv3028, *eerd);
211de0ad60eSAlexandre Belloni
212de0ad60eSAlexandre Belloni return ret;
213de0ad60eSAlexandre Belloni }
214de0ad60eSAlexandre Belloni
215de0ad60eSAlexandre Belloni return 0;
216de0ad60eSAlexandre Belloni }
217de0ad60eSAlexandre Belloni
rv3028_update_eeprom(struct rv3028_data * rv3028,u32 eerd)218024e6f3dSAlexandre Belloni static int rv3028_update_eeprom(struct rv3028_data *rv3028, u32 eerd)
219024e6f3dSAlexandre Belloni {
220024e6f3dSAlexandre Belloni u32 status;
221024e6f3dSAlexandre Belloni int ret;
222024e6f3dSAlexandre Belloni
223024e6f3dSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
224024e6f3dSAlexandre Belloni if (ret)
225024e6f3dSAlexandre Belloni goto exit_eerd;
226024e6f3dSAlexandre Belloni
227024e6f3dSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, RV3028_EEPROM_CMD_UPDATE);
228024e6f3dSAlexandre Belloni if (ret)
229024e6f3dSAlexandre Belloni goto exit_eerd;
230024e6f3dSAlexandre Belloni
231024e6f3dSAlexandre Belloni usleep_range(63000, RV3028_EEBUSY_TIMEOUT);
232024e6f3dSAlexandre Belloni
233024e6f3dSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
234024e6f3dSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY),
235024e6f3dSAlexandre Belloni RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
236024e6f3dSAlexandre Belloni
237024e6f3dSAlexandre Belloni exit_eerd:
238024e6f3dSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd);
239024e6f3dSAlexandre Belloni
240024e6f3dSAlexandre Belloni return ret;
241024e6f3dSAlexandre Belloni }
242024e6f3dSAlexandre Belloni
rv3028_update_cfg(struct rv3028_data * rv3028,unsigned int reg,unsigned int mask,unsigned int val)243024e6f3dSAlexandre Belloni static int rv3028_update_cfg(struct rv3028_data *rv3028, unsigned int reg,
244024e6f3dSAlexandre Belloni unsigned int mask, unsigned int val)
245024e6f3dSAlexandre Belloni {
246024e6f3dSAlexandre Belloni u32 eerd;
247024e6f3dSAlexandre Belloni int ret;
248024e6f3dSAlexandre Belloni
249024e6f3dSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd);
250024e6f3dSAlexandre Belloni if (ret)
251024e6f3dSAlexandre Belloni return ret;
252024e6f3dSAlexandre Belloni
253024e6f3dSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, reg, mask, val);
254024e6f3dSAlexandre Belloni if (ret) {
255024e6f3dSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd);
256024e6f3dSAlexandre Belloni return ret;
257024e6f3dSAlexandre Belloni }
258024e6f3dSAlexandre Belloni
259024e6f3dSAlexandre Belloni return rv3028_update_eeprom(rv3028, eerd);
260024e6f3dSAlexandre Belloni }
261024e6f3dSAlexandre Belloni
rv3028_handle_irq(int irq,void * dev_id)262e6e7376cSAlexandre Belloni static irqreturn_t rv3028_handle_irq(int irq, void *dev_id)
263e6e7376cSAlexandre Belloni {
264e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_id;
265e6e7376cSAlexandre Belloni unsigned long events = 0;
266e6e7376cSAlexandre Belloni u32 status = 0, ctrl = 0;
267e6e7376cSAlexandre Belloni
268e6e7376cSAlexandre Belloni if (regmap_read(rv3028->regmap, RV3028_STATUS, &status) < 0 ||
269e6e7376cSAlexandre Belloni status == 0) {
270e6e7376cSAlexandre Belloni return IRQ_NONE;
271e6e7376cSAlexandre Belloni }
272e6e7376cSAlexandre Belloni
273f007c479SAlexandre Belloni status &= ~RV3028_STATUS_PORF;
274f007c479SAlexandre Belloni
275e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_TF) {
276e6e7376cSAlexandre Belloni status |= RV3028_STATUS_TF;
277e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_TIE;
278e6e7376cSAlexandre Belloni events |= RTC_PF;
279e6e7376cSAlexandre Belloni }
280e6e7376cSAlexandre Belloni
281e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_AF) {
282e6e7376cSAlexandre Belloni status |= RV3028_STATUS_AF;
283e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_AIE;
284e6e7376cSAlexandre Belloni events |= RTC_AF;
285e6e7376cSAlexandre Belloni }
286e6e7376cSAlexandre Belloni
287e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_UF) {
288e6e7376cSAlexandre Belloni status |= RV3028_STATUS_UF;
289e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_UIE;
290e6e7376cSAlexandre Belloni events |= RTC_UF;
291e6e7376cSAlexandre Belloni }
292e6e7376cSAlexandre Belloni
293e6e7376cSAlexandre Belloni if (events) {
294e6e7376cSAlexandre Belloni rtc_update_irq(rv3028->rtc, 1, events);
295e6e7376cSAlexandre Belloni regmap_update_bits(rv3028->regmap, RV3028_STATUS, status, 0);
296e6e7376cSAlexandre Belloni regmap_update_bits(rv3028->regmap, RV3028_CTRL2, ctrl, 0);
297e6e7376cSAlexandre Belloni }
298e6e7376cSAlexandre Belloni
299e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_EVF) {
300e6e7376cSAlexandre Belloni sysfs_notify(&rv3028->rtc->dev.kobj, NULL,
301e6e7376cSAlexandre Belloni dev_attr_timestamp0.attr.name);
302e6e7376cSAlexandre Belloni dev_warn(&rv3028->rtc->dev, "event detected");
303e6e7376cSAlexandre Belloni }
304e6e7376cSAlexandre Belloni
305e6e7376cSAlexandre Belloni return IRQ_HANDLED;
306e6e7376cSAlexandre Belloni }
307e6e7376cSAlexandre Belloni
rv3028_get_time(struct device * dev,struct rtc_time * tm)308e6e7376cSAlexandre Belloni static int rv3028_get_time(struct device *dev, struct rtc_time *tm)
309e6e7376cSAlexandre Belloni {
310e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
311e6e7376cSAlexandre Belloni u8 date[7];
312e6e7376cSAlexandre Belloni int ret, status;
313e6e7376cSAlexandre Belloni
314e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
315e6e7376cSAlexandre Belloni if (ret < 0)
316e6e7376cSAlexandre Belloni return ret;
317e6e7376cSAlexandre Belloni
318c37b6430SAlexandre Belloni if (status & RV3028_STATUS_PORF)
319e6e7376cSAlexandre Belloni return -EINVAL;
320e6e7376cSAlexandre Belloni
321e6e7376cSAlexandre Belloni ret = regmap_bulk_read(rv3028->regmap, RV3028_SEC, date, sizeof(date));
322e6e7376cSAlexandre Belloni if (ret)
323e6e7376cSAlexandre Belloni return ret;
324e6e7376cSAlexandre Belloni
325e6e7376cSAlexandre Belloni tm->tm_sec = bcd2bin(date[RV3028_SEC] & 0x7f);
326e6e7376cSAlexandre Belloni tm->tm_min = bcd2bin(date[RV3028_MIN] & 0x7f);
327e6e7376cSAlexandre Belloni tm->tm_hour = bcd2bin(date[RV3028_HOUR] & 0x3f);
3286e00b6d0SHeiko Schocher tm->tm_wday = date[RV3028_WDAY] & 0x7f;
329e6e7376cSAlexandre Belloni tm->tm_mday = bcd2bin(date[RV3028_DAY] & 0x3f);
330e6e7376cSAlexandre Belloni tm->tm_mon = bcd2bin(date[RV3028_MONTH] & 0x1f) - 1;
331e6e7376cSAlexandre Belloni tm->tm_year = bcd2bin(date[RV3028_YEAR]) + 100;
332e6e7376cSAlexandre Belloni
333e6e7376cSAlexandre Belloni return 0;
334e6e7376cSAlexandre Belloni }
335e6e7376cSAlexandre Belloni
rv3028_set_time(struct device * dev,struct rtc_time * tm)336e6e7376cSAlexandre Belloni static int rv3028_set_time(struct device *dev, struct rtc_time *tm)
337e6e7376cSAlexandre Belloni {
338e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
339e6e7376cSAlexandre Belloni u8 date[7];
340e6e7376cSAlexandre Belloni int ret;
341e6e7376cSAlexandre Belloni
342e6e7376cSAlexandre Belloni date[RV3028_SEC] = bin2bcd(tm->tm_sec);
343e6e7376cSAlexandre Belloni date[RV3028_MIN] = bin2bcd(tm->tm_min);
344e6e7376cSAlexandre Belloni date[RV3028_HOUR] = bin2bcd(tm->tm_hour);
3456e00b6d0SHeiko Schocher date[RV3028_WDAY] = tm->tm_wday;
346e6e7376cSAlexandre Belloni date[RV3028_DAY] = bin2bcd(tm->tm_mday);
347e6e7376cSAlexandre Belloni date[RV3028_MONTH] = bin2bcd(tm->tm_mon + 1);
348e6e7376cSAlexandre Belloni date[RV3028_YEAR] = bin2bcd(tm->tm_year - 100);
349e6e7376cSAlexandre Belloni
350e6e7376cSAlexandre Belloni /*
351e6e7376cSAlexandre Belloni * Writing to the Seconds register has the same effect as setting RESET
352e6e7376cSAlexandre Belloni * bit to 1
353e6e7376cSAlexandre Belloni */
354e6e7376cSAlexandre Belloni ret = regmap_bulk_write(rv3028->regmap, RV3028_SEC, date,
355e6e7376cSAlexandre Belloni sizeof(date));
356e6e7376cSAlexandre Belloni if (ret)
357e6e7376cSAlexandre Belloni return ret;
358e6e7376cSAlexandre Belloni
359e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
360e6e7376cSAlexandre Belloni RV3028_STATUS_PORF, 0);
361e6e7376cSAlexandre Belloni
362e6e7376cSAlexandre Belloni return ret;
363e6e7376cSAlexandre Belloni }
364e6e7376cSAlexandre Belloni
rv3028_get_alarm(struct device * dev,struct rtc_wkalrm * alrm)365e6e7376cSAlexandre Belloni static int rv3028_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
366e6e7376cSAlexandre Belloni {
367e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
368e6e7376cSAlexandre Belloni u8 alarmvals[3];
369e6e7376cSAlexandre Belloni int status, ctrl, ret;
370e6e7376cSAlexandre Belloni
371e6e7376cSAlexandre Belloni ret = regmap_bulk_read(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
372e6e7376cSAlexandre Belloni sizeof(alarmvals));
373e6e7376cSAlexandre Belloni if (ret)
374e6e7376cSAlexandre Belloni return ret;
375e6e7376cSAlexandre Belloni
376e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
377e6e7376cSAlexandre Belloni if (ret < 0)
378e6e7376cSAlexandre Belloni return ret;
379e6e7376cSAlexandre Belloni
380e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_CTRL2, &ctrl);
381e6e7376cSAlexandre Belloni if (ret < 0)
382e6e7376cSAlexandre Belloni return ret;
383e6e7376cSAlexandre Belloni
384e6e7376cSAlexandre Belloni alrm->time.tm_sec = 0;
385e6e7376cSAlexandre Belloni alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
386e6e7376cSAlexandre Belloni alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
387e6e7376cSAlexandre Belloni alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
388e6e7376cSAlexandre Belloni
389e6e7376cSAlexandre Belloni alrm->enabled = !!(ctrl & RV3028_CTRL2_AIE);
390e6e7376cSAlexandre Belloni alrm->pending = (status & RV3028_STATUS_AF) && alrm->enabled;
391e6e7376cSAlexandre Belloni
392e6e7376cSAlexandre Belloni return 0;
393e6e7376cSAlexandre Belloni }
394e6e7376cSAlexandre Belloni
rv3028_set_alarm(struct device * dev,struct rtc_wkalrm * alrm)395e6e7376cSAlexandre Belloni static int rv3028_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
396e6e7376cSAlexandre Belloni {
397e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
398e6e7376cSAlexandre Belloni u8 alarmvals[3];
399e6e7376cSAlexandre Belloni u8 ctrl = 0;
400e6e7376cSAlexandre Belloni int ret;
401e6e7376cSAlexandre Belloni
402e6e7376cSAlexandre Belloni /* The alarm has no seconds, round up to nearest minute */
403e6e7376cSAlexandre Belloni if (alrm->time.tm_sec) {
404e6e7376cSAlexandre Belloni time64_t alarm_time = rtc_tm_to_time64(&alrm->time);
405e6e7376cSAlexandre Belloni
406e6e7376cSAlexandre Belloni alarm_time += 60 - alrm->time.tm_sec;
407e6e7376cSAlexandre Belloni rtc_time64_to_tm(alarm_time, &alrm->time);
408e6e7376cSAlexandre Belloni }
409e6e7376cSAlexandre Belloni
410e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
411e6e7376cSAlexandre Belloni RV3028_CTRL2_AIE | RV3028_CTRL2_UIE, 0);
412e6e7376cSAlexandre Belloni if (ret)
413e6e7376cSAlexandre Belloni return ret;
414e6e7376cSAlexandre Belloni
415e6e7376cSAlexandre Belloni alarmvals[0] = bin2bcd(alrm->time.tm_min);
416e6e7376cSAlexandre Belloni alarmvals[1] = bin2bcd(alrm->time.tm_hour);
417e6e7376cSAlexandre Belloni alarmvals[2] = bin2bcd(alrm->time.tm_mday);
418e6e7376cSAlexandre Belloni
419e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
420e6e7376cSAlexandre Belloni RV3028_STATUS_AF, 0);
421e6e7376cSAlexandre Belloni if (ret)
422e6e7376cSAlexandre Belloni return ret;
423e6e7376cSAlexandre Belloni
424e6e7376cSAlexandre Belloni ret = regmap_bulk_write(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
425e6e7376cSAlexandre Belloni sizeof(alarmvals));
426e6e7376cSAlexandre Belloni if (ret)
427e6e7376cSAlexandre Belloni return ret;
428e6e7376cSAlexandre Belloni
429e6e7376cSAlexandre Belloni if (alrm->enabled) {
430e6e7376cSAlexandre Belloni if (rv3028->rtc->uie_rtctimer.enabled)
431e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_UIE;
432e6e7376cSAlexandre Belloni if (rv3028->rtc->aie_timer.enabled)
433e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_AIE;
434e6e7376cSAlexandre Belloni }
435e6e7376cSAlexandre Belloni
436e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
437e6e7376cSAlexandre Belloni RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
438e6e7376cSAlexandre Belloni
439e6e7376cSAlexandre Belloni return ret;
440e6e7376cSAlexandre Belloni }
441e6e7376cSAlexandre Belloni
rv3028_alarm_irq_enable(struct device * dev,unsigned int enabled)442e6e7376cSAlexandre Belloni static int rv3028_alarm_irq_enable(struct device *dev, unsigned int enabled)
443e6e7376cSAlexandre Belloni {
444e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
445e6e7376cSAlexandre Belloni int ctrl = 0, ret;
446e6e7376cSAlexandre Belloni
447e6e7376cSAlexandre Belloni if (enabled) {
448e6e7376cSAlexandre Belloni if (rv3028->rtc->uie_rtctimer.enabled)
449e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_UIE;
450e6e7376cSAlexandre Belloni if (rv3028->rtc->aie_timer.enabled)
451e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_AIE;
452e6e7376cSAlexandre Belloni }
453e6e7376cSAlexandre Belloni
454e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
455e6e7376cSAlexandre Belloni RV3028_STATUS_AF | RV3028_STATUS_UF, 0);
456e6e7376cSAlexandre Belloni if (ret)
457e6e7376cSAlexandre Belloni return ret;
458e6e7376cSAlexandre Belloni
459e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
460e6e7376cSAlexandre Belloni RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
461e6e7376cSAlexandre Belloni if (ret)
462e6e7376cSAlexandre Belloni return ret;
463e6e7376cSAlexandre Belloni
464e6e7376cSAlexandre Belloni return 0;
465e6e7376cSAlexandre Belloni }
466e6e7376cSAlexandre Belloni
rv3028_read_offset(struct device * dev,long * offset)467e6e7376cSAlexandre Belloni static int rv3028_read_offset(struct device *dev, long *offset)
468e6e7376cSAlexandre Belloni {
469e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
470e6e7376cSAlexandre Belloni int ret, value, steps;
471e6e7376cSAlexandre Belloni
472e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_OFFSET, &value);
473e6e7376cSAlexandre Belloni if (ret < 0)
474e6e7376cSAlexandre Belloni return ret;
475e6e7376cSAlexandre Belloni
476e6e7376cSAlexandre Belloni steps = sign_extend32(value << 1, 8);
477e6e7376cSAlexandre Belloni
478e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
479e6e7376cSAlexandre Belloni if (ret < 0)
480e6e7376cSAlexandre Belloni return ret;
481e6e7376cSAlexandre Belloni
482e6e7376cSAlexandre Belloni steps += value >> 7;
483e6e7376cSAlexandre Belloni
484e6e7376cSAlexandre Belloni *offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000);
485e6e7376cSAlexandre Belloni
486e6e7376cSAlexandre Belloni return 0;
487e6e7376cSAlexandre Belloni }
488e6e7376cSAlexandre Belloni
rv3028_set_offset(struct device * dev,long offset)489e6e7376cSAlexandre Belloni static int rv3028_set_offset(struct device *dev, long offset)
490e6e7376cSAlexandre Belloni {
491e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
492024e6f3dSAlexandre Belloni u32 eerd;
493e6e7376cSAlexandre Belloni int ret;
494e6e7376cSAlexandre Belloni
495e6e7376cSAlexandre Belloni offset = clamp(offset, -244141L, 243187L) * 1000;
496e6e7376cSAlexandre Belloni offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT);
497e6e7376cSAlexandre Belloni
498024e6f3dSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd);
499024e6f3dSAlexandre Belloni if (ret)
500e6e7376cSAlexandre Belloni return ret;
501e6e7376cSAlexandre Belloni
502024e6f3dSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_OFFSET, offset >> 1);
503024e6f3dSAlexandre Belloni if (ret < 0)
504024e6f3dSAlexandre Belloni goto exit_eerd;
505024e6f3dSAlexandre Belloni
506024e6f3dSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7),
507e6e7376cSAlexandre Belloni offset << 7);
508024e6f3dSAlexandre Belloni if (ret < 0)
509024e6f3dSAlexandre Belloni goto exit_eerd;
510024e6f3dSAlexandre Belloni
511024e6f3dSAlexandre Belloni return rv3028_update_eeprom(rv3028, eerd);
512024e6f3dSAlexandre Belloni
513024e6f3dSAlexandre Belloni exit_eerd:
514024e6f3dSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd);
515024e6f3dSAlexandre Belloni
516024e6f3dSAlexandre Belloni return ret;
517024e6f3dSAlexandre Belloni
518e6e7376cSAlexandre Belloni }
519e6e7376cSAlexandre Belloni
rv3028_param_get(struct device * dev,struct rtc_param * param)520018d959bSAlexandre Belloni static int rv3028_param_get(struct device *dev, struct rtc_param *param)
521018d959bSAlexandre Belloni {
522018d959bSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
523018d959bSAlexandre Belloni int ret;
524018d959bSAlexandre Belloni u32 value;
525018d959bSAlexandre Belloni
526e5f12a39SKe Sun switch(param->param) {
527018d959bSAlexandre Belloni case RTC_PARAM_BACKUP_SWITCH_MODE:
528018d959bSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
529018d959bSAlexandre Belloni if (ret < 0)
530018d959bSAlexandre Belloni return ret;
531018d959bSAlexandre Belloni
532018d959bSAlexandre Belloni value = FIELD_GET(RV3028_BACKUP_BSM, value);
533018d959bSAlexandre Belloni
534018d959bSAlexandre Belloni switch(value) {
535018d959bSAlexandre Belloni case RV3028_BACKUP_BSM_DSM:
536018d959bSAlexandre Belloni param->uvalue = RTC_BSM_DIRECT;
537018d959bSAlexandre Belloni break;
538018d959bSAlexandre Belloni case RV3028_BACKUP_BSM_LSM:
539018d959bSAlexandre Belloni param->uvalue = RTC_BSM_LEVEL;
540018d959bSAlexandre Belloni break;
541018d959bSAlexandre Belloni default:
542018d959bSAlexandre Belloni param->uvalue = RTC_BSM_DISABLED;
543018d959bSAlexandre Belloni }
544018d959bSAlexandre Belloni break;
545018d959bSAlexandre Belloni
546018d959bSAlexandre Belloni default:
547018d959bSAlexandre Belloni return -EINVAL;
548018d959bSAlexandre Belloni }
549018d959bSAlexandre Belloni
550018d959bSAlexandre Belloni return 0;
551018d959bSAlexandre Belloni }
552018d959bSAlexandre Belloni
rv3028_param_set(struct device * dev,struct rtc_param * param)553018d959bSAlexandre Belloni static int rv3028_param_set(struct device *dev, struct rtc_param *param)
554018d959bSAlexandre Belloni {
555018d959bSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
556e5f12a39SKe Sun u8 mode;
557018d959bSAlexandre Belloni
558018d959bSAlexandre Belloni switch(param->param) {
559018d959bSAlexandre Belloni case RTC_PARAM_BACKUP_SWITCH_MODE:
560018d959bSAlexandre Belloni switch (param->uvalue) {
561018d959bSAlexandre Belloni case RTC_BSM_DISABLED:
562018d959bSAlexandre Belloni mode = 0;
563018d959bSAlexandre Belloni break;
564018d959bSAlexandre Belloni case RTC_BSM_DIRECT:
565018d959bSAlexandre Belloni mode = RV3028_BACKUP_BSM_DSM;
566018d959bSAlexandre Belloni break;
567018d959bSAlexandre Belloni case RTC_BSM_LEVEL:
568018d959bSAlexandre Belloni mode = RV3028_BACKUP_BSM_LSM;
569018d959bSAlexandre Belloni break;
570018d959bSAlexandre Belloni default:
571018d959bSAlexandre Belloni return -EINVAL;
572018d959bSAlexandre Belloni }
573018d959bSAlexandre Belloni
574018d959bSAlexandre Belloni return rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_BSM,
575018d959bSAlexandre Belloni FIELD_PREP(RV3028_BACKUP_BSM, mode));
576018d959bSAlexandre Belloni
577018d959bSAlexandre Belloni default:
578018d959bSAlexandre Belloni return -EINVAL;
579018d959bSAlexandre Belloni }
580018d959bSAlexandre Belloni
581018d959bSAlexandre Belloni return 0;
582018d959bSAlexandre Belloni }
583018d959bSAlexandre Belloni
rv3028_ioctl(struct device * dev,unsigned int cmd,unsigned long arg)584e6e7376cSAlexandre Belloni static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
585e6e7376cSAlexandre Belloni {
586e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev);
587e6e7376cSAlexandre Belloni int status, ret = 0;
588e6e7376cSAlexandre Belloni
589e6e7376cSAlexandre Belloni switch (cmd) {
590e6e7376cSAlexandre Belloni case RTC_VL_READ:
591e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
592e6e7376cSAlexandre Belloni if (ret < 0)
593e6e7376cSAlexandre Belloni return ret;
594e6e7376cSAlexandre Belloni
59586e655f9SAlexandre Belloni status = status & RV3028_STATUS_PORF ? RTC_VL_DATA_INVALID : 0;
59686e655f9SAlexandre Belloni return put_user(status, (unsigned int __user *)arg);
597e6e7376cSAlexandre Belloni
598e6e7376cSAlexandre Belloni default:
599e6e7376cSAlexandre Belloni return -ENOIOCTLCMD;
600e6e7376cSAlexandre Belloni }
601e6e7376cSAlexandre Belloni }
602e6e7376cSAlexandre Belloni
rv3028_nvram_write(void * priv,unsigned int offset,void * val,size_t bytes)603e6e7376cSAlexandre Belloni static int rv3028_nvram_write(void *priv, unsigned int offset, void *val,
604e6e7376cSAlexandre Belloni size_t bytes)
605e6e7376cSAlexandre Belloni {
606e6e7376cSAlexandre Belloni return regmap_bulk_write(priv, RV3028_RAM1 + offset, val, bytes);
607e6e7376cSAlexandre Belloni }
608e6e7376cSAlexandre Belloni
rv3028_nvram_read(void * priv,unsigned int offset,void * val,size_t bytes)609e6e7376cSAlexandre Belloni static int rv3028_nvram_read(void *priv, unsigned int offset, void *val,
610e6e7376cSAlexandre Belloni size_t bytes)
611e6e7376cSAlexandre Belloni {
612e6e7376cSAlexandre Belloni return regmap_bulk_read(priv, RV3028_RAM1 + offset, val, bytes);
613e6e7376cSAlexandre Belloni }
614e6e7376cSAlexandre Belloni
rv3028_eeprom_write(void * priv,unsigned int offset,void * val,size_t bytes)615e6e7376cSAlexandre Belloni static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val,
616e6e7376cSAlexandre Belloni size_t bytes)
617e6e7376cSAlexandre Belloni {
618de0ad60eSAlexandre Belloni struct rv3028_data *rv3028 = priv;
619de0ad60eSAlexandre Belloni u32 status, eerd;
620de0ad60eSAlexandre Belloni int i, ret;
621e6e7376cSAlexandre Belloni u8 *buf = val;
622e6e7376cSAlexandre Belloni
623de0ad60eSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd);
624e6e7376cSAlexandre Belloni if (ret)
625e6e7376cSAlexandre Belloni return ret;
626e6e7376cSAlexandre Belloni
627e6e7376cSAlexandre Belloni for (i = 0; i < bytes; i++) {
628de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i);
629e6e7376cSAlexandre Belloni if (ret)
630e6e7376cSAlexandre Belloni goto restore_eerd;
631e6e7376cSAlexandre Belloni
632de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_DATA, buf[i]);
633e6e7376cSAlexandre Belloni if (ret)
634e6e7376cSAlexandre Belloni goto restore_eerd;
635e6e7376cSAlexandre Belloni
636de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
637e6e7376cSAlexandre Belloni if (ret)
638e6e7376cSAlexandre Belloni goto restore_eerd;
639e6e7376cSAlexandre Belloni
640de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD,
641e6e7376cSAlexandre Belloni RV3028_EEPROM_CMD_WRITE);
642e6e7376cSAlexandre Belloni if (ret)
643e6e7376cSAlexandre Belloni goto restore_eerd;
644e6e7376cSAlexandre Belloni
645e6e7376cSAlexandre Belloni usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
646e6e7376cSAlexandre Belloni
647de0ad60eSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
648e6e7376cSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY),
649e6e7376cSAlexandre Belloni RV3028_EEBUSY_POLL,
650e6e7376cSAlexandre Belloni RV3028_EEBUSY_TIMEOUT);
651e6e7376cSAlexandre Belloni if (ret)
652e6e7376cSAlexandre Belloni goto restore_eerd;
653e6e7376cSAlexandre Belloni }
654e6e7376cSAlexandre Belloni
655e6e7376cSAlexandre Belloni restore_eerd:
656de0ad60eSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd);
657e6e7376cSAlexandre Belloni
658e6e7376cSAlexandre Belloni return ret;
659e6e7376cSAlexandre Belloni }
660e6e7376cSAlexandre Belloni
rv3028_eeprom_read(void * priv,unsigned int offset,void * val,size_t bytes)661e6e7376cSAlexandre Belloni static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val,
662e6e7376cSAlexandre Belloni size_t bytes)
663e6e7376cSAlexandre Belloni {
664de0ad60eSAlexandre Belloni struct rv3028_data *rv3028 = priv;
665de0ad60eSAlexandre Belloni u32 status, eerd, data;
666de0ad60eSAlexandre Belloni int i, ret;
667e6e7376cSAlexandre Belloni u8 *buf = val;
668e6e7376cSAlexandre Belloni
669de0ad60eSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd);
670e6e7376cSAlexandre Belloni if (ret)
671e6e7376cSAlexandre Belloni return ret;
672e6e7376cSAlexandre Belloni
673e6e7376cSAlexandre Belloni for (i = 0; i < bytes; i++) {
674de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i);
675e6e7376cSAlexandre Belloni if (ret)
676e6e7376cSAlexandre Belloni goto restore_eerd;
677e6e7376cSAlexandre Belloni
678de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
679e6e7376cSAlexandre Belloni if (ret)
680e6e7376cSAlexandre Belloni goto restore_eerd;
681e6e7376cSAlexandre Belloni
682de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD,
683e6e7376cSAlexandre Belloni RV3028_EEPROM_CMD_READ);
684e6e7376cSAlexandre Belloni if (ret)
685e6e7376cSAlexandre Belloni goto restore_eerd;
686e6e7376cSAlexandre Belloni
687de0ad60eSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
688e6e7376cSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY),
689e6e7376cSAlexandre Belloni RV3028_EEBUSY_POLL,
690e6e7376cSAlexandre Belloni RV3028_EEBUSY_TIMEOUT);
691e6e7376cSAlexandre Belloni if (ret)
692e6e7376cSAlexandre Belloni goto restore_eerd;
693e6e7376cSAlexandre Belloni
694de0ad60eSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_EEPROM_DATA, &data);
695e6e7376cSAlexandre Belloni if (ret)
696e6e7376cSAlexandre Belloni goto restore_eerd;
697e6e7376cSAlexandre Belloni buf[i] = data;
698e6e7376cSAlexandre Belloni }
699e6e7376cSAlexandre Belloni
700e6e7376cSAlexandre Belloni restore_eerd:
701de0ad60eSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd);
702e6e7376cSAlexandre Belloni
703e6e7376cSAlexandre Belloni return ret;
704e6e7376cSAlexandre Belloni }
705e6e7376cSAlexandre Belloni
706f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK
707f583c341SParthiban Nallathambi #define clkout_hw_to_rv3028(hw) container_of(hw, struct rv3028_data, clkout_hw)
708f583c341SParthiban Nallathambi
709f583c341SParthiban Nallathambi static int clkout_rates[] = {
710f583c341SParthiban Nallathambi 32768,
711f583c341SParthiban Nallathambi 8192,
712f583c341SParthiban Nallathambi 1024,
713f583c341SParthiban Nallathambi 64,
714f583c341SParthiban Nallathambi 32,
715f583c341SParthiban Nallathambi 1,
716f583c341SParthiban Nallathambi };
717f583c341SParthiban Nallathambi
rv3028_clkout_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)718f583c341SParthiban Nallathambi static unsigned long rv3028_clkout_recalc_rate(struct clk_hw *hw,
719f583c341SParthiban Nallathambi unsigned long parent_rate)
720f583c341SParthiban Nallathambi {
721f583c341SParthiban Nallathambi int clkout, ret;
722f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
723f583c341SParthiban Nallathambi
724f583c341SParthiban Nallathambi ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout);
725f583c341SParthiban Nallathambi if (ret < 0)
726f583c341SParthiban Nallathambi return 0;
727f583c341SParthiban Nallathambi
728f583c341SParthiban Nallathambi clkout &= RV3028_CLKOUT_FD_MASK;
729f583c341SParthiban Nallathambi return clkout_rates[clkout];
730f583c341SParthiban Nallathambi }
731f583c341SParthiban Nallathambi
rv3028_clkout_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)732f583c341SParthiban Nallathambi static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
733f583c341SParthiban Nallathambi unsigned long *prate)
734f583c341SParthiban Nallathambi {
735f583c341SParthiban Nallathambi int i;
736f583c341SParthiban Nallathambi
737f583c341SParthiban Nallathambi for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
738f583c341SParthiban Nallathambi if (clkout_rates[i] <= rate)
739f583c341SParthiban Nallathambi return clkout_rates[i];
740f583c341SParthiban Nallathambi
741f583c341SParthiban Nallathambi return 0;
742f583c341SParthiban Nallathambi }
743f583c341SParthiban Nallathambi
rv3028_clkout_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)744f583c341SParthiban Nallathambi static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
745f583c341SParthiban Nallathambi unsigned long parent_rate)
746f583c341SParthiban Nallathambi {
747f583c341SParthiban Nallathambi int i, ret;
74800e8e87fSAlexandre Belloni u32 enabled;
749f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
750f583c341SParthiban Nallathambi
75100e8e87fSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &enabled);
75200e8e87fSAlexandre Belloni if (ret < 0)
75300e8e87fSAlexandre Belloni return ret;
75400e8e87fSAlexandre Belloni
755f583c341SParthiban Nallathambi ret = regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0);
756f583c341SParthiban Nallathambi if (ret < 0)
757f583c341SParthiban Nallathambi return ret;
758f583c341SParthiban Nallathambi
75900e8e87fSAlexandre Belloni enabled &= RV3028_CLKOUT_CLKOE;
760f583c341SParthiban Nallathambi
76100e8e87fSAlexandre Belloni for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
76200e8e87fSAlexandre Belloni if (clkout_rates[i] == rate)
763024e6f3dSAlexandre Belloni return rv3028_update_cfg(rv3028, RV3028_CLKOUT, 0xff,
76400e8e87fSAlexandre Belloni RV3028_CLKOUT_CLKSY | enabled | i);
765f583c341SParthiban Nallathambi
766f583c341SParthiban Nallathambi return -EINVAL;
767f583c341SParthiban Nallathambi }
768f583c341SParthiban Nallathambi
rv3028_clkout_prepare(struct clk_hw * hw)769f583c341SParthiban Nallathambi static int rv3028_clkout_prepare(struct clk_hw *hw)
770f583c341SParthiban Nallathambi {
771f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
772f583c341SParthiban Nallathambi
773f583c341SParthiban Nallathambi return regmap_write(rv3028->regmap, RV3028_CLKOUT,
774f583c341SParthiban Nallathambi RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE);
775f583c341SParthiban Nallathambi }
776f583c341SParthiban Nallathambi
rv3028_clkout_unprepare(struct clk_hw * hw)777f583c341SParthiban Nallathambi static void rv3028_clkout_unprepare(struct clk_hw *hw)
778f583c341SParthiban Nallathambi {
779f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
780f583c341SParthiban Nallathambi
781f583c341SParthiban Nallathambi regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0);
782f583c341SParthiban Nallathambi regmap_update_bits(rv3028->regmap, RV3028_STATUS,
783f583c341SParthiban Nallathambi RV3028_STATUS_CLKF, 0);
784f583c341SParthiban Nallathambi }
785f583c341SParthiban Nallathambi
rv3028_clkout_is_prepared(struct clk_hw * hw)786f583c341SParthiban Nallathambi static int rv3028_clkout_is_prepared(struct clk_hw *hw)
787f583c341SParthiban Nallathambi {
788f583c341SParthiban Nallathambi int clkout, ret;
789f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw);
790f583c341SParthiban Nallathambi
791f583c341SParthiban Nallathambi ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout);
792f583c341SParthiban Nallathambi if (ret < 0)
793f583c341SParthiban Nallathambi return ret;
794f583c341SParthiban Nallathambi
795f583c341SParthiban Nallathambi return !!(clkout & RV3028_CLKOUT_CLKOE);
796f583c341SParthiban Nallathambi }
797f583c341SParthiban Nallathambi
798f583c341SParthiban Nallathambi static const struct clk_ops rv3028_clkout_ops = {
799f583c341SParthiban Nallathambi .prepare = rv3028_clkout_prepare,
800f583c341SParthiban Nallathambi .unprepare = rv3028_clkout_unprepare,
801f583c341SParthiban Nallathambi .is_prepared = rv3028_clkout_is_prepared,
802f583c341SParthiban Nallathambi .recalc_rate = rv3028_clkout_recalc_rate,
803f583c341SParthiban Nallathambi .round_rate = rv3028_clkout_round_rate,
804f583c341SParthiban Nallathambi .set_rate = rv3028_clkout_set_rate,
805f583c341SParthiban Nallathambi };
806f583c341SParthiban Nallathambi
rv3028_clkout_register_clk(struct rv3028_data * rv3028,struct i2c_client * client)807f583c341SParthiban Nallathambi static int rv3028_clkout_register_clk(struct rv3028_data *rv3028,
808f583c341SParthiban Nallathambi struct i2c_client *client)
809f583c341SParthiban Nallathambi {
810f583c341SParthiban Nallathambi int ret;
811f583c341SParthiban Nallathambi struct clk *clk;
812f583c341SParthiban Nallathambi struct clk_init_data init;
813f583c341SParthiban Nallathambi struct device_node *node = client->dev.of_node;
814f583c341SParthiban Nallathambi
815f583c341SParthiban Nallathambi ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
816f583c341SParthiban Nallathambi RV3028_STATUS_CLKF, 0);
817f583c341SParthiban Nallathambi if (ret < 0)
818f583c341SParthiban Nallathambi return ret;
819f583c341SParthiban Nallathambi
820f583c341SParthiban Nallathambi init.name = "rv3028-clkout";
821f583c341SParthiban Nallathambi init.ops = &rv3028_clkout_ops;
822f583c341SParthiban Nallathambi init.flags = 0;
823f583c341SParthiban Nallathambi init.parent_names = NULL;
824f583c341SParthiban Nallathambi init.num_parents = 0;
825f583c341SParthiban Nallathambi rv3028->clkout_hw.init = &init;
826f583c341SParthiban Nallathambi
827f583c341SParthiban Nallathambi /* optional override of the clockname */
828f583c341SParthiban Nallathambi of_property_read_string(node, "clock-output-names", &init.name);
829f583c341SParthiban Nallathambi
830f583c341SParthiban Nallathambi /* register the clock */
831f583c341SParthiban Nallathambi clk = devm_clk_register(&client->dev, &rv3028->clkout_hw);
832f583c341SParthiban Nallathambi if (!IS_ERR(clk))
833f583c341SParthiban Nallathambi of_clk_add_provider(node, of_clk_src_simple_get, clk);
834f583c341SParthiban Nallathambi
835f583c341SParthiban Nallathambi return 0;
836f583c341SParthiban Nallathambi }
837f583c341SParthiban Nallathambi #endif
838f583c341SParthiban Nallathambi
8390f769569SAlexandre Belloni static const struct rtc_class_ops rv3028_rtc_ops = {
840e6e7376cSAlexandre Belloni .read_time = rv3028_get_time,
841e6e7376cSAlexandre Belloni .set_time = rv3028_set_time,
8420f769569SAlexandre Belloni .read_alarm = rv3028_get_alarm,
8430f769569SAlexandre Belloni .set_alarm = rv3028_set_alarm,
8440f769569SAlexandre Belloni .alarm_irq_enable = rv3028_alarm_irq_enable,
845e6e7376cSAlexandre Belloni .read_offset = rv3028_read_offset,
846e6e7376cSAlexandre Belloni .set_offset = rv3028_set_offset,
847e6e7376cSAlexandre Belloni .ioctl = rv3028_ioctl,
848018d959bSAlexandre Belloni .param_get = rv3028_param_get,
849018d959bSAlexandre Belloni .param_set = rv3028_param_set,
850e6e7376cSAlexandre Belloni };
851e6e7376cSAlexandre Belloni
852e6e7376cSAlexandre Belloni static const struct regmap_config regmap_config = {
853e6e7376cSAlexandre Belloni .reg_bits = 8,
854e6e7376cSAlexandre Belloni .val_bits = 8,
855e6e7376cSAlexandre Belloni .max_register = 0x37,
856e6e7376cSAlexandre Belloni };
857e6e7376cSAlexandre Belloni
rv3028_set_trickle_charger(struct rv3028_data * rv3028,struct i2c_client * client)8583c87b351SAndrej Picej static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028,
8593c87b351SAndrej Picej struct i2c_client *client)
8603c87b351SAndrej Picej {
8613c87b351SAndrej Picej int ret, val_old, val;
8623c87b351SAndrej Picej u32 ohms, chargeable;
8633c87b351SAndrej Picej
8643c87b351SAndrej Picej ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old);
8653c87b351SAndrej Picej if (ret < 0)
8663c87b351SAndrej Picej return ret;
8673c87b351SAndrej Picej
8683c87b351SAndrej Picej /* mask out only trickle charger bits */
8693c87b351SAndrej Picej val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK);
8703c87b351SAndrej Picej val = val_old;
8713c87b351SAndrej Picej
8723c87b351SAndrej Picej /* setup trickle charger */
8733c87b351SAndrej Picej if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
8743c87b351SAndrej Picej &ohms)) {
8753c87b351SAndrej Picej int i;
8763c87b351SAndrej Picej
8773c87b351SAndrej Picej for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
8783c87b351SAndrej Picej if (ohms == rv3028_trickle_resistors[i])
8793c87b351SAndrej Picej break;
8803c87b351SAndrej Picej
8813c87b351SAndrej Picej if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
8823c87b351SAndrej Picej /* enable trickle charger and its resistor */
8833c87b351SAndrej Picej val = RV3028_BACKUP_TCE | i;
8843c87b351SAndrej Picej } else {
8853c87b351SAndrej Picej dev_warn(&client->dev, "invalid trickle resistor value\n");
8863c87b351SAndrej Picej }
8873c87b351SAndrej Picej }
8883c87b351SAndrej Picej
8893c87b351SAndrej Picej if (!device_property_read_u32(&client->dev, "aux-voltage-chargeable",
8903c87b351SAndrej Picej &chargeable)) {
8913c87b351SAndrej Picej switch (chargeable) {
8923c87b351SAndrej Picej case 0:
8933c87b351SAndrej Picej val &= ~RV3028_BACKUP_TCE;
8943c87b351SAndrej Picej break;
8953c87b351SAndrej Picej case 1:
8963c87b351SAndrej Picej val |= RV3028_BACKUP_TCE;
8973c87b351SAndrej Picej break;
8983c87b351SAndrej Picej default:
8993c87b351SAndrej Picej dev_warn(&client->dev,
9003c87b351SAndrej Picej "unsupported aux-voltage-chargeable value\n");
9013c87b351SAndrej Picej break;
9023c87b351SAndrej Picej }
9033c87b351SAndrej Picej }
9043c87b351SAndrej Picej
9053c87b351SAndrej Picej /* only update EEPROM if changes are necessary */
9063c87b351SAndrej Picej if (val_old != val) {
9073c87b351SAndrej Picej ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE |
9083c87b351SAndrej Picej RV3028_BACKUP_TCR_MASK, val);
9093c87b351SAndrej Picej if (ret)
9103c87b351SAndrej Picej return ret;
9113c87b351SAndrej Picej }
9123c87b351SAndrej Picej
9133c87b351SAndrej Picej return ret;
9143c87b351SAndrej Picej }
9153c87b351SAndrej Picej
rv3028_probe(struct i2c_client * client)916e6e7376cSAlexandre Belloni static int rv3028_probe(struct i2c_client *client)
917e6e7376cSAlexandre Belloni {
918e6e7376cSAlexandre Belloni struct rv3028_data *rv3028;
919e6e7376cSAlexandre Belloni int ret, status;
920e6e7376cSAlexandre Belloni struct nvmem_config nvmem_cfg = {
921e6e7376cSAlexandre Belloni .name = "rv3028_nvram",
922e6e7376cSAlexandre Belloni .word_size = 1,
923e6e7376cSAlexandre Belloni .stride = 1,
924e6e7376cSAlexandre Belloni .size = 2,
925e6e7376cSAlexandre Belloni .type = NVMEM_TYPE_BATTERY_BACKED,
926e6e7376cSAlexandre Belloni .reg_read = rv3028_nvram_read,
927e6e7376cSAlexandre Belloni .reg_write = rv3028_nvram_write,
928e6e7376cSAlexandre Belloni };
929e6e7376cSAlexandre Belloni struct nvmem_config eeprom_cfg = {
930e6e7376cSAlexandre Belloni .name = "rv3028_eeprom",
931e6e7376cSAlexandre Belloni .word_size = 1,
932e6e7376cSAlexandre Belloni .stride = 1,
933e6e7376cSAlexandre Belloni .size = 43,
934e6e7376cSAlexandre Belloni .type = NVMEM_TYPE_EEPROM,
935e6e7376cSAlexandre Belloni .reg_read = rv3028_eeprom_read,
936e6e7376cSAlexandre Belloni .reg_write = rv3028_eeprom_write,
937e6e7376cSAlexandre Belloni };
938e6e7376cSAlexandre Belloni
939e6e7376cSAlexandre Belloni rv3028 = devm_kzalloc(&client->dev, sizeof(struct rv3028_data),
940e6e7376cSAlexandre Belloni GFP_KERNEL);
941e6e7376cSAlexandre Belloni if (!rv3028)
942e6e7376cSAlexandre Belloni return -ENOMEM;
943e6e7376cSAlexandre Belloni
944e6e7376cSAlexandre Belloni rv3028->regmap = devm_regmap_init_i2c(client, ®map_config);
945c3b29bf6SChuhong Yuan if (IS_ERR(rv3028->regmap))
946c3b29bf6SChuhong Yuan return PTR_ERR(rv3028->regmap);
947e6e7376cSAlexandre Belloni
948e6e7376cSAlexandre Belloni i2c_set_clientdata(client, rv3028);
949e6e7376cSAlexandre Belloni
950e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
951e6e7376cSAlexandre Belloni if (ret < 0)
952e6e7376cSAlexandre Belloni return ret;
953e6e7376cSAlexandre Belloni
954e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_AF)
955e6e7376cSAlexandre Belloni dev_warn(&client->dev, "An alarm may have been missed.\n");
956e6e7376cSAlexandre Belloni
957e6e7376cSAlexandre Belloni rv3028->rtc = devm_rtc_allocate_device(&client->dev);
95844c638ceSAlexandre Belloni if (IS_ERR(rv3028->rtc))
959e6e7376cSAlexandre Belloni return PTR_ERR(rv3028->rtc);
960e6e7376cSAlexandre Belloni
961e6e7376cSAlexandre Belloni if (client->irq > 0) {
96216b26f60SWadim Egorov unsigned long flags;
96316b26f60SWadim Egorov
96416b26f60SWadim Egorov /*
96516b26f60SWadim Egorov * If flags = 0, devm_request_threaded_irq() will use IRQ flags
96616b26f60SWadim Egorov * obtained from device tree.
96716b26f60SWadim Egorov */
96816b26f60SWadim Egorov if (dev_fwnode(&client->dev))
96916b26f60SWadim Egorov flags = 0;
97016b26f60SWadim Egorov else
97116b26f60SWadim Egorov flags = IRQF_TRIGGER_LOW;
97216b26f60SWadim Egorov
973e6e7376cSAlexandre Belloni ret = devm_request_threaded_irq(&client->dev, client->irq,
974e6e7376cSAlexandre Belloni NULL, rv3028_handle_irq,
97516b26f60SWadim Egorov flags | IRQF_ONESHOT,
976e6e7376cSAlexandre Belloni "rv3028", rv3028);
977e6e7376cSAlexandre Belloni if (ret) {
978e6e7376cSAlexandre Belloni dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
979e6e7376cSAlexandre Belloni client->irq = 0;
980e6e7376cSAlexandre Belloni }
981e6e7376cSAlexandre Belloni }
9820f769569SAlexandre Belloni if (!client->irq)
9830f769569SAlexandre Belloni clear_bit(RTC_FEATURE_ALARM, rv3028->rtc->features);
984e6e7376cSAlexandre Belloni
985e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
986e6e7376cSAlexandre Belloni RV3028_CTRL1_WADA, RV3028_CTRL1_WADA);
987e6e7376cSAlexandre Belloni if (ret)
988e6e7376cSAlexandre Belloni return ret;
989e6e7376cSAlexandre Belloni
990e6e7376cSAlexandre Belloni /* setup timestamping */
991e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
992e6e7376cSAlexandre Belloni RV3028_CTRL2_EIE | RV3028_CTRL2_TSE,
993e6e7376cSAlexandre Belloni RV3028_CTRL2_EIE | RV3028_CTRL2_TSE);
994e6e7376cSAlexandre Belloni if (ret)
995e6e7376cSAlexandre Belloni return ret;
996e6e7376cSAlexandre Belloni
9973c87b351SAndrej Picej ret = rv3028_set_trickle_charger(rv3028, client);
998e6e7376cSAlexandre Belloni if (ret)
999e6e7376cSAlexandre Belloni return ret;
1000e6e7376cSAlexandre Belloni
1001e6e7376cSAlexandre Belloni ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
1002e6e7376cSAlexandre Belloni if (ret)
1003e6e7376cSAlexandre Belloni return ret;
1004e6e7376cSAlexandre Belloni
1005018d959bSAlexandre Belloni set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3028->rtc->features);
1006018d959bSAlexandre Belloni
1007e6e7376cSAlexandre Belloni rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
1008e6e7376cSAlexandre Belloni rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099;
1009e6e7376cSAlexandre Belloni rv3028->rtc->ops = &rv3028_rtc_ops;
1010fdcfd854SBartosz Golaszewski ret = devm_rtc_register_device(rv3028->rtc);
1011e6e7376cSAlexandre Belloni if (ret)
1012e6e7376cSAlexandre Belloni return ret;
1013e6e7376cSAlexandre Belloni
1014e6e7376cSAlexandre Belloni nvmem_cfg.priv = rv3028->regmap;
10153a905c2dSBartosz Golaszewski devm_rtc_nvmem_register(rv3028->rtc, &nvmem_cfg);
1016de0ad60eSAlexandre Belloni eeprom_cfg.priv = rv3028;
10173a905c2dSBartosz Golaszewski devm_rtc_nvmem_register(rv3028->rtc, &eeprom_cfg);
1018e6e7376cSAlexandre Belloni
1019e6e7376cSAlexandre Belloni rv3028->rtc->max_user_freq = 1;
1020e6e7376cSAlexandre Belloni
1021f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK
1022f583c341SParthiban Nallathambi rv3028_clkout_register_clk(rv3028, client);
1023f583c341SParthiban Nallathambi #endif
1024e6e7376cSAlexandre Belloni return 0;
1025e6e7376cSAlexandre Belloni }
1026e6e7376cSAlexandre Belloni
1027b6ef5d4aSAlexandre Belloni static const struct acpi_device_id rv3028_i2c_acpi_match[] = {
1028b6ef5d4aSAlexandre Belloni { "MCRY3028" },
1029b6ef5d4aSAlexandre Belloni { }
1030b6ef5d4aSAlexandre Belloni };
1031b6ef5d4aSAlexandre Belloni MODULE_DEVICE_TABLE(acpi, rv3028_i2c_acpi_match);
1032b6ef5d4aSAlexandre Belloni
1033dff31b0bSAlexandre Belloni static const __maybe_unused struct of_device_id rv3028_of_match[] = {
1034e6e7376cSAlexandre Belloni { .compatible = "microcrystal,rv3028", },
1035e6e7376cSAlexandre Belloni { }
1036e6e7376cSAlexandre Belloni };
1037e6e7376cSAlexandre Belloni MODULE_DEVICE_TABLE(of, rv3028_of_match);
1038e6e7376cSAlexandre Belloni
10397e2a60efSJohannes Kirchmair static const struct i2c_device_id rv3028_id_table[] = {
10407e2a60efSJohannes Kirchmair { .name = "rv3028", },
10417e2a60efSJohannes Kirchmair { }
10427e2a60efSJohannes Kirchmair };
10437e2a60efSJohannes Kirchmair MODULE_DEVICE_TABLE(i2c, rv3028_id_table);
10447e2a60efSJohannes Kirchmair
1045e6e7376cSAlexandre Belloni static struct i2c_driver rv3028_driver = {
1046e6e7376cSAlexandre Belloni .driver = {
1047e6e7376cSAlexandre Belloni .name = "rtc-rv3028",
1048b6ef5d4aSAlexandre Belloni .acpi_match_table = rv3028_i2c_acpi_match,
1049e6e7376cSAlexandre Belloni .of_match_table = of_match_ptr(rv3028_of_match),
1050e6e7376cSAlexandre Belloni },
10517e2a60efSJohannes Kirchmair .id_table = rv3028_id_table,
105231b0cecbSUwe Kleine-König .probe = rv3028_probe,
1053e6e7376cSAlexandre Belloni };
1054e6e7376cSAlexandre Belloni module_i2c_driver(rv3028_driver);
1055e6e7376cSAlexandre Belloni
1056e6e7376cSAlexandre Belloni MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
1057e6e7376cSAlexandre Belloni MODULE_DESCRIPTION("Micro Crystal RV3028 RTC driver");
1058e6e7376cSAlexandre Belloni MODULE_LICENSE("GPL v2");
1059