Blame view

drivers/rtc/rtc-max6900.c 6.92 KB
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * rtc class driver for the Maxim MAX6900 chip
   *
   * Author: Dale Farnsworth <dale@farnsworth.org>
   *
   * based on previously existing rtc class drivers
   *
   * 2007 (c) MontaVista, Software, Inc.  This file is licensed under
   * the terms of the GNU General Public License version 2.  This program
   * is licensed "as is" without any warranty of any kind, whether express
   * or implied.
   */
  
  #include <linux/module.h>
  #include <linux/i2c.h>
  #include <linux/bcd.h>
  #include <linux/rtc.h>
  #include <linux/delay.h>
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
19
  #define DRV_VERSION "0.2"
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
20
21
22
23
  
  /*
   * register indices
   */
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
24
25
26
27
28
29
30
  #define MAX6900_REG_SC			0	/* seconds      00-59 */
  #define MAX6900_REG_MN			1	/* minutes      00-59 */
  #define MAX6900_REG_HR			2	/* hours        00-23 */
  #define MAX6900_REG_DT			3	/* day of month 00-31 */
  #define MAX6900_REG_MO			4	/* month        01-12 */
  #define MAX6900_REG_DW			5	/* day of week   1-7  */
  #define MAX6900_REG_YR			6	/* year         00-99 */
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
31
  #define MAX6900_REG_CT			7	/* control */
8a2601f6a   Dale Farnsworth   rtc: update and u...
32
33
34
35
36
  						/* register 8 is undocumented */
  #define MAX6900_REG_CENTURY		9	/* century */
  #define MAX6900_REG_LEN			10
  
  #define MAX6900_BURST_LEN		8	/* can burst r/w first 8 regs */
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
37
38
39
40
41
42
43
  
  #define MAX6900_REG_CT_WP		(1 << 7)	/* Write Protect */
  
  /*
   * register read/write commands
   */
  #define MAX6900_REG_CONTROL_WRITE	0x8e
8a2601f6a   Dale Farnsworth   rtc: update and u...
44
45
  #define MAX6900_REG_CENTURY_WRITE	0x92
  #define MAX6900_REG_CENTURY_READ	0x93
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
46
  #define MAX6900_REG_RESERVED_READ	0x96
8a2601f6a   Dale Farnsworth   rtc: update and u...
47
48
  #define MAX6900_REG_BURST_WRITE		0xbe
  #define MAX6900_REG_BURST_READ		0xbf
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
49
50
  
  #define MAX6900_IDLE_TIME_AFTER_WRITE	3	/* specification says 2.5 mS */
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
51
  static struct i2c_driver max6900_driver;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
