Blame view

drivers/rtc/rtc-rs5c372.c 17.7 KB
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
1
  /*
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
2
   * An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
3
4
5
   *
   * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
   * Copyright (C) 2006 Tower Technologies
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
6
   * Copyright (C) 2008 Paul Mundt
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
7
8
9
10
11
12
13
14
15
   *
   * 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/rtc.h>
  #include <linux/bcd.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
2113852b2   Paul Gortmaker   rtc: Add module.h...
17
  #include <linux/module.h>
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
18

0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
19
  #define DRV_VERSION "0.6"
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
20

cb26b572d   David Brownell   [PATCH] Update th...
21
22
23
24
25
26
27
  
  /*
   * Ricoh has a family of I2C based RTCs, which differ only slightly from
   * each other.  Differences center on pinout (e.g. how many interrupts,
   * output clock, etc) and how the control registers are used.  The '372
   * is significant only because that's the one this driver first supported.
   */
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
28
29
30
31
32
33
34
35
  #define RS5C372_REG_SECS	0
  #define RS5C372_REG_MINS	1
  #define RS5C372_REG_HOURS	2
  #define RS5C372_REG_WDAY	3
  #define RS5C372_REG_DAY		4
  #define RS5C372_REG_MONTH	5
  #define RS5C372_REG_YEAR	6
  #define RS5C372_REG_TRIM	7
cb26b572d   David Brownell   [PATCH] Update th...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  #	define RS5C372_TRIM_XSL		0x80
  #	define RS5C372_TRIM_MASK	0x7F
  
  #define RS5C_REG_ALARM_A_MIN	8			/* or ALARM_W */
  #define RS5C_REG_ALARM_A_HOURS	9
  #define RS5C_REG_ALARM_A_WDAY	10
  
  #define RS5C_REG_ALARM_B_MIN	11			/* or ALARM_D */
  #define RS5C_REG_ALARM_B_HOURS	12
  #define RS5C_REG_ALARM_B_WDAY	13			/* (ALARM_B only) */
  
  #define RS5C_REG_CTRL1		14
  #	define RS5C_CTRL1_AALE		(1 << 7)	/* or WALE */
  #	define RS5C_CTRL1_BALE		(1 << 6)	/* or DALE */
  #	define RV5C387_CTRL1_24		(1 << 5)
  #	define RS5C372A_CTRL1_SL1	(1 << 5)
  #	define RS5C_CTRL1_CT_MASK	(7 << 0)
  #	define RS5C_CTRL1_CT0		(0 << 0)	/* no periodic irq */
  #	define RS5C_CTRL1_CT4		(4 << 0)	/* 1 Hz level irq */
  #define RS5C_REG_CTRL2		15
  #	define RS5C372_CTRL2_24		(1 << 5)
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
57
58
  #	define R2025_CTRL2_XST		(1 << 5)
  #	define RS5C_CTRL2_XSTP		(1 << 4)	/* only if !R2025S/D */
cb26b572d   David Brownell   [PATCH] Update th...
59
60
61
62
63
64
65
66
67
68
69
  #	define RS5C_CTRL2_CTFG		(1 << 2)
  #	define RS5C_CTRL2_AAFG		(1 << 1)	/* or WAFG */
  #	define RS5C_CTRL2_BAFG		(1 << 0)	/* or DAFG */
  
  
  /* to read (style 1) or write registers starting at R */
  #define RS5C_ADDR(R)		(((R) << 4) | 0)
  
  
  enum rtc_type {
  	rtc_undef = 0,
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
70
  	rtc_r2025sd,
cb26b572d   David Brownell   [PATCH] Update th...
71
72
73
74
75
  	rtc_rs5c372a,
  	rtc_rs5c372b,
  	rtc_rv5c386,
  	rtc_rv5c387a,
  };
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
76

3760f7367   Jean Delvare   i2c: Convert most...
77
  static const struct i2c_device_id rs5c372_id[] = {
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
78
  	{ "r2025sd", rtc_r2025sd },
3760f7367   Jean Delvare   i2c: Convert most...
79
80
81
82
83
84
85
  	{ "rs5c372a", rtc_rs5c372a },
  	{ "rs5c372b", rtc_rs5c372b },
  	{ "rv5c386", rtc_rv5c386 },
  	{ "rv5c387a", rtc_rv5c387a },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, rs5c372_id);
