root/drivers/hwmon/ds620.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ds620_init_client
  2. ds620_update_client
  3. temp_show
  4. temp_store
  5. alarm_show
  6. ds620_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  ds620.c - Support for temperature sensor and thermostat DS620
   4  *
   5  *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
   6  *
   7  *  based on ds1621.c by Christian W. Zuckschwerdt  <zany@triq.net>
   8  */
   9 
  10 #include <linux/module.h>
  11 #include <linux/init.h>
  12 #include <linux/slab.h>
  13 #include <linux/jiffies.h>
  14 #include <linux/i2c.h>
  15 #include <linux/hwmon.h>
  16 #include <linux/hwmon-sysfs.h>
  17 #include <linux/err.h>
  18 #include <linux/mutex.h>
  19 #include <linux/sysfs.h>
  20 #include <linux/platform_data/ds620.h>
  21 
  22 /*
  23  * Many DS620 constants specified below
  24  *  15   14   13   12   11   10   09    08
  25  * |Done|NVB |THF |TLF |R1  |R0  |AUTOC|1SHOT|
  26  *
  27  *  07   06   05   04   03   02   01    00
  28  * |PO2 |PO1 |A2  |A1  |A0  |    |     |     |
  29  */
  30 #define DS620_REG_CONFIG_DONE           0x8000
  31 #define DS620_REG_CONFIG_NVB            0x4000
  32 #define DS620_REG_CONFIG_THF            0x2000
  33 #define DS620_REG_CONFIG_TLF            0x1000
  34 #define DS620_REG_CONFIG_R1             0x0800
  35 #define DS620_REG_CONFIG_R0             0x0400
  36 #define DS620_REG_CONFIG_AUTOC          0x0200
  37 #define DS620_REG_CONFIG_1SHOT          0x0100
  38 #define DS620_REG_CONFIG_PO2            0x0080
  39 #define DS620_REG_CONFIG_PO1            0x0040
  40 #define DS620_REG_CONFIG_A2             0x0020
  41 #define DS620_REG_CONFIG_A1             0x0010
  42 #define DS620_REG_CONFIG_A0             0x0008
  43 
  44 /* The DS620 registers */
  45 static const u8 DS620_REG_TEMP[3] = {
  46         0xAA,                   /* input, word, RO */
  47         0xA2,                   /* min, word, RW */
  48         0xA0,                   /* max, word, RW */
  49 };
  50 
  51 #define DS620_REG_CONF          0xAC    /* word, RW */
  52 #define DS620_COM_START         0x51    /* no data */
  53 #define DS620_COM_STOP          0x22    /* no data */
  54 
  55 /* Each client has this additional data */
  56 struct ds620_data {
  57         struct i2c_client *client;
  58         struct mutex update_lock;
  59         char valid;             /* !=0 if following fields are valid */
  60         unsigned long last_updated;     /* In jiffies */
  61 
  62         s16 temp[3];            /* Register values, word */
  63 };
  64 
  65 static void ds620_init_client(struct i2c_client *client)
  66 {
  67         struct ds620_platform_data *ds620_info = dev_get_platdata(&client->dev);
  68         u16 conf, new_conf;
  69 
  70         new_conf = conf =
  71             i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
  72 
  73         /* switch to continuous conversion mode */
  74         new_conf &= ~DS620_REG_CONFIG_1SHOT;
  75         /* already high at power-on, but don't trust the BIOS! */
  76         new_conf |= DS620_REG_CONFIG_PO2;
  77         /* thermostat mode according to platform data */
  78         if (ds620_info && ds620_info->pomode == 1)
  79                 new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */
  80         else if (ds620_info && ds620_info->pomode == 2)
  81                 new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */
  82         else
  83                 new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */
  84         /* with highest precision */
  85         new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0;
  86 
  87         if (conf != new_conf)
  88                 i2c_smbus_write_word_swapped(client, DS620_REG_CONF, new_conf);
  89 
  90         /* start conversion */
  91         i2c_smbus_write_byte(client, DS620_COM_START);
  92 }
  93 
  94 static struct ds620_data *ds620_update_client(struct device *dev)
  95 {
  96         struct ds620_data *data = dev_get_drvdata(dev);
  97         struct i2c_client *client = data->client;
  98         struct ds620_data *ret = data;
  99 
 100         mutex_lock(&data->update_lock);
 101 
 102         if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 103             || !data->valid) {
 104                 int i;
 105                 int res;
 106 
 107                 dev_dbg(&client->dev, "Starting ds620 update\n");
 108 
 109                 for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
 110                         res = i2c_smbus_read_word_swapped(client,
 111                                                           DS620_REG_TEMP[i]);
 112                         if (res < 0) {
 113                                 ret = ERR_PTR(res);
 114                                 goto abort;
 115                         }
 116 
 117                         data->temp[i] = res;
 118                 }
 119 
 120                 data->last_updated = jiffies;
 121                 data->valid = 1;
 122         }
 123 abort:
 124         mutex_unlock(&data->update_lock);
 125 
 126         return ret;
 127 }
 128 
 129 static ssize_t temp_show(struct device *dev, struct device_attribute *da,
 130                          char *buf)
 131 {
 132         struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 133         struct ds620_data *data = ds620_update_client(dev);
 134 
 135         if (IS_ERR(data))
 136                 return PTR_ERR(data);
 137 
 138         return sprintf(buf, "%d\n", ((data->temp[attr->index] / 8) * 625) / 10);
 139 }
 140 
 141 static ssize_t temp_store(struct device *dev, struct device_attribute *da,
 142                           const char *buf, size_t count)
 143 {
 144         int res;
 145         long val;
 146 
 147         struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 148         struct ds620_data *data = dev_get_drvdata(dev);
 149         struct i2c_client *client = data->client;
 150 
 151         res = kstrtol(buf, 10, &val);
 152 
 153         if (res)
 154                 return res;
 155 
 156         val = (clamp_val(val, -128000, 128000) * 10 / 625) * 8;
 157 
 158         mutex_lock(&data->update_lock);
 159         data->temp[attr->index] = val;
 160         i2c_smbus_write_word_swapped(client, DS620_REG_TEMP[attr->index],
 161                                      data->temp[attr->index]);
 162         mutex_unlock(&data->update_lock);
 163         return count;
 164 }
 165 
 166 static ssize_t alarm_show(struct device *dev, struct device_attribute *da,
 167                           char *buf)
 168 {
 169         struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 170         struct ds620_data *data = ds620_update_client(dev);
 171         struct i2c_client *client;
 172         u16 conf, new_conf;
 173         int res;
 174 
 175         if (IS_ERR(data))
 176                 return PTR_ERR(data);
 177 
 178         client = data->client;
 179 
 180         /* reset alarms if necessary */
 181         res = i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
 182         if (res < 0)
 183                 return res;
 184 
 185         new_conf = conf = res;
 186         new_conf &= ~attr->index;
 187         if (conf != new_conf) {
 188                 res = i2c_smbus_write_word_swapped(client, DS620_REG_CONF,
 189                                                    new_conf);
 190                 if (res < 0)
 191                         return res;
 192         }
 193 
 194         return sprintf(buf, "%d\n", !!(conf & attr->index));
 195 }
 196 
 197 static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
 198 static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, 1);
 199 static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, 2);
 200 static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, DS620_REG_CONFIG_TLF);
 201 static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, DS620_REG_CONFIG_THF);
 202 
 203 static struct attribute *ds620_attrs[] = {
 204         &sensor_dev_attr_temp1_input.dev_attr.attr,
 205         &sensor_dev_attr_temp1_min.dev_attr.attr,
 206         &sensor_dev_attr_temp1_max.dev_attr.attr,
 207         &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
 208         &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 209         NULL
 210 };
 211 
 212 ATTRIBUTE_GROUPS(ds620);
 213 
 214 static int ds620_probe(struct i2c_client *client,
 215                        const struct i2c_device_id *id)
 216 {
 217         struct device *dev = &client->dev;
 218         struct device *hwmon_dev;
 219         struct ds620_data *data;
 220 
 221         data = devm_kzalloc(dev, sizeof(struct ds620_data), GFP_KERNEL);
 222         if (!data)
 223                 return -ENOMEM;
 224 
 225         data->client = client;
 226         mutex_init(&data->update_lock);
 227 
 228         /* Initialize the DS620 chip */
 229         ds620_init_client(client);
 230 
 231         hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 232                                                            data, ds620_groups);
 233         return PTR_ERR_OR_ZERO(hwmon_dev);
 234 }
 235 
 236 static const struct i2c_device_id ds620_id[] = {
 237         {"ds620", 0},
 238         {}
 239 };
 240 
 241 MODULE_DEVICE_TABLE(i2c, ds620_id);
 242 
 243 /* This is the driver that will be inserted */
 244 static struct i2c_driver ds620_driver = {
 245         .class = I2C_CLASS_HWMON,
 246         .driver = {
 247                    .name = "ds620",
 248         },
 249         .probe = ds620_probe,
 250         .id_table = ds620_id,
 251 };
 252 
 253 module_i2c_driver(ds620_driver);
 254 
 255 MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
 256 MODULE_DESCRIPTION("DS620 driver");
 257 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */