Blame view

drivers/rtc/rtc-x1205.c 15.7 KB
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
1
2
3
4
5
6
7
8
9
10
11
  /*
   * An i2c driver for the Xicor/Intersil X1205 RTC
   * Copyright 2004 Karen Spearel
   * Copyright 2005 Alessandro Zummo
   *
   * please send all reports to:
   * 	Karen Spearel <kas111 at gmail dot com>
   *	Alessandro Zummo <a.zummo@towertech.it>
   *
   * based on a lot of other RTC drivers.
   *
890e03750   Jean Delvare   i2c: Delete outda...
12
13
14
   * Information and datasheet:
   * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
   *
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
15
16
17
18
19
20
21
22
23
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/i2c.h>
  #include <linux/bcd.h>
  #include <linux/rtc.h>
  #include <linux/delay.h>
2113852b2   Paul Gortmaker   rtc: Add module.h...
24
  #include <linux/module.h>
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
25

4edac2b44   Alessandro Zummo   rtc-x1205: new st...
26
  #define DRV_VERSION "1.0.8"
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  
  /* offsets into CCR area */
  
  #define CCR_SEC			0
  #define CCR_MIN			1
  #define CCR_HOUR		2
  #define CCR_MDAY		3
  #define CCR_MONTH		4
  #define CCR_YEAR		5
  #define CCR_WDAY		6
  #define CCR_Y2K			7
  
  #define X1205_REG_SR		0x3F	/* status register */
  #define X1205_REG_Y2K		0x37
  #define X1205_REG_DW		0x36
  #define X1205_REG_YR		0x35
  #define X1205_REG_MO		0x34
  #define X1205_REG_DT		0x33
  #define X1205_REG_HR		0x32
  #define X1205_REG_MN		0x31
  #define X1205_REG_SC		0x30
  #define X1205_REG_DTR		0x13
  #define X1205_REG_ATR		0x12
  #define X1205_REG_INT		0x11
  #define X1205_REG_0		0x10
  #define X1205_REG_Y2K1		0x0F
  #define X1205_REG_DWA1		0x0E
  #define X1205_REG_YRA1		0x0D
  #define X1205_REG_MOA1		0x0C
  #define X1205_REG_DTA1		0x0B
  #define X1205_REG_HRA1		0x0A
  #define X1205_REG_MNA1		0x09
  #define X1205_REG_SCA1		0x08
  #define X1205_REG_Y2K0		0x07
  #define X1205_REG_DWA0		0x06
  #define X1205_REG_YRA0		0x05
  #define X1205_REG_MOA0		0x04
  #define X1205_REG_DTA0		0x03
  #define X1205_REG_HRA0		0x02
  #define X1205_REG_MNA0		0x01
  #define X1205_REG_SCA0		0x00
  
  #define X1205_CCR_BASE		0x30	/* Base address of CCR */
  #define X1205_ALM0_BASE		0x00	/* Base address of ALARM0 */
  
  #define X1205_SR_RTCF		0x01	/* Clock failure */
  #define X1205_SR_WEL		0x02	/* Write Enable Latch */
  #define X1205_SR_RWEL		0x04	/* Register Write Enable */
471d47e32   Michael Hamel   rtc-x1205: Fix al...
75
  #define X1205_SR_AL0		0x20	/* Alarm 0 match */
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
76
77
78
79
80
81
  
  #define X1205_DTR_DTR0		0x01
  #define X1205_DTR_DTR1		0x02
  #define X1205_DTR_DTR2		0x04
  
  #define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
471d47e32   Michael Hamel   rtc-x1205: Fix al...
82
  #define X1205_INT_AL0E		0x20	/* Alarm 0 enable */
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
83
  static struct i2c_driver x1205_driver;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
