diff options
Diffstat (limited to 'drivers/i2c/chips/ds1337.c')
-rw-r--r-- | drivers/i2c/chips/ds1337.c | 97 |
1 files changed, 40 insertions, 57 deletions
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 07f16c3fb084..74ece8ac1c23 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c | |||
@@ -3,17 +3,16 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2005 James Chapman <jchapman@katalix.com> | 4 | * Copyright (C) 2005 James Chapman <jchapman@katalix.com> |
5 | * | 5 | * |
6 | * based on linux/drivers/acron/char/pcf8583.c | 6 | * based on linux/drivers/acorn/char/pcf8583.c |
7 | * Copyright (C) 2000 Russell King | 7 | * Copyright (C) 2000 Russell King |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * Driver for Dallas Semiconductor DS1337 real time clock chip | 13 | * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/config.h> | ||
17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
19 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
@@ -69,13 +68,11 @@ static struct i2c_driver ds1337_driver = { | |||
69 | struct ds1337_data { | 68 | struct ds1337_data { |
70 | struct i2c_client client; | 69 | struct i2c_client client; |
71 | struct list_head list; | 70 | struct list_head list; |
72 | int id; | ||
73 | }; | 71 | }; |
74 | 72 | ||
75 | /* | 73 | /* |
76 | * Internal variables | 74 | * Internal variables |
77 | */ | 75 | */ |
78 | static int ds1337_id; | ||
79 | static LIST_HEAD(ds1337_clients); | 76 | static LIST_HEAD(ds1337_clients); |
80 | 77 | ||
81 | static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) | 78 | static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) |
@@ -95,7 +92,6 @@ static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) | |||
95 | */ | 92 | */ |
96 | static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) | 93 | static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) |
97 | { | 94 | { |
98 | struct ds1337_data *data = i2c_get_clientdata(client); | ||
99 | int result; | 95 | int result; |
100 | u8 buf[7]; | 96 | u8 buf[7]; |
101 | u8 val; | 97 | u8 val; |
@@ -103,9 +99,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) | |||
103 | u8 offs = 0; | 99 | u8 offs = 0; |
104 | 100 | ||
105 | if (!dt) { | 101 | if (!dt) { |
106 | dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", | 102 | dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); |
107 | __FUNCTION__); | ||
108 | |||
109 | return -EINVAL; | 103 | return -EINVAL; |
110 | } | 104 | } |
111 | 105 | ||
@@ -119,98 +113,86 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) | |||
119 | msg[1].len = sizeof(buf); | 113 | msg[1].len = sizeof(buf); |
120 | msg[1].buf = &buf[0]; | 114 | msg[1].buf = &buf[0]; |
121 | 115 | ||
122 | result = client->adapter->algo->master_xfer(client->adapter, | 116 | result = i2c_transfer(client->adapter, msg, 2); |
123 | &msg[0], 2); | ||
124 | 117 | ||
125 | dev_dbg(&client->adapter->dev, | 118 | dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", |
126 | "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", | ||
127 | __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], | 119 | __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], |
128 | buf[4], buf[5], buf[6]); | 120 | buf[4], buf[5], buf[6]); |
129 | 121 | ||
130 | if (result >= 0) { | 122 | if (result == 2) { |
131 | dt->tm_sec = BCD_TO_BIN(buf[0]); | 123 | dt->tm_sec = BCD2BIN(buf[0]); |
132 | dt->tm_min = BCD_TO_BIN(buf[1]); | 124 | dt->tm_min = BCD2BIN(buf[1]); |
133 | val = buf[2] & 0x3f; | 125 | val = buf[2] & 0x3f; |
134 | dt->tm_hour = BCD_TO_BIN(val); | 126 | dt->tm_hour = BCD2BIN(val); |
135 | dt->tm_wday = BCD_TO_BIN(buf[3]) - 1; | 127 | dt->tm_wday = BCD2BIN(buf[3]) - 1; |
136 | dt->tm_mday = BCD_TO_BIN(buf[4]); | 128 | dt->tm_mday = BCD2BIN(buf[4]); |
137 | val = buf[5] & 0x7f; | 129 | val = buf[5] & 0x7f; |
138 | dt->tm_mon = BCD_TO_BIN(val); | 130 | dt->tm_mon = BCD2BIN(val) - 1; |
139 | dt->tm_year = 1900 + BCD_TO_BIN(buf[6]); | 131 | dt->tm_year = BCD2BIN(buf[6]); |
140 | if (buf[5] & 0x80) | 132 | if (buf[5] & 0x80) |
141 | dt->tm_year += 100; | 133 | dt->tm_year += 100; |
142 | 134 | ||
143 | dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, " | 135 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, " |
144 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | 136 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", |
145 | __FUNCTION__, dt->tm_sec, dt->tm_min, | 137 | __FUNCTION__, dt->tm_sec, dt->tm_min, |
146 | dt->tm_hour, dt->tm_mday, | 138 | dt->tm_hour, dt->tm_mday, |
147 | dt->tm_mon, dt->tm_year, dt->tm_wday); | 139 | dt->tm_mon, dt->tm_year, dt->tm_wday); |
148 | } else { | 140 | |
149 | dev_err(&client->adapter->dev, "ds1337[%d]: error reading " | 141 | return 0; |
150 | "data! %d\n", data->id, result); | ||
151 | result = -EIO; | ||
152 | } | 142 | } |
153 | 143 | ||
154 | return result; | 144 | dev_err(&client->dev, "error reading data! %d\n", result); |
145 | return -EIO; | ||
155 | } | 146 | } |
156 | 147 | ||
157 | static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) | 148 | static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) |
158 | { | 149 | { |
159 | struct ds1337_data *data = i2c_get_clientdata(client); | ||
160 | int result; | 150 | int result; |
161 | u8 buf[8]; | 151 | u8 buf[8]; |
162 | u8 val; | 152 | u8 val; |
163 | struct i2c_msg msg[1]; | 153 | struct i2c_msg msg[1]; |
164 | 154 | ||
165 | if (!dt) { | 155 | if (!dt) { |
166 | dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", | 156 | dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); |
167 | __FUNCTION__); | ||
168 | |||
169 | return -EINVAL; | 157 | return -EINVAL; |
170 | } | 158 | } |
171 | 159 | ||
172 | dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, " | 160 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " |
173 | "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, | 161 | "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, |
174 | dt->tm_sec, dt->tm_min, dt->tm_hour, | 162 | dt->tm_sec, dt->tm_min, dt->tm_hour, |
175 | dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); | 163 | dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); |
176 | 164 | ||
177 | buf[0] = 0; /* reg offset */ | 165 | buf[0] = 0; /* reg offset */ |
178 | buf[1] = BIN_TO_BCD(dt->tm_sec); | 166 | buf[1] = BIN2BCD(dt->tm_sec); |
179 | buf[2] = BIN_TO_BCD(dt->tm_min); | 167 | buf[2] = BIN2BCD(dt->tm_min); |
180 | buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6); | 168 | buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6); |
181 | buf[4] = BIN_TO_BCD(dt->tm_wday) + 1; | 169 | buf[4] = BIN2BCD(dt->tm_wday) + 1; |
182 | buf[5] = BIN_TO_BCD(dt->tm_mday); | 170 | buf[5] = BIN2BCD(dt->tm_mday); |
183 | buf[6] = BIN_TO_BCD(dt->tm_mon); | 171 | buf[6] = BIN2BCD(dt->tm_mon) + 1; |
184 | if (dt->tm_year >= 2000) { | 172 | val = dt->tm_year; |
185 | val = dt->tm_year - 2000; | 173 | if (val >= 100) { |
174 | val -= 100; | ||
186 | buf[6] |= (1 << 7); | 175 | buf[6] |= (1 << 7); |
187 | } else { | ||
188 | val = dt->tm_year - 1900; | ||
189 | } | 176 | } |
190 | buf[7] = BIN_TO_BCD(val); | 177 | buf[7] = BIN2BCD(val); |
191 | 178 | ||
192 | msg[0].addr = client->addr; | 179 | msg[0].addr = client->addr; |
193 | msg[0].flags = 0; | 180 | msg[0].flags = 0; |
194 | msg[0].len = sizeof(buf); | 181 | msg[0].len = sizeof(buf); |
195 | msg[0].buf = &buf[0]; | 182 | msg[0].buf = &buf[0]; |
196 | 183 | ||
197 | result = client->adapter->algo->master_xfer(client->adapter, | 184 | result = i2c_transfer(client->adapter, msg, 1); |
198 | &msg[0], 1); | 185 | if (result == 1) |
199 | if (result < 0) { | 186 | return 0; |
200 | dev_err(&client->adapter->dev, "ds1337[%d]: error " | ||
201 | "writing data! %d\n", data->id, result); | ||
202 | result = -EIO; | ||
203 | } else { | ||
204 | result = 0; | ||
205 | } | ||
206 | 187 | ||
207 | return result; | 188 | dev_err(&client->dev, "error writing data! %d\n", result); |
189 | return -EIO; | ||
208 | } | 190 | } |
209 | 191 | ||
210 | static int ds1337_command(struct i2c_client *client, unsigned int cmd, | 192 | static int ds1337_command(struct i2c_client *client, unsigned int cmd, |
211 | void *arg) | 193 | void *arg) |
212 | { | 194 | { |
213 | dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); | 195 | dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); |
214 | 196 | ||
215 | switch (cmd) { | 197 | switch (cmd) { |
216 | case DS1337_GET_DATE: | 198 | case DS1337_GET_DATE: |
@@ -228,7 +210,7 @@ static int ds1337_command(struct i2c_client *client, unsigned int cmd, | |||
228 | * Public API for access to specific device. Useful for low-level | 210 | * Public API for access to specific device. Useful for low-level |
229 | * RTC access from kernel code. | 211 | * RTC access from kernel code. |
230 | */ | 212 | */ |
231 | int ds1337_do_command(int id, int cmd, void *arg) | 213 | int ds1337_do_command(int bus, int cmd, void *arg) |
232 | { | 214 | { |
233 | struct list_head *walk; | 215 | struct list_head *walk; |
234 | struct list_head *tmp; | 216 | struct list_head *tmp; |
@@ -236,7 +218,7 @@ int ds1337_do_command(int id, int cmd, void *arg) | |||
236 | 218 | ||
237 | list_for_each_safe(walk, tmp, &ds1337_clients) { | 219 | list_for_each_safe(walk, tmp, &ds1337_clients) { |
238 | data = list_entry(walk, struct ds1337_data, list); | 220 | data = list_entry(walk, struct ds1337_data, list); |
239 | if (data->id == id) | 221 | if (data->client.adapter->nr == bus) |
240 | return ds1337_command(&data->client, cmd, arg); | 222 | return ds1337_command(&data->client, cmd, arg); |
241 | } | 223 | } |
242 | 224 | ||
@@ -346,7 +328,6 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind) | |||
346 | ds1337_init_client(new_client); | 328 | ds1337_init_client(new_client); |
347 | 329 | ||
348 | /* Add client to local list */ | 330 | /* Add client to local list */ |
349 | data->id = ds1337_id++; | ||
350 | list_add(&data->list, &ds1337_clients); | 331 | list_add(&data->list, &ds1337_clients); |
351 | 332 | ||
352 | return 0; | 333 | return 0; |
@@ -398,5 +379,7 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); | |||
398 | MODULE_DESCRIPTION("DS1337 RTC driver"); | 379 | MODULE_DESCRIPTION("DS1337 RTC driver"); |
399 | MODULE_LICENSE("GPL"); | 380 | MODULE_LICENSE("GPL"); |
400 | 381 | ||
382 | EXPORT_SYMBOL_GPL(ds1337_do_command); | ||
383 | |||
401 | module_init(ds1337_init); | 384 | module_init(ds1337_init); |
402 | module_exit(ds1337_exit); | 385 | module_exit(ds1337_exit); |