Commit cae2caae78258d623c7b687029a19fa6b33c76f4

Authored by Corentin Labbe
Committed by Jean Delvare
1 parent 657c93b10f

hwmon: New driver for the Analog Devices ADM1029

Signed-off-by: Corentin Labbe <corentin.labbe@geomatys.fr>
Signed-off-by: Jean Delvare <khali@linux-fr.org>

Showing 4 changed files with 526 additions and 0 deletions Side-by-side Diff

... ... @@ -268,6 +268,12 @@
268 268 L: lm-sensors@lm-sensors.org
269 269 S: Maintained
270 270  
  271 +ADM1029 HARDWARE MONITOR DRIVER
  272 +P: Corentin Labbe
  273 +M: corentin.labbe@geomatys.fr
  274 +L: lm-sensors@lm-sensors.org
  275 +S: Maintained
  276 +
271 277 ADT746X FAN DRIVER
272 278 P: Colin Leroy
273 279 M: colin@colino.net
drivers/hwmon/Kconfig
... ... @@ -73,6 +73,17 @@
73 73 This driver can also be built as a module. If so, the module
74 74 will be called adm1026.
75 75  
  76 +config SENSORS_ADM1029
  77 + tristate "Analog Devices ADM1029"
  78 + depends on HWMON && I2C && EXPERIMENTAL
  79 + help
  80 + If you say yes here you get support for Analog Devices ADM1029
  81 + sensor chip.
  82 + Very rare chip, please let us know you use it.
  83 +
  84 + This driver can also be built as a module. If so, the module
  85 + will be called adm1029.
  86 +
76 87 config SENSORS_ADM1031
77 88 tristate "Analog Devices ADM1031 and compatibles"
78 89 depends on HWMON && I2C && EXPERIMENTAL
drivers/hwmon/Makefile
... ... @@ -17,6 +17,7 @@
17 17 obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
18 18 obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
19 19 obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
  20 +obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
