Commit e07babde13460d7b03842a6de8f22fbef93709e1
Committed by
Matthew Garrett
1 parent
2f686b54fb
Exists in
master
and in
4 other branches
asus-wmi: add hwmon interface and pwm1
Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Showing 2 changed files with 129 additions and 0 deletions Side-by-side Diff
drivers/platform/x86/Kconfig
drivers/platform/x86/asus-wmi.c
... | ... | @@ -39,6 +39,8 @@ |
39 | 39 | #include <linux/rfkill.h> |
40 | 40 | #include <linux/pci.h> |
41 | 41 | #include <linux/pci_hotplug.h> |
42 | +#include <linux/hwmon.h> | |
43 | +#include <linux/hwmon-sysfs.h> | |
42 | 44 | #include <linux/debugfs.h> |
43 | 45 | #include <linux/seq_file.h> |
44 | 46 | #include <linux/platform_device.h> |
... | ... | @@ -167,6 +169,7 @@ |
167 | 169 | |
168 | 170 | struct input_dev *inputdev; |
169 | 171 | struct backlight_device *backlight_device; |
172 | + struct device *hwmon_device; | |
170 | 173 | struct platform_device *platform_device; |
171 | 174 | |
172 | 175 | struct led_classdev tpd_led; |
... | ... | @@ -791,6 +794,124 @@ |
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 | 915 | * Backlight |
795 | 916 | */ |
796 | 917 | static int read_backlight_power(struct asus_wmi *asus) |
... | ... | @@ -1331,6 +1452,10 @@ |
1331 | 1452 | if (err) |
1332 | 1453 | goto fail_input; |
1333 | 1454 | |
1455 | + err = asus_wmi_hwmon_init(asus); | |
1456 | + if (err) | |
1457 | + goto fail_hwmon; | |
1458 | + | |
1334 | 1459 | err = asus_wmi_led_init(asus); |
1335 | 1460 | if (err) |
1336 | 1461 | goto fail_leds; |
... | ... | @@ -1369,6 +1494,8 @@ |
1369 | 1494 | fail_rfkill: |
1370 | 1495 | asus_wmi_led_exit(asus); |
1371 | 1496 | fail_leds: |
1497 | + asus_wmi_hwmon_exit(asus); | |
1498 | +fail_hwmon: | |
1372 | 1499 | asus_wmi_input_exit(asus); |
1373 | 1500 | fail_input: |
1374 | 1501 | asus_wmi_platform_exit(asus); |
... | ... | @@ -1385,6 +1512,7 @@ |
1385 | 1512 | wmi_remove_notify_handler(asus->driver->event_guid); |
1386 | 1513 | asus_wmi_backlight_exit(asus); |
1387 | 1514 | asus_wmi_input_exit(asus); |
1515 | + asus_wmi_hwmon_exit(asus); | |
1388 | 1516 | asus_wmi_led_exit(asus); |
1389 | 1517 | asus_wmi_rfkill_exit(asus); |
1390 | 1518 | asus_wmi_debugfs_exit(asus); |