84
85
86
87
88
89
90
91
92
93
  
  /*
   * In the routines that deal directly with the x1205 hardware, we use
   * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
   * Epoch is initialized as 2000. Time is set to UTC.
   */
  static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
  				unsigned char reg_base)
  {
  	unsigned char dt_addr[2] = { 0, reg_base };
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
94
  	unsigned char buf[8];
471d47e32   Michael Hamel   rtc-x1205: Fix al...
95
  	int i;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
96
97
98
99
100
101
102
  
  	struct i2c_msg msgs[] = {
  		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
  		{ client->addr, I2C_M_RD, 8, buf },	/* read date */
  	};
  
  	/* read date registers */
471d47e32   Michael Hamel   rtc-x1205: Fix al...
103
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
104
105
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
106
107
108
109
110
111
112
  		return -EIO;
  	}
  
  	dev_dbg(&client->dev,
  		"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
  		"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
113
  		__func__,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
114
115
  		buf[0], buf[1], buf[2], buf[3],
  		buf[4], buf[5], buf[6], buf[7]);
471d47e32   Michael Hamel   rtc-x1205: Fix al...
116
117
118
119
  	/* Mask out the enable bits if these are alarm registers */
  	if (reg_base < X1205_CCR_BASE)
  		for (i = 0; i <= 4; i++)
  			buf[i] &= 0x7F;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
120
121
122
123
124
125
126
  	tm->tm_sec = bcd2bin(buf[CCR_SEC]);
  	tm->tm_min = bcd2bin(buf[CCR_MIN]);
  	tm->tm_hour = bcd2bin(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
  	tm->tm_mday = bcd2bin(buf[CCR_MDAY]);
  	tm->tm_mon = bcd2bin(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
  	tm->tm_year = bcd2bin(buf[CCR_YEAR])
  			+ (bcd2bin(buf[CCR_Y2K]) * 100) - 1900;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
127
128
129
130
131
  	tm->tm_wday = buf[CCR_WDAY];
  
  	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
  		"mday=%d, mon=%d, year=%d, wday=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
132
  		__func__,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  		tm->tm_sec, tm->tm_min, tm->tm_hour,
  		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
  
  	return 0;
  }
  
  static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
  {
  	static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
  
  	struct i2c_msg msgs[] = {
  		{ client->addr, 0, 2, sr_addr },	/* setup read ptr */
  		{ client->addr, I2C_M_RD, 1, sr },	/* read status */
  	};
  
  	/* read status register */
471d47e32   Michael Hamel   rtc-x1205: Fix al...
149
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
150
151
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
152
153
154
155
156
157
158
  		return -EIO;
  	}
  
  	return 0;
  }
  
  static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
d973b632a   Johannes Weiner   rtc-x1205: uncond...
159
  			u8 reg_base, unsigned char alm_enable)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
160
  {
d973b632a   Johannes Weiner   rtc-x1205: uncond...
161
  	int i, xfer;
471d47e32   Michael Hamel   rtc-x1205: Fix al...
162
  	unsigned char rdata[10] = { 0, reg_base };
d973b632a   Johannes Weiner   rtc-x1205: uncond...
163
  	unsigned char *buf = rdata + 2;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
164
165
166
167
168
169
170
171
172
173
  
  	static const unsigned char wel[3] = { 0, X1205_REG_SR,
  						X1205_SR_WEL };
  
  	static const unsigned char rwel[3] = { 0, X1205_REG_SR,
  						X1205_SR_WEL | X1205_SR_RWEL };
  
  	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
  
  	dev_dbg(&client->dev,
d973b632a   Johannes Weiner   rtc-x1205: uncond...
174
175
176
177
  		"%s: sec=%d min=%d hour=%d mday=%d mon=%d year=%d wday=%d
  ",
  		__func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday,
  		tm->tm_mon, tm->tm_year, tm->tm_wday);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
178

fe20ba70a   Adrian Bunk   drivers/rtc/: use...
179
180
  	buf[CCR_SEC] = bin2bcd(tm->tm_sec);
  	buf[CCR_MIN] = bin2bcd(tm->tm_min);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
181
182
  
  	/* set hour and 24hr bit */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
183
  	buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
184

d973b632a   Johannes Weiner   rtc-x1205: uncond...
185
  	buf[CCR_MDAY] = bin2bcd(tm->tm_mday);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
186

d973b632a   Johannes Weiner   rtc-x1205: uncond...
187
188
  	/* month, 1 - 12 */
  	buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
189

d973b632a   Johannes Weiner   rtc-x1205: uncond...
190
191
192
193
  	/* year, since the rtc epoch*/
  	buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100);
  	buf[CCR_WDAY] = tm->tm_wday & 0x07;
  	buf[CCR_Y2K] = bin2bcd((tm->tm_year + 1900) / 100);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
