Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * lm77.c - Part of lm_sensors, Linux kernel modules for hardware
0004  *      monitoring
0005  *
0006  * Copyright (c) 2004  Andras BALI <drewie@freemail.hu>
0007  *
0008  * Heavily based on lm75.c by Frodo Looijaard <frodol@dds.nl>.  The LM77
0009  * is a temperature sensor and thermal window comparator with 0.5 deg
0010  * resolution made by National Semiconductor.  Complete datasheet can be
0011  * obtained at their site:
0012  *  http://www.national.com/pf/LM/LM77.html
0013  */
0014 
0015 #include <linux/module.h>
0016 #include <linux/init.h>
0017 #include <linux/slab.h>
0018 #include <linux/jiffies.h>
0019 #include <linux/i2c.h>
0020 #include <linux/hwmon.h>
0021 #include <linux/hwmon-sysfs.h>
0022 #include <linux/err.h>
0023 #include <linux/mutex.h>
0024 
0025 /* Addresses to scan */
0026 static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
0027                         I2C_CLIENT_END };
0028 
0029 /* The LM77 registers */
0030 #define LM77_REG_TEMP       0x00
0031 #define LM77_REG_CONF       0x01
0032 #define LM77_REG_TEMP_HYST  0x02
0033 #define LM77_REG_TEMP_CRIT  0x03
0034 #define LM77_REG_TEMP_MIN   0x04
0035 #define LM77_REG_TEMP_MAX   0x05
0036 
0037 enum temp_index {
0038     t_input = 0,
0039     t_crit,
0040     t_min,
0041     t_max,
0042     t_hyst,
0043     t_num_temp
0044 };
0045 
0046 static const u8 temp_regs[t_num_temp] = {
0047     [t_input] = LM77_REG_TEMP,
0048     [t_min] = LM77_REG_TEMP_MIN,
0049     [t_max] = LM77_REG_TEMP_MAX,
0050     [t_crit] = LM77_REG_TEMP_CRIT,
0051     [t_hyst] = LM77_REG_TEMP_HYST,
0052 };
0053 
0054 /* Each client has this additional data */
0055 struct lm77_data {
0056     struct i2c_client   *client;
0057     struct mutex        update_lock;
0058     bool            valid;
0059     unsigned long       last_updated;   /* In jiffies */
0060     int         temp[t_num_temp]; /* index using temp_index */
0061     u8          alarms;
0062 };
0063 
0064 /* straight from the datasheet */
0065 #define LM77_TEMP_MIN (-55000)
0066 #define LM77_TEMP_MAX 125000
0067 
0068 /*
0069  * In the temperature registers, the low 3 bits are not part of the
0070  * temperature values; they are the status bits.
0071  */
0072 static inline s16 LM77_TEMP_TO_REG(int temp)
0073 {
0074     return (temp / 500) * 8;
0075 }
0076 
0077 static inline int LM77_TEMP_FROM_REG(s16 reg)
0078 {
0079     return (reg / 8) * 500;
0080 }
0081 
0082 /*
0083  * All registers are word-sized, except for the configuration register.
0084  * The LM77 uses the high-byte first convention.
0085  */
0086 static u16 lm77_read_value(struct i2c_client *client, u8 reg)
0087 {
0088     if (reg == LM77_REG_CONF)
0089         return i2c_smbus_read_byte_data(client, reg);
0090     else
0091         return i2c_smbus_read_word_swapped(client, reg);
0092 }
0093 
0094 static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
0095 {
0096     if (reg == LM77_REG_CONF)
0097         return i2c_smbus_write_byte_data(client, reg, value);
0098     else
0099         return i2c_smbus_write_word_swapped(client, reg, value);
0100 }
0101 
0102 static struct lm77_data *lm77_update_device(struct device *dev)
0103 {
0104     struct lm77_data *data = dev_get_drvdata(dev);
0105     struct i2c_client *client = data->client;
0106     int i;
0107 
0108     mutex_lock(&data->update_lock);
0109 
0110     if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
0111         || !data->valid) {
0112         dev_dbg(&client->dev, "Starting lm77 update\n");
0113         for (i = 0; i < t_num_temp; i++) {
0114             data->temp[i] =
0115               LM77_TEMP_FROM_REG(lm77_read_value(client,
0116                                  temp_regs[i]));
0117         }
0118         data->alarms =
0119             lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
0120         data->last_updated = jiffies;
0121         data->valid = true;
0122     }
0123 
0124     mutex_unlock(&data->update_lock);
0125 
0126     return data;
0127 }
0128 
0129 /* sysfs stuff */
0130 
0131 static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
0132              char *buf)
0133 {
0134     struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0135     struct lm77_data *data = lm77_update_device(dev);
0136 
0137     return sprintf(buf, "%d\n", data->temp[attr->index]);
0138 }
0139 
0140 static ssize_t temp_hyst_show(struct device *dev,
0141                   struct device_attribute *devattr, char *buf)
0142 {
0143     struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0144     struct lm77_data *data = lm77_update_device(dev);
0145     int nr = attr->index;
0146     int temp;
0147 
0148     temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] :
0149                  data->temp[nr] - data->temp[t_hyst];
0150 
0151     return sprintf(buf, "%d\n", temp);
0152 }
0153 
0154 static ssize_t temp_store(struct device *dev,
0155               struct device_attribute *devattr, const char *buf,
0156               size_t count)
0157 {
0158     struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0159     struct lm77_data *data = dev_get_drvdata(dev);
0160     struct i2c_client *client = data->client;
0161     int nr = attr->index;
0162     long val;
0163     int err;
0164 
0165     err = kstrtol(buf, 10, &val);
0166     if (err)
0167         return err;
0168 
0169     val = clamp_val(val, LM77_TEMP_MIN, LM77_TEMP_MAX);
0170     mutex_lock(&data->update_lock);
0171     data->temp[nr] = val;
0172     lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val));
0173     mutex_unlock(&data->update_lock);
0174     return count;
0175 }
0176 
0177 /*
0178  * hysteresis is stored as a relative value on the chip, so it has to be
0179  * converted first.
0180  */
0181 static ssize_t temp_hyst_store(struct device *dev,
0182                    struct device_attribute *devattr,
0183                    const char *buf, size_t count)
0184 {
0185     struct lm77_data *data = dev_get_drvdata(dev);
0186     struct i2c_client *client = data->client;
0187     long val;
0188     int err;
0189 
0190     err = kstrtol(buf, 10, &val);
0191     if (err)
0192         return err;
0193 
0194     mutex_lock(&data->update_lock);
0195     val = clamp_val(data->temp[t_crit] - val, LM77_TEMP_MIN, LM77_TEMP_MAX);
0196     data->temp[t_hyst] = val;
0197     lm77_write_value(client, LM77_REG_TEMP_HYST,
0198              LM77_TEMP_TO_REG(data->temp[t_hyst]));
0199     mutex_unlock(&data->update_lock);
0200     return count;
0201 }
0202 
0203 static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
0204               char *buf)
0205 {
0206     int bitnr = to_sensor_dev_attr(attr)->index;
0207     struct lm77_data *data = lm77_update_device(dev);
0208     return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
0209 }
0210 
0211 static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, t_input);
0212 static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp, t_crit);
0213 static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, t_min);
0214 static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, t_max);
0215 
0216 static SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, temp_hyst, t_crit);
0217 static SENSOR_DEVICE_ATTR_RO(temp1_min_hyst, temp_hyst, t_min);
0218 static SENSOR_DEVICE_ATTR_RO(temp1_max_hyst, temp_hyst, t_max);
0219 
0220 static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 2);
0221 static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 0);
0222 static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 1);
0223 
0224 static struct attribute *lm77_attrs[] = {
0225     &sensor_dev_attr_temp1_input.dev_attr.attr,
0226     &sensor_dev_attr_temp1_crit.dev_attr.attr,
0227     &sensor_dev_attr_temp1_min.dev_attr.attr,
0228     &sensor_dev_attr_temp1_max.dev_attr.attr,
0229     &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
0230     &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
0231     &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
0232     &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
0233     &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
0234     &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
0235     NULL
0236 };
0237 ATTRIBUTE_GROUPS(lm77);
0238 
0239 /* Return 0 if detection is successful, -ENODEV otherwise */
0240 static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
0241 {
0242     struct i2c_adapter *adapter = client->adapter;
0243     int i, cur, conf, hyst, crit, min, max;
0244 
0245     if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
0246                      I2C_FUNC_SMBUS_WORD_DATA))
0247         return -ENODEV;
0248 
0249     /*
0250      * Here comes the remaining detection.  Since the LM77 has no
0251      * register dedicated to identification, we have to rely on the
0252      * following tricks:
0253      *
0254      * 1. the high 4 bits represent the sign and thus they should
0255      *    always be the same
0256      * 2. the high 3 bits are unused in the configuration register
0257      * 3. addresses 0x06 and 0x07 return the last read value
0258      * 4. registers cycling over 8-address boundaries
0259      *
0260      * Word-sized registers are high-byte first.
0261      */
0262 
0263     /* addresses cycling */
0264     cur = i2c_smbus_read_word_data(client, 0);
0265     conf = i2c_smbus_read_byte_data(client, 1);
0266     hyst = i2c_smbus_read_word_data(client, 2);
0267     crit = i2c_smbus_read_word_data(client, 3);
0268     min = i2c_smbus_read_word_data(client, 4);
0269     max = i2c_smbus_read_word_data(client, 5);
0270     for (i = 8; i <= 0xff; i += 8) {
0271         if (i2c_smbus_read_byte_data(client, i + 1) != conf
0272          || i2c_smbus_read_word_data(client, i + 2) != hyst
0273          || i2c_smbus_read_word_data(client, i + 3) != crit
0274          || i2c_smbus_read_word_data(client, i + 4) != min
0275          || i2c_smbus_read_word_data(client, i + 5) != max)
0276             return -ENODEV;
0277     }
0278 
0279     /* sign bits */
0280     if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
0281      || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0)
0282      || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
0283      || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
0284      || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
0285         return -ENODEV;
0286 
0287     /* unused bits */
0288     if (conf & 0xe0)
0289         return -ENODEV;
0290 
0291     /* 0x06 and 0x07 return the last read value */
0292     cur = i2c_smbus_read_word_data(client, 0);
0293     if (i2c_smbus_read_word_data(client, 6) != cur
0294      || i2c_smbus_read_word_data(client, 7) != cur)
0295         return -ENODEV;
0296     hyst = i2c_smbus_read_word_data(client, 2);
0297     if (i2c_smbus_read_word_data(client, 6) != hyst
0298      || i2c_smbus_read_word_data(client, 7) != hyst)
0299         return -ENODEV;
0300     min = i2c_smbus_read_word_data(client, 4);
0301     if (i2c_smbus_read_word_data(client, 6) != min
0302      || i2c_smbus_read_word_data(client, 7) != min)
0303         return -ENODEV;
0304 
0305     strlcpy(info->type, "lm77", I2C_NAME_SIZE);
0306 
0307     return 0;
0308 }
0309 
0310 static void lm77_init_client(struct i2c_client *client)
0311 {
0312     /* Initialize the LM77 chip - turn off shutdown mode */
0313     int conf = lm77_read_value(client, LM77_REG_CONF);
0314     if (conf & 1)
0315         lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
0316 }
0317 
0318 static int lm77_probe(struct i2c_client *client)
0319 {
0320     struct device *dev = &client->dev;
0321     struct device *hwmon_dev;
0322     struct lm77_data *data;
0323 
0324     data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
0325     if (!data)
0326         return -ENOMEM;
0327 
0328     data->client = client;
0329     mutex_init(&data->update_lock);
0330 
0331     /* Initialize the LM77 chip */
0332     lm77_init_client(client);
0333 
0334     hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
0335                                data, lm77_groups);
0336     return PTR_ERR_OR_ZERO(hwmon_dev);
0337 }
0338 
0339 static const struct i2c_device_id lm77_id[] = {
0340     { "lm77", 0 },
0341     { }
0342 };
0343 MODULE_DEVICE_TABLE(i2c, lm77_id);
0344 
0345 /* This is the driver that will be inserted */
0346 static struct i2c_driver lm77_driver = {
0347     .class      = I2C_CLASS_HWMON,
0348     .driver = {
0349         .name   = "lm77",
0350     },
0351     .probe_new  = lm77_probe,
0352     .id_table   = lm77_id,
0353     .detect     = lm77_detect,
0354     .address_list   = normal_i2c,
0355 };
0356 
0357 module_i2c_driver(lm77_driver);
0358 
0359 MODULE_AUTHOR("Andras BALI <drewie@freemail.hu>");
0360 MODULE_DESCRIPTION("LM77 driver");
0361 MODULE_LICENSE("GPL");