cb26b572d   David Brownell   [PATCH] Update th...
86
87
88
89
90
91
92
93
94
95
96
  /* REVISIT:  this assumes that:
   *  - we're in the 21st century, so it's safe to ignore the century
   *    bit for rv5c38[67] (REG_MONTH bit 7);
   *  - we should use ALARM_A not ALARM_B (may be wrong on some boards)
   */
  struct rs5c372 {
  	struct i2c_client	*client;
  	struct rtc_device	*rtc;
  	enum rtc_type		type;
  	unsigned		time24:1;
  	unsigned		has_irq:1;
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
97
  	unsigned		smbus:1;
cb26b572d   David Brownell   [PATCH] Update th...
98
99
  	char			buf[17];
  	char			*regs;
cb26b572d   David Brownell   [PATCH] Update th...
100
  };
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
101

cb26b572d   David Brownell   [PATCH] Update th...
102
103
104
105
106
107
108
109
110
111
112
113
114
  static int rs5c_get_regs(struct rs5c372 *rs5c)
  {
  	struct i2c_client	*client = rs5c->client;
  	struct i2c_msg		msgs[] = {
  		{ client->addr, I2C_M_RD, sizeof rs5c->buf, rs5c->buf },
  	};
  
  	/* This implements the third reading method from the datasheet, using
  	 * an internal address that's reset after each transaction (by STOP)
  	 * to 0x0f ... so we read extra registers, and skip the first one.
  	 *
  	 * The first method doesn't work with the iop3xx adapter driver, on at
  	 * least 80219 chips; this works around that bug.
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
115
116
117
118
  	 *
  	 * The third method on the other hand doesn't work for the SMBus-only
  	 * configurations, so we use the the first method there, stripping off
  	 * the extra register in the process.
cb26b572d   David Brownell   [PATCH] Update th...
119
  	 */
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  	if (rs5c->smbus) {
  		int addr = RS5C_ADDR(RS5C372_REG_SECS);
  		int size = sizeof(rs5c->buf) - 1;
  
  		if (i2c_smbus_read_i2c_block_data(client, addr, size,
  						  rs5c->buf + 1) != size) {
  			dev_warn(&client->dev, "can't read registers
  ");
  			return -EIO;
  		}
  	} else {
  		if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
  			dev_warn(&client->dev, "can't read registers
  ");
  			return -EIO;
  		}
cb26b572d   David Brownell   [PATCH] Update th...
136
  	}
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
137

cb26b572d   David Brownell   [PATCH] Update th...
138
139
140
141
142
143
144
145
  	dev_dbg(&client->dev,
  		"%02x %02x %02x (%02x) %02x %02x %02x (%02x), "
  		"%02x %02x %02x, %02x %02x %02x; %02x %02x
  ",
  		rs5c->regs[0],  rs5c->regs[1],  rs5c->regs[2],  rs5c->regs[3],
  		rs5c->regs[4],  rs5c->regs[5],  rs5c->regs[6],  rs5c->regs[7],
  		rs5c->regs[8],  rs5c->regs[9],  rs5c->regs[10], rs5c->regs[11],
  		rs5c->regs[12], rs5c->regs[13], rs5c->regs[14], rs5c->regs[15]);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
146

cb26b572d   David Brownell   [PATCH] Update th...
147
148
  	return 0;
  }
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
149

cb26b572d   David Brownell   [PATCH] Update th...
150
151
152
  static unsigned rs5c_reg2hr(struct rs5c372 *rs5c, unsigned reg)
  {
  	unsigned	hour;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
153

cb26b572d   David Brownell   [PATCH] Update th...
154
  	if (rs5c->time24)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
155
  		return bcd2bin(reg & 0x3f);
cb26b572d   David Brownell   [PATCH] Update th...
156

fe20ba70a   Adrian Bunk   drivers/rtc/: use...
157
  	hour = bcd2bin(reg & 0x1f);
cb26b572d   David Brownell   [PATCH] Update th...
158
159
160
161
162
163
164
165
  	if (hour == 12)
  		hour = 0;
  	if (reg & 0x20)
  		hour += 12;
  	return hour;
  }
  
  static unsigned rs5c_hr2reg(struct rs5c372 *rs5c, unsigned hour)
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
166
  {
cb26b572d   David Brownell   [PATCH] Update th...
167
  	if (rs5c->time24)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
168
  		return bin2bcd(hour);
cb26b572d   David Brownell   [PATCH] Update th...
169
170
  
  	if (hour > 12)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
171
  		return 0x20 | bin2bcd(hour - 12);
cb26b572d   David Brownell   [PATCH] Update th...
172
  	if (hour == 12)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
173
  		return 0x20 | bin2bcd(12);
cb26b572d   David Brownell   [PATCH] Update th...
174
  	if (hour == 0)
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
175
176
  		return bin2bcd(12);
  	return bin2bcd(hour);
cb26b572d   David Brownell   [PATCH] Update th...
177
  }
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
178

cb26b572d   David Brownell   [PATCH] Update th...
179
180
181
182
  static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
  {
  	struct rs5c372	*rs5c = i2c_get_clientdata(client);
  	int		status = rs5c_get_regs(rs5c);
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
183

cb26b572d   David Brownell   [PATCH] Update th...
184
185
  	if (status < 0)
  		return status;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
186

fe20ba70a   Adrian Bunk   drivers/rtc/: use...
187
188
  	tm->tm_sec = bcd2bin(rs5c->regs[RS5C372_REG_SECS] & 0x7f);
  	tm->tm_min = bcd2bin(rs5c->regs[RS5C372_REG_MINS] & 0x7f);
cb26b572d   David Brownell   [PATCH] Update th...
189
  	tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
190

fe20ba70a   Adrian Bunk   drivers/rtc/: use...
191
192
  	tm->tm_wday = bcd2bin(rs5c->regs[RS5C372_REG_WDAY] & 0x07);
  	tm->tm_mday = bcd2bin(rs5c->regs[RS5C372_REG_DAY] & 0x3f);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
193
194
  
  	/* tm->tm_mon is zero-based */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
195
  	tm->tm_mon = bcd2bin(rs5c->regs[RS5C372_REG_MONTH] & 0x1f) - 1;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
196
197
  
  	/* year is 1900 + tm->tm_year */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
198
  	tm->tm_year = bcd2bin(rs5c->regs[RS5C372_REG_YEAR]) + 100;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
199
200
201
202
  
  	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...
203
  		__func__,
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
204
205
  		tm->tm_sec, tm->tm_min, tm->tm_hour,
  		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
cb26b572d   David Brownell   [PATCH] Update th...
206
207
  	/* rtc might need initialization */
  	return rtc_valid_tm(tm);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
208
209
210
211
  }
  
  static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
  {
cb26b572d   David Brownell   [PATCH] Update th...
212
  	struct rs5c372	*rs5c = i2c_get_clientdata(client);
118364948   Wolfram Sang   rtc: rs5c372: fix...
213
  	unsigned char	buf[7];
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
214
  	int		addr;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
215

cb26b572d   David Brownell   [PATCH] Update th...
216
  	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
217
218
  		"mday=%d, mon=%d, year=%d, wday=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
219
  		__func__,
cb26b572d   David Brownell   [PATCH] Update th...
220
  		tm->tm_sec, tm->tm_min, tm->tm_hour,
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
221
  		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
222
  	addr   = RS5C_ADDR(RS5C372_REG_SECS);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
223
224
  	buf[0] = bin2bcd(tm->tm_sec);
  	buf[1] = bin2bcd(tm->tm_min);
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
225
  	buf[2] = rs5c_hr2reg(rs5c, tm->tm_hour);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
226
227
228
229
  	buf[3] = bin2bcd(tm->tm_wday);
  	buf[4] = bin2bcd(tm->tm_mday);
  	buf[5] = bin2bcd(tm->tm_mon + 1);
  	buf[6] = bin2bcd(tm->tm_year - 100);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
230

0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
231
  	if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
232
233
  		dev_err(&client->dev, "%s: write error
  ", __func__);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
234
235
236
237
238
  		return -EIO;
  	}
  
  	return 0;
  }
cb26b572d   David Brownell   [PATCH] Update th...
239
240
241
242
243
244
245
246
247
  #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
  #define	NEED_TRIM
  #endif
  
  #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
  #define	NEED_TRIM
  #endif
  
  #ifdef	NEED_TRIM
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
248
249
  static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
  {
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
250
  	struct rs5c372 *rs5c372 = i2c_get_clientdata(client);
cb26b572d   David Brownell   [PATCH] Update th...
251
  	u8 tmp = rs5c372->regs[RS5C372_REG_TRIM];
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
252

7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
253
  	if (osc)
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
254
  		*osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
255

17ad78e59   Adrian Bunk   [PATCH] drivers/r...
256
  	if (trim) {
2a4e2b878   Harvey Harrison   rtc: replace rema...
257
258
  		dev_dbg(&client->dev, "%s: raw trim=%x
  ", __func__, tmp);
cb26b572d   David Brownell   [PATCH] Update th...
259
260
261
262
263
264
265
266
267
268
269
270
271
  		tmp &= RS5C372_TRIM_MASK;
  		if (tmp & 0x3e) {
  			int t = tmp & 0x3f;
  
  			if (tmp & 0x40)
  				t = (~t | (s8)0xc0) + 1;
  			else
  				t = t - 1;
  
  			tmp = t * 2;
  		} else
  			tmp = 0;
  		*trim = tmp;
17ad78e59   Adrian Bunk   [PATCH] drivers/r...
272
  	}
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
273
274
275
  
  	return 0;
  }
cb26b572d   David Brownell   [PATCH] Update th...
276
  #endif
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
277
278
279
280
281
282
283
284
285
286
  
  static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	return rs5c372_get_datetime(to_i2c_client(dev), tm);
  }
  
  static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	return rs5c372_set_datetime(to_i2c_client(dev), tm);
  }