194

471d47e32   Michael Hamel   rtc-x1205: Fix al...
195
196
197
198
  	/* If writing alarm registers, set compare bits on registers 0-4 */
  	if (reg_base < X1205_CCR_BASE)
  		for (i = 0; i <= 4; i++)
  			buf[i] |= 0x80;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
199
200
  	/* this sequence is required to unlock the chip */
  	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
201
202
  		dev_err(&client->dev, "%s: wel - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
203
204
205
206
  		return -EIO;
  	}
  
  	if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
207
208
  		dev_err(&client->dev, "%s: rwel - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
209
210
  		return -EIO;
  	}
d973b632a   Johannes Weiner   rtc-x1205: uncond...
211
212
  	xfer = i2c_master_send(client, rdata, sizeof(rdata));
  	if (xfer != sizeof(rdata)) {
471d47e32   Michael Hamel   rtc-x1205: Fix al...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  		dev_err(&client->dev,
  			"%s: result=%d addr=%02x, data=%02x
  ",
  			__func__,
  			 xfer, rdata[1], rdata[2]);
  		return -EIO;
  	}
  
  	/* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
  	if (reg_base < X1205_CCR_BASE) {
  		unsigned char al0e[3] = { 0, X1205_REG_INT, 0 };
  
  		msleep(10);
  
  		/* ...and set or clear the AL0E bit in the INT register */
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
228

471d47e32   Michael Hamel   rtc-x1205: Fix al...
229
230
  		/* Need to set RWEL again as the write has cleared it */
  		xfer = i2c_master_send(client, rwel, 3);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
231
232
  		if (xfer != 3) {
  			dev_err(&client->dev,
471d47e32   Michael Hamel   rtc-x1205: Fix al...
233
234
  				"%s: aloe rwel - %d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
235
  				__func__,
471d47e32   Michael Hamel   rtc-x1205: Fix al...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  				xfer);
  			return -EIO;
  		}
  
  		if (alm_enable)
  			al0e[2] = X1205_INT_AL0E;
  
  		xfer = i2c_master_send(client, al0e, 3);
  		if (xfer != 3) {
  			dev_err(&client->dev,
  				"%s: al0e - %d
  ",
  				__func__,
  				xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
250
251
  			return -EIO;
  		}
471d47e32   Michael Hamel   rtc-x1205: Fix al...
252
253
254
255
  
  		/* and wait 10msec again for this write to complete */
  		msleep(10);
  	}
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
256
257
258
  
  	/* disable further writes */
  	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
