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>
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,
d973b632a   Johannes Weiner   rtc-x1205: uncond...
157
  			u8 reg_base, unsigned char alm_enable)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
158
  {
d973b632a   Johannes Weiner   rtc-x1205: uncond...
159
  	int i, xfer;
471d47e32   Michael Hamel   rtc-x1205: Fix al...
160
  	unsigned char rdata[10] = { 0, reg_base };
d973b632a   Johannes Weiner   rtc-x1205: uncond...
161
  	unsigned char *buf = rdata + 2;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
162
163
164
165
166
167
168
169
170
171
  
  	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...
172
173
174
175
  		"%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...
176

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

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

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

d973b632a   Johannes Weiner   rtc-x1205: uncond...
188
189
190
191
  	/* 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...
192

471d47e32   Michael Hamel   rtc-x1205: Fix al...
193
194
195
196
  	/* 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...
197
198
  	/* this sequence is required to unlock the chip */
  	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
199
200
  		dev_err(&client->dev, "%s: wel - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
201
202
203
204
  		return -EIO;
  	}
  
  	if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
205
206
  		dev_err(&client->dev, "%s: rwel - %d
  ", __func__, xfer);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
207
208
  		return -EIO;
  	}
d973b632a   Johannes Weiner   rtc-x1205: uncond...
209
210
  	xfer = i2c_master_send(client, rdata, sizeof(rdata));
  	if (xfer != sizeof(rdata)) {
471d47e32   Michael Hamel   rtc-x1205: Fix al...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  		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...
226

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

d973b632a   Johannes Weiner   rtc-x1205: uncond...
271
  	err = x1205_set_datetime(client, &tm, X1205_CCR_BASE, 0);
471d47e32   Michael Hamel   rtc-x1205: Fix al...
272
273
274
  	if (err < 0)
  		dev_err(&client->dev, "unable to restart the oscillator
  ");
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  
  	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...
290
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
291
292
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
293
294
  		return -EIO;
  	}
2a4e2b878   Harvey Harrison   rtc: replace rema...
295
296
  	dev_dbg(&client->dev, "%s: raw dtr=%x
  ", __func__, dtr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  
  	*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...
323
  	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
324
325
  		dev_err(&client->dev, "%s: read error
  ", __func__);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
326
327
  		return -EIO;
  	}
2a4e2b878   Harvey Harrison   rtc: replace rema...
328
329
  	dev_dbg(&client->dev, "%s: raw atr=%x
  ", __func__, atr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
330
331
332
333
334
335
336
  
  	/* 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...
337
338
  	dev_dbg(&client->dev, "%s: raw atr=%x (%d)
  ", __func__, atr, atr);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
339
340
  
  	*trim = (atr * 250) + 11000;
2a4e2b878   Harvey Harrison   rtc: replace rema...
341
342
  	dev_dbg(&client->dev, "%s: real=%d
  ", __func__, *trim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
343
344
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
  
  	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'...
394
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
395
396
  				"%s: could not read register %x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
397
  				__func__, probe_zero_pattern[i]);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
398
399
400
401
402
  
  			return -EIO;
  		}
  
  		if ((buf & probe_zero_pattern[i+1]) != 0) {
a14e18935   David Brownell   [PATCH] RTCs don'...
403
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
404
405
  				"%s: register=%02x, zero pattern=%d, value=%x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
406
  				__func__, probe_zero_pattern[i], i, buf);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  
  			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'...
424
  			dev_err(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
425
426
  				"%s: could not read register %x
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
427
  				__func__, probe_limits_pattern[i].reg);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
428
429
430
  
  			return -EIO;
  		}
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
431
  		value = bcd2bin(reg & probe_limits_pattern[i].mask);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
432
433
434
  
  		if (value > probe_limits_pattern[i].max ||
  			value < probe_limits_pattern[i].min) {
a14e18935   David Brownell   [PATCH] RTCs don'...
435
  			dev_dbg(&client->dev,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
436
437
  				"%s: register=%x, lim pattern=%d, value=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
438
  				__func__, probe_limits_pattern[i].reg,
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
439
440
441
442
443
444
445
446
447
448
449
  				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...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  	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...
472
473
474
475
476
  }
  
  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...
477
  		&alrm->time, X1205_ALM0_BASE, alrm->enabled);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
478
479
480
481
482
483
484
485
486
487
488
  }
  
  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...
489
  		tm, X1205_CCR_BASE, 0);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
490
491
492
493
494
  }
  
  static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	int err, dtrim, atrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
495
496
497
498
499
500
501
502
503
504
  	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 ...
505
  static const struct rtc_class_ops x1205_rtc_ops = {
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
506
507
508
509
510
511
512
513
514
515
  	.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...
516
  	int err, atrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
517

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
518
519
520
521
522
523
  	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...
524
525
526
527
528
529
  }
  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...
530
  	int err, dtrim;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
531

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

015aefbb8   Alessandro Zummo   [PATCH] RTC subsy...
536
537
  	return sprintf(buf, "%d ppm
  ", dtrim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
538
539
  }
  static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
  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...
556
  {
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
557
558
  	device_remove_file(dev, &dev_attr_atrim);
  	device_remove_file(dev, &dev_attr_dtrim);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
559
  }
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
560

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

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

4edac2b44   Alessandro Zummo   rtc-x1205: new st...
573
574
  	if (x1205_validate_client(client) < 0)
  		return -ENODEV;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
575
576
577
578
579
580
  
  	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...
581
582
  	if (IS_ERR(rtc))
  		return PTR_ERR(rtc);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
583
584
  
  	i2c_set_clientdata(client, rtc);
25985edce   Lucas De Marchi   Fix common misspe...
585
  	/* Check for power failures and eventually enable the osc */
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
586
587
588
589
590
591
592
593
594
595
596
597
598
  	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...
599
600
601
  	err = x1205_sysfs_register(&client->dev);
  	if (err)
  		goto exit_devreg;
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
602
603
  
  	return 0;
91046a8a6   Jeff Garzik   [PATCH] RTC: hand...
604
605
  exit_devreg:
  	rtc_device_unregister(rtc);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
606
607
  	return err;
  }
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
608
  static int x1205_remove(struct i2c_client *client)
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
609
  {
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
610
  	struct rtc_device *rtc = i2c_get_clientdata(client);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
611
612
  	rtc_device_unregister(rtc);
  	x1205_sysfs_unregister(&client->dev);
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
613
614
  	return 0;
  }
3760f7367   Jean Delvare   i2c: Convert most...
615
616
617
618
619
  static const struct i2c_device_id x1205_id[] = {
  	{ "x1205", 0 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, x1205_id);
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
620
621
622
623
624
625
  static struct i2c_driver x1205_driver = {
  	.driver		= {
  		.name	= "rtc-x1205",
  	},
  	.probe		= x1205_probe,
  	.remove		= x1205_remove,
3760f7367   Jean Delvare   i2c: Convert most...
626
  	.id_table	= x1205_id,
4edac2b44   Alessandro Zummo   rtc-x1205: new st...
627
  };
1fec7c66b   Alessandro Zummo   [PATCH] RTC subsy...
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  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);