cb26b572d   David Brownell   [PATCH] Update th...
287

16380c153   John Stultz   RTC: Convert rtc ...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
  {
  	struct i2c_client	*client = to_i2c_client(dev);
  	struct rs5c372		*rs5c = i2c_get_clientdata(client);
  	unsigned char		buf;
  	int			status, addr;
  
  	buf = rs5c->regs[RS5C_REG_CTRL1];
  
  	if (!rs5c->has_irq)
  		return -EINVAL;
  
  	status = rs5c_get_regs(rs5c);
  	if (status < 0)
  		return status;
  
  	addr = RS5C_ADDR(RS5C_REG_CTRL1);
  	if (enabled)
  		buf |= RS5C_CTRL1_AALE;
  	else
  		buf &= ~RS5C_CTRL1_AALE;
  
  	if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
  		printk(KERN_WARNING "%s: can't update alarm
  ",
  			rs5c->rtc->name);
  		status = -EIO;
  	} else
  		rs5c->regs[RS5C_REG_CTRL1] = buf;
  
  	return status;
  }
cb26b572d   David Brownell   [PATCH] Update th...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  /* NOTE:  Since RTC_WKALM_{RD,SET} were originally defined for EFI,
   * which only exposes a polled programming interface; and since
   * these calls map directly to those EFI requests; we don't demand
   * we have an IRQ for this chip when we go through this API.
   *
   * The older x86_pc derived RTC_ALM_{READ,SET} calls require irqs
   * though, managed through RTC_AIE_{ON,OFF} requests.
   */
  
  static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
  {
  	struct i2c_client	*client = to_i2c_client(dev);
  	struct rs5c372		*rs5c = i2c_get_clientdata(client);
  	int			status;
  
  	status = rs5c_get_regs(rs5c);
  	if (status < 0)
  		return status;
  
  	/* report alarm time */
  	t->time.tm_sec = 0;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
341
  	t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
cb26b572d   David Brownell   [PATCH] Update th...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  	t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
  	t->time.tm_mday = -1;
  	t->time.tm_mon = -1;
  	t->time.tm_year = -1;
  	t->time.tm_wday = -1;
  	t->time.tm_yday = -1;
  	t->time.tm_isdst = -1;
  
  	/* ... and status */
  	t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
  	t->pending = !!(rs5c->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_AAFG);
  
  	return 0;
  }
  
  static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
  {
  	struct i2c_client	*client = to_i2c_client(dev);
  	struct rs5c372		*rs5c = i2c_get_clientdata(client);
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
361
362
  	int			status, addr, i;
  	unsigned char		buf[3];
cb26b572d   David Brownell   [PATCH] Update th...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  
  	/* only handle up to 24 hours in the future, like RTC_ALM_SET */
  	if (t->time.tm_mday != -1
  			|| t->time.tm_mon != -1
  			|| t->time.tm_year != -1)
  		return -EINVAL;
  
  	/* REVISIT: round up tm_sec */
  
  	/* if needed, disable irq (clears pending status) */
  	status = rs5c_get_regs(rs5c);
  	if (status < 0)
  		return status;
  	if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
377
378
379
  		addr = RS5C_ADDR(RS5C_REG_CTRL1);
  		buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
  		if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
cb26b572d   David Brownell   [PATCH] Update th...
380
381
382
383
  			pr_debug("%s: can't disable alarm
  ", rs5c->rtc->name);
  			return -EIO;
  		}
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
384
  		rs5c->regs[RS5C_REG_CTRL1] = buf[0];
cb26b572d   David Brownell   [PATCH] Update th...
385
386
387
  	}
  
  	/* set alarm */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
