aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/asus_atk0110.c
diff options
context:
space:
mode:
authorLuca Tettamanti <kronos.it@gmail.com>2009-10-09 14:35:18 -0400
committerJean Delvare <khali@linux-fr.org>2009-10-09 14:35:18 -0400
commit9e6eba610c2eb68b05841a15ece1cf929c44aea3 (patch)
treef7a4f25d1a5768b02d688afd72606f8f2f1e38d6 /drivers/hwmon/asus_atk0110.c
parent18e255558574c5663c9d72fe82c099d2115aee55 (diff)
hwmon: (asus_atk0110) Enable the EC
On newer ASUS boards (e.g. P7P55D) the EC (that - among other things - is responsible for updating the readings from the hwmon sensors) is disabled by default since ASUS detected conflict with some tools under Windows. The following patch checks the state of the EC and enable it if needed; under Linux, native drivers are locked out from ACPI owned resources so there's no risk of conflict. Signed-off-by: Luca Tettamanti <kronos.it@gmail.com> Tested-by: Robert Hancock <hancockrwd@gmail.com> Tested-by: Thomas Backlund <tmb@mandriva.org> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/asus_atk0110.c')
-rw-r--r--drivers/hwmon/asus_atk0110.c185
1 files changed, 184 insertions, 1 deletions
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 19f3fd32e10a..5a3ee00c0e7d 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -35,18 +35,22 @@
35#define METHOD_OLD_ENUM_FAN "FSIF" 35#define METHOD_OLD_ENUM_FAN "FSIF"
36 36
37#define ATK_MUX_HWMON 0x00000006ULL 37#define ATK_MUX_HWMON 0x00000006ULL
38#define ATK_MUX_MGMT 0x00000011ULL
38 39
39#define ATK_CLASS_MASK 0xff000000ULL 40#define ATK_CLASS_MASK 0xff000000ULL
40#define ATK_CLASS_FREQ_CTL 0x03000000ULL 41#define ATK_CLASS_FREQ_CTL 0x03000000ULL
41#define ATK_CLASS_FAN_CTL 0x04000000ULL 42#define ATK_CLASS_FAN_CTL 0x04000000ULL
42#define ATK_CLASS_HWMON 0x06000000ULL 43#define ATK_CLASS_HWMON 0x06000000ULL
44#define ATK_CLASS_MGMT 0x11000000ULL
43 45
44#define ATK_TYPE_MASK 0x00ff0000ULL 46#define ATK_TYPE_MASK 0x00ff0000ULL
45#define HWMON_TYPE_VOLT 0x00020000ULL 47#define HWMON_TYPE_VOLT 0x00020000ULL
46#define HWMON_TYPE_TEMP 0x00030000ULL 48#define HWMON_TYPE_TEMP 0x00030000ULL
47#define HWMON_TYPE_FAN 0x00040000ULL 49#define HWMON_TYPE_FAN 0x00040000ULL
48 50
49#define HWMON_SENSOR_ID_MASK 0x0000ffffULL 51#define ATK_ELEMENT_ID_MASK 0x0000ffffULL
52
53#define ATK_EC_ID 0x11060004ULL
50 54
51enum atk_pack_member { 55enum atk_pack_member {
52 HWMON_PACK_FLAGS, 56 HWMON_PACK_FLAGS,
@@ -89,6 +93,9 @@ struct atk_data {
89 /* new inteface */ 93 /* new inteface */
90 acpi_handle enumerate_handle; 94 acpi_handle enumerate_handle;
91 acpi_handle read_handle; 95 acpi_handle read_handle;
96 acpi_handle write_handle;
97
98 bool disable_ec;
92 99
93 int voltage_count; 100 int voltage_count;
94 int temperature_count; 101 int temperature_count;
@@ -529,6 +536,43 @@ static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
529 return obj; 536 return obj;
530} 537}
531 538
539static union acpi_object *atk_sitm(struct atk_data *data,
540 struct atk_acpi_input_buf *buf)
541{
542 struct device *dev = &data->acpi_dev->dev;
543 struct acpi_object_list params;
544 union acpi_object tmp;
545 struct acpi_buffer ret;
546 union acpi_object *obj;
547 acpi_status status;
548
549 tmp.type = ACPI_TYPE_BUFFER;
550 tmp.buffer.pointer = (u8 *)buf;
551 tmp.buffer.length = sizeof(*buf);
552
553 params.count = 1;
554 params.pointer = &tmp;
555
556 ret.length = ACPI_ALLOCATE_BUFFER;
557 status = acpi_evaluate_object_typed(data->write_handle, NULL, &params,
558 &ret, ACPI_TYPE_BUFFER);
559 if (status != AE_OK) {
560 dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
561 acpi_format_exception(status));
562 return ERR_PTR(-EIO);
563 }
564 obj = ret.pointer;
565
566 /* Sanity check */
567 if (obj->buffer.length < 8) {
568 dev_warn(dev, "Unexpected ASBF length: %u\n",
569 obj->buffer.length);
570 ACPI_FREE(obj);
571 return ERR_PTR(-EIO);
572 }
573 return obj;
574}
575
532static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) 576static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
533{ 577{
534 struct atk_data *data = sensor->data; 578 struct atk_data *data = sensor->data;
@@ -784,6 +828,111 @@ cleanup:
784 return ret; 828 return ret;
785} 829}
786 830
831static int atk_ec_present(struct atk_data *data)
832{
833 struct device *dev = &data->acpi_dev->dev;
834 union acpi_object *pack;
835 union acpi_object *ec;
836 int ret;
837 int i;
838
839 pack = atk_ggrp(data, ATK_MUX_MGMT);
840 if (IS_ERR(pack)) {
841 if (PTR_ERR(pack) == -ENOENT) {
842 /* The MGMT class does not exists - that's ok */
843 dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
844 return 0;
845 }
846 return PTR_ERR(pack);
847 }
848
849 /* Search the EC */
850 ec = NULL;
851 for (i = 0; i < pack->package.count; i++) {
852 union acpi_object *obj = &pack->package.elements[i];
853 union acpi_object *id;
854
855 if (obj->type != ACPI_TYPE_PACKAGE)
856 continue;
857
858 id = &obj->package.elements[0];
859 if (id->type != ACPI_TYPE_INTEGER)
860 continue;
861
862 if (id->integer.value == ATK_EC_ID) {
863 ec = obj;
864 break;
865 }
866 }
867
868 ret = (ec != NULL);
869 if (!ret)
870 /* The system has no EC */
871 dev_dbg(dev, "EC not found\n");
872
873 ACPI_FREE(pack);
874 return ret;
875}
876
877static int atk_ec_enabled(struct atk_data *data)
878{
879 struct device *dev = &data->acpi_dev->dev;
880 union acpi_object *obj;
881 struct atk_acpi_ret_buffer *buf;
882 int err;
883
884 obj = atk_gitm(data, ATK_EC_ID);
885 if (IS_ERR(obj)) {
886 dev_err(dev, "Unable to query EC status\n");
887 return PTR_ERR(obj);
888 }
889 buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
890
891 if (buf->flags == 0) {
892 dev_err(dev, "Unable to query EC status\n");
893 err = -EIO;
894 } else {
895 err = (buf->value != 0);
896 dev_dbg(dev, "EC is %sabled\n",
897 err ? "en" : "dis");
898 }
899
900 ACPI_FREE(obj);
901 return err;
902}
903
904static int atk_ec_ctl(struct atk_data *data, int enable)
905{
906 struct device *dev = &data->acpi_dev->dev;
907 union acpi_object *obj;
908 struct atk_acpi_input_buf sitm;
909 struct atk_acpi_ret_buffer *ec_ret;
910 int err = 0;
911
912 sitm.id = ATK_EC_ID;
913 sitm.param1 = enable;
914 sitm.param2 = 0;
915
916 obj = atk_sitm(data, &sitm);
917 if (IS_ERR(obj)) {
918 dev_err(dev, "Failed to %sable the EC\n",
919 enable ? "en" : "dis");
920 return PTR_ERR(obj);
921 }
922 ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
923 if (ec_ret->flags == 0) {
924 dev_err(dev, "Failed to %sable the EC\n",
925 enable ? "en" : "dis");
926 err = -EIO;
927 } else {
928 dev_info(dev, "EC %sabled\n",
929 enable ? "en" : "dis");
930 }
931
932 ACPI_FREE(obj);
933 return err;
934}
935
787static int atk_enumerate_new_hwmon(struct atk_data *data) 936static int atk_enumerate_new_hwmon(struct atk_data *data)
788{ 937{
789 struct device *dev = &data->acpi_dev->dev; 938 struct device *dev = &data->acpi_dev->dev;
@@ -791,6 +940,23 @@ static int atk_enumerate_new_hwmon(struct atk_data *data)
791 int err; 940 int err;
792 int i; 941 int i;
793 942
943 err = atk_ec_present(data);
944 if (err < 0)
945 return err;
946 if (err) {
947 err = atk_ec_enabled(data);
948 if (err < 0)
949 return err;
950 /* If the EC was disabled we will disable it again on unload */
951 data->disable_ec = err;
952
953 err = atk_ec_ctl(data, 1);
954 if (err) {
955 data->disable_ec = false;
956 return err;
957 }
958 }
959
794 dev_dbg(dev, "Enumerating hwmon sensors\n"); 960 dev_dbg(dev, "Enumerating hwmon sensors\n");
795 961
796 pack = atk_ggrp(data, ATK_MUX_HWMON); 962 pack = atk_ggrp(data, ATK_MUX_HWMON);
@@ -941,6 +1107,15 @@ static int atk_check_new_if(struct atk_data *data)
941 } 1107 }
942 data->read_handle = ret; 1108 data->read_handle = ret;
943 1109
1110 /* De-multiplexer (write) */
1111 status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
1112 if (status != AE_OK) {
1113 dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
1114 acpi_format_exception(status));
1115 return -ENODEV;
1116 }
1117 data->write_handle = ret;
1118
944 return 0; 1119 return 0;
945} 1120}
946 1121
@@ -961,6 +1136,7 @@ static int atk_add(struct acpi_device *device)
961 data->acpi_dev = device; 1136 data->acpi_dev = device;
962 data->atk_handle = device->handle; 1137 data->atk_handle = device->handle;
963 INIT_LIST_HEAD(&data->sensor_list); 1138 INIT_LIST_HEAD(&data->sensor_list);
1139 data->disable_ec = false;
964 1140
965 buf.length = ACPI_ALLOCATE_BUFFER; 1141 buf.length = ACPI_ALLOCATE_BUFFER;
966 ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL, 1142 ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
@@ -1019,6 +1195,8 @@ static int atk_add(struct acpi_device *device)
1019cleanup: 1195cleanup:
1020 atk_free_sensors(data); 1196 atk_free_sensors(data);
1021out: 1197out:
1198 if (data->disable_ec)
1199 atk_ec_ctl(data, 0);
1022 kfree(data); 1200 kfree(data);
1023 return err; 1201 return err;
1024} 1202}
@@ -1034,6 +1212,11 @@ static int atk_remove(struct acpi_device *device, int type)
1034 atk_free_sensors(data); 1212 atk_free_sensors(data);
1035 hwmon_device_unregister(data->hwmon_dev); 1213 hwmon_device_unregister(data->hwmon_dev);
1036 1214
1215 if (data->disable_ec) {
1216 if (atk_ec_ctl(data, 0))
1217 dev_err(&device->dev, "Failed to disable EC\n");
1218 }
1219
1037 kfree(data); 1220 kfree(data);
1038 1221
1039 return 0; 1222 return 0;