Blame view

drivers/rtc/rtc-x1205.c 15.9 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>
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
24
  #define DRV_VERSION "1.0.8"
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
25
26
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
  
  /* 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...
73
  #define X1205_SR_AL0		0x20	/* Alarm 0 match */
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
74
75
76
77
78
79
  
  #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...
80
  #define X1205_INT_AL0E		0x20	/* Alarm 0 enable */
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
81
  static struct i2c_driver x1205_driver;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
82
83
84
85
86
87
88
89
90
91
  
  /*
   * 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...
92
  	unsigned char buf[8];
471d47e32   Michael Hamel   rtc-x1205: Fix al...
93
  	int i;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
94
95
96
97
98
99
100
  
  	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...
101
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
102
103
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
104
105
106
107
108
109
110
  		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...
111
  		__func__,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
112
113
  		buf[0], buf[1], buf[2], buf[3],
  		buf[4], buf[5], buf[6], buf[7]);
471d47e32   Michael Hamel   rtc-x1205: Fix al...
114
115
116
117
  	/* 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...
118
119
120
121
122
123
124
  	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...
125
126
127
128
129
  	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...
130
  		__func__,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  		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...
147
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
148
149
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
150
151
152
153
154
155
156
  		return -EIO;
  	}
  
  	return 0;
  }
  
  static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
471d47e32   Michael Hamel   rtc-x1205: Fix al...
157
  			int datetoo, u8 reg_base, unsigned char alm_enable)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
158
  {
471d47e32   Michael Hamel   rtc-x1205: Fix al...
159
  	int i, xfer, nbytes;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
160
  	unsigned char buf[8];
471d47e32   Michael Hamel   rtc-x1205: Fix al...
161
  	unsigned char rdata[10] = { 0, reg_base };
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
162
163
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,
  		"%s: secs=%d, mins=%d, hours=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
174
  		__func__,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
175
  		tm->tm_sec, tm->tm_min, tm->tm_hour);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
176
177
  	buf[CCR_SEC] = bin2bcd(tm->tm_sec);
  	buf[CCR_MIN] = bin2bcd(tm->tm_min);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
178
179
  
  	/* set hour and 24hr bit */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
180
  	buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