259
260
  		dev_err(&client->dev, "%s: diswe - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
261
262
263
264
265
266
267
268
269
270
  		return -EIO;
  	}
  
  	return 0;
  }
  
  static int x1205_fix_osc(struct i2c_client *client)
  {
  	int err;
  	struct rtc_time tm;
cb8799eed   Johannes Weiner   rtc-x1205: reset ...
271
  	memset(&tm, 0, sizeof(tm));
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
272

d973b632a   Johannes Weiner   rtc-x1205: uncond...
273
  	err = x1205_set_datetime(client, &tm, X1205_CCR_BASE, 0);
471d47e32   Michael Hamel   rtc-x1205: Fix al...
274
275
276
  	if (err < 0)
  		dev_err(&client->dev, "unable to restart the oscillator
  ");
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  
  	return err;
  }
  
  static int x1205_get_dtrim(struct i2c_client *client, int *trim)
  {
  	unsigned char dtr;
  	static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
  
  	struct i2c_msg msgs[] = {
  		{ client->addr, 0, 2, dtr_addr },	/* setup read ptr */
  		{ client->addr, I2C_M_RD, 1, &dtr }, 	/* read dtr */
  	};
  
  	/* read dtr register */
471d47e32   Michael Hamel   rtc-x1205: Fix al...
292
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
293
294
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
295
296
  		return -EIO;
  	}
2a4e2b878   Harvey Harrison   rtc: replace rema...
297
298
  	dev_dbg(&client->dev, "%s: raw dtr=%x
  ", __func__, dtr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  	*trim = 0;
  
  	if (dtr & X1205_DTR_DTR0)
  		*trim += 20;
  
  	if (dtr & X1205_DTR_DTR1)
  		*trim += 10;
  
  	if (dtr & X1205_DTR_DTR2)
  		*trim = -*trim;
  
  	return 0;
  }
  
  static int x1205_get_atrim(struct i2c_client *client, int *trim)
  {
  	s8 atr;
  	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
  
  	struct i2c_msg msgs[] = {
  		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */
  		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */
  	};
  
  	/* read atr register */
471d47e32   Michael Hamel   rtc-x1205: Fix al...
325
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
326
327
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
328
329
  		return -EIO;
  	}
2a4e2b878   Harvey Harrison   rtc: replace rema...
330
331
  	dev_dbg(&client->dev, "%s: raw atr=%x
  ", __func__, atr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
332
333
334
335
336
337
338
  
  	/* atr is a two's complement value on 6 bits,
  	 * perform sign extension. The formula is
  	 * Catr = (atr * 0.25pF) + 11.00pF.
  	 */
  	if (atr & 0x20)
  		atr |= 0xC0;
2a4e2b878   Harvey Harrison   rtc: replace rema...
339
340
  	dev_dbg(&client->dev, "%s: raw atr=%x (%d)
  ", __func__, atr, atr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
341
342
  
  	*trim = (atr * 250) + 11000;
2a4e2b878   Harvey Harrison   rtc: replace rema...
343
344
  	dev_dbg(&client->dev, "%s: real=%d
  ", __func__, *trim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  
  	return 0;
  }
  
  struct x1205_limit
  {
  	unsigned char reg, mask, min, max;
  };
  
  static int x1205_validate_client(struct i2c_client *client)
  {
  	int i, xfer;
  
  	/* Probe array. We will read the register at the specified
  	 * address and check if the given bits are zero.
  	 */
  	static const unsigned char probe_zero_pattern[] = {
  		/* register, mask */
  		X1205_REG_SR,	0x18,
  		X1205_REG_DTR,	0xF8,
  		X1205_REG_ATR,	0xC0,
  		X1205_REG_INT,	0x18,
  		X1205_REG_0,	0xFF,
  	};
  
  	static const struct x1205_limit probe_limits_pattern[] = {
  		/* register, mask, min, max */
  		{ X1205_REG_Y2K,	0xFF,	19,	20	},
  		{ X1205_REG_DW,		0xFF,	0,	6	},
  		{ X1205_REG_YR,		0xFF,	0,	99	},
  		{ X1205_REG_MO,		0xFF,	0,	12	},
  		{ X1205_REG_DT,		0xFF,	0,	31	},
  		{ X1205_REG_HR,		0x7F,	0,	23	},
  		{ X1205_REG_MN,		0xFF,	0,	59	},
  		{ X1205_REG_SC,		0xFF,	0,	59	},
  		{ X1205_REG_Y2K1,	0xFF,	19,	20	},
  		{ X1205_REG_Y2K0,	0xFF,	19,	20	},
  	};
  
  	/* check that registers have bits a 0 where expected */
  	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
  		unsigned char buf;
  
  		unsigned char addr[2] = { 0, probe_zero_pattern[i] };
  
  		struct i2c_msg msgs[2] = {
  			{ client->addr, 0, 2, addr },
  			{ client->addr, I2C_M_RD, 1, &buf },
  		};
  
  		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
a14e18935   David Brownell   [PATCH] RTCs don'...
396
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
397
398
  				"%s: could not read register %x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
399
  				__func__, probe_zero_pattern[i]);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
400
401
402
403
404
  
  			return -EIO;
  		}
  
  		if ((buf & probe_zero_pattern[i+1]) != 0) {
a14e18935   David Brownell   [PATCH] RTCs don'...
405
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
406
407
  				"%s: register=%02x, zero pattern=%d, value=%x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
408
  				__func__, probe_zero_pattern[i], i, buf);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
  
  			return -ENODEV;
  		}
  	}
  
  	/* check limits (only registers with bcd values) */
  	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
  		unsigned char reg, value;
  
  		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
  
  		struct i2c_msg msgs[2] = {
  			{ client->addr, 0, 2, addr },
  			{ client->addr, I2C_M_RD, 1, &reg },
  		};
  
  		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