388
  	buf[0] = bin2bcd(t->time.tm_min);
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
389
390
391
392
393
394
395
396
397
398
  	buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
  	buf[2] = 0x7f;	/* any/all days */
  
  	for (i = 0; i < sizeof(buf); i++) {
  		addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
  		if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
  			pr_debug("%s: can't set alarm time
  ", rs5c->rtc->name);
  			return -EIO;
  		}
cb26b572d   David Brownell   [PATCH] Update th...
399
400
401
402
  	}
  
  	/* ... and maybe enable its irq */
  	if (t->enabled) {
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
403
404
405
  		addr = RS5C_ADDR(RS5C_REG_CTRL1);
  		buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
  		if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
cb26b572d   David Brownell   [PATCH] Update th...
406
407
408
  			printk(KERN_WARNING "%s: can't enable alarm
  ",
  				rs5c->rtc->name);
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
409
  		rs5c->regs[RS5C_REG_CTRL1] = buf[0];
cb26b572d   David Brownell   [PATCH] Update th...
410
411
412
413
414
415
  	}
  
  	return 0;
  }
  
  #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
416
417
418
  static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	int err, osc, trim;
adfb43412   Alessandro Zummo   [PATCH] RTC subsy...
419
420
  	err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim);
  	if (err == 0) {
cb26b572d   David Brownell   [PATCH] Update th...
421
422
423
424
425
  		seq_printf(seq, "crystal\t\t: %d.%03d KHz
  ",
  				osc / 1000, osc % 1000);
  		seq_printf(seq, "trim\t\t: %d
  ", trim);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
426
427
428
429
  	}
  
  	return 0;
  }
