aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c59
1 files changed, 46 insertions, 13 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index d411017f8c06..7222a18a0319 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -26,6 +26,9 @@
26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 */ 27 */
28 28
29/* Uncomment next line to get verbose print outs*/
30/* #define DEBUG */
31
29#include <linux/kernel.h> 32#include <linux/kernel.h>
30#include <linux/module.h> 33#include <linux/module.h>
31#include <linux/init.h> 34#include <linux/init.h>
@@ -47,9 +50,6 @@
47#undef PREFIX 50#undef PREFIX
48#define PREFIX "ACPI: EC: " 51#define PREFIX "ACPI: EC: "
49 52
50/* Uncomment next line to get verbose print outs*/
51/* #define DEBUG */
52
53/* EC status register */ 53/* EC status register */
54#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ 54#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
55#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ 55#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
@@ -82,6 +82,7 @@ enum {
82 EC_FLAGS_ADDRESS, /* Address is being written */ 82 EC_FLAGS_ADDRESS, /* Address is being written */
83 EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ 83 EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
84 EC_FLAGS_WDATA, /* Data is being written */ 84 EC_FLAGS_WDATA, /* Data is being written */
85 EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */
85}; 86};
86 87
87static int acpi_ec_remove(struct acpi_device *device, int type); 88static int acpi_ec_remove(struct acpi_device *device, int type);
@@ -138,26 +139,26 @@ static struct acpi_ec {
138static inline u8 acpi_ec_read_status(struct acpi_ec *ec) 139static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
139{ 140{
140 u8 x = inb(ec->command_addr); 141 u8 x = inb(ec->command_addr);
141 pr_debug(PREFIX "---> status = 0x%2x\n", x); 142 pr_debug(PREFIX "---> status = 0x%2.2x\n", x);
142 return x; 143 return x;
143} 144}
144 145
145static inline u8 acpi_ec_read_data(struct acpi_ec *ec) 146static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
146{ 147{
147 u8 x = inb(ec->data_addr); 148 u8 x = inb(ec->data_addr);
148 pr_debug(PREFIX "---> data = 0x%2x\n", x); 149 pr_debug(PREFIX "---> data = 0x%2.2x\n", x);
149 return inb(ec->data_addr); 150 return inb(ec->data_addr);
150} 151}
151 152
152static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) 153static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
153{ 154{
154 pr_debug(PREFIX "<--- command = 0x%2x\n", command); 155 pr_debug(PREFIX "<--- command = 0x%2.2x\n", command);
155 outb(command, ec->command_addr); 156 outb(command, ec->command_addr);
156} 157}
157 158
158static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) 159static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
159{ 160{
160 pr_debug(PREFIX "<--- data = 0x%2x\n", data); 161 pr_debug(PREFIX "<--- data = 0x%2.2x\n", data);
161 outb(data, ec->data_addr); 162 outb(data, ec->data_addr);
162} 163}
163 164
@@ -179,6 +180,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
179static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) 180static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
180{ 181{
181 int ret = 0; 182 int ret = 0;
183
184 if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
185 test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
186 force_poll = 1;
182 if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && 187 if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
183 test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) 188 test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
184 force_poll = 1; 189 force_poll = 1;
@@ -192,7 +197,12 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
192 goto end; 197 goto end;
193 clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); 198 clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
194 if (acpi_ec_check_status(ec, event)) { 199 if (acpi_ec_check_status(ec, event)) {
195 if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { 200 if (event == ACPI_EC_EVENT_OBF_1) {
201 /* miss OBF_1 GPE, don't expect it */
202 pr_info(PREFIX "missing OBF confirmation, "
203 "don't expect it any longer.\n");
204 set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
205 } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
196 /* miss address GPE, don't expect it anymore */ 206 /* miss address GPE, don't expect it anymore */
197 pr_info(PREFIX "missing address confirmation, " 207 pr_info(PREFIX "missing address confirmation, "
198 "don't expect it any longer.\n"); 208 "don't expect it any longer.\n");
@@ -563,7 +573,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
563 void *handler_context, void *region_context) 573 void *handler_context, void *region_context)
564{ 574{
565 struct acpi_ec *ec = handler_context; 575 struct acpi_ec *ec = handler_context;
566 int result = 0, i = 0; 576 int result = 0, i;
567 u8 temp = 0; 577 u8 temp = 0;
568 578
569 if ((address > 0xFF) || !value || !handler_context) 579 if ((address > 0xFF) || !value || !handler_context)
@@ -575,7 +585,18 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
575 if (bits != 8 && acpi_strict) 585 if (bits != 8 && acpi_strict)
576 return AE_BAD_PARAMETER; 586 return AE_BAD_PARAMETER;
577 587
578 while (bits - i > 0) { 588 acpi_ec_burst_enable(ec);
589
590 if (function == ACPI_READ) {
591 result = acpi_ec_read(ec, address, &temp);
592 *value = temp;
593 } else {
594 temp = 0xff & (*value);
595 result = acpi_ec_write(ec, address, temp);
596 }
597
598 for (i = 8; unlikely(bits - i > 0); i += 8) {
599 ++address;
579 if (function == ACPI_READ) { 600 if (function == ACPI_READ) {
580 result = acpi_ec_read(ec, address, &temp); 601 result = acpi_ec_read(ec, address, &temp);
581 (*value) |= ((acpi_integer)temp) << i; 602 (*value) |= ((acpi_integer)temp) << i;
@@ -583,10 +604,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
583 temp = 0xff & ((*value) >> i); 604 temp = 0xff & ((*value) >> i);
584 result = acpi_ec_write(ec, address, temp); 605 result = acpi_ec_write(ec, address, temp);
585 } 606 }
586 i += 8;
587 ++address;
588 } 607 }
589 608
609 acpi_ec_burst_disable(ec);
610
590 switch (result) { 611 switch (result) {
591 case -EINVAL: 612 case -EINVAL:
592 return AE_BAD_PARAMETER; 613 return AE_BAD_PARAMETER;
@@ -892,6 +913,17 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
892 return 0; 913 return 0;
893} 914}
894 915
916int __init acpi_boot_ec_enable(void)
917{
918 if (!boot_ec || boot_ec->handlers_installed)
919 return 0;
920 if (!ec_install_handlers(boot_ec)) {
921 first_ec = boot_ec;
922 return 0;
923 }
924 return -EFAULT;
925}
926
895int __init acpi_ec_ecdt_probe(void) 927int __init acpi_ec_ecdt_probe(void)
896{ 928{
897 int ret; 929 int ret;
@@ -924,9 +956,10 @@ int __init acpi_ec_ecdt_probe(void)
924 goto error; 956 goto error;
925 /* We really need to limit this workaround, the only ASUS, 957 /* We really need to limit this workaround, the only ASUS,
926 * which needs it, has fake EC._INI method, so use it as flag. 958 * which needs it, has fake EC._INI method, so use it as flag.
959 * Keep boot_ec struct as it will be needed soon.
927 */ 960 */
928 if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x))) 961 if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
929 goto error; 962 return -ENODEV;
930 } 963 }
931 964
932 ret = ec_install_handlers(boot_ec); 965 ret = ec_install_handlers(boot_ec);