diff options
author | Riku Voipio <riku.voipio@movial.fi> | 2006-12-06 23:39:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:42 -0500 |
commit | c6f24f99cd70a383699bdb34ddd9e6e51c83304c (patch) | |
tree | 75ef9877b86d0b48230f06105679c497df7244f1 /drivers/rtc/rtc-rs5c372.c | |
parent | c55747682e938c57a9a859d3b26f2c4c83cea011 (diff) |
[PATCH] rtc-rs5c372: change register reading method
According to the datasheet rs5c372 supports three different methods for
reading register values. Change from method #1 to method #3, since method #3
is the only one that works on Thecus N2100 board with this RTC.
Signed-off-by: Riku Voipio <riku.voipio@movial.fi>
Cc: Alessandro Zummo <alessandro.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/rtc/rtc-rs5c372.c')
-rw-r--r-- | drivers/rtc/rtc-rs5c372.c | 84 |
1 files changed, 44 insertions, 40 deletions
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 9e1bb3a72f7a..e2c7698fdba3 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/rtc.h> | 13 | #include <linux/rtc.h> |
14 | #include <linux/bcd.h> | 14 | #include <linux/bcd.h> |
15 | 15 | ||
16 | #define DRV_VERSION "0.2" | 16 | #define DRV_VERSION "0.3" |
17 | 17 | ||
18 | /* Addresses to scan */ | 18 | /* Addresses to scan */ |
19 | static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; | 19 | static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; |
@@ -39,6 +39,14 @@ static int rs5c372_attach(struct i2c_adapter *adapter); | |||
39 | static int rs5c372_detach(struct i2c_client *client); | 39 | static int rs5c372_detach(struct i2c_client *client); |
40 | static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind); | 40 | static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind); |
41 | 41 | ||
42 | struct rs5c372 { | ||
43 | u8 reg_addr; | ||
44 | u8 regs[17]; | ||
45 | struct i2c_msg msg[1]; | ||
46 | struct i2c_client client; | ||
47 | struct rtc_device *rtc; | ||
48 | }; | ||
49 | |||
42 | static struct i2c_driver rs5c372_driver = { | 50 | static struct i2c_driver rs5c372_driver = { |
43 | .driver = { | 51 | .driver = { |
44 | .name = "rs5c372", | 52 | .name = "rs5c372", |
@@ -49,18 +57,16 @@ static struct i2c_driver rs5c372_driver = { | |||
49 | 57 | ||
50 | static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) | 58 | static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) |
51 | { | 59 | { |
52 | unsigned char buf[7] = { RS5C372_REG_BASE }; | ||
53 | 60 | ||
54 | /* this implements the 1st reading method, according | 61 | struct rs5c372 *rs5c372 = i2c_get_clientdata(client); |
55 | * to the datasheet. buf[0] is initialized with | 62 | u8 *buf = &(rs5c372->regs[1]); |
56 | * address ptr and transmission format register. | 63 | |
64 | /* this implements the 3rd reading method, according | ||
65 | * to the datasheet. rs5c372 defaults to internal | ||
66 | * address 0xF, so 0x0 is in regs[1] | ||
57 | */ | 67 | */ |
58 | struct i2c_msg msgs[] = { | ||
59 | { client->addr, 0, 1, buf }, | ||
60 | { client->addr, I2C_M_RD, 7, buf }, | ||
61 | }; | ||
62 | 68 | ||
63 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { | 69 | if ((i2c_transfer(client->adapter, rs5c372->msg, 1)) != 1) { |
64 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | 70 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); |
65 | return -EIO; | 71 | return -EIO; |
66 | } | 72 | } |
@@ -114,23 +120,14 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
114 | 120 | ||
115 | static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) | 121 | static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) |
116 | { | 122 | { |
117 | unsigned char buf = RS5C372_REG_TRIM; | 123 | struct rs5c372 *rs5c372 = i2c_get_clientdata(client); |
118 | 124 | u8 tmp = rs5c372->regs[RS5C372_REG_TRIM + 1]; | |
119 | struct i2c_msg msgs[] = { | ||
120 | { client->addr, 0, 1, &buf }, | ||
121 | { client->addr, I2C_M_RD, 1, &buf }, | ||
122 | }; | ||
123 | |||
124 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { | ||
125 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | ||
126 | return -EIO; | ||
127 | } | ||
128 | 125 | ||
129 | if (osc) | 126 | if (osc) |
130 | *osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768; | 127 | *osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768; |
131 | 128 | ||
132 | if (trim) { | 129 | if (trim) { |
133 | *trim = buf & RS5C372_TRIM_MASK; | 130 | *trim = tmp & RS5C372_TRIM_MASK; |
134 | dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim); | 131 | dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim); |
135 | } | 132 | } |
136 | 133 | ||
@@ -201,7 +198,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
201 | { | 198 | { |
202 | int err = 0; | 199 | int err = 0; |
203 | struct i2c_client *client; | 200 | struct i2c_client *client; |
204 | struct rtc_device *rtc; | 201 | struct rs5c372 *rs5c372; |
205 | 202 | ||
206 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | 203 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); |
207 | 204 | ||
@@ -210,10 +207,11 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
210 | goto exit; | 207 | goto exit; |
211 | } | 208 | } |
212 | 209 | ||
213 | if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { | 210 | if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) { |
214 | err = -ENOMEM; | 211 | err = -ENOMEM; |
215 | goto exit; | 212 | goto exit; |
216 | } | 213 | } |
214 | client = &rs5c372->client; | ||
217 | 215 | ||
218 | /* I2C client */ | 216 | /* I2C client */ |
219 | client->addr = address; | 217 | client->addr = address; |
@@ -222,26 +220,33 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
222 | 220 | ||
223 | strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE); | 221 | strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE); |
224 | 222 | ||
223 | i2c_set_clientdata(client, rs5c372); | ||
224 | |||
225 | rs5c372->msg[0].addr = address; | ||
226 | rs5c372->msg[0].flags = I2C_M_RD; | ||
227 | rs5c372->msg[0].len = sizeof(rs5c372->regs); | ||
228 | rs5c372->msg[0].buf = rs5c372->regs; | ||
229 | |||
225 | /* Inform the i2c layer */ | 230 | /* Inform the i2c layer */ |
226 | if ((err = i2c_attach_client(client))) | 231 | if ((err = i2c_attach_client(client))) |
227 | goto exit_kfree; | 232 | goto exit_kfree; |
228 | 233 | ||
229 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | 234 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); |
230 | 235 | ||
231 | rtc = rtc_device_register(rs5c372_driver.driver.name, &client->dev, | 236 | rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name, |
232 | &rs5c372_rtc_ops, THIS_MODULE); | 237 | &client->dev, &rs5c372_rtc_ops, THIS_MODULE); |
233 | 238 | ||
234 | if (IS_ERR(rtc)) { | 239 | if (IS_ERR(rs5c372->rtc)) { |
235 | err = PTR_ERR(rtc); | 240 | err = PTR_ERR(rs5c372->rtc); |
236 | goto exit_detach; | 241 | goto exit_detach; |
237 | } | 242 | } |
238 | 243 | ||
239 | i2c_set_clientdata(client, rtc); | ||
240 | |||
241 | err = device_create_file(&client->dev, &dev_attr_trim); | 244 | err = device_create_file(&client->dev, &dev_attr_trim); |
242 | if (err) goto exit_devreg; | 245 | if (err) |
246 | goto exit_devreg; | ||
243 | err = device_create_file(&client->dev, &dev_attr_osc); | 247 | err = device_create_file(&client->dev, &dev_attr_osc); |
244 | if (err) goto exit_trim; | 248 | if (err) |
249 | goto exit_trim; | ||
245 | 250 | ||
246 | return 0; | 251 | return 0; |
247 | 252 | ||
@@ -249,13 +254,13 @@ exit_trim: | |||
249 | device_remove_file(&client->dev, &dev_attr_trim); | 254 | device_remove_file(&client->dev, &dev_attr_trim); |
250 | 255 | ||
251 | exit_devreg: | 256 | exit_devreg: |
252 | rtc_device_unregister(rtc); | 257 | rtc_device_unregister(rs5c372->rtc); |
253 | 258 | ||
254 | exit_detach: | 259 | exit_detach: |
255 | i2c_detach_client(client); | 260 | i2c_detach_client(client); |
256 | 261 | ||
257 | exit_kfree: | 262 | exit_kfree: |
258 | kfree(client); | 263 | kfree(rs5c372); |
259 | 264 | ||
260 | exit: | 265 | exit: |
261 | return err; | 266 | return err; |
@@ -264,16 +269,15 @@ exit: | |||
264 | static int rs5c372_detach(struct i2c_client *client) | 269 | static int rs5c372_detach(struct i2c_client *client) |
265 | { | 270 | { |
266 | int err; | 271 | int err; |
267 | struct rtc_device *rtc = i2c_get_clientdata(client); | 272 | struct rs5c372 *rs5c372 = i2c_get_clientdata(client); |
268 | 273 | ||
269 | if (rtc) | 274 | if (rs5c372->rtc) |
270 | rtc_device_unregister(rtc); | 275 | rtc_device_unregister(rs5c372->rtc); |
271 | 276 | ||
272 | if ((err = i2c_detach_client(client))) | 277 | if ((err = i2c_detach_client(client))) |
273 | return err; | 278 | return err; |
274 | 279 | ||
275 | kfree(client); | 280 | kfree(rs5c372); |
276 | |||
277 | return 0; | 281 | return 0; |
278 | } | 282 | } |
279 | 283 | ||