cb26b572d   David Brownell   [PATCH] Update th...
430
431
432
  #else
  #define	rs5c372_rtc_proc	NULL
  #endif
ff8371ac9   David Brownell   [PATCH] constify ...
433
  static const struct rtc_class_ops rs5c372_rtc_ops = {
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
434
435
436
  	.proc		= rs5c372_rtc_proc,
  	.read_time	= rs5c372_rtc_read_time,
  	.set_time	= rs5c372_rtc_set_time,
cb26b572d   David Brownell   [PATCH] Update th...
437
438
  	.read_alarm	= rs5c_read_alarm,
  	.set_alarm	= rs5c_set_alarm,
16380c153   John Stultz   RTC: Convert rtc ...
439
  	.alarm_irq_enable = rs5c_rtc_alarm_irq_enable,
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
440
  };
cb26b572d   David Brownell   [PATCH] Update th...
441
  #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
442
443
444
  static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
828960724   Alessandro Zummo   [PATCH] RTC subsy...
445
  	int err, trim;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
446

828960724   Alessandro Zummo   [PATCH] RTC subsy...
447
448
449
  	err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim);
  	if (err)
  		return err;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
450

cb26b572d   David Brownell   [PATCH] Update th...
451
452
  	return sprintf(buf, "%d
  ", trim);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
453
454
455
456
457
458
  }
  static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL);
  
  static ssize_t rs5c372_sysfs_show_osc(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
828960724   Alessandro Zummo   [PATCH] RTC subsy...
459
  	int err, osc;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
460

828960724   Alessandro Zummo   [PATCH] RTC subsy...
461
462
463
  	err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL);
  	if (err)
  		return err;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
