aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaud Ebalard <arno@natisbad.org>2013-12-19 17:27:28 -0500
committerJason Cooper <jason@lakedaemon.net>2013-12-22 12:33:16 -0500
commit70e123373c05e336f3f769b32c6132bdc2d6f5ac (patch)
tree002229625d7f6522829dfbde411b3311a1e8b9a6
parent9c8eca3ca43d7337be2485169d4d86a9b6f477d2 (diff)
rtc: Add support for Intersil ISL12057 I2C RTC chip
Intersil ISL12057 is an I2C RTC chip also supporting two alarms. This patch only adds support for basic RTC functionalities (i.e. getting and setting time). Tests have been performed on NETGEAR ReadyNAS 102 w/ startup/shutdown scripts, hwclock, ntpdate and openntpd. Reviewed-by: Mark Brown <broonie@linaro.org> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Arnaud Ebalard <arno@natisbad.org> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt1
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--drivers/rtc/Kconfig11
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-isl12057.c310
5 files changed, 324 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index b1cb3415e6f1..cdf14308ed92 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -39,6 +39,7 @@ fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
39gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface 39gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
40infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) 40infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
41infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) 41infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz)
42isl,isl12057 Intersil ISL12057 I2C RTC Chip
42maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator 43maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
43maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs 44maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
44maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface 45maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ce95ed1c6d3e..507761a22867 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -38,6 +38,7 @@ ibm International Business Machines (IBM)
38idt Integrated Device Technologies, Inc. 38idt Integrated Device Technologies, Inc.
39img Imagination Technologies Ltd. 39img Imagination Technologies Ltd.
40intercontrol Inter Control Group 40intercontrol Inter Control Group
41isl Intersil
41linux Linux-specific binding 42linux Linux-specific binding
42lsi LSI Corp. (LSI Logic) 43lsi LSI Corp. (LSI Logic)
43marvell Marvell Technology Group Ltd. 44marvell Marvell Technology Group Ltd.
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 007730222116..9608210109f9 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -304,6 +304,17 @@ config RTC_DRV_ISL12022
304 This driver can also be built as a module. If so, the module 304 This driver can also be built as a module. If so, the module
305 will be called rtc-isl12022. 305 will be called rtc-isl12022.
306 306
307config RTC_DRV_ISL12057
308 depends on I2C
309 select REGMAP_I2C
310 tristate "Intersil ISL12057"
311 help
312 If you say yes here you get support for the Intersil ISL12057
313 I2C RTC chip.
314
315 This driver can also be built as a module. If so, the module
316 will be called rtc-isl12057.
317
307config RTC_DRV_X1205 318config RTC_DRV_X1205
308 tristate "Xicor/Intersil X1205" 319 tristate "Xicor/Intersil X1205"
309 help 320 help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 27b4bd884066..d4089c0dbe91 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
58obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o 58obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
59obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o 59obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
60obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o 60obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
61obj-$(CONFIG_RTC_DRV_ISL12057) += rtc-isl12057.o
61obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o 62obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
62obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o 63obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
63obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o 64obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c
new file mode 100644
index 000000000000..7854a656628f
--- /dev/null
+++ b/drivers/rtc/rtc-isl12057.c
@@ -0,0 +1,310 @@
1/*
2 * rtc-isl12057 - Driver for Intersil ISL12057 I2C Real Time Clock
3 *
4 * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.org>
5 *
6 * This work is largely based on Intersil ISL1208 driver developed by
7 * Hebert Valerio Riedel <hvr@gnu.org>.
8 *
9 * Detailed datasheet on which this development is based is available here:
10 *
11 * http://natisbad.org/NAS2/refs/ISL12057.pdf
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 */
23
24#include <linux/module.h>
25#include <linux/mutex.h>
26#include <linux/rtc.h>
27#include <linux/i2c.h>
28#include <linux/bcd.h>
29#include <linux/rtc.h>
30#include <linux/of.h>
31#include <linux/of_device.h>
32#include <linux/regmap.h>
33
34#define DRV_NAME "rtc-isl12057"
35
36/* RTC section */
37#define ISL12057_REG_RTC_SC 0x00 /* Seconds */
38#define ISL12057_REG_RTC_MN 0x01 /* Minutes */
39#define ISL12057_REG_RTC_HR 0x02 /* Hours */
40#define ISL12057_REG_RTC_HR_PM BIT(5) /* AM/PM bit in 12h format */
41#define ISL12057_REG_RTC_HR_MIL BIT(6) /* 24h/12h format */
42#define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */
43#define ISL12057_REG_RTC_DT 0x04 /* Date */
44#define ISL12057_REG_RTC_MO 0x05 /* Month */
45#define ISL12057_REG_RTC_YR 0x06 /* Year */
46#define ISL12057_RTC_SEC_LEN 7
47
48/* Alarm 1 section */
49#define ISL12057_REG_A1_SC 0x07 /* Alarm 1 Seconds */
50#define ISL12057_REG_A1_MN 0x08 /* Alarm 1 Minutes */
51#define ISL12057_REG_A1_HR 0x09 /* Alarm 1 Hours */
52#define ISL12057_REG_A1_HR_PM BIT(5) /* AM/PM bit in 12h format */
53#define ISL12057_REG_A1_HR_MIL BIT(6) /* 24h/12h format */
54#define ISL12057_REG_A1_DWDT 0x0A /* Alarm 1 Date / Day of the week */
55#define ISL12057_REG_A1_DWDT_B BIT(6) /* DW / DT selection bit */
56#define ISL12057_A1_SEC_LEN 4
57
58/* Alarm 2 section */
59#define ISL12057_REG_A2_MN 0x0B /* Alarm 2 Minutes */
60#define ISL12057_REG_A2_HR 0x0C /* Alarm 2 Hours */
61#define ISL12057_REG_A2_DWDT 0x0D /* Alarm 2 Date / Day of the week */
62#define ISL12057_A2_SEC_LEN 3
63
64/* Control/Status registers */
65#define ISL12057_REG_INT 0x0E
66#define ISL12057_REG_INT_A1IE BIT(0) /* Alarm 1 interrupt enable bit */
67#define ISL12057_REG_INT_A2IE BIT(1) /* Alarm 2 interrupt enable bit */
68#define ISL12057_REG_INT_INTCN BIT(2) /* Interrupt control enable bit */
69#define ISL12057_REG_INT_RS1 BIT(3) /* Freq out control bit 1 */
70#define ISL12057_REG_INT_RS2 BIT(4) /* Freq out control bit 2 */
71#define ISL12057_REG_INT_EOSC BIT(7) /* Oscillator enable bit */
72
73#define ISL12057_REG_SR 0x0F
74#define ISL12057_REG_SR_A1F BIT(0) /* Alarm 1 interrupt bit */
75#define ISL12057_REG_SR_A2F BIT(1) /* Alarm 2 interrupt bit */
76#define ISL12057_REG_SR_OSF BIT(7) /* Oscillator failure bit */
77
78/* Register memory map length */
79#define ISL12057_MEM_MAP_LEN 0x10
80
81struct isl12057_rtc_data {
82 struct regmap *regmap;
83 struct mutex lock;
84};
85
86static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs)
87{
88 tm->tm_sec = bcd2bin(regs[ISL12057_REG_RTC_SC]);
89 tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]);
90
91 if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */
92 tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x0f);
93 if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM)
94 tm->tm_hour += 12;
95 } else { /* 24 hour mode */
96 tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x3f);
97 }
98
99 tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]);
100 tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */
101 tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO]) - 1; /* starts at 1 */
102 tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100;
103}
104
105static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm)
106{
107 /*
108 * The clock has an 8 bit wide bcd-coded register for the year.
109 * tm_year is an offset from 1900 and we are interested in the
110 * 2000-2099 range, so any value less than 100 is invalid.
111 */
112 if (tm->tm_year < 100)
113 return -EINVAL;
114
115 regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec);
116 regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min);
117 regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */
118 regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday);
119 regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1);
120 regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year - 100);
121 regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1);
122
123 return 0;
124}
125
126/*
127 * Try and match register bits w/ fixed null values to see whether we
128 * are dealing with an ISL12057. Note: this function is called early
129 * during init and hence does need mutex protection.
130 */
131static int isl12057_i2c_validate_chip(struct regmap *regmap)
132{
133 u8 regs[ISL12057_MEM_MAP_LEN];
134 static const u8 mask[ISL12057_MEM_MAP_LEN] = { 0x80, 0x80, 0x80, 0xf8,
135 0xc0, 0x60, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x60, 0x7c };
138 int ret, i;
139
140 ret = regmap_bulk_read(regmap, 0, regs, ISL12057_MEM_MAP_LEN);
141 if (ret)
142 return ret;
143
144 for (i = 0; i < ISL12057_MEM_MAP_LEN; ++i) {
145 if (regs[i] & mask[i]) /* check if bits are cleared */
146 return -ENODEV;
147 }
148
149 return 0;
150}
151
152static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm)
153{
154 struct isl12057_rtc_data *data = dev_get_drvdata(dev);
155 u8 regs[ISL12057_RTC_SEC_LEN];
156 int ret;
157
158 mutex_lock(&data->lock);
159 ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs,
160 ISL12057_RTC_SEC_LEN);
161 mutex_unlock(&data->lock);
162
163 if (ret) {
164 dev_err(dev, "%s: RTC read failed\n", __func__);
165 return ret;
166 }
167
168 isl12057_rtc_regs_to_tm(tm, regs);
169
170 return rtc_valid_tm(tm);
171}
172
173static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm)
174{
175 struct isl12057_rtc_data *data = dev_get_drvdata(dev);
176 u8 regs[ISL12057_RTC_SEC_LEN];
177 int ret;
178
179 ret = isl12057_rtc_tm_to_regs(regs, tm);
180 if (ret)
181 return ret;
182
183 mutex_lock(&data->lock);
184 ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs,
185 ISL12057_RTC_SEC_LEN);
186 mutex_unlock(&data->lock);
187
188 if (ret)
189 dev_err(dev, "%s: RTC write failed\n", __func__);
190
191 return ret;
192}
193
194/*
195 * Check current RTC status and enable/disable what needs to be. Return 0 if
196 * everything went ok and a negative value upon error. Note: this function
197 * is called early during init and hence does need mutex protection.
198 */
199static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap)
200{
201 int ret;
202
203 /* Enable oscillator if not already running */
204 ret = regmap_update_bits(regmap, ISL12057_REG_INT,
205 ISL12057_REG_INT_EOSC, 0);
206 if (ret < 0) {
207 dev_err(dev, "Unable to enable oscillator\n");
208 return ret;
209 }
210
211 /* Clear oscillator failure bit if needed */
212 ret = regmap_update_bits(regmap, ISL12057_REG_SR,
213 ISL12057_REG_SR_OSF, 0);
214 if (ret < 0) {
215 dev_err(dev, "Unable to clear oscillator failure bit\n");
216 return ret;
217 }
218
219 /* Clear alarm bit if needed */
220 ret = regmap_update_bits(regmap, ISL12057_REG_SR,
221 ISL12057_REG_SR_A1F, 0);
222 if (ret < 0) {
223 dev_err(dev, "Unable to clear alarm bit\n");
224 return ret;
225 }
226
227 return 0;
228}
229
230static const struct rtc_class_ops rtc_ops = {
231 .read_time = isl12057_rtc_read_time,
232 .set_time = isl12057_rtc_set_time,
233};
234
235static struct regmap_config isl12057_rtc_regmap_config = {
236 .reg_bits = 8,
237 .val_bits = 8,
238};
239
240static int isl12057_probe(struct i2c_client *client,
241 const struct i2c_device_id *id)
242{
243 struct device *dev = &client->dev;
244 struct isl12057_rtc_data *data;
245 struct rtc_device *rtc;
246 struct regmap *regmap;
247 int ret;
248
249 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
250 I2C_FUNC_SMBUS_BYTE_DATA |
251 I2C_FUNC_SMBUS_I2C_BLOCK))
252 return -ENODEV;
253
254 regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config);
255 if (IS_ERR(regmap)) {
256 ret = PTR_ERR(regmap);
257 dev_err(dev, "regmap allocation failed: %d\n", ret);
258 return ret;
259 }
260
261 ret = isl12057_i2c_validate_chip(regmap);
262 if (ret)
263 return ret;
264
265 ret = isl12057_check_rtc_status(dev, regmap);
266 if (ret)
267 return ret;
268
269 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
270 if (!data)
271 return -ENOMEM;
272
273 mutex_init(&data->lock);
274 data->regmap = regmap;
275 dev_set_drvdata(dev, data);
276
277 rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops, THIS_MODULE);
278 if (IS_ERR(rtc))
279 return PTR_ERR(rtc);
280
281 return 0;
282}
283
284#ifdef CONFIG_OF
285static struct of_device_id isl12057_dt_match[] = {
286 { .compatible = "isl,isl12057" },
287 { },
288};
289#endif
290
291static const struct i2c_device_id isl12057_id[] = {
292 { "isl12057", 0 },
293 { }
294};
295MODULE_DEVICE_TABLE(i2c, isl12057_id);
296
297static struct i2c_driver isl12057_driver = {
298 .driver = {
299 .name = DRV_NAME,
300 .owner = THIS_MODULE,
301 .of_match_table = of_match_ptr(isl12057_dt_match),
302 },
303 .probe = isl12057_probe,
304 .id_table = isl12057_id,
305};
306module_i2c_driver(isl12057_driver);
307
308MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>");
309MODULE_DESCRIPTION("Intersil ISL12057 RTC driver");
310MODULE_LICENSE("GPL");