aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorentin Chary <corentincj@iksaif.net>2011-02-26 04:20:42 -0500
committerMatthew Garrett <mjg@redhat.com>2011-03-28 06:07:23 -0400
commite07babde13460d7b03842a6de8f22fbef93709e1 (patch)
tree8a13aa1ccd92fdb64f42088181f54827f1a973ca
parent2f686b54fbfcd82ebfb650a5c628c1b9ba8b9863 (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/Kconfig1
-rw-r--r--drivers/platform/x86/asus-wmi.c128
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 */
799static 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
828static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0);
829
830static ssize_t
831show_name(struct device *dev, struct device_attribute *attr, char *buf)
832{
833 return sprintf(buf, "asus\n");
834}
835static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
836
837static struct attribute *hwmon_attributes[] = {
838 &sensor_dev_attr_pwm1.dev_attr.attr,
839 &sensor_dev_attr_name.dev_attr.attr,
840 NULL
841};
842
843static 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
880static struct attribute_group hwmon_attribute_group = {
881 .is_visible = asus_hwmon_sysfs_is_visible,
882 .attrs = hwmon_attributes
883};
884
885static 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
897static 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 */
796static int read_backlight_power(struct asus_wmi *asus) 917static 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:
1369fail_rfkill: 1494fail_rfkill:
1370 asus_wmi_led_exit(asus); 1495 asus_wmi_led_exit(asus);
1371fail_leds: 1496fail_leds:
1497 asus_wmi_hwmon_exit(asus);
1498fail_hwmon:
1372 asus_wmi_input_exit(asus); 1499 asus_wmi_input_exit(asus);
1373fail_input: 1500fail_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);