Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
[deliverable/linux.git] / drivers / hwmon / nct6683.c
index 37f01702d08195b1a9bab1f82fe88434302556b9..559c596b24f9b916d9f1fe6b85c7eabc8f1868d9 100644 (file)
@@ -29,7 +29,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/acpi.h>
-#include <linux/dmi.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -45,7 +45,7 @@ enum kinds { nct6683 };
 
 static bool force;
 module_param(force, bool, 0);
-MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards");
+MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
 
 static const char * const nct6683_device_names[] = {
        "nct6683",
@@ -141,6 +141,7 @@ superio_exit(int ioreg)
 #define NCT6683_REG_MON(x)             (0x100 + (x) * 2)
 #define NCT6683_REG_FAN_RPM(x)         (0x140 + (x) * 2)
 #define NCT6683_REG_PWM(x)             (0x160 + (x))
+#define NCT6683_REG_PWM_WRITE(x)       (0xa28 + (x))
 
 #define NCT6683_REG_MON_STS(x)         (0x174 + (x))
 #define NCT6683_REG_IDLE(x)            (0x178 + (x))
@@ -165,8 +166,13 @@ superio_exit(int ioreg)
 
 #define NCT6683_REG_FAN_MIN(x)         (0x3b8 + (x) * 2)       /* 16 bit */
 
+#define NCT6683_REG_FAN_CFG_CTRL       0xa01
+#define NCT6683_FAN_CFG_REQ            0x80
+#define NCT6683_FAN_CFG_DONE           0x40
+
 #define NCT6683_REG_CUSTOMER_ID                0x602
 #define NCT6683_CUSTOMER_ID_INTEL      0x805
+#define NCT6683_CUSTOMER_ID_MITAC      0xa0e
 
 #define NCT6683_REG_BUILD_YEAR         0x604
 #define NCT6683_REG_BUILD_MONTH                0x605
@@ -394,7 +400,8 @@ struct sensor_template_group {
 };
 
 static struct attribute_group *
-nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+nct6683_create_attr_group(struct device *dev,
+                         const struct sensor_template_group *tg,
                          int repeat)
 {
        struct sensor_device_attribute_2 *a2;
@@ -559,6 +566,7 @@ static int get_temp_reg(struct nct6683_data *data, int nr, int index)
                        break;
                }
                break;
+       case NCT6683_CUSTOMER_ID_MITAC:
        default:
                switch (nr) {
                default:
@@ -703,7 +711,7 @@ static struct sensor_device_template *nct6683_attributes_in_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_in_template_group = {
+static const struct sensor_template_group nct6683_in_template_group = {
        .templates = nct6683_attributes_in_template,
        .is_visible = nct6683_in_is_visible,
 };
@@ -774,7 +782,7 @@ static struct sensor_device_template *nct6683_attributes_fan_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_fan_template_group = {
+static const struct sensor_template_group nct6683_fan_template_group = {
        .templates = nct6683_attributes_fan_template,
        .is_visible = nct6683_fan_is_visible,
        .base = 1,
@@ -902,7 +910,7 @@ static struct sensor_device_template *nct6683_attributes_temp_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_temp_template_group = {
+static const struct sensor_template_group nct6683_temp_template_group = {
        .templates = nct6683_attributes_temp_template,
        .is_visible = nct6683_temp_is_visible,
        .base = 1,
@@ -918,7 +926,29 @@ show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
        return sprintf(buf, "%d\n", data->pwm[index]);
 }
 
-SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0);
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
+         size_t count)
+{
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       struct nct6683_data *data = dev_get_drvdata(dev);
+       int index = sattr->index;
+       unsigned long val;
+
+       if (kstrtoul(buf, 10, &val) || val > 255)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_REQ);
+       usleep_range(1000, 2000);
+       nct6683_write(data, NCT6683_REG_PWM_WRITE(index), val);
+       nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_DONE);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, store_pwm, 0);
 
 static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
                                      struct attribute *attr, int index)
@@ -930,6 +960,10 @@ static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
        if (!(data->have_pwm & (1 << pwm)))
                return 0;
 
+       /* Only update pwm values for Mitac boards */
+       if (data->customer_id == NCT6683_CUSTOMER_ID_MITAC)
+               return attr->mode | S_IWUSR;
+
        return attr->mode;
 }
 
@@ -938,7 +972,7 @@ static struct sensor_device_template *nct6683_attributes_pwm_template[] = {
        NULL
 };
 
-static struct sensor_template_group nct6683_pwm_template_group = {
+static const struct sensor_template_group nct6683_pwm_template_group = {
        .templates = nct6683_attributes_pwm_template,
        .is_visible = nct6683_pwm_is_visible,
        .base = 1,
@@ -1170,6 +1204,7 @@ static int nct6683_probe(struct platform_device *pdev)
        struct device *hwmon_dev;
        struct resource *res;
        int groups = 0;
+       char build[16];
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
@@ -1187,6 +1222,17 @@ static int nct6683_probe(struct platform_device *pdev)
 
        data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID);
 
+       /* By default only instantiate driver if the customer ID is known */
+       switch (data->customer_id) {
+       case NCT6683_CUSTOMER_ID_INTEL:
+               break;
+       case NCT6683_CUSTOMER_ID_MITAC:
+               break;
+       default:
+               if (!force)
+                       return -ENODEV;
+       }
+
        nct6683_init_device(data);
        nct6683_setup_fans(data);
        nct6683_setup_sensors(data);
@@ -1230,13 +1276,22 @@ static int nct6683_probe(struct platform_device *pdev)
        }
        data->groups[groups++] = &nct6683_group_other;
 
-       dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n",
+       if (data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+               scnprintf(build, sizeof(build), "%02x/%02x/%02x",
+                         nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+                         nct6683_read(data, NCT6683_REG_BUILD_DAY),
+                         nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+       else
+               scnprintf(build, sizeof(build), "%02d/%02d/%02d",
+                         nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+                         nct6683_read(data, NCT6683_REG_BUILD_DAY),
+                         nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+
+       dev_info(dev, "%s EC firmware version %d.%d build %s\n",
                 nct6683_chip_names[data->kind],
                 nct6683_read(data, NCT6683_REG_VERSION_HI),
                 nct6683_read(data, NCT6683_REG_VERSION_LO),
-                nct6683_read(data, NCT6683_REG_BUILD_MONTH),
-                nct6683_read(data, NCT6683_REG_BUILD_DAY),
-                nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+                build);
 
        hwmon_dev = devm_hwmon_device_register_with_groups(dev,
                        nct6683_device_names[data->kind], data, data->groups);
@@ -1292,20 +1347,10 @@ static struct platform_driver nct6683_driver = {
 
 static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
 {
-       const char *board_vendor;
        int addr;
        u16 val;
        int err;
 
-       /*
-        * Only run on Intel boards unless the 'force' module parameter is set
-        */
-       if (!force) {
-               board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
-               if (!board_vendor || strcmp(board_vendor, "Intel Corporation"))
-                       return -ENODEV;
-       }
-
        err = superio_enter(sioaddr);
        if (err)
                return err;
This page took 0.050374 seconds and 5 git commands to generate.