a14e18935   David Brownell   [PATCH] RTCs don'...
426
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
427
428
  				"%s: could not read register %x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
429
  				__func__, probe_limits_pattern[i].reg);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
430
431
432
  
  			return -EIO;
  		}
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
433
  		value = bcd2bin(reg & probe_limits_pattern[i].mask);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
434
435
436
  
  		if (value > probe_limits_pattern[i].max ||
  			value < probe_limits_pattern[i].min) {
a14e18935   David Brownell   [PATCH] RTCs don'...
437
  			dev_dbg(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
438
439
  				"%s: register=%x, lim pattern=%d, value=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
440
  				__func__, probe_limits_pattern[i].reg,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
441
442
443
444
445
446
447
448
449
450
451
  				i, value);
  
  			return -ENODEV;
  		}
  	}
  
  	return 0;
  }
  
  static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
471d47e32   Michael Hamel   rtc-x1205: Fix al...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  	int err;
  	unsigned char intreg, status;
  	static unsigned char int_addr[2] = { 0, X1205_REG_INT };
  	struct i2c_client *client = to_i2c_client(dev);
  	struct i2c_msg msgs[] = {
  		{ client->addr, 0, 2, int_addr },        /* setup read ptr */
  		{ client->addr, I2C_M_RD, 1, &intreg },  /* read INT register */
  	};
  
  	/* read interrupt register and status register */
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
  		dev_err(&client->dev, "%s: read error
  ", __func__);
  		return -EIO;
  	}
  	err = x1205_get_status(client, &status);
  	if (err == 0) {
  		alrm->pending = (status & X1205_SR_AL0) ? 1 : 0;
  		alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0;
  		err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE);
  	}
  	return err;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
474
475
476
477
478
  }
  
  static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	return x1205_set_datetime(to_i2c_client(dev),
d973b632a   Johannes Weiner   rtc-x1205: uncond...
479
  		&alrm->time, X1205_ALM0_BASE, alrm->enabled);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
480
481
482
483
484
485
486
487
488
489
490
  }
  
  static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	return x1205_get_datetime(to_i2c_client(dev),
  		tm, X1205_CCR_BASE);
  }
  
  static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	return x1205_set_datetime(to_i2c_client(dev),
d973b632a   Johannes Weiner   rtc-x1205: uncond...
491
  		tm, X1205_CCR_BASE, 0);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
492
493
494
495
496
  }
  
  static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	int err, dtrim, atrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
497
498
499
500
501
502
503
504
505
506
  	if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
  		seq_printf(seq, "digital_trim\t: %d ppm
  ", dtrim);
  
  	if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0)
  		seq_printf(seq, "analog_trim\t: %d.%02d pF
  ",
  			atrim / 1000, atrim % 1000);
  	return 0;
  }