20 21 obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
21 22 obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
22 23 obj-$(CONFIG_SENSORS_AMS) += ams/
drivers/hwmon/adm1029.c
  1 +/*
  2 + * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
  3 + *
  4 + * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr>
  5 + *
  6 + * Based on LM83 Driver by Jean Delvare <khali@linux-fr.org>
  7 + *
  8 + * Give only processor, motherboard temperatures and fan tachs
  9 + * Very rare chip please let me know if you use it
  10 + *
  11 + * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf
  12 + *
  13 + *
  14 + * This program is free software; you can redistribute it and/or modify
  15 + * it under the terms of the GNU General Public License as published by
  16 + * the Free Software Foundation version 2 of the License
  17 + *
  18 + * This program is distributed in the hope that it will be useful,
  19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21 + * GNU General Public License for more details.
  22 + *
  23 + * You should have received a copy of the GNU General Public License
  24 + * along with this program; if not, write to the Free Software
  25 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 + */
  27 +
  28 +#include <linux/module.h>
  29 +#include <linux/init.h>
  30 +#include <linux/slab.h>
  31 +#include <linux/jiffies.h>
  32 +#include <linux/i2c.h>
  33 +#include <linux/hwmon-sysfs.h>
  34 +#include <linux/hwmon.h>
  35 +#include <linux/err.h>
  36 +#include <linux/mutex.h>
  37 +
  38 +/*
  39 + * Addresses to scan
  40 + */
  41 +
  42 +static unsigned short normal_i2c[] = {
  43 + 0x28, 0x29, 0x2a,
  44 + 0x2b, 0x2c, 0x2d,
  45 + 0x2e, 0x2f, I2C_CLIENT_END
  46 +};
  47 +
  48 +/*
  49 + * Insmod parameters
  50 + */
  51 +
  52 +I2C_CLIENT_INSMOD_1(adm1029);
  53 +
  54 +/*
  55 + * The ADM1029 registers
  56 + * Manufacturer ID is 0x41 for Analog Devices
  57 + */
  58 +
  59 +#define ADM1029_REG_MAN_ID 0x0D
  60 +#define ADM1029_REG_CHIP_ID 0x0E
  61 +#define ADM1029_REG_CONFIG 0x01
  62 +#define ADM1029_REG_NB_FAN_SUPPORT 0x02
  63 +
  64 +#define ADM1029_REG_TEMP_DEVICES_INSTALLED 0x06
  65 +
  66 +#define ADM1029_REG_LOCAL_TEMP 0xA0
  67 +#define ADM1029_REG_REMOTE1_TEMP 0xA1
  68 +#define ADM1029_REG_REMOTE2_TEMP 0xA2
  69 +
  70 +#define ADM1029_REG_LOCAL_TEMP_HIGH 0x90
  71 +#define ADM1029_REG_REMOTE1_TEMP_HIGH 0x91
  72 +#define ADM1029_REG_REMOTE2_TEMP_HIGH 0x92
  73 +
  74 +#define ADM1029_REG_LOCAL_TEMP_LOW 0x98
  75 +#define ADM1029_REG_REMOTE1_TEMP_LOW 0x99
  76 +#define ADM1029_REG_REMOTE2_TEMP_LOW 0x9A
  77 +
  78 +#define ADM1029_REG_FAN1 0x70
  79 +#define ADM1029_REG_FAN2 0x71
  80 +
  81 +#define ADM1029_REG_FAN1_MIN 0x78
  82 +#define ADM1029_REG_FAN2_MIN 0x79
  83 +
  84 +#define ADM1029_REG_FAN1_CONFIG 0x68
  85 +#define ADM1029_REG_FAN2_CONFIG 0x69
  86 +
  87 +#define TEMP_FROM_REG(val) ((val) * 1000)
  88 +
  89 +#define DIV_FROM_REG(val) ( 1 << (((val) >> 6) - 1))
  90 +
  91 +/* Registers to be checked by adm1029_update_device() */
  92 +static const u8 ADM1029_REG_TEMP[] = {
  93 + ADM1029_REG_LOCAL_TEMP,
  94 + ADM1029_REG_REMOTE1_TEMP,
  95 + ADM1029_REG_REMOTE2_TEMP,
  96 + ADM1029_REG_LOCAL_TEMP_HIGH,
  97 + ADM1029_REG_REMOTE1_TEMP_HIGH,
  98 + ADM1029_REG_REMOTE2_TEMP_HIGH,
  99 + ADM1029_REG_LOCAL_TEMP_LOW,
  100 + ADM1029_REG_REMOTE1_TEMP_LOW,
  101 + ADM1029_REG_REMOTE2_TEMP_LOW,
  102 +};
  103 +
  104 +static const u8 ADM1029_REG_FAN[] = {
  105 + ADM1029_REG_FAN1,
  106 + ADM1029_REG_FAN2,
  107 + ADM1029_REG_FAN1_MIN,
  108 + ADM1029_REG_FAN2_MIN,
  109 +};
  110 +
  111 +static const u8 ADM1029_REG_FAN_DIV[] = {
  112 + ADM1029_REG_FAN1_CONFIG,
  113 + ADM1029_REG_FAN2_CONFIG,
  114 +};
  115 +
  116 +/*
  117 + * Functions declaration
  118 + */
  119 +
  120 +static int adm1029_attach_adapter(struct i2c_adapter *adapter);
  121 +static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind);
  122 +static int adm1029_detach_client(struct i2c_client *client);
  123 +static struct adm1029_data *adm1029_update_device(struct device *dev);
  124 +static int adm1029_init_client(struct i2c_client *client);
  125 +
  126 +/*
  127 + * Driver data (common to all clients)
  128 + */
  129 +
  130 +static struct i2c_driver adm1029_driver = {
  131 + .driver = {
  132 + .name = "adm1029",
  133 + },
  134 + .attach_adapter = adm1029_attach_adapter,
  135 + .detach_client = adm1029_detach_client,
  136 +};
  137 +
  138 +/*
  139 + * Client data (each client gets its own)
  140 + */
  141 +
  142 +struct adm1029_data {
  143 + struct i2c_client client;
  144 + struct class_device *class_dev;
  145 + struct mutex update_lock;
  146 + char valid; /* zero until following fields are valid */
  147 + unsigned long last_updated; /* in jiffies */
  148 +
  149 + /* registers values, signed for temperature, unsigned for other stuff */
  150 + s8 temp[ARRAY_SIZE(ADM1029_REG_TEMP)];
  151 + u8 fan[ARRAY_SIZE(ADM1029_REG_FAN)];
  152 + u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)];
  153 +};
  154 +
  155 +/*
  156 + * Sysfs stuff
  157 + */
  158 +
  159 +static ssize_t
  160 +show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
  161 +{
  162 + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  163 + struct adm1029_data *data = adm1029_update_device(dev);
  164 + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
  165 +}
  166 +
  167 +static ssize_t
  168 +show_fan(struct device *dev, struct device_attribute *devattr, char *buf)
  169 +{
  170 + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  171 + struct adm1029_data *data = adm1029_update_device(dev);
  172 + u16 val;
  173 + if (data->fan[attr->index] == 0 || data->fan_div[attr->index] == 0
  174 + || data->fan[attr->index] == 255) {
  175 + return sprintf(buf, "0\n");
  176 + }
  177 +
  178 + val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])
  179 + / data->fan[attr->index];
  180 + return sprintf(buf, "%d\n", val);
  181 +}
  182 +
  183 +static ssize_t
  184 +show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
  185 +{
  186 + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  187 + struct adm1029_data *data = adm1029_update_device(dev);
  188 + if (data->fan_div[attr->index] == 0)
  189 + return sprintf(buf, "0\n");
  190 + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
  191 +}
  192 +
  193 +static ssize_t set_fan_div(struct device *dev,
  194 + struct device_attribute *devattr, const char *buf, size_t count)
  195 +{
  196 + struct i2c_client *client = to_i2c_client(dev);
  197 + struct adm1029_data *data = i2c_get_clientdata(client);
  198 + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  199 + long val = simple_strtol(buf, NULL, 10);
  200 + u8 reg;
  201 +
  202 + mutex_lock(&data->update_lock);
  203 +
  204 + /*Read actual config */
  205 + reg = i2c_smbus_read_byte_data(client,
  206 + ADM1029_REG_FAN_DIV[attr->index]);
  207 +
  208 + switch (val) {
  209 + case 1:
  210 + val = 1;
  211 + break;
  212 + case 2:
  213 + val = 2;
  214 + break;
  215 + case 4:
  216 + val = 3;
  217 + break;
  218 + default:
  219 + mutex_unlock(&data->update_lock);
  220 + dev_err(&client->dev, "fan_div value %ld not "
  221 + "supported. Choose one of 1, 2 or 4!\n", val);
  222 + return -EINVAL;
  223 + }
  224 + /* Update the value */
  225 + reg = (reg & 0x3F) | (val << 6);
  226 +
  227 + /* Write value */
  228 + i2c_smbus_write_byte_data(client,
  229 + ADM1029_REG_FAN_DIV[attr->index], reg);
  230 + mutex_unlock(&data->update_lock);
  231 +
  232 + return count;
  233 +}
  234 +
  235 +/*
  236 +Access rights on sysfs, S_IRUGO stand for Is Readable by User, Group and Others
  237 + S_IWUSR stand for Is Writable by User
  238 +*/
  239 +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
  240 +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
  241 +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
  242 +
  243 +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 3);
  244 +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp, NULL, 4);
  245 +static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp, NULL, 5);
  246 +
  247 +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, NULL, 6);
  248 +static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp, NULL, 7);
  249 +static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp, NULL, 8);
  250 +
  251 +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
  252 +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
  253 +
  254 +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan, NULL, 2);
  255 +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan, NULL, 3);
  256 +
  257 +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
  258 + show_fan_div, set_fan_div, 0);
  259 +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
  260 + show_fan_div, set_fan_div, 1);
  261 +
  262 +static struct attribute *adm1029_attributes[] = {
  263 + &sensor_dev_attr_temp1_input.dev_attr.attr,
  264 + &sensor_dev_attr_temp1_min.dev_attr.attr,
  265 + &sensor_dev_attr_temp1_max.dev_attr.attr,
  266 + &sensor_dev_attr_temp2_input.dev_attr.attr,
  267 + &sensor_dev_attr_temp2_min.dev_attr.attr,
  268 + &sensor_dev_attr_temp2_max.dev_attr.attr,
  269 + &sensor_dev_attr_temp3_input.dev_attr.attr,
  270 + &sensor_dev_attr_temp3_min.dev_attr.attr,
  271 + &sensor_dev_attr_temp3_max.dev_attr.attr,
  272 + &sensor_dev_attr_fan1_input.dev_attr.attr,
  273 + &sensor_dev_attr_fan2_input.dev_attr.attr,
  274 + &sensor_dev_attr_fan1_min.dev_attr.attr,
  275 + &sensor_dev_attr_fan2_min.dev_attr.attr,
  276 + &sensor_dev_attr_fan1_div.dev_attr.attr,
  277 + &sensor_dev_attr_fan2_div.dev_attr.attr,
  278 + NULL
  279 +};
  280 +
  281 +static const struct attribute_group adm1029_group = {
  282 + .attrs = adm1029_attributes,
  283 +};
  284 +
  285 +/*
  286 + * Real code
  287 + */
  288 +
  289 +static int adm1029_attach_adapter(struct i2c_adapter *adapter)
  290 +{
  291 + if (!(adapter->class & I2C_CLASS_HWMON))
  292 + return 0;
  293 + return i2c_probe(adapter, &addr_data, adm1029_detect);
  294 +}
  295 +
  296 +/*
  297 + * The following function does more than just detection. If detection
  298 + * succeeds, it also registers the new chip.
  299 + */
  300 +
  301 +static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
  302 +{
  303 + struct i2c_client *client;
  304 + struct adm1029_data *data;
  305 + int err = 0;
  306 + const char *name = "";
  307 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  308 + goto exit;
  309 +
  310 + if (!(data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL))) {
  311 + err = -ENOMEM;
  312 + goto exit;
  313 + }
  314 +
  315 + client = &data->client;
  316 + i2c_set_clientdata(client, data);
  317 + client->addr = address;
  318 + client->adapter = adapter;
  319 + client->driver = &adm1029_driver;
  320 +
  321 + /* Now we do the detection and identification. A negative kind
  322 + * means that the driver was loaded with no force parameter
  323 + * (default), so we must both detect and identify the chip
  324 + * (actually there is only one possible kind of chip for now, adm1029).
  325 + * A zero kind means that the driver was loaded with the force
  326 + * parameter, the detection step shall be skipped. A positive kind
  327 + * means that the driver was loaded with the force parameter and a
  328 + * given kind of chip is requested, so both the detection and the
  329 + * identification steps are skipped. */
  330 +
  331 + /* Default to an adm1029 if forced */
  332 + if (kind == 0)
  333 + kind = adm1029;
  334 +
  335 + /* ADM1029 doesn't have CHIP ID, check just MAN ID
  336 + * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,
  337 + * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values
  338 + * documented
  339 + */
  340 +
  341 + if (kind <= 0) { /* identification */
  342 + u8 man_id, chip_id, temp_devices_installed, nb_fan_support;
  343 +
  344 + man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);
  345 + chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);
  346 + temp_devices_installed = i2c_smbus_read_byte_data(client,
  347 + ADM1029_REG_TEMP_DEVICES_INSTALLED);
  348 + nb_fan_support = i2c_smbus_read_byte_data(client,
  349 + ADM1029_REG_NB_FAN_SUPPORT);
  350 + /* 0x41 is Analog Devices */
  351 + if (man_id == 0x41 && (temp_devices_installed & 0xf9) == 0x01
  352 + && nb_fan_support == 0x03) {
  353 + if ((chip_id & 0xF0) == 0x00) {
  354 + kind = adm1029;
  355 + } else {
  356 + /* There are no "official" CHIP ID, so actually
  357 + * we use Major/Minor revision for that */
  358 + printk(KERN_INFO
  359 + "adm1029: Unknown major revision %x, "
  360 + "please let us know\n", chip_id);
  361 + }
  362 + }
  363 +
  364 + if (kind <= 0) { /* identification failed */
  365 + pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
  366 + "chip_id=0x%02X)\n", man_id, chip_id);
  367 + goto exit_free;
  368 + }
  369 + }
  370 +
  371 + if (kind == adm1029) {
  372 + name = "adm1029";
  373 + }
  374 +
  375 + /* We can fill in the remaining client fields */
  376 + strlcpy(client->name, name, I2C_NAME_SIZE);
  377 + mutex_init(&data->update_lock);
  378 +
  379 + /* Tell the I2C layer a new client has arrived */
  380 + if ((err = i2c_attach_client(client)))
  381 + goto exit_free;
  382 +
  383 + /*
  384 + * Initialize the ADM1029 chip
  385 + * Check config register
  386 + */
  387 + if (adm1029_init_client(client) == 0)
  388 + goto exit_detach;
  389 +
  390 + /* Register sysfs hooks */
  391 + if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
  392 + goto exit_detach;
  393 +
  394 + data->class_dev = hwmon_device_register(&client->dev);
  395 + if (IS_ERR(data->class_dev)) {
  396 + err = PTR_ERR(data->class_dev);
  397 + goto exit_remove_files;
  398 + }
  399 +
  400 + return 0;
  401 +
  402 + exit_remove_files:
  403 + sysfs_remove_group(&client->dev.kobj, &adm1029_group);
  404 + exit_detach:
  405 + i2c_detach_client(client);
  406 + exit_free:
  407 + kfree(data);
  408 + exit:
  409 + return err;
  410 +}
  411 +
  412 +static int adm1029_init_client(struct i2c_client *client)
  413 +{
  414 + u8 config;
  415 + config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
  416 + if ((config & 0x10) == 0) {
  417 + i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG,
  418 + config | 0x10);
  419 + }
  420 + /* recheck config */
  421 + config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
  422 + if ((config & 0x10) == 0) {
  423 + dev_err(&client->dev, "Initialization failed!\n");
  424 + return 0;
  425 + }
  426 + return 1;
  427 +}
  428 +
  429 +static int adm1029_detach_client(struct i2c_client *client)
  430 +{
  431 + struct adm1029_data *data = i2c_get_clientdata(client);
  432 + int err;
  433 +
  434 + hwmon_device_unregister(data->class_dev);
  435 + sysfs_remove_group(&client->dev.kobj, &adm1029_group);
  436 +
  437 + if ((err = i2c_detach_client(client)))
  438 + return err;
  439 +
  440 + kfree(data);
  441 + return 0;
  442 +}
  443 +
  444 +/*
  445 +function that update the status of the chips (temperature for exemple)
  446 +*/
  447 +static struct adm1029_data *adm1029_update_device(struct device *dev)
  448 +{
  449 + struct i2c_client *client = to_i2c_client(dev);
  450 + struct adm1029_data *data = i2c_get_clientdata(client);
  451 +
  452 + mutex_lock(&data->update_lock);
  453 + /*
  454 + * Use the "cache" Luke, don't recheck values
  455 + * if there are already checked not a long time later
  456 + */
  457 + if (time_after(jiffies, data->last_updated + HZ * 2)
  458 + || !data->valid) {
  459 + int nr;
  460 +
  461 + dev_dbg(&client->dev, "Updating adm1029 data\n");
  462 +
  463 + for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {
  464 + data->temp[nr] =
  465 + i2c_smbus_read_byte_data(client,
  466 + ADM1029_REG_TEMP[nr]);
  467 + }
  468 + for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {
  469 + data->fan[nr] =
  470 + i2c_smbus_read_byte_data(client,
  471 + ADM1029_REG_FAN[nr]);
  472 + }
  473 + for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {
  474 + data->fan_div[nr] =
  475 + i2c_smbus_read_byte_data(client,
  476 + ADM1029_REG_FAN_DIV[nr]);
  477 + }
  478 +
  479 + data->last_updated = jiffies;
  480 + data->valid = 1;
  481 + }
  482 +
  483 + mutex_unlock(&data->update_lock);
  484 +
  485 + return data;
  486 +}
  487 +
  488 +/*
  489 + Common module stuff
  490 +*/
  491 +static int __init sensors_adm1029_init(void)
  492 +{
  493 +
  494 + return i2c_add_driver(&adm1029_driver);
  495 +}
  496 +
  497 +static void __exit sensors_adm1029_exit(void)
  498 +{
  499 +
  500 + i2c_del_driver(&adm1029_driver);
  501 +}
  502 +
  503 +MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>");
  504 +MODULE_DESCRIPTION("adm1029 driver");
  505 +MODULE_LICENSE("GPL v2");
  506 +
  507 +module_init(sensors_adm1029_init);
  508 +module_exit(sensors_adm1029_exit);