52
53
54
  
  static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
  {
8a2601f6a   Dale Farnsworth   rtc: update and u...
55
56
57
  	u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ };
  	u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
  	struct i2c_msg msgs[4] = {
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
58
  		{
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
59
60
61
62
63
  		 .addr = client->addr,
  		 .flags = 0,	/* write */
  		 .len = sizeof(reg_burst_read),
  		 .buf = reg_burst_read}
  		,
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
64
  		{
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
65
66
67
68
69
  		 .addr = client->addr,
  		 .flags = I2C_M_RD,
  		 .len = MAX6900_BURST_LEN,
  		 .buf = buf}
  		,
8a2601f6a   Dale Farnsworth   rtc: update and u...
70
  		{
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
71
72
73
74
75
  		 .addr = client->addr,
  		 .flags = 0,	/* write */
  		 .len = sizeof(reg_century_read),
  		 .buf = reg_century_read}
  		,
8a2601f6a   Dale Farnsworth   rtc: update and u...
76
  		{
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
77
78
79
80
81
  		 .addr = client->addr,
  		 .flags = I2C_M_RD,
  		 .len = sizeof(buf[MAX6900_REG_CENTURY]),
  		 .buf = &buf[MAX6900_REG_CENTURY]
  		 }
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
82
83
84
85
86
  	};
  	int rc;
  
  	rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
  	if (rc != ARRAY_SIZE(msgs)) {
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
87
88
  		dev_err(&client->dev, "%s: register read failed
  ", __func__);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
89
90
91
92
93
94
95
  		return -EIO;
  	}
  	return 0;
  }
  
  static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
  {
8a2601f6a   Dale Farnsworth   rtc: update and u...
96
97
  	u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
  	struct i2c_msg century_msgs[1] = {
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
98
  		{
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
99
100
101
102
  		 .addr = client->addr,
  		 .flags = 0,	/* write */
  		 .len = sizeof(i2c_century_buf),
  		 .buf = i2c_century_buf}
8a2601f6a   Dale Farnsworth   rtc: update and u...
103
104
105
106
  	};
  	u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
  	struct i2c_msg burst_msgs[1] = {
  		{
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
107
108
109
110
  		 .addr = client->addr,
  		 .flags = 0,	/* write */
  		 .len = sizeof(i2c_burst_buf),
  		 .buf = i2c_burst_buf}
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
111
112
  	};
  	int rc;
8a2601f6a   Dale Farnsworth   rtc: update and u...
113
114
115
116
117
118
119
  	/*
  	 * We have to make separate calls to i2c_transfer because of
  	 * the need to delay after each write to the chip.  Also,
  	 * we write the century byte first, since we set the write-protect
  	 * bit as part of the burst write.
  	 */
  	i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
120

8a2601f6a   Dale Farnsworth   rtc: update and u...
121
122
123
124
  	rc = i2c_transfer(client->adapter, century_msgs,
  			  ARRAY_SIZE(century_msgs));
  	if (rc != ARRAY_SIZE(century_msgs))
  		goto write_failed;
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
125

8a2601f6a   Dale Farnsworth   rtc: update and u...
126
  	msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
127

8a2601f6a   Dale Farnsworth   rtc: update and u...
128
129
130
131
132
  	memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
  
  	rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs));
  	if (rc != ARRAY_SIZE(burst_msgs))
  		goto write_failed;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
133
  	msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
8a2601f6a   Dale Farnsworth   rtc: update and u...
134

aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
135
  	return 0;
8a2601f6a   Dale Farnsworth   rtc: update and u...
136

