diff options
author | Corentin Chary <corentincj@iksaif.net> | 2011-02-26 04:20:42 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-03-28 06:07:23 -0400 |
commit | e07babde13460d7b03842a6de8f22fbef93709e1 (patch) | |
tree | 8a13aa1ccd92fdb64f42088181f54827f1a973ca | |
parent | 2f686b54fbfcd82ebfb650a5c628c1b9ba8b9863 (diff) |
asus-wmi: add hwmon interface and pwm1
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
-rw-r--r-- | drivers/platform/x86/Kconfig | 1 | ||||
-rw-r--r-- | drivers/platform/x86/asus-wmi.c | 128 |
2 files changed, 129 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 45f4d63c7939..0c7cf666a1bc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -458,6 +458,7 @@ config ASUS_WMI | |||
458 | tristate "ASUS WMI Driver (EXPERIMENTAL)" | 458 | tristate "ASUS WMI Driver (EXPERIMENTAL)" |
459 | depends on ACPI_WMI | 459 | depends on ACPI_WMI |
460 | depends on INPUT | 460 | depends on INPUT |
461 | depends on HWMON | ||
461 | depends on EXPERIMENTAL | 462 | depends on EXPERIMENTAL |
462 | depends on BACKLIGHT_CLASS_DEVICE | 463 | depends on BACKLIGHT_CLASS_DEVICE |
463 | depends on RFKILL || RFKILL = n | 464 | depends on RFKILL || RFKILL = n |
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 05db6b2067b5..5b779a9443d6 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <linux/rfkill.h> | 39 | #include <linux/rfkill.h> |
40 | #include <linux/pci.h> | 40 | #include <linux/pci.h> |
41 | #include <linux/pci_hotplug.h> | 41 | #include <linux/pci_hotplug.h> |
42 | #include <linux/hwmon.h> | ||
43 | #include <linux/hwmon-sysfs.h> | ||
42 | #include <linux/debugfs.h> | 44 | #include <linux/debugfs.h> |
43 | #include <linux/seq_file.h> | 45 | #include <linux/seq_file.h> |
44 | #include <linux/platform_device.h> | 46 | #include <linux/platform_device.h> |
@@ -167,6 +169,7 @@ struct asus_wmi { | |||
167 | 169 | ||
168 | struct input_dev *inputdev; | 170 | struct input_dev *inputdev; |
169 | struct backlight_device *backlight_device; | 171 | struct backlight_device *backlight_device; |
172 | struct device *hwmon_device; | ||
170 | struct platform_device *platform_device; | 173 | struct platform_device *platform_device; |
171 | 174 | ||
172 | struct led_classdev tpd_led; | 175 | struct led_classdev tpd_led; |
@@ -791,6 +794,124 @@ exit: | |||
791 | } | 794 | } |
792 | 795 | ||
793 | /* | 796 | /* |
797 | * Hwmon device | ||
798 | */ | ||
799 | static ssize_t asus_hwmon_pwm1(struct device *dev, | ||
800 | struct device_attribute *attr, | ||
801 | char *buf) | ||
802 | { | ||
803 | struct asus_wmi *asus = dev_get_drvdata(dev); | ||
804 | u32 value; | ||
805 | int err; | ||
806 | |||
807 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); | ||
808 | |||
809 | if (err < 0) | ||
810 | return err; | ||
811 | |||
812 | value |= 0xFF; | ||
813 | |||
814 | if (value == 1) /* Low Speed */ | ||
815 | value = 85; | ||
816 | else if (value == 2) | ||
817 | value = 170; | ||
818 | else if (value == 3) | ||
819 | value = 255; | ||
820 | else if (value != 0) { | ||
821 | pr_err("Unknown fan speed %#x", value); | ||
822 | value = -1; | ||
823 | } | ||
824 | |||
825 | return sprintf(buf, "%d\n", value); | ||
826 | } | ||
827 | |||
828 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); | ||
829 | |||
830 | static ssize_t | ||
831 | show_name(struct device *dev, struct device_attribute *attr, char *buf) | ||
832 | { | ||
833 | return sprintf(buf, "asus\n"); | ||
834 | } | ||
835 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); | ||
836 | |||
837 | static struct attribute *hwmon_attributes[] = { | ||
838 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
839 | &sensor_dev_attr_name.dev_attr.attr, | ||
840 | NULL | ||
841 | }; | ||
842 | |||
843 | static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, | ||
844 | struct attribute *attr, int idx) | ||
845 | { | ||
846 | struct device *dev = container_of(kobj, struct device, kobj); | ||
847 | struct platform_device *pdev = to_platform_device(dev->parent); | ||
848 | struct asus_wmi *asus = platform_get_drvdata(pdev); | ||
849 | bool ok = true; | ||
850 | int dev_id = -1; | ||
851 | u32 value = ASUS_WMI_UNSUPPORTED_METHOD; | ||
852 | |||
853 | if (attr == &sensor_dev_attr_pwm1.dev_attr.attr) | ||
854 | dev_id = ASUS_WMI_DEVID_FAN_CTRL; | ||
855 | |||
856 | if (dev_id != -1) { | ||
857 | int err = asus_wmi_get_devstate(asus, dev_id, &value); | ||
858 | |||
859 | if (err < 0) | ||
860 | return err; | ||
861 | } | ||
862 | |||
863 | if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) { | ||
864 | /* | ||
865 | * We need to find a better way, probably using sfun, | ||
866 | * bits or spec ... | ||
867 | * Currently we disable it if: | ||
868 | * - ASUS_WMI_UNSUPPORTED_METHOD is returned | ||
869 | * - reverved bits are non-zero | ||
870 | * - sfun and presence bit are not set | ||
871 | */ | ||
872 | if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 | ||
873 | || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) | ||
874 | ok = false; | ||
875 | } | ||
876 | |||
877 | return ok ? attr->mode : 0; | ||
878 | } | ||
879 | |||
880 | static struct attribute_group hwmon_attribute_group = { | ||
881 | .is_visible = asus_hwmon_sysfs_is_visible, | ||
882 | .attrs = hwmon_attributes | ||
883 | }; | ||
884 | |||
885 | static void asus_wmi_hwmon_exit(struct asus_wmi *asus) | ||
886 | { | ||
887 | struct device *hwmon; | ||
888 | |||
889 | hwmon = asus->hwmon_device; | ||
890 | if (!hwmon) | ||
891 | return; | ||
892 | sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group); | ||
893 | hwmon_device_unregister(hwmon); | ||
894 | asus->hwmon_device = NULL; | ||
895 | } | ||
896 | |||
897 | static int asus_wmi_hwmon_init(struct asus_wmi *asus) | ||
898 | { | ||
899 | struct device *hwmon; | ||
900 | int result; | ||
901 | |||
902 | hwmon = hwmon_device_register(&asus->platform_device->dev); | ||
903 | if (IS_ERR(hwmon)) { | ||
904 | pr_err("Could not register asus hwmon device\n"); | ||
905 | return PTR_ERR(hwmon); | ||
906 | } | ||
907 | asus->hwmon_device = hwmon; | ||
908 | result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group); | ||
909 | if (result) | ||
910 | asus_wmi_hwmon_exit(asus); | ||
911 | return result; | ||
912 | } | ||
913 | |||
914 | /* | ||
794 | * Backlight | 915 | * Backlight |
795 | */ | 916 | */ |
796 | static int read_backlight_power(struct asus_wmi *asus) | 917 | static int read_backlight_power(struct asus_wmi *asus) |
@@ -1331,6 +1452,10 @@ static int asus_wmi_add(struct platform_device *pdev) | |||
1331 | if (err) | 1452 | if (err) |
1332 | goto fail_input; | 1453 | goto fail_input; |
1333 | 1454 | ||
1455 | err = asus_wmi_hwmon_init(asus); | ||
1456 | if (err) | ||
1457 | goto fail_hwmon; | ||
1458 | |||
1334 | err = asus_wmi_led_init(asus); | 1459 | err = asus_wmi_led_init(asus); |
1335 | if (err) | 1460 | if (err) |
1336 | goto fail_leds; | 1461 | goto fail_leds; |
@@ -1369,6 +1494,8 @@ fail_backlight: | |||
1369 | fail_rfkill: | 1494 | fail_rfkill: |
1370 | asus_wmi_led_exit(asus); | 1495 | asus_wmi_led_exit(asus); |
1371 | fail_leds: | 1496 | fail_leds: |
1497 | asus_wmi_hwmon_exit(asus); | ||
1498 | fail_hwmon: | ||
1372 | asus_wmi_input_exit(asus); | 1499 | asus_wmi_input_exit(asus); |
1373 | fail_input: | 1500 | fail_input: |
1374 | asus_wmi_platform_exit(asus); | 1501 | asus_wmi_platform_exit(asus); |
@@ -1385,6 +1512,7 @@ static int asus_wmi_remove(struct platform_device *device) | |||
1385 | wmi_remove_notify_handler(asus->driver->event_guid); | 1512 | wmi_remove_notify_handler(asus->driver->event_guid); |
1386 | asus_wmi_backlight_exit(asus); | 1513 | asus_wmi_backlight_exit(asus); |
1387 | asus_wmi_input_exit(asus); | 1514 | asus_wmi_input_exit(asus); |
1515 | asus_wmi_hwmon_exit(asus); | ||
1388 | asus_wmi_led_exit(asus); | 1516 | asus_wmi_led_exit(asus); |
1389 | asus_wmi_rfkill_exit(asus); | 1517 | asus_wmi_rfkill_exit(asus); |
1390 | asus_wmi_debugfs_exit(asus); | 1518 | asus_wmi_debugfs_exit(asus); |