464

828960724   Alessandro Zummo   [PATCH] RTC subsy...
465
466
  	return sprintf(buf, "%d.%03d KHz
  ", osc / 1000, osc % 1000);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
467
468
  }
  static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL);
cb26b572d   David Brownell   [PATCH] Update th...
469
  static int rs5c_sysfs_register(struct device *dev)
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
470
  {
cb26b572d   David Brownell   [PATCH] Update th...
471
472
473
474
475
476
477
478
479
480
481
  	int err;
  
  	err = device_create_file(dev, &dev_attr_trim);
  	if (err)
  		return err;
  	err = device_create_file(dev, &dev_attr_osc);
  	if (err)
  		device_remove_file(dev, &dev_attr_trim);
  
  	return err;
  }
d815461c7   David Brownell   rtc-rs5c372 becom...
482
483
484
485
486
  static void rs5c_sysfs_unregister(struct device *dev)
  {
  	device_remove_file(dev, &dev_attr_trim);
  	device_remove_file(dev, &dev_attr_osc);
  }
cb26b572d   David Brownell   [PATCH] Update th...
487
488
489
490
  #else
  static int rs5c_sysfs_register(struct device *dev)
  {
  	return 0;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
491
  }
d815461c7   David Brownell   rtc-rs5c372 becom...
492
493
494
495
496
  
  static void rs5c_sysfs_unregister(struct device *dev)
  {
  	/* nothing */
  }
cb26b572d   David Brownell   [PATCH] Update th...
497
498
499
  #endif	/* SYSFS */
  
  static struct i2c_driver rs5c372_driver;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
500

0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
501
502
503
504
  static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
  {
  	unsigned char buf[2];
  	int addr, i, ret = 0;
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
505
506
507
508
509
510
511
512
513
  	if (rs5c372->type == rtc_r2025sd) {
  		if (!(rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST))
  			return ret;
  		rs5c372->regs[RS5C_REG_CTRL2] &= ~R2025_CTRL2_XST;
  	} else {
  		if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP))
  			return ret;
  		rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
  	}
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
514
515
516
517
518
519
520
521
522
523
524
525
  
  	addr   = RS5C_ADDR(RS5C_REG_CTRL1);
  	buf[0] = rs5c372->regs[RS5C_REG_CTRL1];
  	buf[1] = rs5c372->regs[RS5C_REG_CTRL2];
  
  	/* use 24hr mode */
  	switch (rs5c372->type) {
  	case rtc_rs5c372a:
  	case rtc_rs5c372b:
  		buf[1] |= RS5C372_CTRL2_24;
  		rs5c372->time24 = 1;
  		break;
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
526
  	case rtc_r2025sd:
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  	case rtc_rv5c386:
  	case rtc_rv5c387a:
  		buf[0] |= RV5C387_CTRL1_24;
  		rs5c372->time24 = 1;
  		break;
  	default:
  		/* impossible */
  		break;
  	}
  
  	for (i = 0; i < sizeof(buf); i++) {
  		addr = RS5C_ADDR(RS5C_REG_CTRL1 + i);
  		ret = i2c_smbus_write_byte_data(rs5c372->client, addr, buf[i]);
  		if (unlikely(ret < 0))
  			return ret;
  	}
  
  	rs5c372->regs[RS5C_REG_CTRL1] = buf[0];
  	rs5c372->regs[RS5C_REG_CTRL2] = buf[1];
  
  	return 0;
  }