6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
137
138
139
   write_failed:
  	dev_err(&client->dev, "%s: register write failed
  ", __func__);
8a2601f6a   Dale Farnsworth   rtc: update and u...
140
  	return -EIO;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
141
  }
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
142
143
144
145
146
147
148
149
  static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
  {
  	int rc;
  	u8 regs[MAX6900_REG_LEN];
  
  	rc = max6900_i2c_read_regs(client, regs);
  	if (rc < 0)
  		return rc;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
150
151
152
153
154
155
156
157
  	tm->tm_sec = bcd2bin(regs[MAX6900_REG_SC]);
  	tm->tm_min = bcd2bin(regs[MAX6900_REG_MN]);
  	tm->tm_hour = bcd2bin(regs[MAX6900_REG_HR] & 0x3f);
  	tm->tm_mday = bcd2bin(regs[MAX6900_REG_DT]);
  	tm->tm_mon = bcd2bin(regs[MAX6900_REG_MO]) - 1;
  	tm->tm_year = bcd2bin(regs[MAX6900_REG_YR]) +
  		      bcd2bin(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
  	tm->tm_wday = bcd2bin(regs[MAX6900_REG_DW]);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
158

c814dc136   Wan ZongShun   rtc/max6900: use ...
159
  	return rtc_valid_tm(tm);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
160
161
162
163
164
  }
  
  static int max6900_i2c_clear_write_protect(struct i2c_client *client)
  {
  	int rc;
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
165
  	rc = i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
166
167
168
  	if (rc < 0) {
  		dev_err(&client->dev, "%s: control register write failed
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
169
  			__func__);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
170
171
172
173
  		return -EIO;
  	}
  	return 0;
  }
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
174
175
  static int
  max6900_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
176
177
178
179
180
181
182
  {
  	u8 regs[MAX6900_REG_LEN];
  	int rc;
  
  	rc = max6900_i2c_clear_write_protect(client);
  	if (rc < 0)
  		return rc;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
183
184
185
186
187
188
189
190
  	regs[MAX6900_REG_SC] = bin2bcd(tm->tm_sec);
  	regs[MAX6900_REG_MN] = bin2bcd(tm->tm_min);
  	regs[MAX6900_REG_HR] = bin2bcd(tm->tm_hour);
  	regs[MAX6900_REG_DT] = bin2bcd(tm->tm_mday);
  	regs[MAX6900_REG_MO] = bin2bcd(tm->tm_mon + 1);
  	regs[MAX6900_REG_DW] = bin2bcd(tm->tm_wday);
  	regs[MAX6900_REG_YR] = bin2bcd(tm->tm_year % 100);
  	regs[MAX6900_REG_CENTURY] = bin2bcd((tm->tm_year + 1900) / 100);
8a2601f6a   Dale Farnsworth   rtc: update and u...
191
192
  	/* set write protect */
  	regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  
  	rc = max6900_i2c_write_regs(client, regs);
  	if (rc < 0)
  		return rc;
  
  	return 0;
  }
  
  static int max6900_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	return max6900_i2c_read_time(to_i2c_client(dev), tm);
  }
  
  static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	return max6900_i2c_set_time(to_i2c_client(dev), tm);
  }
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
210
  static int max6900_remove(struct i2c_client *client)
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
211
  {
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
212
  	struct rtc_device *rtc = i2c_get_clientdata(client);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
213
214
215
  
  	if (rtc)
  		rtc_device_unregister(rtc);
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
216
  	return 0;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
217
  }
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
218
  static const struct rtc_class_ops max6900_rtc_ops = {
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
219
220
  	.read_time = max6900_rtc_read_time,
  	.set_time = max6900_rtc_set_time,
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
221
  };
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
222
223
  static int
  max6900_probe(struct i2c_client *client, const struct i2c_device_id *id)
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
224
  {
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
225
  	struct rtc_device *rtc;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
226

6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
227
228
  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
  		return -ENODEV;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
229

6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
230
231
  	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "
  ");
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
232
233
  
  	rtc = rtc_device_register(max6900_driver.driver.name,
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
234
235
236
  				  &client->dev, &max6900_rtc_ops, THIS_MODULE);
  	if (IS_ERR(rtc))
  		return PTR_ERR(rtc);
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
237
238
239
240
  
  	i2c_set_clientdata(client, rtc);
  
  	return 0;
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
241
  }
fe102c71a   Alessandro Zummo   rtc: fix missing ...
242
243
244
245
  static struct i2c_device_id max6900_id[] = {
  	{ "max6900", 0 },
  	{ }
  };
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
246
247
248
249
250
251
  static struct i2c_driver max6900_driver = {
  	.driver = {
  		   .name = "rtc-max6900",
  		   },
  	.probe = max6900_probe,
  	.remove = max6900_remove,
fe102c71a   Alessandro Zummo   rtc: fix missing ...
252
  	.id_table = max6900_id,
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
253
  };
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
254
255
256
257
258
259
260
261
262
263
264
  static int __init max6900_init(void)
  {
  	return i2c_add_driver(&max6900_driver);
  }
  
  static void __exit max6900_exit(void)
  {
  	i2c_del_driver(&max6900_driver);
  }
  
  MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
6fd5c03f8   Alessandro Zummo   rtc-max6900 new s...
265
  MODULE_AUTHOR("Dale Farnsworth <dale@farnsworth.org>");
aa5bd7e92   Dale Farnsworth   rtc: add RTC clas...
266
267
268
269
270
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);
  
  module_init(max6900_init);
  module_exit(max6900_exit);