181
182
183
184
185
186
  
  	/* should we also set the date? */
  	if (datetoo) {
  		dev_dbg(&client->dev,
  			"%s: mday=%d, mon=%d, year=%d, wday=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
187
  			__func__,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
188
  			tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
189
  		buf[CCR_MDAY] = bin2bcd(tm->tm_mday);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
190
191
  
  		/* month, 1 - 12 */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
192
  		buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
193
194
  
  		/* year, since the rtc epoch*/
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
195
  		buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
196
  		buf[CCR_WDAY] = tm->tm_wday & 0x07;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
197
  		buf[CCR_Y2K] = bin2bcd(tm->tm_year / 100);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
198
  	}
471d47e32   Michael Hamel   rtc-x1205: Fix al...
199
200
201
202
  	/* 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...
203
204
  	/* this sequence is required to unlock the chip */
  	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
205
206
  		dev_err(&client->dev, "%s: wel - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
207
208
209
210
  		return -EIO;
  	}
  
  	if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
211
212
  		dev_err(&client->dev, "%s: rwel - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
213
214
  		return -EIO;
  	}
471d47e32   Michael Hamel   rtc-x1205: Fix al...
215

1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
216
  	/* write register's data */
471d47e32   Michael Hamel   rtc-x1205: Fix al...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  	if (datetoo)
  		nbytes = 8;
  	else
  		nbytes = 3;
  	for (i = 0; i < nbytes; i++)
  		rdata[2+i] = buf[i];
  
  	xfer = i2c_master_send(client, rdata, nbytes+2);
  	if (xfer != nbytes+2) {
  		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...
241

471d47e32   Michael Hamel   rtc-x1205: Fix al...
242
243
  		/* Need to set RWEL again as the write has cleared it */
  		xfer = i2c_master_send(client, rwel, 3);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
244
245
  		if (xfer != 3) {
  			dev_err(&client->dev,
471d47e32   Michael Hamel   rtc-x1205: Fix al...
246
247
  				"%s: aloe rwel - %d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
248
  				__func__,
471d47e32   Michael Hamel   rtc-x1205: Fix al...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  				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...
263
264
  			return -EIO;
  		}
471d47e32   Michael Hamel   rtc-x1205: Fix al...
265
266
267
268
  
  		/* and wait 10msec again for this write to complete */
  		msleep(10);
  	}
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
269
270
271
  
  	/* disable further writes */
  	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
272
273
  		dev_err(&client->dev, "%s: diswe - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
274
275
276
277
278
279
280
281
282
283
284
285
  		return -EIO;
  	}
  
  	return 0;
  }
  
  static int x1205_fix_osc(struct i2c_client *client)
  {
  	int err;
  	struct rtc_time tm;
  
  	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
471d47e32   Michael Hamel   rtc-x1205: Fix al...
286
287
288
289
  	err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0);
  	if (err < 0)
  		dev_err(&client->dev, "unable to restart the oscillator
  ");
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  
  	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...
305
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
306
307
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
308
309
  		return -EIO;
  	}
2a4e2b878   Harvey Harrison   rtc: replace rema...
310
311
  	dev_dbg(&client->dev, "%s: raw dtr=%x
  ", __func__, dtr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  
  	*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...
338
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
339
340
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
341
342
  		return -EIO;
  	}
2a4e2b878   Harvey Harrison   rtc: replace rema...
343
344
  	dev_dbg(&client->dev, "%s: raw atr=%x
  ", __func__, atr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
345
346
347
348
349
350
351
  
  	/* 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...
352
353
  	dev_dbg(&client->dev, "%s: raw atr=%x (%d)
  ", __func__, atr, atr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
354
355
  
  	*trim = (atr * 250) + 11000;
2a4e2b878   Harvey Harrison   rtc: replace rema...
356
357
  	dev_dbg(&client->dev, "%s: real=%d
  ", __func__, *trim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
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
396
397
398
399
400
401
402
403
404
405
406
407
408
  
  	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'...
409
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
410
411
  				"%s: could not read register %x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
412
  				__func__, probe_zero_pattern[i]);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
413
414
415
416
417
  
  			return -EIO;
  		}
  
  		if ((buf & probe_zero_pattern[i+1]) != 0) {
a14e18935   David Brownell   [PATCH] RTCs don'...
418
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
419
420
  				"%s: register=%02x, zero pattern=%d, value=%x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
421
  				__func__, probe_zero_pattern[i], i, buf);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  
  			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'...
439
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
440
441
  				"%s: could not read register %x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
442
  				__func__, probe_limits_pattern[i].reg);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
443
444
445
  
  			return -EIO;
  		}
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
446
  		value = bcd2bin(reg & probe_limits_pattern[i].mask);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
447
448
449
  
  		if (value > probe_limits_pattern[i].max ||
  			value < probe_limits_pattern[i].min) {
a14e18935   David Brownell   [PATCH] RTCs don'...
450
  			dev_dbg(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
451
452
  				"%s: register=%x, lim pattern=%d, value=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
453
  				__func__, probe_limits_pattern[i].reg,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
454
455
456
457
458
459
460
461
462
463
464
  				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...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  	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...
487
488
489
490
491
  }
  
  static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	return x1205_set_datetime(to_i2c_client(dev),
471d47e32   Michael Hamel   rtc-x1205: Fix al...
492
  		&alrm->time, 1, X1205_ALM0_BASE, alrm->enabled);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
493
494
495
496
497
498
499
500
501
502
503
  }
  
  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),
471d47e32   Michael Hamel   rtc-x1205: Fix al...
504
  		tm, 1, X1205_CCR_BASE, 0);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
505
506
507
508
509
  }
  
  static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	int err, dtrim, atrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
510
511
512
513
514
515
516
517
518
519
  	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 ...
520
  static const struct rtc_class_ops x1205_rtc_ops = {
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
521
522
523
524
525
526
527
528
529
530
  	.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...
531
  	int err, atrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
532

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
533
534
535
536
537
538
  	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...
539
540
541
542
543
544
  }
  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...
545
  	int err, dtrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
546

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
547
548
549
  	err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
  	if (err)
  		return err;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
550

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
551
552
  	return sprintf(buf, "%d ppm
  ", dtrim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
553
554
  }
  static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
  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...
571
  {
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
572
573
  	device_remove_file(dev, &dev_attr_atrim);
  	device_remove_file(dev, &dev_attr_dtrim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
574
  }
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
575

d2653e927   Jean Delvare   i2c: Add support ...
576
577
  static int x1205_probe(struct i2c_client *client,
  			const struct i2c_device_id *id)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
578
579
580
  {
  	int err = 0;
  	unsigned char sr;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
581
  	struct rtc_device *rtc;
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
582
583
  	dev_dbg(&client->dev, "%s
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
584

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

4edac2b44   Alessandro Zummo   rtc-x1205: new st...
588
589
  	if (x1205_validate_client(client) < 0)
  		return -ENODEV;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
590
591
592
593
594
595
  
  	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...
596
597
  	if (IS_ERR(rtc))
  		return PTR_ERR(rtc);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
  
  	i2c_set_clientdata(client, rtc);
  
  	/* Check for power failures and eventualy enable the osc */
  	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...
615
616
617
  	err = x1205_sysfs_register(&client->dev);
  	if (err)
  		goto exit_devreg;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
618
619
  
  	return 0;
91046a8a6   Jeff Garzik   [PATCH] RTC: hand...
620
621
  exit_devreg:
  	rtc_device_unregister(rtc);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
622
623
  	return err;
  }
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
624
  static int x1205_remove(struct i2c_client *client)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
625
  {
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
626
  	struct rtc_device *rtc = i2c_get_clientdata(client);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
627
628
  	rtc_device_unregister(rtc);
  	x1205_sysfs_unregister(&client->dev);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
629
630
  	return 0;
  }
3760f7367   Jean Delvare   i2c: Convert most...
631
632
633
634
635
  static const struct i2c_device_id x1205_id[] = {
  	{ "x1205", 0 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, x1205_id);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
636
637
638
639
640
641
  static struct i2c_driver x1205_driver = {
  	.driver		= {
  		.name	= "rtc-x1205",
  	},
  	.probe		= x1205_probe,
  	.remove		= x1205_remove,
3760f7367   Jean Delvare   i2c: Convert most...
642
  	.id_table	= x1205_id,
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
643
  };
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  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);