ff8371ac9   David Brownell   [PATCH] constify ...
507
  static const struct rtc_class_ops x1205_rtc_ops = {
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
508
509
510
511
512
513
514
515
516
517
  	.proc		= x1205_rtc_proc,
  	.read_time	= x1205_rtc_read_time,
  	.set_time	= x1205_rtc_set_time,
  	.read_alarm	= x1205_rtc_read_alarm,
  	.set_alarm	= x1205_rtc_set_alarm,
  };
  
  static ssize_t x1205_sysfs_show_atrim(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
518
  	int err, atrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
519

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
520
521
522
523
524
525
  	err = x1205_get_atrim(to_i2c_client(dev), &atrim);
  	if (err)
  		return err;
  
  	return sprintf(buf, "%d.%02d pF
  ", atrim / 1000, atrim % 1000);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
526
527
528
529
530
531
  }
  static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
  
  static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
532
  	int err, dtrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
533

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
534
535
536
  	err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
  	if (err)
  		return err;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
537

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
538
539
  	return sprintf(buf, "%d ppm
  ", dtrim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
540
541
  }
  static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  static int x1205_sysfs_register(struct device *dev)
  {
  	int err;
  
  	err = device_create_file(dev, &dev_attr_atrim);
  	if (err)
  		return err;
  
  	err = device_create_file(dev, &dev_attr_dtrim);
  	if (err)
  		device_remove_file(dev, &dev_attr_atrim);
  
  	return err;
  }
  
  static void x1205_sysfs_unregister(struct device *dev)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
558
  {
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
559
560
  	device_remove_file(dev, &dev_attr_atrim);
  	device_remove_file(dev, &dev_attr_dtrim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
561
  }
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
562

d2653e927   Jean Delvare   i2c: Add support ...
563
564
  static int x1205_probe(struct i2c_client *client,
  			const struct i2c_device_id *id)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
565
566
567
  {
  	int err = 0;
  	unsigned char sr;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
568
  	struct rtc_device *rtc;
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
569
570
  	dev_dbg(&client->dev, "%s
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
571

4edac2b44   Alessandro Zummo   rtc-x1205: new st...
572
573
  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
  		return -ENODEV;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
574

4edac2b44   Alessandro Zummo   rtc-x1205: new st...
575
576
  	if (x1205_validate_client(client) < 0)
  		return -ENODEV;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
577
578
579
580
581
582
  
  	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "
  ");
  
  	rtc = rtc_device_register(x1205_driver.driver.name, &client->dev,
  				&x1205_rtc_ops, THIS_MODULE);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
583
584
  	if (IS_ERR(rtc))
  		return PTR_ERR(rtc);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
585
586
  
  	i2c_set_clientdata(client, rtc);
25985edce   Lucas De Marchi   Fix common misspe...
587
  	/* Check for power failures and eventually enable the osc */
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
588
589
590
591
592
593
594
595
596
597
598
599
600
  	if ((err = x1205_get_status(client, &sr)) == 0) {
  		if (sr & X1205_SR_RTCF) {
  			dev_err(&client->dev,
  				"power failure detected, "
  				"please set the clock
  ");
  			udelay(50);
  			x1205_fix_osc(client);
  		}
  	}
  	else
  		dev_err(&client->dev, "couldn't read status
  ");
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
601
602
603
  	err = x1205_sysfs_register(&client->dev);
  	if (err)
  		goto exit_devreg;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
604
605
  
  	return 0;
91046a8a6   Jeff Garzik   [PATCH] RTC: hand...
606
607
  exit_devreg:
  	rtc_device_unregister(rtc);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
608
609
  	return err;
  }
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
610
  static int x1205_remove(struct i2c_client *client)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
611
  {
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
612
  	struct rtc_device *rtc = i2c_get_clientdata(client);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
613
614
  	rtc_device_unregister(rtc);
  	x1205_sysfs_unregister(&client->dev);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
615
616
  	return 0;
  }
3760f7367   Jean Delvare   i2c: Convert most...
617
618
619
620
621
  static const struct i2c_device_id x1205_id[] = {
  	{ "x1205", 0 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, x1205_id);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
622
623
624
625
626
627
  static struct i2c_driver x1205_driver = {
  	.driver		= {
  		.name	= "rtc-x1205",
  	},
  	.probe		= x1205_probe,
  	.remove		= x1205_remove,
3760f7367   Jean Delvare   i2c: Convert most...
628
  	.id_table	= x1205_id,
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
629
  };
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  static int __init x1205_init(void)
  {
  	return i2c_add_driver(&x1205_driver);
  }
  
  static void __exit x1205_exit(void)
  {
  	i2c_del_driver(&x1205_driver);
  }
  
  MODULE_AUTHOR(
  	"Karen Spearel <kas111 at gmail dot com>, "
  	"Alessandro Zummo <a.zummo@towertech.it>");
  MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);
  
  module_init(x1205_init);
  module_exit(x1205_exit);