Merge branches 'acpi-battery', 'acpi-video' and 'acpi-misc'
[sfrench/cifs-2.6.git] / drivers / hwmon / occ / sysfs.c
index b2f788a777469367676fb63f20788cd6005d089a..2317301fc1e9f62cd367a51d5c256bf95e09b1eb 100644 (file)
@@ -6,13 +6,13 @@
 #include <linux/export.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/kernel.h>
+#include <linux/kstrtox.h>
 #include <linux/sysfs.h>
 
 #include "common.h"
 
 /* OCC status register */
 #define OCC_STAT_MASTER                        BIT(7)
-#define OCC_STAT_ACTIVE                        BIT(0)
 
 /* OCC extended status register */
 #define OCC_EXT_STAT_DVFS_OT           BIT(7)
 #define OCC_EXT_STAT_DVFS_VDD          BIT(3)
 #define OCC_EXT_STAT_GPU_THROTTLE      GENMASK(2, 0)
 
+static ssize_t occ_active_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int rc;
+       bool active;
+       struct occ *occ = dev_get_drvdata(dev);
+
+       rc = kstrtobool(buf, &active);
+       if (rc)
+               return rc;
+
+       rc = occ_active(occ, active);
+       if (rc)
+               return rc;
+
+       return count;
+}
+
 static ssize_t occ_sysfs_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
@@ -31,54 +50,64 @@ static ssize_t occ_sysfs_show(struct device *dev,
        struct occ_poll_response_header *header;
        struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
 
-       rc = occ_update_response(occ);
-       if (rc)
-               return rc;
+       if (occ->active) {
+               rc = occ_update_response(occ);
+               if (rc)
+                       return rc;
 
-       header = (struct occ_poll_response_header *)occ->resp.data;
-
-       switch (sattr->index) {
-       case 0:
-               val = !!(header->status & OCC_STAT_MASTER);
-               break;
-       case 1:
-               val = !!(header->status & OCC_STAT_ACTIVE);
-               break;
-       case 2:
-               val = !!(header->ext_status & OCC_EXT_STAT_DVFS_OT);
-               break;
-       case 3:
-               val = !!(header->ext_status & OCC_EXT_STAT_DVFS_POWER);
-               break;
-       case 4:
-               val = !!(header->ext_status & OCC_EXT_STAT_MEM_THROTTLE);
-               break;
-       case 5:
-               val = !!(header->ext_status & OCC_EXT_STAT_QUICK_DROP);
-               break;
-       case 6:
-               val = header->occ_state;
-               break;
-       case 7:
-               if (header->status & OCC_STAT_MASTER)
-                       val = hweight8(header->occs_present);
-               else
+               header = (struct occ_poll_response_header *)occ->resp.data;
+
+               switch (sattr->index) {
+               case 0:
+                       val = !!(header->status & OCC_STAT_MASTER);
+                       break;
+               case 1:
                        val = 1;
-               break;
-       case 8:
-               val = header->ips_status;
-               break;
-       case 9:
-               val = header->mode;
-               break;
-       case 10:
-               val = !!(header->ext_status & OCC_EXT_STAT_DVFS_VDD);
-               break;
-       case 11:
-               val = header->ext_status & OCC_EXT_STAT_GPU_THROTTLE;
-               break;
-       default:
-               return -EINVAL;
+                       break;
+               case 2:
+                       val = !!(header->ext_status & OCC_EXT_STAT_DVFS_OT);
+                       break;
+               case 3:
+                       val = !!(header->ext_status & OCC_EXT_STAT_DVFS_POWER);
+                       break;
+               case 4:
+                       val = !!(header->ext_status &
+                                OCC_EXT_STAT_MEM_THROTTLE);
+                       break;
+               case 5:
+                       val = !!(header->ext_status & OCC_EXT_STAT_QUICK_DROP);
+                       break;
+               case 6:
+                       val = header->occ_state;
+                       break;
+               case 7:
+                       if (header->status & OCC_STAT_MASTER)
+                               val = hweight8(header->occs_present);
+                       else
+                               val = 1;
+                       break;
+               case 8:
+                       val = header->ips_status;
+                       break;
+               case 9:
+                       val = header->mode;
+                       break;
+               case 10:
+                       val = !!(header->ext_status & OCC_EXT_STAT_DVFS_VDD);
+                       break;
+               case 11:
+                       val = header->ext_status & OCC_EXT_STAT_GPU_THROTTLE;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               if (sattr->index == 1)
+                       val = 0;
+               else if (sattr->index <= 11)
+                       val = -ENODATA;
+               else
+                       return -EINVAL;
        }
 
        return sysfs_emit(buf, "%d\n", val);
@@ -95,7 +124,8 @@ static ssize_t occ_error_show(struct device *dev,
 }
 
 static SENSOR_DEVICE_ATTR(occ_master, 0444, occ_sysfs_show, NULL, 0);
-static SENSOR_DEVICE_ATTR(occ_active, 0444, occ_sysfs_show, NULL, 1);
+static SENSOR_DEVICE_ATTR(occ_active, 0644, occ_sysfs_show, occ_active_store,
+                         1);
 static SENSOR_DEVICE_ATTR(occ_dvfs_overtemp, 0444, occ_sysfs_show, NULL, 2);
 static SENSOR_DEVICE_ATTR(occ_dvfs_power, 0444, occ_sysfs_show, NULL, 3);
 static SENSOR_DEVICE_ATTR(occ_mem_throttle, 0444, occ_sysfs_show, NULL, 4);
@@ -139,7 +169,7 @@ void occ_sysfs_poll_done(struct occ *occ)
         * On the first poll response, we haven't yet created the sysfs
         * attributes, so don't make any notify calls.
         */
-       if (!occ->hwmon)
+       if (!occ->active)
                goto done;
 
        if ((header->status & OCC_STAT_MASTER) !=
@@ -148,12 +178,6 @@ void occ_sysfs_poll_done(struct occ *occ)
                sysfs_notify(&occ->bus_dev->kobj, NULL, name);
        }
 
-       if ((header->status & OCC_STAT_ACTIVE) !=
-           (occ->prev_stat & OCC_STAT_ACTIVE)) {
-               name = sensor_dev_attr_occ_active.dev_attr.attr.name;
-               sysfs_notify(&occ->bus_dev->kobj, NULL, name);
-       }
-
        if ((header->ext_status & OCC_EXT_STAT_DVFS_OT) !=
            (occ->prev_ext_stat & OCC_EXT_STAT_DVFS_OT)) {
                name = sensor_dev_attr_occ_dvfs_overtemp.dev_attr.attr.name;
@@ -227,8 +251,7 @@ int occ_setup_sysfs(struct occ *occ)
        return sysfs_create_group(&occ->bus_dev->kobj, &occ_sysfs);
 }
 
-void occ_shutdown(struct occ *occ)
+void occ_shutdown_sysfs(struct occ *occ)
 {
        sysfs_remove_group(&occ->bus_dev->kobj, &occ_sysfs);
 }
-EXPORT_SYMBOL_GPL(occ_shutdown);