blob: d426eac965e930125463f4813ea6b74973943985 [file] [log] [blame]
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -07001/*
2 * Intersil ISL1208 rtc class driver
3 *
4 * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/i2c.h>
15#include <linux/bcd.h>
16#include <linux/rtc.h>
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +000017#include "rtc-core.h"
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070018
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070019/* Register map */
20/* rtc section */
21#define ISL1208_REG_SC 0x00
22#define ISL1208_REG_MN 0x01
23#define ISL1208_REG_HR 0x02
Alessandro Zummo9edae7b2008-04-28 02:11:53 -070024#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */
25#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070026#define ISL1208_REG_DT 0x03
27#define ISL1208_REG_MO 0x04
28#define ISL1208_REG_YR 0x05
29#define ISL1208_REG_DW 0x06
30#define ISL1208_RTC_SECTION_LEN 7
31
32/* control/status section */
33#define ISL1208_REG_SR 0x07
Alessandro Zummo9edae7b2008-04-28 02:11:53 -070034#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
35#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
36#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +000037#define ISL1208_REG_SR_EVT (1<<3) /* event */
Alessandro Zummo9edae7b2008-04-28 02:11:53 -070038#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
39#define ISL1208_REG_SR_BAT (1<<1) /* battery */
40#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070041#define ISL1208_REG_INT 0x08
Ryan Malloncf044f02011-03-22 16:34:53 -070042#define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */
43#define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +000044#define ISL1219_REG_EV 0x09
45#define ISL1219_REG_EV_EVEN (1<<4) /* event detection enable */
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070046#define ISL1208_REG_ATR 0x0a
47#define ISL1208_REG_DTR 0x0b
48
49/* alarm section */
50#define ISL1208_REG_SCA 0x0c
51#define ISL1208_REG_MNA 0x0d
52#define ISL1208_REG_HRA 0x0e
53#define ISL1208_REG_DTA 0x0f
54#define ISL1208_REG_MOA 0x10
55#define ISL1208_REG_DWA 0x11
56#define ISL1208_ALARM_SECTION_LEN 6
57
58/* user section */
59#define ISL1208_REG_USR1 0x12
60#define ISL1208_REG_USR2 0x13
61#define ISL1208_USR_SECTION_LEN 2
62
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +000063/* event section */
64#define ISL1219_REG_SCT 0x14
65#define ISL1219_REG_MNT 0x15
66#define ISL1219_REG_HRT 0x16
67#define ISL1219_REG_DTT 0x17
68#define ISL1219_REG_MOT 0x18
69#define ISL1219_REG_YRT 0x19
70#define ISL1219_EVT_SECTION_LEN 6
71
Alessandro Zummo9edae7b2008-04-28 02:11:53 -070072static struct i2c_driver isl1208_driver;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070073
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +000074/* ISL1208 various variants */
75enum {
76 TYPE_ISL1208 = 0,
77 TYPE_ISL1218,
78 TYPE_ISL1219,
79};
80
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070081/* block read */
82static int
83isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
Alessandro Zummo9edae7b2008-04-28 02:11:53 -070084 unsigned len)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070085{
86 u8 reg_addr[1] = { reg };
87 struct i2c_msg msgs[2] = {
Shubhrajyoti D885ccbb2012-10-04 17:14:27 -070088 {
89 .addr = client->addr,
90 .len = sizeof(reg_addr),
91 .buf = reg_addr
92 },
93 {
94 .addr = client->addr,
95 .flags = I2C_M_RD,
96 .len = len,
97 .buf = buf
98 }
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -070099 };
100 int ret;
101
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000102 WARN_ON(reg > ISL1219_REG_YRT);
103 WARN_ON(reg + len > ISL1219_REG_YRT + 1);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700104
105 ret = i2c_transfer(client->adapter, msgs, 2);
106 if (ret > 0)
107 ret = 0;
108 return ret;
109}
110
111/* block write */
112static int
113isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700114 unsigned len)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700115{
116 u8 i2c_buf[ISL1208_REG_USR2 + 2];
117 struct i2c_msg msgs[1] = {
Shubhrajyoti D885ccbb2012-10-04 17:14:27 -0700118 {
119 .addr = client->addr,
120 .len = len + 1,
121 .buf = i2c_buf
122 }
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700123 };
124 int ret;
125
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000126 WARN_ON(reg > ISL1219_REG_YRT);
127 WARN_ON(reg + len > ISL1219_REG_YRT + 1);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700128
129 i2c_buf[0] = reg;
130 memcpy(&i2c_buf[1], &buf[0], len);
131
132 ret = i2c_transfer(client->adapter, msgs, 1);
133 if (ret > 0)
134 ret = 0;
135 return ret;
136}
137
Adam Buchbinder48fc7f72012-09-19 21:48:00 -0400138/* simple check to see whether we have a isl1208 */
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700139static int
140isl1208_i2c_validate_client(struct i2c_client *client)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700141{
142 u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
143 u8 zero_mask[ISL1208_RTC_SECTION_LEN] = {
144 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8
145 };
146 int i;
147 int ret;
148
149 ret = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
150 if (ret < 0)
151 return ret;
152
153 for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) {
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700154 if (regs[i] & zero_mask[i]) /* check if bits are cleared */
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700155 return -ENODEV;
156 }
157
158 return 0;
159}
160
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700161static int
162isl1208_i2c_get_sr(struct i2c_client *client)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700163{
Sachin Kamatc91fd912013-11-12 15:10:26 -0800164 return i2c_smbus_read_byte_data(client, ISL1208_REG_SR);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700165}
166
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700167static int
168isl1208_i2c_get_atr(struct i2c_client *client)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700169{
170 int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700171 if (atr < 0)
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700172 return atr;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700173
174 /* The 6bit value in the ATR register controls the load
175 * capacitance C_load * in steps of 0.25pF
176 *
177 * bit (1<<5) of the ATR register is inverted
178 *
179 * C_load(ATR=0x20) = 4.50pF
180 * C_load(ATR=0x00) = 12.50pF
181 * C_load(ATR=0x1f) = 20.25pF
182 *
183 */
184
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700185 atr &= 0x3f; /* mask out lsb */
186 atr ^= 1 << 5; /* invert 6th bit */
187 atr += 2 * 9; /* add offset of 4.5pF; unit[atr] = 0.25pF */
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700188
189 return atr;
190}
191
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700192static int
193isl1208_i2c_get_dtr(struct i2c_client *client)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700194{
195 int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700196 if (dtr < 0)
197 return -EIO;
198
199 /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700200 dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700201
202 return dtr;
203}
204
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700205static int
206isl1208_i2c_get_usr(struct i2c_client *client)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700207{
208 u8 buf[ISL1208_USR_SECTION_LEN] = { 0, };
209 int ret;
210
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700211 ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1, buf,
212 ISL1208_USR_SECTION_LEN);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700213 if (ret < 0)
214 return ret;
215
216 return (buf[1] << 8) | buf[0];
217}
218
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700219static int
220isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700221{
222 u8 buf[ISL1208_USR_SECTION_LEN];
223
224 buf[0] = usr & 0xff;
225 buf[1] = (usr >> 8) & 0xff;
226
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700227 return isl1208_i2c_set_regs(client, ISL1208_REG_USR1, buf,
228 ISL1208_USR_SECTION_LEN);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700229}
230
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700231static int
Ryan Malloncf044f02011-03-22 16:34:53 -0700232isl1208_rtc_toggle_alarm(struct i2c_client *client, int enable)
233{
234 int icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT);
235
236 if (icr < 0) {
237 dev_err(&client->dev, "%s: reading INT failed\n", __func__);
238 return icr;
239 }
240
241 if (enable)
242 icr |= ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM;
243 else
244 icr &= ~(ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM);
245
246 icr = i2c_smbus_write_byte_data(client, ISL1208_REG_INT, icr);
247 if (icr < 0) {
248 dev_err(&client->dev, "%s: writing INT failed\n", __func__);
249 return icr;
250 }
251
252 return 0;
253}
254
255static int
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700256isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700257{
258 struct i2c_client *const client = to_i2c_client(dev);
259 int sr, dtr, atr, usr;
260
261 sr = isl1208_i2c_get_sr(client);
262 if (sr < 0) {
263 dev_err(&client->dev, "%s: reading SR failed\n", __func__);
264 return sr;
265 }
266
267 seq_printf(seq, "status_reg\t:%s%s%s%s%s%s (0x%.2x)\n",
268 (sr & ISL1208_REG_SR_RTCF) ? " RTCF" : "",
269 (sr & ISL1208_REG_SR_BAT) ? " BAT" : "",
270 (sr & ISL1208_REG_SR_ALM) ? " ALM" : "",
271 (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "",
272 (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "",
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700273 (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", sr);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700274
275 seq_printf(seq, "batt_status\t: %s\n",
276 (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
277
278 dtr = isl1208_i2c_get_dtr(client);
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700279 if (dtr >= 0 - 1)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700280 seq_printf(seq, "digital_trim\t: %d ppm\n", dtr);
281
282 atr = isl1208_i2c_get_atr(client);
283 if (atr >= 0)
284 seq_printf(seq, "analog_trim\t: %d.%.2d pF\n",
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700285 atr >> 2, (atr & 0x3) * 25);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700286
287 usr = isl1208_i2c_get_usr(client);
288 if (usr >= 0)
289 seq_printf(seq, "user_data\t: 0x%.4x\n", usr);
290
291 return 0;
292}
293
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700294static int
295isl1208_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700296{
297 int sr;
298 u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
299
300 sr = isl1208_i2c_get_sr(client);
301 if (sr < 0) {
302 dev_err(&client->dev, "%s: reading SR failed\n", __func__);
303 return -EIO;
304 }
305
306 sr = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
307 if (sr < 0) {
308 dev_err(&client->dev, "%s: reading RTC section failed\n",
309 __func__);
310 return sr;
311 }
312
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700313 tm->tm_sec = bcd2bin(regs[ISL1208_REG_SC]);
314 tm->tm_min = bcd2bin(regs[ISL1208_REG_MN]);
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700315
316 /* HR field has a more complex interpretation */
317 {
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700318 const u8 _hr = regs[ISL1208_REG_HR];
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700319 if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700320 tm->tm_hour = bcd2bin(_hr & 0x3f);
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700321 else {
322 /* 12h format */
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700323 tm->tm_hour = bcd2bin(_hr & 0x1f);
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700324 if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700325 tm->tm_hour += 12;
326 }
327 }
328
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700329 tm->tm_mday = bcd2bin(regs[ISL1208_REG_DT]);
330 tm->tm_mon = bcd2bin(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
331 tm->tm_year = bcd2bin(regs[ISL1208_REG_YR]) + 100;
332 tm->tm_wday = bcd2bin(regs[ISL1208_REG_DW]);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700333
334 return 0;
335}
336
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700337static int
338isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700339{
340 struct rtc_time *const tm = &alarm->time;
341 u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
Ryan Malloncf044f02011-03-22 16:34:53 -0700342 int icr, yr, sr = isl1208_i2c_get_sr(client);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700343
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700344 if (sr < 0) {
345 dev_err(&client->dev, "%s: reading SR failed\n", __func__);
346 return sr;
347 }
348
349 sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs,
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700350 ISL1208_ALARM_SECTION_LEN);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700351 if (sr < 0) {
352 dev_err(&client->dev, "%s: reading alarm section failed\n",
353 __func__);
354 return sr;
355 }
356
357 /* MSB of each alarm register is an enable bit */
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700358 tm->tm_sec = bcd2bin(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f);
359 tm->tm_min = bcd2bin(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f);
360 tm->tm_hour = bcd2bin(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f);
361 tm->tm_mday = bcd2bin(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f);
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700362 tm->tm_mon =
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700363 bcd2bin(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1;
364 tm->tm_wday = bcd2bin(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700365
Ryan Malloncf044f02011-03-22 16:34:53 -0700366 /* The alarm doesn't store the year so get it from the rtc section */
367 yr = i2c_smbus_read_byte_data(client, ISL1208_REG_YR);
368 if (yr < 0) {
369 dev_err(&client->dev, "%s: reading RTC YR failed\n", __func__);
370 return yr;
371 }
372 tm->tm_year = bcd2bin(yr) + 100;
373
374 icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT);
375 if (icr < 0) {
376 dev_err(&client->dev, "%s: reading INT failed\n", __func__);
377 return icr;
378 }
379 alarm->enabled = !!(icr & ISL1208_REG_INT_ALME);
380
381 return 0;
382}
383
384static int
385isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
386{
387 struct rtc_time *alarm_tm = &alarm->time;
388 u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
389 const int offs = ISL1208_REG_SCA;
Ryan Malloncf044f02011-03-22 16:34:53 -0700390 struct rtc_time rtc_tm;
391 int err, enable;
392
393 err = isl1208_i2c_read_time(client, &rtc_tm);
394 if (err)
395 return err;
Ryan Malloncf044f02011-03-22 16:34:53 -0700396
397 /* If the alarm time is before the current time disable the alarm */
Xunlei Pangf118db12015-06-12 10:04:11 +0800398 if (!alarm->enabled || rtc_tm_sub(alarm_tm, &rtc_tm) <= 0)
Ryan Malloncf044f02011-03-22 16:34:53 -0700399 enable = 0x00;
400 else
401 enable = 0x80;
402
403 /* Program the alarm and enable it for each setting */
404 regs[ISL1208_REG_SCA - offs] = bin2bcd(alarm_tm->tm_sec) | enable;
405 regs[ISL1208_REG_MNA - offs] = bin2bcd(alarm_tm->tm_min) | enable;
406 regs[ISL1208_REG_HRA - offs] = bin2bcd(alarm_tm->tm_hour) |
407 ISL1208_REG_HR_MIL | enable;
408
409 regs[ISL1208_REG_DTA - offs] = bin2bcd(alarm_tm->tm_mday) | enable;
410 regs[ISL1208_REG_MOA - offs] = bin2bcd(alarm_tm->tm_mon + 1) | enable;
411 regs[ISL1208_REG_DWA - offs] = bin2bcd(alarm_tm->tm_wday & 7) | enable;
412
413 /* write ALARM registers */
414 err = isl1208_i2c_set_regs(client, offs, regs,
415 ISL1208_ALARM_SECTION_LEN);
416 if (err < 0) {
417 dev_err(&client->dev, "%s: writing ALARM section failed\n",
418 __func__);
419 return err;
420 }
421
422 err = isl1208_rtc_toggle_alarm(client, enable);
423 if (err)
424 return err;
425
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700426 return 0;
427}
428
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700429static int
430isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700431{
432 return isl1208_i2c_read_time(to_i2c_client(dev), tm);
433}
434
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700435static int
436isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700437{
438 int sr;
439 u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
440
Chris Elstoncc6c2ca2008-12-23 13:57:10 -0800441 /* The clock has an 8 bit wide bcd-coded register (they never learn)
442 * for the year. tm_year is an offset from 1900 and we are interested
443 * in the 2000-2099 range, so any value less than 100 is invalid.
444 */
445 if (tm->tm_year < 100)
446 return -EINVAL;
447
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700448 regs[ISL1208_REG_SC] = bin2bcd(tm->tm_sec);
449 regs[ISL1208_REG_MN] = bin2bcd(tm->tm_min);
450 regs[ISL1208_REG_HR] = bin2bcd(tm->tm_hour) | ISL1208_REG_HR_MIL;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700451
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700452 regs[ISL1208_REG_DT] = bin2bcd(tm->tm_mday);
453 regs[ISL1208_REG_MO] = bin2bcd(tm->tm_mon + 1);
454 regs[ISL1208_REG_YR] = bin2bcd(tm->tm_year - 100);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700455
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700456 regs[ISL1208_REG_DW] = bin2bcd(tm->tm_wday & 7);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700457
458 sr = isl1208_i2c_get_sr(client);
459 if (sr < 0) {
460 dev_err(&client->dev, "%s: reading SR failed\n", __func__);
461 return sr;
462 }
463
464 /* set WRTC */
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700465 sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR,
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700466 sr | ISL1208_REG_SR_WRTC);
467 if (sr < 0) {
468 dev_err(&client->dev, "%s: writing SR failed\n", __func__);
469 return sr;
470 }
471
472 /* write RTC registers */
473 sr = isl1208_i2c_set_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
474 if (sr < 0) {
475 dev_err(&client->dev, "%s: writing RTC section failed\n",
476 __func__);
477 return sr;
478 }
479
480 /* clear WRTC again */
Denis Osterland5b9fc7952018-01-23 13:17:58 +0100481 sr = isl1208_i2c_get_sr(client);
482 if (sr < 0) {
483 dev_err(&client->dev, "%s: reading SR failed\n", __func__);
484 return sr;
485 }
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700486 sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR,
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700487 sr & ~ISL1208_REG_SR_WRTC);
488 if (sr < 0) {
489 dev_err(&client->dev, "%s: writing SR failed\n", __func__);
490 return sr;
491 }
492
493 return 0;
494}
495
496
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700497static int
498isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700499{
500 return isl1208_i2c_set_time(to_i2c_client(dev), tm);
501}
502
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700503static int
504isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700505{
506 return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
507}
508
Ryan Malloncf044f02011-03-22 16:34:53 -0700509static int
510isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
511{
512 return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm);
513}
514
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000515static ssize_t timestamp0_store(struct device *dev,
516 struct device_attribute *attr,
517 const char *buf, size_t count)
518{
519 struct i2c_client *client = dev_get_drvdata(dev);
520 int sr;
521
522 sr = isl1208_i2c_get_sr(client);
523 if (sr < 0) {
524 dev_err(dev, "%s: reading SR failed\n", __func__);
525 return sr;
526 }
527
528 sr &= ~ISL1208_REG_SR_EVT;
529
530 sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
531 if (sr < 0)
532 dev_err(dev, "%s: writing SR failed\n",
533 __func__);
534
535 return count;
536};
537
538static ssize_t timestamp0_show(struct device *dev,
539 struct device_attribute *attr, char *buf)
540{
541 struct i2c_client *client = dev_get_drvdata(dev);
542 u8 regs[ISL1219_EVT_SECTION_LEN] = { 0, };
543 struct rtc_time tm;
544 int sr;
545
546 sr = isl1208_i2c_get_sr(client);
547 if (sr < 0) {
548 dev_err(dev, "%s: reading SR failed\n", __func__);
549 return sr;
550 }
551
552 if (!(sr & ISL1208_REG_SR_EVT))
553 return 0;
554
555 sr = isl1208_i2c_read_regs(client, ISL1219_REG_SCT, regs,
556 ISL1219_EVT_SECTION_LEN);
557 if (sr < 0) {
558 dev_err(dev, "%s: reading event section failed\n",
559 __func__);
560 return 0;
561 }
562
563 /* MSB of each alarm register is an enable bit */
564 tm.tm_sec = bcd2bin(regs[ISL1219_REG_SCT - ISL1219_REG_SCT] & 0x7f);
565 tm.tm_min = bcd2bin(regs[ISL1219_REG_MNT - ISL1219_REG_SCT] & 0x7f);
566 tm.tm_hour = bcd2bin(regs[ISL1219_REG_HRT - ISL1219_REG_SCT] & 0x3f);
567 tm.tm_mday = bcd2bin(regs[ISL1219_REG_DTT - ISL1219_REG_SCT] & 0x3f);
568 tm.tm_mon =
569 bcd2bin(regs[ISL1219_REG_MOT - ISL1219_REG_SCT] & 0x1f) - 1;
570 tm.tm_year = bcd2bin(regs[ISL1219_REG_YRT - ISL1219_REG_SCT]) + 100;
571
572 sr = rtc_valid_tm(&tm);
573 if (sr)
574 return sr;
575
576 return sprintf(buf, "%llu\n",
577 (unsigned long long)rtc_tm_to_time64(&tm));
578};
579
580static DEVICE_ATTR_RW(timestamp0);
581
Ryan Malloncf044f02011-03-22 16:34:53 -0700582static irqreturn_t
583isl1208_rtc_interrupt(int irq, void *data)
584{
585 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
586 struct i2c_client *client = data;
Jan Luebbe72fca4a2013-02-04 14:28:53 -0800587 struct rtc_device *rtc = i2c_get_clientdata(client);
Ryan Malloncf044f02011-03-22 16:34:53 -0700588 int handled = 0, sr, err;
589
590 /*
591 * I2C reads get NAK'ed if we read straight away after an interrupt?
592 * Using a mdelay/msleep didn't seem to help either, so we work around
593 * this by continually trying to read the register for a short time.
594 */
595 while (1) {
596 sr = isl1208_i2c_get_sr(client);
597 if (sr >= 0)
598 break;
599
600 if (time_after(jiffies, timeout)) {
601 dev_err(&client->dev, "%s: reading SR failed\n",
602 __func__);
603 return sr;
604 }
605 }
606
607 if (sr & ISL1208_REG_SR_ALM) {
608 dev_dbg(&client->dev, "alarm!\n");
609
Jan Luebbe72fca4a2013-02-04 14:28:53 -0800610 rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
611
Ryan Malloncf044f02011-03-22 16:34:53 -0700612 /* Clear the alarm */
613 sr &= ~ISL1208_REG_SR_ALM;
614 sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
615 if (sr < 0)
616 dev_err(&client->dev, "%s: writing SR failed\n",
617 __func__);
618 else
619 handled = 1;
620
621 /* Disable the alarm */
622 err = isl1208_rtc_toggle_alarm(client, 0);
623 if (err)
624 return err;
625 }
626
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000627 if (sr & ISL1208_REG_SR_EVT) {
628 sysfs_notify(&rtc->dev.kobj, NULL,
629 dev_attr_timestamp0.attr.name);
630 dev_warn(&client->dev, "event detected");
631 handled = 1;
632 }
633
Ryan Malloncf044f02011-03-22 16:34:53 -0700634 return handled ? IRQ_HANDLED : IRQ_NONE;
635}
636
David Brownellff8371a2006-09-30 23:28:17 -0700637static const struct rtc_class_ops isl1208_rtc_ops = {
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700638 .proc = isl1208_rtc_proc,
639 .read_time = isl1208_rtc_read_time,
640 .set_time = isl1208_rtc_set_time,
641 .read_alarm = isl1208_rtc_read_alarm,
Ryan Malloncf044f02011-03-22 16:34:53 -0700642 .set_alarm = isl1208_rtc_set_alarm,
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700643};
644
645/* sysfs interface */
646
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700647static ssize_t
648isl1208_sysfs_show_atrim(struct device *dev,
649 struct device_attribute *attr, char *buf)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700650{
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700651 int atr = isl1208_i2c_get_atr(to_i2c_client(dev));
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700652 if (atr < 0)
653 return atr;
654
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700655 return sprintf(buf, "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700656}
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700657
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700658static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL);
659
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700660static ssize_t
661isl1208_sysfs_show_dtrim(struct device *dev,
662 struct device_attribute *attr, char *buf)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700663{
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700664 int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700665 if (dtr < 0)
666 return dtr;
667
668 return sprintf(buf, "%d ppm\n", dtr);
669}
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700670
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700671static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
672
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700673static ssize_t
674isl1208_sysfs_show_usr(struct device *dev,
675 struct device_attribute *attr, char *buf)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700676{
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700677 int usr = isl1208_i2c_get_usr(to_i2c_client(dev));
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700678 if (usr < 0)
679 return usr;
680
681 return sprintf(buf, "0x%.4x\n", usr);
682}
683
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700684static ssize_t
685isl1208_sysfs_store_usr(struct device *dev,
686 struct device_attribute *attr,
687 const char *buf, size_t count)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700688{
689 int usr = -1;
690
691 if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) {
692 if (sscanf(buf, "%x", &usr) != 1)
693 return -EINVAL;
694 } else {
695 if (sscanf(buf, "%d", &usr) != 1)
696 return -EINVAL;
697 }
698
699 if (usr < 0 || usr > 0xffff)
700 return -EINVAL;
701
702 return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
703}
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700704
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700705static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
706 isl1208_sysfs_store_usr);
707
H Hartley Sweetene17ab5cb2010-05-24 14:33:46 -0700708static struct attribute *isl1208_rtc_attrs[] = {
709 &dev_attr_atrim.attr,
710 &dev_attr_dtrim.attr,
711 &dev_attr_usr.attr,
712 NULL
713};
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700714
H Hartley Sweetene17ab5cb2010-05-24 14:33:46 -0700715static const struct attribute_group isl1208_rtc_sysfs_files = {
716 .attrs = isl1208_rtc_attrs,
717};
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700718
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000719static struct attribute *isl1219_rtc_attrs[] = {
720 &dev_attr_timestamp0.attr,
721 NULL
722};
723
724static const struct attribute_group isl1219_rtc_sysfs_files = {
725 .attrs = isl1219_rtc_attrs,
726};
727
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700728static int
Jean Delvared2653e92008-04-29 23:11:39 +0200729isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700730{
731 int rc = 0;
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700732 struct rtc_device *rtc;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700733
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700734 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
735 return -ENODEV;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700736
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700737 if (isl1208_i2c_validate_client(client) < 0)
738 return -ENODEV;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700739
Denis Osterland236b7182018-03-05 10:43:53 +0000740 rtc = devm_rtc_allocate_device(&client->dev);
Sachin Kamatadce8c12013-11-12 15:10:30 -0800741 if (IS_ERR(rtc))
742 return PTR_ERR(rtc);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700743
Denis Osterland236b7182018-03-05 10:43:53 +0000744 rtc->ops = &isl1208_rtc_ops;
745
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700746 i2c_set_clientdata(client, rtc);
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000747 dev_set_drvdata(&rtc->dev, client);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700748
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700749 rc = isl1208_i2c_get_sr(client);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700750 if (rc < 0) {
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700751 dev_err(&client->dev, "reading status failed\n");
Sachin Kamatadce8c12013-11-12 15:10:30 -0800752 return rc;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700753 }
754
755 if (rc & ISL1208_REG_SR_RTCF)
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700756 dev_warn(&client->dev, "rtc power failure detected, "
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700757 "please set clock.\n");
758
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000759 if (id->driver_data == TYPE_ISL1219) {
760 rc = i2c_smbus_write_byte_data(client, ISL1219_REG_EV,
761 ISL1219_REG_EV_EVEN);
762 if (rc < 0) {
763 dev_err(&client->dev, "could not enable tamper detection\n");
764 return rc;
765 }
766 rc = rtc_add_group(rtc, &isl1219_rtc_sysfs_files);
767 if (rc)
768 return rc;
769 }
770
H Hartley Sweetene17ab5cb2010-05-24 14:33:46 -0700771 rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700772 if (rc)
Sachin Kamatadce8c12013-11-12 15:10:30 -0800773 return rc;
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700774
Michael Grzeschik9d327c22018-03-05 10:43:53 +0000775 if (client->irq > 0) {
776 rc = devm_request_threaded_irq(&client->dev, client->irq, NULL,
777 isl1208_rtc_interrupt,
778 IRQF_SHARED | IRQF_ONESHOT,
779 isl1208_driver.driver.name,
780 client);
781 if (!rc) {
782 device_init_wakeup(&client->dev, 1);
783 enable_irq_wake(client->irq);
784 } else {
785 dev_err(&client->dev,
786 "Unable to request irq %d, no alarm support\n",
787 client->irq);
788 client->irq = 0;
789 }
790 }
791
Denis Osterland236b7182018-03-05 10:43:53 +0000792 return rtc_register_device(rtc);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700793}
794
795static int
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700796isl1208_remove(struct i2c_client *client)
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700797{
H Hartley Sweetene17ab5cb2010-05-24 14:33:46 -0700798 sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700799
800 return 0;
801}
802
Jean Delvare3760f732008-04-29 23:11:40 +0200803static const struct i2c_device_id isl1208_id[] = {
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000804 { "isl1208", TYPE_ISL1208 },
805 { "isl1218", TYPE_ISL1218 },
806 { "isl1219", TYPE_ISL1219 },
Jean Delvare3760f732008-04-29 23:11:40 +0200807 { }
808};
809MODULE_DEVICE_TABLE(i2c, isl1208_id);
810
Javier Martinez Canillas03835502017-03-03 11:29:20 -0300811static const struct of_device_id isl1208_of_match[] = {
812 { .compatible = "isil,isl1208" },
813 { .compatible = "isil,isl1218" },
Michael Grzeschikdd35bdb2018-07-24 11:31:21 +0000814 { .compatible = "isil,isl1219" },
Javier Martinez Canillas03835502017-03-03 11:29:20 -0300815 { }
816};
817MODULE_DEVICE_TABLE(of, isl1208_of_match);
818
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700819static struct i2c_driver isl1208_driver = {
820 .driver = {
Javier Martinez Canillas03835502017-03-03 11:29:20 -0300821 .name = "rtc-isl1208",
822 .of_match_table = of_match_ptr(isl1208_of_match),
823 },
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700824 .probe = isl1208_probe,
825 .remove = isl1208_remove,
Jean Delvare3760f732008-04-29 23:11:40 +0200826 .id_table = isl1208_id,
Alessandro Zummo9edae7b2008-04-28 02:11:53 -0700827};
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700828
Axel Lin0abc9202012-03-23 15:02:31 -0700829module_i2c_driver(isl1208_driver);
Herbert Valerio Riedel7e56a7d2006-07-14 00:24:11 -0700830
831MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
832MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
833MODULE_LICENSE("GPL");