diff options
Diffstat (limited to 'drivers/rtc/rtc-ds1307.c')
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 176 |
1 files changed, 124 insertions, 52 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 3f0f7b8fa813..75e30c6a7d5d 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
@@ -24,15 +24,22 @@ | |||
24 | * setting the date and time), Linux can ignore the non-clock features. | 24 | * setting the date and time), Linux can ignore the non-clock features. |
25 | * That's a natural job for a factory or repair bench. | 25 | * That's a natural job for a factory or repair bench. |
26 | * | 26 | * |
27 | * This is currently a simple no-alarms driver. If your board has the | ||
28 | * alarm irq wired up on a ds1337 or ds1339, and you want to use that, | ||
29 | * then look at the rtc-rs5c372 driver for code to steal... | ||
30 | * | ||
27 | * If the I2C "force" mechanism is used, we assume the chip is a ds1337. | 31 | * If the I2C "force" mechanism is used, we assume the chip is a ds1337. |
28 | * (Much better would be board-specific tables of I2C devices, along with | 32 | * (Much better would be board-specific tables of I2C devices, along with |
29 | * the platform_data drivers would use to sort such issues out.) | 33 | * the platform_data drivers would use to sort such issues out.) |
30 | */ | 34 | */ |
31 | enum ds_type { | 35 | enum ds_type { |
32 | unknown = 0, | 36 | unknown = 0, |
33 | ds_1307, /* or ds1338, ... */ | 37 | ds_1307, |
34 | ds_1337, /* or ds1339, ... */ | 38 | ds_1337, |
35 | ds_1340, /* or st m41t00, ... */ | 39 | ds_1338, |
40 | ds_1339, | ||
41 | ds_1340, | ||
42 | m41t00, | ||
36 | // rs5c372 too? different address... | 43 | // rs5c372 too? different address... |
37 | }; | 44 | }; |
38 | 45 | ||
@@ -56,11 +63,12 @@ I2C_CLIENT_INSMOD; | |||
56 | #define DS1307_REG_YEAR 0x06 /* 00-99 */ | 63 | #define DS1307_REG_YEAR 0x06 /* 00-99 */ |
57 | 64 | ||
58 | /* Other registers (control, status, alarms, trickle charge, NVRAM, etc) | 65 | /* Other registers (control, status, alarms, trickle charge, NVRAM, etc) |
59 | * start at 7, and they differ a lot. Only control and status matter for RTC; | 66 | * start at 7, and they differ a LOT. Only control and status matter for |
60 | * be careful using them. | 67 | * basic RTC date and time functionality; be careful using them. |
61 | */ | 68 | */ |
62 | #define DS1307_REG_CONTROL 0x07 | 69 | #define DS1307_REG_CONTROL 0x07 /* or ds1338 */ |
63 | # define DS1307_BIT_OUT 0x80 | 70 | # define DS1307_BIT_OUT 0x80 |
71 | # define DS1338_BIT_STOP 0x20 | ||
64 | # define DS1307_BIT_SQWE 0x10 | 72 | # define DS1307_BIT_SQWE 0x10 |
65 | # define DS1307_BIT_RS1 0x02 | 73 | # define DS1307_BIT_RS1 0x02 |
66 | # define DS1307_BIT_RS0 0x01 | 74 | # define DS1307_BIT_RS0 0x01 |
@@ -71,6 +79,13 @@ I2C_CLIENT_INSMOD; | |||
71 | # define DS1337_BIT_INTCN 0x04 | 79 | # define DS1337_BIT_INTCN 0x04 |
72 | # define DS1337_BIT_A2IE 0x02 | 80 | # define DS1337_BIT_A2IE 0x02 |
73 | # define DS1337_BIT_A1IE 0x01 | 81 | # define DS1337_BIT_A1IE 0x01 |
82 | #define DS1340_REG_CONTROL 0x07 | ||
83 | # define DS1340_BIT_OUT 0x80 | ||
84 | # define DS1340_BIT_FT 0x40 | ||
85 | # define DS1340_BIT_CALIB_SIGN 0x20 | ||
86 | # define DS1340_M_CALIBRATION 0x1f | ||
87 | #define DS1338_REG_FLAG 0x09 | ||
88 | # define DS1338_BIT_OSF 0x80 | ||
74 | #define DS1337_REG_STATUS 0x0f | 89 | #define DS1337_REG_STATUS 0x0f |
75 | # define DS1337_BIT_OSF 0x80 | 90 | # define DS1337_BIT_OSF 0x80 |
76 | # define DS1337_BIT_A2I 0x02 | 91 | # define DS1337_BIT_A2I 0x02 |
@@ -84,21 +99,63 @@ struct ds1307 { | |||
84 | u8 regs[8]; | 99 | u8 regs[8]; |
85 | enum ds_type type; | 100 | enum ds_type type; |
86 | struct i2c_msg msg[2]; | 101 | struct i2c_msg msg[2]; |
87 | struct i2c_client client; | 102 | struct i2c_client *client; |
103 | struct i2c_client dev; | ||
88 | struct rtc_device *rtc; | 104 | struct rtc_device *rtc; |
89 | }; | 105 | }; |
90 | 106 | ||
107 | struct chip_desc { | ||
108 | char name[9]; | ||
109 | unsigned nvram56:1; | ||
110 | unsigned alarm:1; | ||
111 | enum ds_type type; | ||
112 | }; | ||
113 | |||
114 | static const struct chip_desc chips[] = { { | ||
115 | .name = "ds1307", | ||
116 | .type = ds_1307, | ||
117 | .nvram56 = 1, | ||
118 | }, { | ||
119 | .name = "ds1337", | ||
120 | .type = ds_1337, | ||
121 | .alarm = 1, | ||
122 | }, { | ||
123 | .name = "ds1338", | ||
124 | .type = ds_1338, | ||
125 | .nvram56 = 1, | ||
126 | }, { | ||
127 | .name = "ds1339", | ||
128 | .type = ds_1339, | ||
129 | .alarm = 1, | ||
130 | }, { | ||
131 | .name = "ds1340", | ||
132 | .type = ds_1340, | ||
133 | }, { | ||
134 | .name = "m41t00", | ||
135 | .type = m41t00, | ||
136 | }, }; | ||
137 | |||
138 | static inline const struct chip_desc *find_chip(const char *s) | ||
139 | { | ||
140 | unsigned i; | ||
141 | |||
142 | for (i = 0; i < ARRAY_SIZE(chips); i++) | ||
143 | if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0) | ||
144 | return &chips[i]; | ||
145 | return NULL; | ||
146 | } | ||
91 | 147 | ||
92 | static int ds1307_get_time(struct device *dev, struct rtc_time *t) | 148 | static int ds1307_get_time(struct device *dev, struct rtc_time *t) |
93 | { | 149 | { |
94 | struct ds1307 *ds1307 = dev_get_drvdata(dev); | 150 | struct ds1307 *ds1307 = dev_get_drvdata(dev); |
95 | int tmp; | 151 | int tmp; |
96 | 152 | ||
97 | /* read the RTC registers all at once */ | 153 | /* read the RTC date and time registers all at once */ |
98 | ds1307->msg[1].flags = I2C_M_RD; | 154 | ds1307->msg[1].flags = I2C_M_RD; |
99 | ds1307->msg[1].len = 7; | 155 | ds1307->msg[1].len = 7; |
100 | 156 | ||
101 | tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2); | 157 | tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), |
158 | ds1307->msg, 2); | ||
102 | if (tmp != 2) { | 159 | if (tmp != 2) { |
103 | dev_err(dev, "%s error %d\n", "read", tmp); | 160 | dev_err(dev, "%s error %d\n", "read", tmp); |
104 | return -EIO; | 161 | return -EIO; |
@@ -129,7 +186,8 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) | |||
129 | t->tm_hour, t->tm_mday, | 186 | t->tm_hour, t->tm_mday, |
130 | t->tm_mon, t->tm_year, t->tm_wday); | 187 | t->tm_mon, t->tm_year, t->tm_wday); |
131 | 188 | ||
132 | return 0; | 189 | /* initial clock setting can be undefined */ |
190 | return rtc_valid_tm(t); | ||
133 | } | 191 | } |
134 | 192 | ||
135 | static int ds1307_set_time(struct device *dev, struct rtc_time *t) | 193 | static int ds1307_set_time(struct device *dev, struct rtc_time *t) |
@@ -170,7 +228,8 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) | |||
170 | "write", buf[0], buf[1], buf[2], buf[3], | 228 | "write", buf[0], buf[1], buf[2], buf[3], |
171 | buf[4], buf[5], buf[6]); | 229 | buf[4], buf[5], buf[6]); |
172 | 230 | ||
173 | result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1); | 231 | result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), |
232 | &ds1307->msg[1], 1); | ||
174 | if (result != 1) { | 233 | if (result != 1) { |
175 | dev_err(dev, "%s error %d\n", "write", tmp); | 234 | dev_err(dev, "%s error %d\n", "write", tmp); |
176 | return -EIO; | 235 | return -EIO; |
@@ -192,18 +251,34 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) | |||
192 | int err = -ENODEV; | 251 | int err = -ENODEV; |
193 | struct i2c_client *client; | 252 | struct i2c_client *client; |
194 | int tmp; | 253 | int tmp; |
254 | const struct chip_desc *chip; | ||
195 | 255 | ||
196 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) { | 256 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) { |
197 | err = -ENOMEM; | 257 | err = -ENOMEM; |
198 | goto exit; | 258 | goto exit; |
199 | } | 259 | } |
200 | 260 | ||
201 | client = &ds1307->client; | 261 | /* REVISIT: pending driver model conversion, set up "client" |
262 | * ourselves, and use a hack to determine the RTC type (instead | ||
263 | * of reading the client->name we're given) | ||
264 | */ | ||
265 | client = &ds1307->dev; | ||
202 | client->addr = address; | 266 | client->addr = address; |
203 | client->adapter = adapter; | 267 | client->adapter = adapter; |
204 | client->driver = &ds1307_driver; | 268 | client->driver = &ds1307_driver; |
205 | client->flags = 0; | ||
206 | 269 | ||
270 | /* HACK: "force" implies "needs ds1337-style-oscillator setup", and | ||
271 | * that's the only kind of chip setup we'll know about. Until the | ||
272 | * driver model conversion, here's where to add any board-specific | ||
273 | * code to say what kind of chip is present... | ||
274 | */ | ||
275 | if (kind >= 0) | ||
276 | chip = find_chip("ds1337"); | ||
277 | else | ||
278 | chip = find_chip("ds1307"); | ||
279 | strlcpy(client->name, chip->name, I2C_NAME_SIZE); | ||
280 | |||
281 | ds1307->client = client; | ||
207 | i2c_set_clientdata(client, ds1307); | 282 | i2c_set_clientdata(client, ds1307); |
208 | 283 | ||
209 | ds1307->msg[0].addr = client->addr; | 284 | ds1307->msg[0].addr = client->addr; |
@@ -216,14 +291,17 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) | |||
216 | ds1307->msg[1].len = sizeof(ds1307->regs); | 291 | ds1307->msg[1].len = sizeof(ds1307->regs); |
217 | ds1307->msg[1].buf = ds1307->regs; | 292 | ds1307->msg[1].buf = ds1307->regs; |
218 | 293 | ||
219 | /* HACK: "force" implies "needs ds1337-style-oscillator setup" */ | 294 | ds1307->type = chip->type; |
220 | if (kind >= 0) { | 295 | |
296 | switch (ds1307->type) { | ||
297 | case ds_1337: | ||
298 | case ds_1339: | ||
221 | ds1307->type = ds_1337; | 299 | ds1307->type = ds_1337; |
222 | 300 | ||
223 | ds1307->reg_addr = DS1337_REG_CONTROL; | 301 | ds1307->reg_addr = DS1337_REG_CONTROL; |
224 | ds1307->msg[1].len = 2; | 302 | ds1307->msg[1].len = 2; |
225 | 303 | ||
226 | tmp = i2c_transfer(client->adapter, ds1307->msg, 2); | 304 | tmp = i2c_transfer(adapter, ds1307->msg, 2); |
227 | if (tmp != 2) { | 305 | if (tmp != 2) { |
228 | pr_debug("read error %d\n", tmp); | 306 | pr_debug("read error %d\n", tmp); |
229 | err = -EIO; | 307 | err = -EIO; |
@@ -236,16 +314,20 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) | |||
236 | /* oscillator is off; need to turn it on */ | 314 | /* oscillator is off; need to turn it on */ |
237 | if ((ds1307->regs[0] & DS1337_BIT_nEOSC) | 315 | if ((ds1307->regs[0] & DS1337_BIT_nEOSC) |
238 | || (ds1307->regs[1] & DS1337_BIT_OSF)) { | 316 | || (ds1307->regs[1] & DS1337_BIT_OSF)) { |
239 | printk(KERN_ERR "no ds1337 oscillator code\n"); | 317 | no_osc_start: |
318 | printk(KERN_ERR "no %s oscillator code\n", | ||
319 | chip->name); | ||
240 | goto exit_free; | 320 | goto exit_free; |
241 | } | 321 | } |
242 | } else | 322 | break; |
243 | ds1307->type = ds_1307; | 323 | default: |
324 | break; | ||
325 | } | ||
244 | 326 | ||
245 | read_rtc: | 327 | read_rtc: |
246 | /* read RTC registers */ | 328 | /* read RTC registers */ |
247 | 329 | ||
248 | tmp = i2c_transfer(client->adapter, ds1307->msg, 2); | 330 | tmp = i2c_transfer(adapter, ds1307->msg, 2); |
249 | if (tmp != 2) { | 331 | if (tmp != 2) { |
250 | pr_debug("read error %d\n", tmp); | 332 | pr_debug("read error %d\n", tmp); |
251 | err = -EIO; | 333 | err = -EIO; |
@@ -257,20 +339,27 @@ read_rtc: | |||
257 | * still a few values that are clearly out-of-range. | 339 | * still a few values that are clearly out-of-range. |
258 | */ | 340 | */ |
259 | tmp = ds1307->regs[DS1307_REG_SECS]; | 341 | tmp = ds1307->regs[DS1307_REG_SECS]; |
260 | if (tmp & DS1307_BIT_CH) { | 342 | switch (ds1307->type) { |
261 | if (ds1307->type && ds1307->type != ds_1307) { | 343 | case ds_1307: |
262 | pr_debug("not a ds1307?\n"); | 344 | case ds_1338: |
263 | goto exit_free; | 345 | case m41t00: |
346 | if (tmp & DS1307_BIT_CH) { | ||
347 | i2c_smbus_write_byte_data(client, 0, 0); | ||
348 | dev_warn(&client->dev, | ||
349 | "oscillator started; SET TIME!\n"); | ||
350 | goto read_rtc; | ||
264 | } | 351 | } |
265 | ds1307->type = ds_1307; | 352 | break; |
266 | 353 | case ds_1340: | |
267 | /* this partial initialization should work for ds1307, | 354 | /* FIXME write code to start the oscillator */ |
268 | * ds1338, ds1340, st m41t00, and more. | 355 | if (tmp & DS1307_BIT_CH) |
269 | */ | 356 | goto no_osc_start; |
270 | dev_warn(&client->dev, "oscillator started; SET TIME!\n"); | 357 | break; |
271 | i2c_smbus_write_byte_data(client, 0, 0); | 358 | default: |
272 | goto read_rtc; | 359 | break; |
273 | } | 360 | } |
361 | |||
362 | tmp = ds1307->regs[DS1307_REG_SECS]; | ||
274 | tmp = BCD2BIN(tmp & 0x7f); | 363 | tmp = BCD2BIN(tmp & 0x7f); |
275 | if (tmp > 60) | 364 | if (tmp > 60) |
276 | goto exit_free; | 365 | goto exit_free; |
@@ -288,6 +377,9 @@ read_rtc: | |||
288 | 377 | ||
289 | /* force into in 24 hour mode (most chips) or | 378 | /* force into in 24 hour mode (most chips) or |
290 | * disable century bit (ds1340) | 379 | * disable century bit (ds1340) |
380 | * | ||
381 | * REVISIT forcing 24 hour mode can prevent multi-master | ||
382 | * configs from sharing this RTC ... don't do this. | ||
291 | */ | 383 | */ |
292 | tmp = ds1307->regs[DS1307_REG_HOUR]; | 384 | tmp = ds1307->regs[DS1307_REG_HOUR]; |
293 | if (tmp & (1 << 6)) { | 385 | if (tmp & (1 << 6)) { |
@@ -300,26 +392,6 @@ read_rtc: | |||
300 | BIN2BCD(tmp)); | 392 | BIN2BCD(tmp)); |
301 | } | 393 | } |
302 | 394 | ||
303 | /* FIXME chips like 1337 can generate alarm irqs too; those are | ||
304 | * worth exposing through the API (especially when the irq is | ||
305 | * wakeup-capable). | ||
306 | */ | ||
307 | |||
308 | switch (ds1307->type) { | ||
309 | case unknown: | ||
310 | strlcpy(client->name, "unknown", I2C_NAME_SIZE); | ||
311 | break; | ||
312 | case ds_1307: | ||
313 | strlcpy(client->name, "ds1307", I2C_NAME_SIZE); | ||
314 | break; | ||
315 | case ds_1337: | ||
316 | strlcpy(client->name, "ds1337", I2C_NAME_SIZE); | ||
317 | break; | ||
318 | case ds_1340: | ||
319 | strlcpy(client->name, "ds1340", I2C_NAME_SIZE); | ||
320 | break; | ||
321 | } | ||
322 | |||
323 | /* Tell the I2C layer a new client has arrived */ | 395 | /* Tell the I2C layer a new client has arrived */ |
324 | if ((err = i2c_attach_client(client))) | 396 | if ((err = i2c_attach_client(client))) |
325 | goto exit_free; | 397 | goto exit_free; |