Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  ds620.c - Support for temperature sensor and thermostat DS620
0004  *
0005  *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
0006  *
0007  *  based on ds1621.c by Christian W. Zuckschwerdt  <zany@triq.net>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/init.h>
0012 #include <linux/slab.h>
0013 #include <linux/jiffies.h>
0014 #include <linux/i2c.h>
0015 #include <linux/hwmon.h>
0016 #include <linux/hwmon-sysfs.h>
0017 #include <linux/err.h>
0018 #include <linux/mutex.h>
0019 #include <linux/sysfs.h>
0020 #include <linux/platform_data/ds620.h>
0021 
0022 /*
0023  * Many DS620 constants specified below
0024  *  15   14   13   12   11   10   09    08
0025  * |Done|NVB |THF |TLF |R1  |R0  |AUTOC|1SHOT|
0026  *
0027  *  07   06   05   04   03   02   01    00
0028  * |PO2 |PO1 |A2  |A1  |A0  |    |     |     |
0029  */
0030 #define DS620_REG_CONFIG_DONE       0x8000
0031 #define DS620_REG_CONFIG_NVB        0x4000
0032 #define DS620_REG_CONFIG_THF        0x2000
0033 #define DS620_REG_CONFIG_TLF        0x1000
0034 #define DS620_REG_CONFIG_R1     0x0800
0035 #define DS620_REG_CONFIG_R0     0x0400
0036 #define DS620_REG_CONFIG_AUTOC      0x0200
0037 #define DS620_REG_CONFIG_1SHOT      0x0100
0038 #define DS620_REG_CONFIG_PO2        0x0080
0039 #define DS620_REG_CONFIG_PO1        0x0040
0040 #define DS620_REG_CONFIG_A2     0x0020
0041 #define DS620_REG_CONFIG_A1     0x0010
0042 #define DS620_REG_CONFIG_A0     0x0008
0043 
0044 /* The DS620 registers */
0045 static const u8 DS620_REG_TEMP[3] = {
0046     0xAA,           /* input, word, RO */
0047     0xA2,           /* min, word, RW */
0048     0xA0,           /* max, word, RW */
0049 };
0050 
0051 #define DS620_REG_CONF      0xAC    /* word, RW */
0052 #define DS620_COM_START     0x51    /* no data */
0053 #define DS620_COM_STOP      0x22    /* no data */
0054 
0055 /* Each client has this additional data */
0056 struct ds620_data {
0057     struct i2c_client *client;
0058     struct mutex update_lock;
0059     bool valid;     /* true if following fields are valid */
0060     unsigned long last_updated; /* In jiffies */
0061 
0062     s16 temp[3];        /* Register values, word */
0063 };
0064 
0065 static void ds620_init_client(struct i2c_client *client)
0066 {
0067     struct ds620_platform_data *ds620_info = dev_get_platdata(&client->dev);
0068     u16 conf, new_conf;
0069 
0070     new_conf = conf =
0071         i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
0072 
0073     /* switch to continuous conversion mode */
0074     new_conf &= ~DS620_REG_CONFIG_1SHOT;
0075     /* already high at power-on, but don't trust the BIOS! */
0076     new_conf |= DS620_REG_CONFIG_PO2;
0077     /* thermostat mode according to platform data */
0078     if (ds620_info && ds620_info->pomode == 1)
0079         new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */
0080     else if (ds620_info && ds620_info->pomode == 2)
0081         new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */
0082     else
0083         new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */
0084     /* with highest precision */
0085     new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0;
0086 
0087     if (conf != new_conf)
0088         i2c_smbus_write_word_swapped(client, DS620_REG_CONF, new_conf);
0089 
0090     /* start conversion */
0091     i2c_smbus_write_byte(client, DS620_COM_START);
0092 }
0093 
0094 static struct ds620_data *ds620_update_client(struct device *dev)
0095 {
0096     struct ds620_data *data = dev_get_drvdata(dev);
0097     struct i2c_client *client = data->client;
0098     struct ds620_data *ret = data;
0099 
0100     mutex_lock(&data->update_lock);
0101 
0102     if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
0103         || !data->valid) {
0104         int i;
0105         int res;
0106 
0107         dev_dbg(&client->dev, "Starting ds620 update\n");
0108 
0109         for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
0110             res = i2c_smbus_read_word_swapped(client,
0111                               DS620_REG_TEMP[i]);
0112             if (res < 0) {
0113                 ret = ERR_PTR(res);
0114                 goto abort;
0115             }
0116 
0117             data->temp[i] = res;
0118         }
0119 
0120         data->last_updated = jiffies;
0121         data->valid = true;
0122     }
0123 abort:
0124     mutex_unlock(&data->update_lock);
0125 
0126     return ret;
0127 }
0128 
0129 static ssize_t temp_show(struct device *dev, struct device_attribute *da,
0130              char *buf)
0131 {
0132     struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
0133     struct ds620_data *data = ds620_update_client(dev);
0134 
0135     if (IS_ERR(data))
0136         return PTR_ERR(data);
0137 
0138     return sprintf(buf, "%d\n", ((data->temp[attr->index] / 8) * 625) / 10);
0139 }
0140 
0141 static ssize_t temp_store(struct device *dev, struct device_attribute *da,
0142               const char *buf, size_t count)
0143 {
0144     int res;
0145     long val;
0146 
0147     struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
0148     struct ds620_data *data = dev_get_drvdata(dev);
0149     struct i2c_client *client = data->client;
0150 
0151     res = kstrtol(buf, 10, &val);
0152 
0153     if (res)
0154         return res;
0155 
0156     val = (clamp_val(val, -128000, 128000) * 10 / 625) * 8;
0157 
0158     mutex_lock(&data->update_lock);
0159     data->temp[attr->index] = val;
0160     i2c_smbus_write_word_swapped(client, DS620_REG_TEMP[attr->index],
0161                      data->temp[attr->index]);
0162     mutex_unlock(&data->update_lock);
0163     return count;
0164 }
0165 
0166 static ssize_t alarm_show(struct device *dev, struct device_attribute *da,
0167               char *buf)
0168 {
0169     struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
0170     struct ds620_data *data = ds620_update_client(dev);
0171     struct i2c_client *client;
0172     u16 conf, new_conf;
0173     int res;
0174 
0175     if (IS_ERR(data))
0176         return PTR_ERR(data);
0177 
0178     client = data->client;
0179 
0180     /* reset alarms if necessary */
0181     res = i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
0182     if (res < 0)
0183         return res;
0184 
0185     new_conf = conf = res;
0186     new_conf &= ~attr->index;
0187     if (conf != new_conf) {
0188         res = i2c_smbus_write_word_swapped(client, DS620_REG_CONF,
0189                            new_conf);
0190         if (res < 0)
0191             return res;
0192     }
0193 
0194     return sprintf(buf, "%d\n", !!(conf & attr->index));
0195 }
0196 
0197 static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
0198 static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, 1);
0199 static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, 2);
0200 static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, DS620_REG_CONFIG_TLF);
0201 static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, DS620_REG_CONFIG_THF);
0202 
0203 static struct attribute *ds620_attrs[] = {
0204     &sensor_dev_attr_temp1_input.dev_attr.attr,
0205     &sensor_dev_attr_temp1_min.dev_attr.attr,
0206     &sensor_dev_attr_temp1_max.dev_attr.attr,
0207     &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
0208     &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
0209     NULL
0210 };
0211 
0212 ATTRIBUTE_GROUPS(ds620);
0213 
0214 static int ds620_probe(struct i2c_client *client)
0215 {
0216     struct device *dev = &client->dev;
0217     struct device *hwmon_dev;
0218     struct ds620_data *data;
0219 
0220     data = devm_kzalloc(dev, sizeof(struct ds620_data), GFP_KERNEL);
0221     if (!data)
0222         return -ENOMEM;
0223 
0224     data->client = client;
0225     mutex_init(&data->update_lock);
0226 
0227     /* Initialize the DS620 chip */
0228     ds620_init_client(client);
0229 
0230     hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
0231                                data, ds620_groups);
0232     return PTR_ERR_OR_ZERO(hwmon_dev);
0233 }
0234 
0235 static const struct i2c_device_id ds620_id[] = {
0236     {"ds620", 0},
0237     {}
0238 };
0239 
0240 MODULE_DEVICE_TABLE(i2c, ds620_id);
0241 
0242 /* This is the driver that will be inserted */
0243 static struct i2c_driver ds620_driver = {
0244     .class = I2C_CLASS_HWMON,
0245     .driver = {
0246            .name = "ds620",
0247     },
0248     .probe_new = ds620_probe,
0249     .id_table = ds620_id,
0250 };
0251 
0252 module_i2c_driver(ds620_driver);
0253 
0254 MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
0255 MODULE_DESCRIPTION("DS620 driver");
0256 MODULE_LICENSE("GPL");