d2653e927   Jean Delvare   i2c: Add support ...
549
550
  static int rs5c372_probe(struct i2c_client *client,
  			 const struct i2c_device_id *id)
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
551
552
  {
  	int err = 0;
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
553
  	int smbus_mode = 0;
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
554
  	struct rs5c372 *rs5c372;
cb26b572d   David Brownell   [PATCH] Update th...
555
  	struct rtc_time tm;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
556

2a4e2b878   Harvey Harrison   rtc: replace rema...
557
558
  	dev_dbg(&client->dev, "%s
  ", __func__);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
559

0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
  			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) {
  		/*
  		 * If we don't have any master mode adapter, try breaking
  		 * it down in to the barest of capabilities.
  		 */
  		if (i2c_check_functionality(client->adapter,
  				I2C_FUNC_SMBUS_BYTE_DATA |
  				I2C_FUNC_SMBUS_I2C_BLOCK))
  			smbus_mode = 1;
  		else {
  			/* Still no good, give up */
  			err = -ENODEV;
  			goto exit;
  		}
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
575
  	}
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
576
  	if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) {
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
577
578
579
  		err = -ENOMEM;
  		goto exit;
  	}
cb26b572d   David Brownell   [PATCH] Update th...
580

cb26b572d   David Brownell   [PATCH] Update th...
581
  	rs5c372->client = client;
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
582
  	i2c_set_clientdata(client, rs5c372);
3760f7367   Jean Delvare   i2c: Convert most...
583
  	rs5c372->type = id->driver_data;
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
584

e2bfe3424   Paul Mundt   rtc: rtc-rs5c372:...
585
586
  	/* we read registers 0x0f then 0x00-0x0f; skip the first one */
  	rs5c372->regs = &rs5c372->buf[1];
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
587
  	rs5c372->smbus = smbus_mode;
e2bfe3424   Paul Mundt   rtc: rtc-rs5c372:...
588

cb26b572d   David Brownell   [PATCH] Update th...
589
590
  	err = rs5c_get_regs(rs5c372);
  	if (err < 0)
d815461c7   David Brownell   rtc-rs5c372 becom...
591
  		goto exit_kfree;
cb26b572d   David Brownell   [PATCH] Update th...
592

cb26b572d   David Brownell   [PATCH] Update th...
593
594
595
596
597
598
599
600
601
602
  	/* clock may be set for am/pm or 24 hr time */
  	switch (rs5c372->type) {
  	case rtc_rs5c372a:
  	case rtc_rs5c372b:
  		/* alarm uses ALARM_A; and nINTRA on 372a, nINTR on 372b.
  		 * so does periodic irq, except some 327a modes.
  		 */
  		if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24)
  			rs5c372->time24 = 1;
  		break;
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
603
  	case rtc_r2025sd:
cb26b572d   David Brownell   [PATCH] Update th...
604
605
606
607
608
609
610
611
612
613
614
  	case rtc_rv5c386:
  	case rtc_rv5c387a:
  		if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
  			rs5c372->time24 = 1;
  		/* alarm uses ALARM_W; and nINTRB for alarm and periodic
  		 * irq, on both 386 and 387
  		 */
  		break;
  	default:
  		dev_err(&client->dev, "unknown RTC type
  ");
d815461c7   David Brownell   rtc-rs5c372 becom...
615
  		goto exit_kfree;
cb26b572d   David Brownell   [PATCH] Update th...
616
617
618
619
  	}
  
  	/* if the oscillator lost power and no other software (like
  	 * the bootloader) set it up, do it here.
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
620
621
622
  	 *
  	 * The R2025S/D does this a little differently than the other
  	 * parts, so we special case that..
cb26b572d   David Brownell   [PATCH] Update th...
623
  	 */
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
624
625
626
627
628
  	err = rs5c_oscillator_setup(rs5c372);
  	if (unlikely(err < 0)) {
  		dev_err(&client->dev, "setup error
  ");
  		goto exit_kfree;
cb26b572d   David Brownell   [PATCH] Update th...
629
630
631
632
633
634
635
636
637
  	}
  
  	if (rs5c372_get_datetime(client, &tm) < 0)
  		dev_warn(&client->dev, "clock needs to be set
  ");
  
  	dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "
  ",
  			({ char *s; switch (rs5c372->type) {
37fc5e2c4   Paul Mundt   rtc: rtc-rs5c372:...
638
  			case rtc_r2025sd:	s = "r2025sd"; break;
cb26b572d   David Brownell   [PATCH] Update th...
639
640
641
642
643
644
645
646
  			case rtc_rs5c372a:	s = "rs5c372a"; break;
  			case rtc_rs5c372b:	s = "rs5c372b"; break;
  			case rtc_rv5c386:	s = "rv5c386"; break;
  			case rtc_rv5c387a:	s = "rv5c387a"; break;
  			default:		s = "chip"; break;
  			}; s;}),
  			rs5c372->time24 ? "24hr" : "am/pm"
  			);
d815461c7   David Brownell   rtc-rs5c372 becom...
647
  	/* REVISIT use client->irq to register alarm irq ... */
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
648

c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
649
650
  	rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name,
  				&client->dev, &rs5c372_rtc_ops, THIS_MODULE);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
651

c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
652
653
  	if (IS_ERR(rs5c372->rtc)) {
  		err = PTR_ERR(rs5c372->rtc);
d815461c7   David Brownell   rtc-rs5c372 becom...
654
  		goto exit_kfree;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
655
  	}
cb26b572d   David Brownell   [PATCH] Update th...
656
  	err = rs5c_sysfs_register(&client->dev);
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
657
658
  	if (err)
  		goto exit_devreg;
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
659
660
  
  	return 0;
91046a8a6   Jeff Garzik   [PATCH] RTC: hand...
661
  exit_devreg:
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
662
  	rtc_device_unregister(rs5c372->rtc);
91046a8a6   Jeff Garzik   [PATCH] RTC: hand...
663

7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
664
  exit_kfree:
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
665
  	kfree(rs5c372);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
666
667
668
669
  
  exit:
  	return err;
  }
d815461c7   David Brownell   rtc-rs5c372 becom...
670
  static int rs5c372_remove(struct i2c_client *client)
cb26b572d   David Brownell   [PATCH] Update th...
671
  {
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
672
  	struct rs5c372 *rs5c372 = i2c_get_clientdata(client);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
673

d815461c7   David Brownell   rtc-rs5c372 becom...
674
675
  	rtc_device_unregister(rs5c372->rtc);
  	rs5c_sysfs_unregister(&client->dev);
c6f24f99c   Riku Voipio   [PATCH] rtc-rs5c3...
676
  	kfree(rs5c372);
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
677
678
  	return 0;
  }
cb26b572d   David Brownell   [PATCH] Update th...
679
680
681
682
  static struct i2c_driver rs5c372_driver = {
  	.driver		= {
  		.name	= "rtc-rs5c372",
  	},
d815461c7   David Brownell   rtc-rs5c372 becom...
683
684
  	.probe		= rs5c372_probe,
  	.remove		= rs5c372_remove,
3760f7367   Jean Delvare   i2c: Convert most...
685
  	.id_table	= rs5c372_id,
cb26b572d   David Brownell   [PATCH] Update th...
686
  };
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  static __init int rs5c372_init(void)
  {
  	return i2c_add_driver(&rs5c372_driver);
  }
  
  static __exit void rs5c372_exit(void)
  {
  	i2c_del_driver(&rs5c372_driver);
  }
  
  module_init(rs5c372_init);
  module_exit(rs5c372_exit);
  
  MODULE_AUTHOR(
  		"Pavel Mironchik <pmironchik@optifacio.net>, "
0053dc0d1   Paul Mundt   rtc: rtc-rs5c372:...
702
703
  		"Alessandro Zummo <a.zummo@towertech.it>, "
  		"Paul Mundt <lethal@linux-sh.org>");
7520b94de   Alessandro Zummo   [PATCH] RTC subsy...
704
705
706
  MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);