diff options
author | Alexey Starikovskiy <astarikovskiy@suse.de> | 2007-09-26 11:43:28 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-09-27 15:50:22 -0400 |
commit | 91087dfa51a29b3c190e99339c4c32eb13646c51 (patch) | |
tree | cb508e1786c46d6dbc56292dbdae26a598a3593a | |
parent | 30c08574da0ead1a47797ce028218ce5b2de61c7 (diff) |
ACPI: SBS: Split host controller (ACPI0001) from SBS driver (ACPI0002)
Replace poll-based host controller driver with the notify-based one.
Split it out of sbs.c.
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/sbs.c | 374 | ||||
-rw-r--r-- | drivers/acpi/sbshc.c | 309 | ||||
-rw-r--r-- | drivers/acpi/sbshc.h | 27 |
4 files changed, 412 insertions, 299 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d4336f1730e9..54e3ab0e5fc0 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -60,3 +60,4 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o | |||
60 | obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o | 60 | obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o |
61 | obj-y += cm_sbs.o | 61 | obj-y += cm_sbs.o |
62 | obj-$(CONFIG_ACPI_SBS) += sbs.o | 62 | obj-$(CONFIG_ACPI_SBS) += sbs.o |
63 | obj-$(CONFIG_ACPI_SBS) += sbshc.o | ||
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 33ba4bf551ef..7bb8c62fb92c 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <linux/jiffies.h> | 34 | #include <linux/jiffies.h> |
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | 36 | ||
37 | #include "sbshc.h" | ||
38 | |||
37 | #define ACPI_SBS_COMPONENT 0x00080000 | 39 | #define ACPI_SBS_COMPONENT 0x00080000 |
38 | #define ACPI_SBS_CLASS "sbs" | 40 | #define ACPI_SBS_CLASS "sbs" |
39 | #define ACPI_AC_CLASS "ac_adapter" | 41 | #define ACPI_AC_CLASS "ac_adapter" |
@@ -59,28 +61,6 @@ MODULE_AUTHOR("Rich Townsend"); | |||
59 | MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); | 61 | MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); |
60 | MODULE_LICENSE("GPL"); | 62 | MODULE_LICENSE("GPL"); |
61 | 63 | ||
62 | #define xmsleep(t) msleep(t) | ||
63 | |||
64 | #define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */ | ||
65 | |||
66 | #define ACPI_EC_SMB_STS 0x01 /* status */ | ||
67 | #define ACPI_EC_SMB_ADDR 0x02 /* address */ | ||
68 | #define ACPI_EC_SMB_CMD 0x03 /* command */ | ||
69 | #define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */ | ||
70 | #define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */ | ||
71 | |||
72 | #define ACPI_EC_SMB_STS_DONE 0x80 | ||
73 | #define ACPI_EC_SMB_STS_STATUS 0x1f | ||
74 | |||
75 | #define ACPI_EC_SMB_PRTCL_WRITE 0x00 | ||
76 | #define ACPI_EC_SMB_PRTCL_READ 0x01 | ||
77 | #define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08 | ||
78 | #define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a | ||
79 | |||
80 | #define ACPI_EC_SMB_TRANSACTION_SLEEP 1 | ||
81 | #define ACPI_EC_SMB_ACCESS_SLEEP1 1 | ||
82 | #define ACPI_EC_SMB_ACCESS_SLEEP2 10 | ||
83 | |||
84 | #define DEF_CAPACITY_UNIT 3 | 64 | #define DEF_CAPACITY_UNIT 3 |
85 | #define MAH_CAPACITY_UNIT 1 | 65 | #define MAH_CAPACITY_UNIT 1 |
86 | #define MWH_CAPACITY_UNIT 2 | 66 | #define MWH_CAPACITY_UNIT 2 |
@@ -103,12 +83,6 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | |||
103 | #define MAX_SBS_BAT 4 | 83 | #define MAX_SBS_BAT 4 |
104 | #define ACPI_SBS_BLOCK_MAX 32 | 84 | #define ACPI_SBS_BLOCK_MAX 32 |
105 | 85 | ||
106 | #define ACPI_SBS_SMBUS_READ 1 | ||
107 | #define ACPI_SBS_SMBUS_WRITE 2 | ||
108 | |||
109 | #define ACPI_SBS_WORD_DATA 1 | ||
110 | #define ACPI_SBS_BLOCK_DATA 2 | ||
111 | |||
112 | #define UPDATE_DELAY 10 | 86 | #define UPDATE_DELAY 10 |
113 | 87 | ||
114 | /* 0 - every time, > 0 - by update_time */ | 88 | /* 0 - every time, > 0 - by update_time */ |
@@ -124,8 +98,7 @@ static int acpi_sbs_remove(struct acpi_device *device, int type); | |||
124 | static int acpi_sbs_resume(struct acpi_device *device); | 98 | static int acpi_sbs_resume(struct acpi_device *device); |
125 | 99 | ||
126 | static const struct acpi_device_id sbs_device_ids[] = { | 100 | static const struct acpi_device_id sbs_device_ids[] = { |
127 | {"ACPI0001", 0}, | 101 | {"ACPI0002", 0}, |
128 | {"ACPI0005", 0}, | ||
129 | {"", 0}, | 102 | {"", 0}, |
130 | }; | 103 | }; |
131 | MODULE_DEVICE_TABLE(acpi, sbs_device_ids); | 104 | MODULE_DEVICE_TABLE(acpi, sbs_device_ids); |
@@ -182,8 +155,8 @@ struct acpi_battery { | |||
182 | }; | 155 | }; |
183 | 156 | ||
184 | struct acpi_sbs { | 157 | struct acpi_sbs { |
185 | int base; | ||
186 | struct acpi_device *device; | 158 | struct acpi_device *device; |
159 | struct acpi_smb_hc *hc; | ||
187 | struct mutex mutex; | 160 | struct mutex mutex; |
188 | int sbsm_present; | 161 | int sbsm_present; |
189 | int sbsm_batteries_supported; | 162 | int sbsm_batteries_supported; |
@@ -199,190 +172,6 @@ struct acpi_sbs { | |||
199 | static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type); | 172 | static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type); |
200 | static void acpi_sbs_update_time(void *data); | 173 | static void acpi_sbs_update_time(void *data); |
201 | 174 | ||
202 | union sbs_rw_data { | ||
203 | u16 word; | ||
204 | u8 block[ACPI_SBS_BLOCK_MAX + 2]; | ||
205 | }; | ||
206 | |||
207 | static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, | ||
208 | char read_write, u8 command, int size, | ||
209 | union sbs_rw_data *data); | ||
210 | |||
211 | /* -------------------------------------------------------------------------- | ||
212 | SMBus Communication | ||
213 | -------------------------------------------------------------------------- */ | ||
214 | |||
215 | static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data) | ||
216 | { | ||
217 | u8 val; | ||
218 | int err; | ||
219 | |||
220 | err = ec_read(sbs->base + address, &val); | ||
221 | if (!err) { | ||
222 | *data = val; | ||
223 | } | ||
224 | xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP); | ||
225 | return (err); | ||
226 | } | ||
227 | |||
228 | static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data) | ||
229 | { | ||
230 | int err; | ||
231 | |||
232 | err = ec_write(sbs->base + address, data); | ||
233 | return (err); | ||
234 | } | ||
235 | |||
236 | static int | ||
237 | acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, | ||
238 | char read_write, u8 command, int size, | ||
239 | union sbs_rw_data *data) | ||
240 | { | ||
241 | unsigned char protocol, len = 0, temp[2] = { 0, 0 }; | ||
242 | int i; | ||
243 | |||
244 | if (read_write == ACPI_SBS_SMBUS_READ) { | ||
245 | protocol = ACPI_EC_SMB_PRTCL_READ; | ||
246 | } else { | ||
247 | protocol = ACPI_EC_SMB_PRTCL_WRITE; | ||
248 | } | ||
249 | |||
250 | switch (size) { | ||
251 | |||
252 | case ACPI_SBS_WORD_DATA: | ||
253 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); | ||
254 | if (read_write == ACPI_SBS_SMBUS_WRITE) { | ||
255 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word); | ||
256 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1, | ||
257 | data->word >> 8); | ||
258 | } | ||
259 | protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA; | ||
260 | break; | ||
261 | case ACPI_SBS_BLOCK_DATA: | ||
262 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); | ||
263 | if (read_write == ACPI_SBS_SMBUS_WRITE) { | ||
264 | len = min_t(u8, data->block[0], 32); | ||
265 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len); | ||
266 | for (i = 0; i < len; i++) | ||
267 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i, | ||
268 | data->block[i + 1]); | ||
269 | } | ||
270 | protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA; | ||
271 | break; | ||
272 | default: | ||
273 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
274 | "unsupported transaction %d", size)); | ||
275 | return (-1); | ||
276 | } | ||
277 | |||
278 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1); | ||
279 | acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol); | ||
280 | |||
281 | acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); | ||
282 | |||
283 | if (~temp[0] & ACPI_EC_SMB_STS_DONE) { | ||
284 | xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1); | ||
285 | acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); | ||
286 | } | ||
287 | if (~temp[0] & ACPI_EC_SMB_STS_DONE) { | ||
288 | xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2); | ||
289 | acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); | ||
290 | } | ||
291 | if ((~temp[0] & ACPI_EC_SMB_STS_DONE) | ||
292 | || (temp[0] & ACPI_EC_SMB_STS_STATUS)) { | ||
293 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
294 | "transaction %d error", size)); | ||
295 | return (-1); | ||
296 | } | ||
297 | |||
298 | if (read_write == ACPI_SBS_SMBUS_WRITE) { | ||
299 | return (0); | ||
300 | } | ||
301 | |||
302 | switch (size) { | ||
303 | |||
304 | case ACPI_SBS_WORD_DATA: | ||
305 | acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp); | ||
306 | acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1); | ||
307 | data->word = (temp[1] << 8) | temp[0]; | ||
308 | break; | ||
309 | |||
310 | case ACPI_SBS_BLOCK_DATA: | ||
311 | len = 0; | ||
312 | acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len); | ||
313 | len = min_t(u8, len, 32); | ||
314 | for (i = 0; i < len; i++) | ||
315 | acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i, | ||
316 | data->block + i + 1); | ||
317 | data->block[0] = len; | ||
318 | break; | ||
319 | default: | ||
320 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
321 | "unsupported transaction %d", size)); | ||
322 | return (-1); | ||
323 | } | ||
324 | |||
325 | return (0); | ||
326 | } | ||
327 | |||
328 | static int | ||
329 | acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word) | ||
330 | { | ||
331 | union sbs_rw_data data; | ||
332 | int result = 0; | ||
333 | |||
334 | result = acpi_ec_sbs_access(sbs, addr, | ||
335 | ACPI_SBS_SMBUS_READ, func, | ||
336 | ACPI_SBS_WORD_DATA, &data); | ||
337 | if (result) { | ||
338 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
339 | "acpi_ec_sbs_access() failed")); | ||
340 | } else { | ||
341 | *word = data.word; | ||
342 | } | ||
343 | |||
344 | return result; | ||
345 | } | ||
346 | |||
347 | static int | ||
348 | acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str) | ||
349 | { | ||
350 | union sbs_rw_data data; | ||
351 | int result = 0; | ||
352 | |||
353 | result = acpi_ec_sbs_access(sbs, addr, | ||
354 | ACPI_SBS_SMBUS_READ, func, | ||
355 | ACPI_SBS_BLOCK_DATA, &data); | ||
356 | if (result) { | ||
357 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
358 | "acpi_ec_sbs_access() failed")); | ||
359 | } else { | ||
360 | strncpy(str, (const char *)data.block + 1, data.block[0]); | ||
361 | str[data.block[0]] = 0; | ||
362 | } | ||
363 | |||
364 | return result; | ||
365 | } | ||
366 | |||
367 | static int | ||
368 | acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word) | ||
369 | { | ||
370 | union sbs_rw_data data; | ||
371 | int result = 0; | ||
372 | |||
373 | data.word = word; | ||
374 | |||
375 | result = acpi_ec_sbs_access(sbs, addr, | ||
376 | ACPI_SBS_SMBUS_WRITE, func, | ||
377 | ACPI_SBS_WORD_DATA, &data); | ||
378 | if (result) { | ||
379 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
380 | "acpi_ec_sbs_access() failed")); | ||
381 | } | ||
382 | |||
383 | return result; | ||
384 | } | ||
385 | |||
386 | static int sbs_zombie(struct acpi_sbs *sbs) | 175 | static int sbs_zombie(struct acpi_sbs *sbs) |
387 | { | 176 | { |
388 | return (sbs->zombie); | 177 | return (sbs->zombie); |
@@ -433,11 +222,11 @@ static int acpi_battery_get_present(struct acpi_battery *battery) | |||
433 | int result = 0; | 222 | int result = 0; |
434 | int is_present = 0; | 223 | int is_present = 0; |
435 | 224 | ||
436 | result = acpi_sbs_read_word(battery->sbs, | 225 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, |
437 | ACPI_SBSM_SMBUS_ADDR, 0x01, &state); | 226 | ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); |
438 | if (result) { | 227 | if (result) { |
439 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 228 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
440 | "acpi_sbs_read_word() failed")); | 229 | "acpi_smbus_read() failed")); |
441 | } | 230 | } |
442 | if (!result) { | 231 | if (!result) { |
443 | is_present = (state & 0x000f) & (1 << battery->id); | 232 | is_present = (state & 0x000f) & (1 << battery->id); |
@@ -461,19 +250,19 @@ static int acpi_battery_select(struct acpi_battery *battery) | |||
461 | * it causes charging to halt on SBSELs */ | 250 | * it causes charging to halt on SBSELs */ |
462 | 251 | ||
463 | result = | 252 | result = |
464 | acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state); | 253 | acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&state); |
465 | if (result) { | 254 | if (result) { |
466 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 255 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
467 | "acpi_sbs_read_word() failed")); | 256 | "acpi_smbus_read() failed")); |
468 | goto end; | 257 | goto end; |
469 | } | 258 | } |
470 | 259 | ||
471 | foo = (state & 0x0fff) | (1 << (battery->id + 12)); | 260 | foo = (state & 0x0fff) | (1 << (battery->id + 12)); |
472 | result = | 261 | result = |
473 | acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo); | 262 | acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD, ACPI_SBSM_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); |
474 | if (result) { | 263 | if (result) { |
475 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 264 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
476 | "acpi_sbs_write_word() failed")); | 265 | "acpi_smbus_write() failed")); |
477 | goto end; | 266 | goto end; |
478 | } | 267 | } |
479 | } | 268 | } |
@@ -487,11 +276,11 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) | |||
487 | int result = 0; | 276 | int result = 0; |
488 | s16 battery_system_info; | 277 | s16 battery_system_info; |
489 | 278 | ||
490 | result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04, | 279 | result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBSM_SMBUS_ADDR, 0x04, |
491 | &battery_system_info); | 280 | (u8 *)&battery_system_info); |
492 | if (result) { | 281 | if (result) { |
493 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 282 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
494 | "acpi_sbs_read_word() failed")); | 283 | "acpi_smbus_read() failed")); |
495 | goto end; | 284 | goto end; |
496 | } | 285 | } |
497 | sbs->sbsm_present = 1; | 286 | sbs->sbsm_present = 1; |
@@ -504,50 +293,49 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) | |||
504 | 293 | ||
505 | static int acpi_battery_get_info(struct acpi_battery *battery) | 294 | static int acpi_battery_get_info(struct acpi_battery *battery) |
506 | { | 295 | { |
507 | struct acpi_sbs *sbs = battery->sbs; | ||
508 | int result = 0; | 296 | int result = 0; |
509 | s16 battery_mode; | 297 | s16 battery_mode; |
510 | s16 specification_info; | 298 | s16 specification_info; |
511 | 299 | ||
512 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, | 300 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x03, |
513 | &battery_mode); | 301 | (u8 *)&battery_mode); |
514 | if (result) { | 302 | if (result) { |
515 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 303 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
516 | "acpi_sbs_read_word() failed")); | 304 | "acpi_smbus_read() failed")); |
517 | goto end; | 305 | goto end; |
518 | } | 306 | } |
519 | battery->info.capacity_mode = (battery_mode & 0x8000) >> 15; | 307 | battery->info.capacity_mode = (battery_mode & 0x8000) >> 15; |
520 | 308 | ||
521 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10, | 309 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x10, |
522 | &battery->info.full_charge_capacity); | 310 | (u8 *)&battery->info.full_charge_capacity); |
523 | if (result) { | 311 | if (result) { |
524 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 312 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
525 | "acpi_sbs_read_word() failed")); | 313 | "acpi_smbus_read() failed")); |
526 | goto end; | 314 | goto end; |
527 | } | 315 | } |
528 | 316 | ||
529 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18, | 317 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x18, |
530 | &battery->info.design_capacity); | 318 | (u8 *)&battery->info.design_capacity); |
531 | 319 | ||
532 | if (result) { | 320 | if (result) { |
533 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 321 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
534 | "acpi_sbs_read_word() failed")); | 322 | "acpi_smbus_read() failed")); |
535 | goto end; | 323 | goto end; |
536 | } | 324 | } |
537 | 325 | ||
538 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19, | 326 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x19, |
539 | &battery->info.design_voltage); | 327 | (u8 *)&battery->info.design_voltage); |
540 | if (result) { | 328 | if (result) { |
541 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 329 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
542 | "acpi_sbs_read_word() failed")); | 330 | "acpi_smbus_read() failed")); |
543 | goto end; | 331 | goto end; |
544 | } | 332 | } |
545 | 333 | ||
546 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a, | 334 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x1a, |
547 | &specification_info); | 335 | (u8 *)&specification_info); |
548 | if (result) { | 336 | if (result) { |
549 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 337 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
550 | "acpi_sbs_read_word() failed")); | 338 | "acpi_smbus_read() failed")); |
551 | goto end; | 339 | goto end; |
552 | } | 340 | } |
553 | 341 | ||
@@ -579,32 +367,32 @@ static int acpi_battery_get_info(struct acpi_battery *battery) | |||
579 | battery->info.ipscale = 1; | 367 | battery->info.ipscale = 1; |
580 | } | 368 | } |
581 | 369 | ||
582 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c, | 370 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x1c, |
583 | &battery->info.serial_number); | 371 | (u8 *)&battery->info.serial_number); |
584 | if (result) { | 372 | if (result) { |
585 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 373 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
586 | "acpi_sbs_read_word() failed")); | 374 | "acpi_smbus_read() failed")); |
587 | goto end; | 375 | goto end; |
588 | } | 376 | } |
589 | 377 | ||
590 | result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20, | 378 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x20, |
591 | battery->info.manufacturer_name); | 379 | (u8 *)battery->info.manufacturer_name); |
592 | if (result) { | 380 | if (result) { |
593 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 381 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
594 | "acpi_sbs_read_str() failed")); | 382 | "acpi_sbs_read_str() failed")); |
595 | goto end; | 383 | goto end; |
596 | } | 384 | } |
597 | 385 | ||
598 | result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21, | 386 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x21, |
599 | battery->info.device_name); | 387 | (u8 *)battery->info.device_name); |
600 | if (result) { | 388 | if (result) { |
601 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 389 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
602 | "acpi_sbs_read_str() failed")); | 390 | "acpi_sbs_read_str() failed")); |
603 | goto end; | 391 | goto end; |
604 | } | 392 | } |
605 | 393 | ||
606 | result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22, | 394 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_BLOCK, ACPI_SB_SMBUS_ADDR, 0x22, |
607 | battery->info.device_chemistry); | 395 | (u8 *)battery->info.device_chemistry); |
608 | if (result) { | 396 | if (result) { |
609 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 397 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
610 | "acpi_sbs_read_str() failed")); | 398 | "acpi_sbs_read_str() failed")); |
@@ -617,38 +405,37 @@ static int acpi_battery_get_info(struct acpi_battery *battery) | |||
617 | 405 | ||
618 | static int acpi_battery_get_state(struct acpi_battery *battery) | 406 | static int acpi_battery_get_state(struct acpi_battery *battery) |
619 | { | 407 | { |
620 | struct acpi_sbs *sbs = battery->sbs; | ||
621 | int result = 0; | 408 | int result = 0; |
622 | 409 | ||
623 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09, | 410 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x09, |
624 | &battery->state.voltage); | 411 | (u8 *)&battery->state.voltage); |
625 | if (result) { | 412 | if (result) { |
626 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 413 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
627 | "acpi_sbs_read_word() failed")); | 414 | "acpi_smbus_read() failed")); |
628 | goto end; | 415 | goto end; |
629 | } | 416 | } |
630 | 417 | ||
631 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a, | 418 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0a, |
632 | &battery->state.amperage); | 419 | (u8 *)&battery->state.amperage); |
633 | if (result) { | 420 | if (result) { |
634 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 421 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
635 | "acpi_sbs_read_word() failed")); | 422 | "acpi_smbus_read() failed")); |
636 | goto end; | 423 | goto end; |
637 | } | 424 | } |
638 | 425 | ||
639 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f, | 426 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x0f, |
640 | &battery->state.remaining_capacity); | 427 | (u8 *)&battery->state.remaining_capacity); |
641 | if (result) { | 428 | if (result) { |
642 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 429 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
643 | "acpi_sbs_read_word() failed")); | 430 | "acpi_smbus_read() failed")); |
644 | goto end; | 431 | goto end; |
645 | } | 432 | } |
646 | 433 | ||
647 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16, | 434 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x16, |
648 | &battery->state.battery_state); | 435 | (u8 *)&battery->state.battery_state); |
649 | if (result) { | 436 | if (result) { |
650 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 437 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
651 | "acpi_sbs_read_word() failed")); | 438 | "acpi_smbus_read() failed")); |
652 | goto end; | 439 | goto end; |
653 | } | 440 | } |
654 | 441 | ||
@@ -658,14 +445,13 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
658 | 445 | ||
659 | static int acpi_battery_get_alarm(struct acpi_battery *battery) | 446 | static int acpi_battery_get_alarm(struct acpi_battery *battery) |
660 | { | 447 | { |
661 | struct acpi_sbs *sbs = battery->sbs; | ||
662 | int result = 0; | 448 | int result = 0; |
663 | 449 | ||
664 | result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, | 450 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, |
665 | &battery->alarm.remaining_capacity); | 451 | (u8 *)&battery->alarm.remaining_capacity); |
666 | if (result) { | 452 | if (result) { |
667 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 453 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
668 | "acpi_sbs_read_word() failed")); | 454 | "acpi_smbus_read() failed")); |
669 | goto end; | 455 | goto end; |
670 | } | 456 | } |
671 | 457 | ||
@@ -677,7 +463,6 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery) | |||
677 | static int acpi_battery_set_alarm(struct acpi_battery *battery, | 463 | static int acpi_battery_set_alarm(struct acpi_battery *battery, |
678 | unsigned long alarm) | 464 | unsigned long alarm) |
679 | { | 465 | { |
680 | struct acpi_sbs *sbs = battery->sbs; | ||
681 | int result = 0; | 466 | int result = 0; |
682 | s16 battery_mode; | 467 | s16 battery_mode; |
683 | int foo; | 468 | int foo; |
@@ -693,29 +478,30 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, | |||
693 | 478 | ||
694 | if (alarm > 0) { | 479 | if (alarm > 0) { |
695 | result = | 480 | result = |
696 | acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, | 481 | acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x03, |
697 | &battery_mode); | 482 | (u8 *)&battery_mode); |
698 | if (result) { | 483 | if (result) { |
699 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 484 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
700 | "acpi_sbs_read_word() failed")); | 485 | "acpi_smbus_read() failed")); |
701 | goto end; | 486 | goto end; |
702 | } | 487 | } |
703 | 488 | ||
489 | battery_mode &= 0xbfff; | ||
704 | result = | 490 | result = |
705 | acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, | 491 | acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, |
706 | battery_mode & 0xbfff); | 492 | (u8 *)&battery_mode, 2); |
707 | if (result) { | 493 | if (result) { |
708 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 494 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
709 | "acpi_sbs_write_word() failed")); | 495 | "acpi_smbus_write() failed")); |
710 | goto end; | 496 | goto end; |
711 | } | 497 | } |
712 | } | 498 | } |
713 | 499 | ||
714 | foo = alarm / (battery->info.capacity_mode ? 10 : 1); | 500 | foo = alarm / (battery->info.capacity_mode ? 10 : 1); |
715 | result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo); | 501 | result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, ACPI_SB_SMBUS_ADDR, 0x01, (u8 *)&foo, 2); |
716 | if (result) { | 502 | if (result) { |
717 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 503 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
718 | "acpi_sbs_write_word() failed")); | 504 | "acpi_smbus_write() failed")); |
719 | goto end; | 505 | goto end; |
720 | } | 506 | } |
721 | 507 | ||
@@ -726,7 +512,6 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, | |||
726 | 512 | ||
727 | static int acpi_battery_set_mode(struct acpi_battery *battery) | 513 | static int acpi_battery_set_mode(struct acpi_battery *battery) |
728 | { | 514 | { |
729 | struct acpi_sbs *sbs = battery->sbs; | ||
730 | int result = 0; | 515 | int result = 0; |
731 | s16 battery_mode; | 516 | s16 battery_mode; |
732 | 517 | ||
@@ -734,11 +519,11 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) | |||
734 | goto end; | 519 | goto end; |
735 | } | 520 | } |
736 | 521 | ||
737 | result = acpi_sbs_read_word(sbs, | 522 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, |
738 | ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); | 523 | ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); |
739 | if (result) { | 524 | if (result) { |
740 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 525 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
741 | "acpi_sbs_read_word() failed")); | 526 | "acpi_smbus_read() failed")); |
742 | goto end; | 527 | goto end; |
743 | } | 528 | } |
744 | 529 | ||
@@ -747,19 +532,19 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) | |||
747 | } else { | 532 | } else { |
748 | battery_mode |= 0x8000; | 533 | battery_mode |= 0x8000; |
749 | } | 534 | } |
750 | result = acpi_sbs_write_word(sbs, | 535 | result = acpi_smbus_write(battery->sbs->hc, SMBUS_READ_WORD, |
751 | ACPI_SB_SMBUS_ADDR, 0x03, battery_mode); | 536 | ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode, 2); |
752 | if (result) { | 537 | if (result) { |
753 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 538 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
754 | "acpi_sbs_write_word() failed")); | 539 | "acpi_smbus_write() failed")); |
755 | goto end; | 540 | goto end; |
756 | } | 541 | } |
757 | 542 | ||
758 | result = acpi_sbs_read_word(sbs, | 543 | result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, |
759 | ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); | 544 | ACPI_SB_SMBUS_ADDR, 0x03, (u8 *)&battery_mode); |
760 | if (result) { | 545 | if (result) { |
761 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 546 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
762 | "acpi_sbs_read_word() failed")); | 547 | "acpi_smbus_read() failed")); |
763 | goto end; | 548 | goto end; |
764 | } | 549 | } |
765 | 550 | ||
@@ -815,12 +600,12 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) | |||
815 | int result = 0; | 600 | int result = 0; |
816 | s16 charger_status; | 601 | s16 charger_status; |
817 | 602 | ||
818 | result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13, | 603 | result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBC_SMBUS_ADDR, 0x13, |
819 | &charger_status); | 604 | (u8 *)&charger_status); |
820 | 605 | ||
821 | if (result) { | 606 | if (result) { |
822 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 607 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
823 | "acpi_sbs_read_word() failed")); | 608 | "acpi_smbus_read() failed")); |
824 | goto end; | 609 | goto end; |
825 | } | 610 | } |
826 | 611 | ||
@@ -1614,15 +1399,6 @@ static int acpi_sbs_add(struct acpi_device *device) | |||
1614 | struct acpi_sbs *sbs = NULL; | 1399 | struct acpi_sbs *sbs = NULL; |
1615 | int result = 0, remove_result = 0; | 1400 | int result = 0, remove_result = 0; |
1616 | int id; | 1401 | int id; |
1617 | acpi_status status = AE_OK; | ||
1618 | unsigned long val; | ||
1619 | |||
1620 | status = | ||
1621 | acpi_evaluate_integer(device->handle, "_EC", NULL, &val); | ||
1622 | if (ACPI_FAILURE(status)) { | ||
1623 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC")); | ||
1624 | return -EIO; | ||
1625 | } | ||
1626 | 1402 | ||
1627 | sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); | 1403 | sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); |
1628 | if (!sbs) { | 1404 | if (!sbs) { |
@@ -1635,8 +1411,8 @@ static int acpi_sbs_add(struct acpi_device *device) | |||
1635 | 1411 | ||
1636 | sbs_mutex_lock(sbs); | 1412 | sbs_mutex_lock(sbs); |
1637 | 1413 | ||
1638 | sbs->base = 0xff & (val >> 8); | ||
1639 | sbs->device = device; | 1414 | sbs->device = device; |
1415 | sbs->hc = acpi_driver_data(device->parent); | ||
1640 | 1416 | ||
1641 | strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); | 1417 | strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); |
1642 | strcpy(acpi_device_class(device), ACPI_SBS_CLASS); | 1418 | strcpy(acpi_device_class(device), ACPI_SBS_CLASS); |
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c new file mode 100644 index 000000000000..046d7c3ed356 --- /dev/null +++ b/drivers/acpi/sbshc.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * SMBus driver for ACPI Embedded Controller (v0.1) | ||
3 | * | ||
4 | * Copyright (c) 2007 Alexey Starikovskiy | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation version 2. | ||
9 | */ | ||
10 | |||
11 | #include <acpi/acpi_bus.h> | ||
12 | #include <acpi/acpi_drivers.h> | ||
13 | #include <acpi/actypes.h> | ||
14 | #include <linux/wait.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include "sbshc.h" | ||
18 | |||
19 | #define ACPI_SMB_HC_CLASS "smbus_host_controller" | ||
20 | #define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC" | ||
21 | |||
22 | struct acpi_smb_hc { | ||
23 | struct acpi_ec *ec; | ||
24 | struct mutex lock; | ||
25 | wait_queue_head_t wait; | ||
26 | u8 offset; | ||
27 | u8 query_bit; | ||
28 | smbus_alarm_callback callback; | ||
29 | void *context; | ||
30 | }; | ||
31 | |||
32 | static int acpi_smbus_hc_add(struct acpi_device *device); | ||
33 | static int acpi_smbus_hc_remove(struct acpi_device *device, int type); | ||
34 | |||
35 | static const struct acpi_device_id sbs_device_ids[] = { | ||
36 | {"ACPI0001", 0}, | ||
37 | {"ACPI0005", 0}, | ||
38 | {"", 0}, | ||
39 | }; | ||
40 | |||
41 | MODULE_DEVICE_TABLE(acpi, sbs_device_ids); | ||
42 | |||
43 | static struct acpi_driver acpi_smb_hc_driver = { | ||
44 | .name = "smbus_hc", | ||
45 | .class = ACPI_SMB_HC_CLASS, | ||
46 | .ids = sbs_device_ids, | ||
47 | .ops = { | ||
48 | .add = acpi_smbus_hc_add, | ||
49 | .remove = acpi_smbus_hc_remove, | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | union acpi_smb_status { | ||
54 | u8 raw; | ||
55 | struct { | ||
56 | u8 status:5; | ||
57 | u8 reserved:1; | ||
58 | u8 alarm:1; | ||
59 | u8 done:1; | ||
60 | } fields; | ||
61 | }; | ||
62 | |||
63 | enum acpi_smb_status_codes { | ||
64 | SMBUS_OK = 0, | ||
65 | SMBUS_UNKNOWN_FAILURE = 0x07, | ||
66 | SMBUS_DEVICE_ADDRESS_NACK = 0x10, | ||
67 | SMBUS_DEVICE_ERROR = 0x11, | ||
68 | SMBUS_DEVICE_COMMAND_ACCESS_DENIED = 0x12, | ||
69 | SMBUS_UNKNOWN_ERROR = 0x13, | ||
70 | SMBUS_DEVICE_ACCESS_DENIED = 0x17, | ||
71 | SMBUS_TIMEOUT = 0x18, | ||
72 | SMBUS_HOST_UNSUPPORTED_PROTOCOL = 0x19, | ||
73 | SMBUS_BUSY = 0x1a, | ||
74 | SMBUS_PEC_ERROR = 0x1f, | ||
75 | }; | ||
76 | |||
77 | enum acpi_smb_offset { | ||
78 | ACPI_SMB_PROTOCOL = 0, /* protocol, PEC */ | ||
79 | ACPI_SMB_STATUS = 1, /* status */ | ||
80 | ACPI_SMB_ADDRESS = 2, /* address */ | ||
81 | ACPI_SMB_COMMAND = 3, /* command */ | ||
82 | ACPI_SMB_DATA = 4, /* 32 data registers */ | ||
83 | ACPI_SMB_BLOCK_COUNT = 0x24, /* number of data bytes */ | ||
84 | ACPI_SMB_ALARM_ADDRESS = 0x25, /* alarm address */ | ||
85 | ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ | ||
86 | }; | ||
87 | |||
88 | static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) | ||
89 | { | ||
90 | return ec_read(hc->offset + address, data); | ||
91 | } | ||
92 | |||
93 | static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data) | ||
94 | { | ||
95 | return ec_write(hc->offset + address, data); | ||
96 | } | ||
97 | |||
98 | static inline int smb_check_done(struct acpi_smb_hc *hc) | ||
99 | { | ||
100 | union acpi_smb_status status = {.raw = 0}; | ||
101 | smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw); | ||
102 | return status.fields.done && (status.fields.status == SMBUS_OK); | ||
103 | } | ||
104 | |||
105 | static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout) | ||
106 | { | ||
107 | if (wait_event_timeout(hc->wait, smb_check_done(hc), | ||
108 | msecs_to_jiffies(timeout))) | ||
109 | return 0; | ||
110 | else | ||
111 | return -ETIME; | ||
112 | } | ||
113 | |||
114 | int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address, | ||
115 | u8 command, u8 *data, u8 length) | ||
116 | { | ||
117 | int ret = -EFAULT, i; | ||
118 | u8 temp, sz = 0; | ||
119 | |||
120 | mutex_lock(&hc->lock); | ||
121 | if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) | ||
122 | goto end; | ||
123 | if (temp) { | ||
124 | ret = -EBUSY; | ||
125 | goto end; | ||
126 | } | ||
127 | smb_hc_write(hc, ACPI_SMB_COMMAND, command); | ||
128 | smb_hc_write(hc, ACPI_SMB_COMMAND, command); | ||
129 | if (!(protocol & 0x01)) { | ||
130 | smb_hc_write(hc, ACPI_SMB_BLOCK_COUNT, length); | ||
131 | for (i = 0; i < length; ++i) | ||
132 | smb_hc_write(hc, ACPI_SMB_DATA + i, data[i]); | ||
133 | } | ||
134 | smb_hc_write(hc, ACPI_SMB_ADDRESS, address << 1); | ||
135 | smb_hc_write(hc, ACPI_SMB_PROTOCOL, protocol); | ||
136 | /* | ||
137 | * Wait for completion. Save the status code, data size, | ||
138 | * and data into the return package (if required by the protocol). | ||
139 | */ | ||
140 | ret = wait_transaction_complete(hc, 1000); | ||
141 | if (ret || !(protocol & 0x01)) | ||
142 | goto end; | ||
143 | switch (protocol) { | ||
144 | case SMBUS_RECEIVE_BYTE: | ||
145 | case SMBUS_READ_BYTE: | ||
146 | sz = 1; | ||
147 | break; | ||
148 | case SMBUS_READ_WORD: | ||
149 | sz = 2; | ||
150 | break; | ||
151 | case SMBUS_READ_BLOCK: | ||
152 | if (smb_hc_read(hc, ACPI_SMB_BLOCK_COUNT, &sz)) { | ||
153 | ret = -EFAULT; | ||
154 | goto end; | ||
155 | } | ||
156 | sz &= 0x1f; | ||
157 | break; | ||
158 | } | ||
159 | for (i = 0; i < sz; ++i) | ||
160 | smb_hc_read(hc, ACPI_SMB_DATA + i, &data[i]); | ||
161 | end: | ||
162 | mutex_unlock(&hc->lock); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address, | ||
167 | u8 command, u8 *data) | ||
168 | { | ||
169 | return acpi_smbus_transaction(hc, protocol, address, command, data, 0); | ||
170 | } | ||
171 | |||
172 | EXPORT_SYMBOL_GPL(acpi_smbus_read); | ||
173 | |||
174 | int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address, | ||
175 | u8 command, u8 *data, u8 length) | ||
176 | { | ||
177 | return acpi_smbus_transaction(hc, protocol, address, command, data, length); | ||
178 | } | ||
179 | |||
180 | EXPORT_SYMBOL_GPL(acpi_smbus_write); | ||
181 | |||
182 | int acpi_smbus_register_callback(struct acpi_smb_hc *hc, | ||
183 | smbus_alarm_callback callback, void *context) | ||
184 | { | ||
185 | mutex_lock(&hc->lock); | ||
186 | hc->callback = callback; | ||
187 | hc->context = context; | ||
188 | mutex_unlock(&hc->lock); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | EXPORT_SYMBOL_GPL(acpi_smbus_register_callback); | ||
193 | |||
194 | int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc) | ||
195 | { | ||
196 | mutex_lock(&hc->lock); | ||
197 | hc->callback = NULL; | ||
198 | hc->context = NULL; | ||
199 | mutex_unlock(&hc->lock); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback); | ||
204 | |||
205 | static void acpi_smbus_callback(void *context) | ||
206 | { | ||
207 | struct acpi_smb_hc *hc = context; | ||
208 | |||
209 | if (hc->callback) | ||
210 | hc->callback(hc->context); | ||
211 | } | ||
212 | |||
213 | static int smbus_alarm(void *context) | ||
214 | { | ||
215 | struct acpi_smb_hc *hc = context; | ||
216 | union acpi_smb_status status; | ||
217 | if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw)) | ||
218 | return 0; | ||
219 | /* Check if it is only a completion notify */ | ||
220 | if (status.fields.done) | ||
221 | wake_up(&hc->wait); | ||
222 | if (!status.fields.alarm) | ||
223 | return 0; | ||
224 | mutex_lock(&hc->lock); | ||
225 | smb_hc_write(hc, ACPI_SMB_STATUS, status.raw); | ||
226 | if (hc->callback) | ||
227 | acpi_os_execute(OSL_GPE_HANDLER, acpi_smbus_callback, hc); | ||
228 | mutex_unlock(&hc->lock); | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | typedef int (*acpi_ec_query_func) (void *data); | ||
233 | |||
234 | extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | ||
235 | acpi_handle handle, acpi_ec_query_func func, | ||
236 | void *data); | ||
237 | |||
238 | static int acpi_smbus_hc_add(struct acpi_device *device) | ||
239 | { | ||
240 | int status; | ||
241 | unsigned long val; | ||
242 | struct acpi_smb_hc *hc; | ||
243 | |||
244 | if (!device) | ||
245 | return -EINVAL; | ||
246 | |||
247 | status = acpi_evaluate_integer(device->handle, "_EC", NULL, &val); | ||
248 | if (ACPI_FAILURE(status)) { | ||
249 | printk(KERN_ERR PREFIX "error obtaining _EC.\n"); | ||
250 | return -EIO; | ||
251 | } | ||
252 | |||
253 | strcpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME); | ||
254 | strcpy(acpi_device_class(device), ACPI_SMB_HC_CLASS); | ||
255 | |||
256 | hc = kzalloc(sizeof(struct acpi_smb_hc), GFP_KERNEL); | ||
257 | if (!hc) | ||
258 | return -ENOMEM; | ||
259 | mutex_init(&hc->lock); | ||
260 | init_waitqueue_head(&hc->wait); | ||
261 | |||
262 | hc->ec = acpi_driver_data(device->parent); | ||
263 | hc->offset = (val >> 8) & 0xff; | ||
264 | hc->query_bit = val & 0xff; | ||
265 | acpi_driver_data(device) = hc; | ||
266 | |||
267 | acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); | ||
268 | printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", | ||
269 | hc->ec, hc->offset, hc->query_bit); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); | ||
275 | |||
276 | static int acpi_smbus_hc_remove(struct acpi_device *device, int type) | ||
277 | { | ||
278 | struct acpi_smb_hc *hc; | ||
279 | |||
280 | if (!device) | ||
281 | return -EINVAL; | ||
282 | |||
283 | hc = acpi_driver_data(device); | ||
284 | acpi_ec_remove_query_handler(hc->ec, hc->query_bit); | ||
285 | kfree(hc); | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int __init acpi_smb_hc_init(void) | ||
290 | { | ||
291 | int result; | ||
292 | |||
293 | result = acpi_bus_register_driver(&acpi_smb_hc_driver); | ||
294 | if (result < 0) | ||
295 | return -ENODEV; | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void __exit acpi_smb_hc_exit(void) | ||
300 | { | ||
301 | acpi_bus_unregister_driver(&acpi_smb_hc_driver); | ||
302 | } | ||
303 | |||
304 | module_init(acpi_smb_hc_init); | ||
305 | module_exit(acpi_smb_hc_exit); | ||
306 | |||
307 | MODULE_LICENSE("GPL"); | ||
308 | MODULE_AUTHOR("Alexey Starikovskiy"); | ||
309 | MODULE_DESCRIPTION("ACPI SMBus HC driver"); | ||
diff --git a/drivers/acpi/sbshc.h b/drivers/acpi/sbshc.h new file mode 100644 index 000000000000..3bda3491a97b --- /dev/null +++ b/drivers/acpi/sbshc.h | |||
@@ -0,0 +1,27 @@ | |||
1 | struct acpi_smb_hc; | ||
2 | enum acpi_smb_protocol { | ||
3 | SMBUS_WRITE_QUICK = 2, | ||
4 | SMBUS_READ_QUICK = 3, | ||
5 | SMBUS_SEND_BYTE = 4, | ||
6 | SMBUS_RECEIVE_BYTE = 5, | ||
7 | SMBUS_WRITE_BYTE = 6, | ||
8 | SMBUS_READ_BYTE = 7, | ||
9 | SMBUS_WRITE_WORD = 8, | ||
10 | SMBUS_READ_WORD = 9, | ||
11 | SMBUS_WRITE_BLOCK = 0xa, | ||
12 | SMBUS_READ_BLOCK = 0xb, | ||
13 | SMBUS_PROCESS_CALL = 0xc, | ||
14 | SMBUS_BLOCK_PROCESS_CALL = 0xd, | ||
15 | }; | ||
16 | |||
17 | static const u8 SMBUS_PEC = 0x80; | ||
18 | |||
19 | typedef void (*smbus_alarm_callback)(void *context); | ||
20 | |||
21 | extern int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address, | ||
22 | u8 command, u8 * data); | ||
23 | extern int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 slave_address, | ||
24 | u8 command, u8 * data, u8 length); | ||
25 | extern int acpi_smbus_register_callback(struct acpi_smb_hc *hc, | ||
26 | smbus_alarm_callback callback, void *context); | ||
27 | extern int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc); | ||