aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2015-02-19 12:21:29 -0500
committerGuenter Roeck <linux@roeck-us.net>2016-01-09 10:31:58 -0500
commit91918d13eb17b8c11a9b6b76bfdd7cc0efab4f50 (patch)
tree2667e606bd2674a2b0ffe6a419ca2c517d04ef32
parent449278d9244277cbcaf04e0d2bb8b54797c3d5cd (diff)
hwmon: (nct6683) Add basic support for NCT6683 on Mitac boards
Mitac microcode differs from Intel microcode. One key difference is that pwm values can be written. Detect vendor from customer ID field and no longer use DMI data to identify which microcode is running on the chip. Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--drivers/hwmon/nct6683.c78
1 files changed, 61 insertions, 17 deletions
diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c
index 6cf392c22803..559c596b24f9 100644
--- a/drivers/hwmon/nct6683.c
+++ b/drivers/hwmon/nct6683.c
@@ -29,7 +29,7 @@
29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30 30
31#include <linux/acpi.h> 31#include <linux/acpi.h>
32#include <linux/dmi.h> 32#include <linux/delay.h>
33#include <linux/err.h> 33#include <linux/err.h>
34#include <linux/init.h> 34#include <linux/init.h>
35#include <linux/io.h> 35#include <linux/io.h>
@@ -45,7 +45,7 @@ enum kinds { nct6683 };
45 45
46static bool force; 46static bool force;
47module_param(force, bool, 0); 47module_param(force, bool, 0);
48MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards"); 48MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
49 49
50static const char * const nct6683_device_names[] = { 50static const char * const nct6683_device_names[] = {
51 "nct6683", 51 "nct6683",
@@ -141,6 +141,7 @@ superio_exit(int ioreg)
141#define NCT6683_REG_MON(x) (0x100 + (x) * 2) 141#define NCT6683_REG_MON(x) (0x100 + (x) * 2)
142#define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2) 142#define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2)
143#define NCT6683_REG_PWM(x) (0x160 + (x)) 143#define NCT6683_REG_PWM(x) (0x160 + (x))
144#define NCT6683_REG_PWM_WRITE(x) (0xa28 + (x))
144 145
145#define NCT6683_REG_MON_STS(x) (0x174 + (x)) 146#define NCT6683_REG_MON_STS(x) (0x174 + (x))
146#define NCT6683_REG_IDLE(x) (0x178 + (x)) 147#define NCT6683_REG_IDLE(x) (0x178 + (x))
@@ -165,8 +166,13 @@ superio_exit(int ioreg)
165 166
166#define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */ 167#define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */
167 168
169#define NCT6683_REG_FAN_CFG_CTRL 0xa01
170#define NCT6683_FAN_CFG_REQ 0x80
171#define NCT6683_FAN_CFG_DONE 0x40
172
168#define NCT6683_REG_CUSTOMER_ID 0x602 173#define NCT6683_REG_CUSTOMER_ID 0x602
169#define NCT6683_CUSTOMER_ID_INTEL 0x805 174#define NCT6683_CUSTOMER_ID_INTEL 0x805
175#define NCT6683_CUSTOMER_ID_MITAC 0xa0e
170 176
171#define NCT6683_REG_BUILD_YEAR 0x604 177#define NCT6683_REG_BUILD_YEAR 0x604
172#define NCT6683_REG_BUILD_MONTH 0x605 178#define NCT6683_REG_BUILD_MONTH 0x605
@@ -560,6 +566,7 @@ static int get_temp_reg(struct nct6683_data *data, int nr, int index)
560 break; 566 break;
561 } 567 }
562 break; 568 break;
569 case NCT6683_CUSTOMER_ID_MITAC:
563 default: 570 default:
564 switch (nr) { 571 switch (nr) {
565 default: 572 default:
@@ -919,7 +926,29 @@ show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
919 return sprintf(buf, "%d\n", data->pwm[index]); 926 return sprintf(buf, "%d\n", data->pwm[index]);
920} 927}
921 928
922SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0); 929static ssize_t
930store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
931 size_t count)
932{
933 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
934 struct nct6683_data *data = dev_get_drvdata(dev);
935 int index = sattr->index;
936 unsigned long val;
937
938 if (kstrtoul(buf, 10, &val) || val > 255)
939 return -EINVAL;
940
941 mutex_lock(&data->update_lock);
942 nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_REQ);
943 usleep_range(1000, 2000);
944 nct6683_write(data, NCT6683_REG_PWM_WRITE(index), val);
945 nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_DONE);
946 mutex_unlock(&data->update_lock);
947
948 return count;
949}
950
951SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, store_pwm, 0);
923 952
924static umode_t nct6683_pwm_is_visible(struct kobject *kobj, 953static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
925 struct attribute *attr, int index) 954 struct attribute *attr, int index)
@@ -931,6 +960,10 @@ static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
931 if (!(data->have_pwm & (1 << pwm))) 960 if (!(data->have_pwm & (1 << pwm)))
932 return 0; 961 return 0;
933 962
963 /* Only update pwm values for Mitac boards */
964 if (data->customer_id == NCT6683_CUSTOMER_ID_MITAC)
965 return attr->mode | S_IWUSR;
966
934 return attr->mode; 967 return attr->mode;
935} 968}
936 969
@@ -1171,6 +1204,7 @@ static int nct6683_probe(struct platform_device *pdev)
1171 struct device *hwmon_dev; 1204 struct device *hwmon_dev;
1172 struct resource *res; 1205 struct resource *res;
1173 int groups = 0; 1206 int groups = 0;
1207 char build[16];
1174 1208
1175 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 1209 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1176 if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME)) 1210 if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
@@ -1188,6 +1222,17 @@ static int nct6683_probe(struct platform_device *pdev)
1188 1222
1189 data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID); 1223 data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID);
1190 1224
1225 /* By default only instantiate driver if the customer ID is known */
1226 switch (data->customer_id) {
1227 case NCT6683_CUSTOMER_ID_INTEL:
1228 break;
1229 case NCT6683_CUSTOMER_ID_MITAC:
1230 break;
1231 default:
1232 if (!force)
1233 return -ENODEV;
1234 }
1235
1191 nct6683_init_device(data); 1236 nct6683_init_device(data);
1192 nct6683_setup_fans(data); 1237 nct6683_setup_fans(data);
1193 nct6683_setup_sensors(data); 1238 nct6683_setup_sensors(data);
@@ -1231,13 +1276,22 @@ static int nct6683_probe(struct platform_device *pdev)
1231 } 1276 }
1232 data->groups[groups++] = &nct6683_group_other; 1277 data->groups[groups++] = &nct6683_group_other;
1233 1278
1234 dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n", 1279 if (data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
1280 scnprintf(build, sizeof(build), "%02x/%02x/%02x",
1281 nct6683_read(data, NCT6683_REG_BUILD_MONTH),
1282 nct6683_read(data, NCT6683_REG_BUILD_DAY),
1283 nct6683_read(data, NCT6683_REG_BUILD_YEAR));
1284 else
1285 scnprintf(build, sizeof(build), "%02d/%02d/%02d",
1286 nct6683_read(data, NCT6683_REG_BUILD_MONTH),
1287 nct6683_read(data, NCT6683_REG_BUILD_DAY),
1288 nct6683_read(data, NCT6683_REG_BUILD_YEAR));
1289
1290 dev_info(dev, "%s EC firmware version %d.%d build %s\n",
1235 nct6683_chip_names[data->kind], 1291 nct6683_chip_names[data->kind],
1236 nct6683_read(data, NCT6683_REG_VERSION_HI), 1292 nct6683_read(data, NCT6683_REG_VERSION_HI),
1237 nct6683_read(data, NCT6683_REG_VERSION_LO), 1293 nct6683_read(data, NCT6683_REG_VERSION_LO),
1238 nct6683_read(data, NCT6683_REG_BUILD_MONTH), 1294 build);
1239 nct6683_read(data, NCT6683_REG_BUILD_DAY),
1240 nct6683_read(data, NCT6683_REG_BUILD_YEAR));
1241 1295
1242 hwmon_dev = devm_hwmon_device_register_with_groups(dev, 1296 hwmon_dev = devm_hwmon_device_register_with_groups(dev,
1243 nct6683_device_names[data->kind], data, data->groups); 1297 nct6683_device_names[data->kind], data, data->groups);
@@ -1293,20 +1347,10 @@ static struct platform_driver nct6683_driver = {
1293 1347
1294static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data) 1348static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
1295{ 1349{
1296 const char *board_vendor;
1297 int addr; 1350 int addr;
1298 u16 val; 1351 u16 val;
1299 int err; 1352 int err;
1300 1353
1301 /*
1302 * Only run on Intel boards unless the 'force' module parameter is set
1303 */
1304 if (!force) {
1305 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
1306 if (!board_vendor || strcmp(board_vendor, "Intel Corporation"))
1307 return -ENODEV;
1308 }
1309
1310 err = superio_enter(sioaddr); 1354 err = superio_enter(sioaddr);
1311 if (err) 1355 if (err)
1312 return err; 1356 return err;