aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorRiku Voipio <riku.voipio@movial.fi>2006-12-06 23:39:13 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:42 -0500
commitc6f24f99cd70a383699bdb34ddd9e6e51c83304c (patch)
tree75ef9877b86d0b48230f06105679c497df7244f1 /drivers/rtc
parentc55747682e938c57a9a859d3b26f2c4c83cea011 (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')
-rw-r--r--drivers/rtc/rtc-rs5c372.c84
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 */
19static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; 19static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END };
@@ -39,6 +39,14 @@ static int rs5c372_attach(struct i2c_adapter *adapter);
39static int rs5c372_detach(struct i2c_client *client); 39static int rs5c372_detach(struct i2c_client *client);
40static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind); 40static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind);
41 41
42struct 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
42static struct i2c_driver rs5c372_driver = { 50static 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
50static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) 58static 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
115static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) 121static 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
251exit_devreg: 256exit_devreg:
252 rtc_device_unregister(rtc); 257 rtc_device_unregister(rs5c372->rtc);
253 258
254exit_detach: 259exit_detach:
255 i2c_detach_client(client); 260 i2c_detach_client(client);
256 261
257exit_kfree: 262exit_kfree:
258 kfree(client); 263 kfree(rs5c372);
259 264
260exit: 265exit:
261 return err; 266 return err;
@@ -264,16 +269,15 @@ exit:
264static int rs5c372_detach(struct i2c_client *client) 269static 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