diff options
-rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 112 |
1 files changed, 34 insertions, 78 deletions
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index b3317fcc16c3..a1e2f39521f8 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c | |||
@@ -18,17 +18,7 @@ | |||
18 | #include <linux/bcd.h> | 18 | #include <linux/bcd.h> |
19 | #include <linux/rtc.h> | 19 | #include <linux/rtc.h> |
20 | 20 | ||
21 | #define DRV_VERSION "0.4.2" | 21 | #define DRV_VERSION "0.4.3" |
22 | |||
23 | /* Addresses to scan: none | ||
24 | * This chip cannot be reliably autodetected. An empty eeprom | ||
25 | * located at 0x51 will pass the validation routine due to | ||
26 | * the way the registers are implemented. | ||
27 | */ | ||
28 | static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; | ||
29 | |||
30 | /* Module parameters */ | ||
31 | I2C_CLIENT_INSMOD; | ||
32 | 22 | ||
33 | #define PCF8563_REG_ST1 0x00 /* status */ | 23 | #define PCF8563_REG_ST1 0x00 /* status */ |
34 | #define PCF8563_REG_ST2 0x01 | 24 | #define PCF8563_REG_ST2 0x01 |
@@ -53,8 +43,10 @@ I2C_CLIENT_INSMOD; | |||
53 | #define PCF8563_SC_LV 0x80 /* low voltage */ | 43 | #define PCF8563_SC_LV 0x80 /* low voltage */ |
54 | #define PCF8563_MO_C 0x80 /* century */ | 44 | #define PCF8563_MO_C 0x80 /* century */ |
55 | 45 | ||
46 | static struct i2c_driver pcf8563_driver; | ||
47 | |||
56 | struct pcf8563 { | 48 | struct pcf8563 { |
57 | struct i2c_client client; | 49 | struct rtc_device *rtc; |
58 | /* | 50 | /* |
59 | * The meaning of MO_C bit varies by the chip type. | 51 | * The meaning of MO_C bit varies by the chip type. |
60 | * From PCF8563 datasheet: this bit is toggled when the years | 52 | * From PCF8563 datasheet: this bit is toggled when the years |
@@ -72,16 +64,13 @@ struct pcf8563 { | |||
72 | int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ | 64 | int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ |
73 | }; | 65 | }; |
74 | 66 | ||
75 | static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind); | ||
76 | static int pcf8563_detach(struct i2c_client *client); | ||
77 | |||
78 | /* | 67 | /* |
79 | * In the routines that deal directly with the pcf8563 hardware, we use | 68 | * In the routines that deal directly with the pcf8563 hardware, we use |
80 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | 69 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. |
81 | */ | 70 | */ |
82 | static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | 71 | static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) |
83 | { | 72 | { |
84 | struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); | 73 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); |
85 | unsigned char buf[13] = { PCF8563_REG_ST1 }; | 74 | unsigned char buf[13] = { PCF8563_REG_ST1 }; |
86 | 75 | ||
87 | struct i2c_msg msgs[] = { | 76 | struct i2c_msg msgs[] = { |
@@ -138,7 +127,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
138 | 127 | ||
139 | static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) | 128 | static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) |
140 | { | 129 | { |
141 | struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); | 130 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); |
142 | int i, err; | 131 | int i, err; |
143 | unsigned char buf[9]; | 132 | unsigned char buf[9]; |
144 | 133 | ||
@@ -257,100 +246,67 @@ static const struct rtc_class_ops pcf8563_rtc_ops = { | |||
257 | .set_time = pcf8563_rtc_set_time, | 246 | .set_time = pcf8563_rtc_set_time, |
258 | }; | 247 | }; |
259 | 248 | ||
260 | static int pcf8563_attach(struct i2c_adapter *adapter) | 249 | static int pcf8563_probe(struct i2c_client *client) |
261 | { | ||
262 | return i2c_probe(adapter, &addr_data, pcf8563_probe); | ||
263 | } | ||
264 | |||
265 | static struct i2c_driver pcf8563_driver = { | ||
266 | .driver = { | ||
267 | .name = "pcf8563", | ||
268 | }, | ||
269 | .id = I2C_DRIVERID_PCF8563, | ||
270 | .attach_adapter = &pcf8563_attach, | ||
271 | .detach_client = &pcf8563_detach, | ||
272 | }; | ||
273 | |||
274 | static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) | ||
275 | { | 250 | { |
276 | struct pcf8563 *pcf8563; | 251 | struct pcf8563 *pcf8563; |
277 | struct i2c_client *client; | ||
278 | struct rtc_device *rtc; | ||
279 | 252 | ||
280 | int err = 0; | 253 | int err = 0; |
281 | 254 | ||
282 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | 255 | dev_dbg(&client->dev, "%s\n", __func__); |
283 | 256 | ||
284 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { | 257 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) |
285 | err = -ENODEV; | 258 | return -ENODEV; |
286 | goto exit; | ||
287 | } | ||
288 | 259 | ||
289 | if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) { | 260 | pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL); |
290 | err = -ENOMEM; | 261 | if (!pcf8563) |
291 | goto exit; | 262 | return -ENOMEM; |
292 | } | ||
293 | |||
294 | client = &pcf8563->client; | ||
295 | client->addr = address; | ||
296 | client->driver = &pcf8563_driver; | ||
297 | client->adapter = adapter; | ||
298 | |||
299 | strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE); | ||
300 | 263 | ||
301 | /* Verify the chip is really an PCF8563 */ | 264 | /* Verify the chip is really an PCF8563 */ |
302 | if (kind < 0) { | 265 | if (pcf8563_validate_client(client) < 0) { |
303 | if (pcf8563_validate_client(client) < 0) { | 266 | err = -ENODEV; |
304 | err = -ENODEV; | ||
305 | goto exit_kfree; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | /* Inform the i2c layer */ | ||
310 | if ((err = i2c_attach_client(client))) | ||
311 | goto exit_kfree; | 267 | goto exit_kfree; |
268 | } | ||
312 | 269 | ||
313 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | 270 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); |
314 | 271 | ||
315 | rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev, | 272 | pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name, |
316 | &pcf8563_rtc_ops, THIS_MODULE); | 273 | &client->dev, &pcf8563_rtc_ops, THIS_MODULE); |
317 | 274 | ||
318 | if (IS_ERR(rtc)) { | 275 | if (IS_ERR(pcf8563->rtc)) { |
319 | err = PTR_ERR(rtc); | 276 | err = PTR_ERR(pcf8563->rtc); |
320 | goto exit_detach; | 277 | goto exit_kfree; |
321 | } | 278 | } |
322 | 279 | ||
323 | i2c_set_clientdata(client, rtc); | 280 | i2c_set_clientdata(client, pcf8563); |
324 | 281 | ||
325 | return 0; | 282 | return 0; |
326 | 283 | ||
327 | exit_detach: | ||
328 | i2c_detach_client(client); | ||
329 | |||
330 | exit_kfree: | 284 | exit_kfree: |
331 | kfree(pcf8563); | 285 | kfree(pcf8563); |
332 | 286 | ||
333 | exit: | ||
334 | return err; | 287 | return err; |
335 | } | 288 | } |
336 | 289 | ||
337 | static int pcf8563_detach(struct i2c_client *client) | 290 | static int pcf8563_remove(struct i2c_client *client) |
338 | { | 291 | { |
339 | struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); | 292 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); |
340 | int err; | ||
341 | struct rtc_device *rtc = i2c_get_clientdata(client); | ||
342 | 293 | ||
343 | if (rtc) | 294 | if (pcf8563->rtc) |
344 | rtc_device_unregister(rtc); | 295 | rtc_device_unregister(pcf8563->rtc); |
345 | |||
346 | if ((err = i2c_detach_client(client))) | ||
347 | return err; | ||
348 | 296 | ||
349 | kfree(pcf8563); | 297 | kfree(pcf8563); |
350 | 298 | ||
351 | return 0; | 299 | return 0; |
352 | } | 300 | } |
353 | 301 | ||
302 | static struct i2c_driver pcf8563_driver = { | ||
303 | .driver = { | ||
304 | .name = "rtc-pcf8563", | ||
305 | }, | ||
306 | .probe = pcf8563_probe, | ||
307 | .remove = pcf8563_remove, | ||
308 | }; | ||
309 | |||
354 | static int __init pcf8563_init(void) | 310 | static int __init pcf8563_init(void) |
355 | { | 311 | { |
356 | return i2c_add_driver(&pcf8563_driver); | 312 | return i2c_add_driver(&pcf8563_driver); |