linux/drivers/hwmon/w83l785ts.c
<<
>>
Prefs
   1/*
   2 * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware
   3 *               monitoring
   4 * Copyright (C) 2003-2009  Jean Delvare <khali@linux-fr.org>
   5 *
   6 * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made
   7 * by Winbond. It reports a single external temperature with a 1 deg
   8 * resolution and a 3 deg accuracy. Datasheet can be obtained from
   9 * Winbond's website at:
  10 *   http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
  11 *
  12 * Ported to Linux 2.6 by Wolfgang Ziegler <nuppla@gmx.at> and Jean Delvare
  13 * <khali@linux-fr.org>.
  14 *
  15 * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
  16 * error handling mechanism.
  17 *
  18 * This program is free software; you can redistribute it and/or modify
  19 * it under the terms of the GNU General Public License as published by
  20 * the Free Software Foundation; either version 2 of the License, or
  21 * (at your option) any later version.
  22 *
  23 * This program is distributed in the hope that it will be useful,
  24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26 * GNU General Public License for more details.
  27 *
  28 * You should have received a copy of the GNU General Public License
  29 * along with this program; if not, write to the Free Software
  30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  31 */
  32
  33#include <linux/module.h>
  34#include <linux/delay.h>
  35#include <linux/init.h>
  36#include <linux/slab.h>
  37#include <linux/jiffies.h>
  38#include <linux/i2c.h>
  39#include <linux/hwmon.h>
  40#include <linux/hwmon-sysfs.h>
  41#include <linux/err.h>
  42#include <linux/mutex.h>
  43
  44/* How many retries on register read error */
  45#define MAX_RETRIES     5
  46
  47/*
  48 * Address to scan
  49 * Address is fully defined internally and cannot be changed.
  50 */
  51
  52static const unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
  53
  54/*
  55 * The W83L785TS-S registers
  56 * Manufacturer ID is 0x5CA3 for Winbond.
  57 */
  58
  59#define W83L785TS_REG_MAN_ID1           0x4D
  60#define W83L785TS_REG_MAN_ID2           0x4C
  61#define W83L785TS_REG_CHIP_ID           0x4E
  62#define W83L785TS_REG_CONFIG            0x40
  63#define W83L785TS_REG_TYPE              0x52
  64#define W83L785TS_REG_TEMP              0x27
  65#define W83L785TS_REG_TEMP_OVER         0x53 /* not sure about this one */
  66
  67/*
  68 * Conversions
  69 * The W83L785TS-S uses signed 8-bit values.
  70 */
  71
  72#define TEMP_FROM_REG(val)      ((val) * 1000)
  73
  74/*
  75 * Functions declaration
  76 */
  77
  78static int w83l785ts_probe(struct i2c_client *client,
  79                           const struct i2c_device_id *id);
  80static int w83l785ts_detect(struct i2c_client *client,
  81                            struct i2c_board_info *info);
  82static int w83l785ts_remove(struct i2c_client *client);
  83static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
  84static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
  85
  86/*
  87 * Driver data (common to all clients)
  88 */
  89
  90static const struct i2c_device_id w83l785ts_id[] = {
  91        { "w83l785ts", 0 },
  92        { }
  93};
  94MODULE_DEVICE_TABLE(i2c, w83l785ts_id);
  95
  96static struct i2c_driver w83l785ts_driver = {
  97        .class          = I2C_CLASS_HWMON,
  98        .driver = {
  99                .name   = "w83l785ts",
 100        },
 101        .probe          = w83l785ts_probe,
 102        .remove         = w83l785ts_remove,
 103        .id_table       = w83l785ts_id,
 104        .detect         = w83l785ts_detect,
 105        .address_list   = normal_i2c,
 106};
 107
 108/*
 109 * Client data (each client gets its own)
 110 */
 111
 112struct w83l785ts_data {
 113        struct device *hwmon_dev;
 114        struct mutex update_lock;
 115        char valid; /* zero until following fields are valid */
 116        unsigned long last_updated; /* in jiffies */
 117
 118        /* registers values */
 119        s8 temp[2]; /* 0: input, 1: critical limit */
 120};
 121
 122/*
 123 * Sysfs stuff
 124 */
 125
 126static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 127        char *buf)
 128{
 129        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 130        struct w83l785ts_data *data = w83l785ts_update_device(dev);
 131        return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
 132}
 133
 134static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
 135static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1);
 136
 137/*
 138 * Real code
 139 */
 140
 141/* Return 0 if detection is successful, -ENODEV otherwise */
 142static int w83l785ts_detect(struct i2c_client *client,
 143                            struct i2c_board_info *info)
 144{
 145        struct i2c_adapter *adapter = client->adapter;
 146        u16 man_id;
 147        u8 chip_id;
 148
 149        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 150                return -ENODEV;
 151
 152        /* detection */
 153        if ((w83l785ts_read_value(client, W83L785TS_REG_CONFIG, 0) & 0x80)
 154         || (w83l785ts_read_value(client, W83L785TS_REG_TYPE, 0) & 0xFC)) {
 155                dev_dbg(&adapter->dev,
 156                        "W83L785TS-S detection failed at 0x%02x\n",
 157                        client->addr);
 158                return -ENODEV;
 159        }
 160
 161        /* Identification */
 162        man_id = (w83l785ts_read_value(client, W83L785TS_REG_MAN_ID1, 0) << 8)
 163               + w83l785ts_read_value(client, W83L785TS_REG_MAN_ID2, 0);
 164        chip_id = w83l785ts_read_value(client, W83L785TS_REG_CHIP_ID, 0);
 165
 166        if (man_id != 0x5CA3            /* Winbond */
 167         || chip_id != 0x70) {          /* W83L785TS-S */
 168                dev_dbg(&adapter->dev,
 169                        "Unsupported chip (man_id=0x%04X, chip_id=0x%02X)\n",
 170                        man_id, chip_id);
 171                return -ENODEV;
 172        }
 173
 174        strlcpy(info->type, "w83l785ts", I2C_NAME_SIZE);
 175
 176        return 0;
 177}
 178
 179static int w83l785ts_probe(struct i2c_client *client,
 180                           const struct i2c_device_id *id)
 181{
 182        struct w83l785ts_data *data;
 183        struct device *dev = &client->dev;
 184        int err;
 185
 186        data = devm_kzalloc(dev, sizeof(struct w83l785ts_data), GFP_KERNEL);
 187        if (!data)
 188                return -ENOMEM;
 189
 190        i2c_set_clientdata(client, data);
 191        data->valid = 0;
 192        mutex_init(&data->update_lock);
 193
 194        /* Default values in case the first read fails (unlikely). */
 195        data->temp[1] = data->temp[0] = 0;
 196
 197        /*
 198         * Initialize the W83L785TS chip
 199         * Nothing yet, assume it is already started.
 200         */
 201
 202        err = device_create_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
 203        if (err)
 204                return err;
 205
 206        err = device_create_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
 207        if (err)
 208                goto exit_remove;
 209
 210        /* Register sysfs hooks */
 211        data->hwmon_dev = hwmon_device_register(dev);
 212        if (IS_ERR(data->hwmon_dev)) {
 213                err = PTR_ERR(data->hwmon_dev);
 214                goto exit_remove;
 215        }
 216
 217        return 0;
 218
 219exit_remove:
 220        device_remove_file(dev, &sensor_dev_attr_temp1_input.dev_attr);
 221        device_remove_file(dev, &sensor_dev_attr_temp1_max.dev_attr);
 222        return err;
 223}
 224
 225static int w83l785ts_remove(struct i2c_client *client)
 226{
 227        struct w83l785ts_data *data = i2c_get_clientdata(client);
 228
 229        hwmon_device_unregister(data->hwmon_dev);
 230        device_remove_file(&client->dev,
 231                           &sensor_dev_attr_temp1_input.dev_attr);
 232        device_remove_file(&client->dev,
 233                           &sensor_dev_attr_temp1_max.dev_attr);
 234
 235        return 0;
 236}
 237
 238static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
 239{
 240        int value, i;
 241        struct device *dev;
 242        const char *prefix;
 243
 244        /*
 245         * We might be called during detection, at which point the client
 246         * isn't yet fully initialized, so we can't use dev_dbg on it
 247         */
 248        if (i2c_get_clientdata(client)) {
 249                dev = &client->dev;
 250                prefix = "";
 251        } else {
 252                dev = &client->adapter->dev;
 253                prefix = "w83l785ts: ";
 254        }
 255
 256        /*
 257         * Frequent read errors have been reported on Asus boards, so we
 258         * retry on read errors. If it still fails (unlikely), return the
 259         * default value requested by the caller.
 260         */
 261        for (i = 1; i <= MAX_RETRIES; i++) {
 262                value = i2c_smbus_read_byte_data(client, reg);
 263                if (value >= 0) {
 264                        dev_dbg(dev, "%sRead 0x%02x from register 0x%02x.\n",
 265                                prefix, value, reg);
 266                        return value;
 267                }
 268                dev_dbg(dev, "%sRead failed, will retry in %d.\n", prefix, i);
 269                msleep(i);
 270        }
 271
 272        dev_err(dev, "%sCouldn't read value from register 0x%02x.\n", prefix,
 273                reg);
 274        return defval;
 275}
 276
 277static struct w83l785ts_data *w83l785ts_update_device(struct device *dev)
 278{
 279        struct i2c_client *client = to_i2c_client(dev);
 280        struct w83l785ts_data *data = i2c_get_clientdata(client);
 281
 282        mutex_lock(&data->update_lock);
 283
 284        if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) {
 285                dev_dbg(&client->dev, "Updating w83l785ts data.\n");
 286                data->temp[0] = w83l785ts_read_value(client,
 287                                W83L785TS_REG_TEMP, data->temp[0]);
 288                data->temp[1] = w83l785ts_read_value(client,
 289                                W83L785TS_REG_TEMP_OVER, data->temp[1]);
 290
 291                data->last_updated = jiffies;
 292                data->valid = 1;
 293        }
 294
 295        mutex_unlock(&data->update_lock);
 296
 297        return data;
 298}
 299
 300module_i2c_driver(w83l785ts_driver);
 301
 302MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
 303MODULE_DESCRIPTION("W83L785TS-S driver");
 304MODULE_LICENSE("GPL");
 305
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.