Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
0004  *   monitoring
0005  * This driver handles the ADT7410 and compatible digital temperature sensors.
0006  * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
0007  * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
0008  * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
0009  */
0010 
0011 #include <linux/device.h>
0012 #include <linux/module.h>
0013 #include <linux/init.h>
0014 #include <linux/slab.h>
0015 #include <linux/jiffies.h>
0016 #include <linux/hwmon.h>
0017 #include <linux/err.h>
0018 #include <linux/mutex.h>
0019 #include <linux/delay.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/regmap.h>
0022 
0023 #include "adt7x10.h"
0024 
0025 /*
0026  * ADT7X10 status
0027  */
0028 #define ADT7X10_STAT_T_LOW      (1 << 4)
0029 #define ADT7X10_STAT_T_HIGH     (1 << 5)
0030 #define ADT7X10_STAT_T_CRIT     (1 << 6)
0031 #define ADT7X10_STAT_NOT_RDY        (1 << 7)
0032 
0033 /*
0034  * ADT7X10 config
0035  */
0036 #define ADT7X10_FAULT_QUEUE_MASK    (1 << 0 | 1 << 1)
0037 #define ADT7X10_CT_POLARITY     (1 << 2)
0038 #define ADT7X10_INT_POLARITY        (1 << 3)
0039 #define ADT7X10_EVENT_MODE      (1 << 4)
0040 #define ADT7X10_MODE_MASK       (1 << 5 | 1 << 6)
0041 #define ADT7X10_FULL            (0 << 5 | 0 << 6)
0042 #define ADT7X10_PD          (1 << 5 | 1 << 6)
0043 #define ADT7X10_RESOLUTION      (1 << 7)
0044 
0045 /*
0046  * ADT7X10 masks
0047  */
0048 #define ADT7X10_T13_VALUE_MASK      0xFFF8
0049 #define ADT7X10_T_HYST_MASK     0xF
0050 
0051 /* straight from the datasheet */
0052 #define ADT7X10_TEMP_MIN (-55000)
0053 #define ADT7X10_TEMP_MAX 150000
0054 
0055 /* Each client has this additional data */
0056 struct adt7x10_data {
0057     struct regmap       *regmap;
0058     struct mutex        update_lock;
0059     u8          config;
0060     u8          oldconfig;
0061     bool            valid;      /* true if temperature valid */
0062 };
0063 
0064 enum {
0065     adt7x10_temperature = 0,
0066     adt7x10_t_alarm_high,
0067     adt7x10_t_alarm_low,
0068     adt7x10_t_crit,
0069 };
0070 
0071 static const u8 ADT7X10_REG_TEMP[] = {
0072     [adt7x10_temperature] = ADT7X10_TEMPERATURE,        /* input */
0073     [adt7x10_t_alarm_high] = ADT7X10_T_ALARM_HIGH,      /* high */
0074     [adt7x10_t_alarm_low] = ADT7X10_T_ALARM_LOW,        /* low */
0075     [adt7x10_t_crit] = ADT7X10_T_CRIT,          /* critical */
0076 };
0077 
0078 static irqreturn_t adt7x10_irq_handler(int irq, void *private)
0079 {
0080     struct device *dev = private;
0081     struct adt7x10_data *d = dev_get_drvdata(dev);
0082     unsigned int status;
0083     int ret;
0084 
0085     ret = regmap_read(d->regmap, ADT7X10_STATUS, &status);
0086     if (ret < 0)
0087         return IRQ_HANDLED;
0088 
0089     if (status & ADT7X10_STAT_T_HIGH)
0090         hwmon_notify_event(dev, hwmon_temp, hwmon_temp_max_alarm, 0);
0091     if (status & ADT7X10_STAT_T_LOW)
0092         hwmon_notify_event(dev, hwmon_temp, hwmon_temp_min_alarm, 0);
0093     if (status & ADT7X10_STAT_T_CRIT)
0094         hwmon_notify_event(dev, hwmon_temp, hwmon_temp_crit_alarm, 0);
0095 
0096     return IRQ_HANDLED;
0097 }
0098 
0099 static int adt7x10_temp_ready(struct regmap *regmap)
0100 {
0101     unsigned int status;
0102     int i, ret;
0103 
0104     for (i = 0; i < 6; i++) {
0105         ret = regmap_read(regmap, ADT7X10_STATUS, &status);
0106         if (ret < 0)
0107             return ret;
0108         if (!(status & ADT7X10_STAT_NOT_RDY))
0109             return 0;
0110         msleep(60);
0111     }
0112     return -ETIMEDOUT;
0113 }
0114 
0115 static s16 ADT7X10_TEMP_TO_REG(long temp)
0116 {
0117     return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN,
0118                        ADT7X10_TEMP_MAX) * 128, 1000);
0119 }
0120 
0121 static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg)
0122 {
0123     /* in 13 bit mode, bits 0-2 are status flags - mask them out */
0124     if (!(data->config & ADT7X10_RESOLUTION))
0125         reg &= ADT7X10_T13_VALUE_MASK;
0126     /*
0127      * temperature is stored in twos complement format, in steps of
0128      * 1/128°C
0129      */
0130     return DIV_ROUND_CLOSEST(reg * 1000, 128);
0131 }
0132 
0133 /*-----------------------------------------------------------------------*/
0134 
0135 static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val)
0136 {
0137     unsigned int regval;
0138     int ret;
0139 
0140     mutex_lock(&data->update_lock);
0141     if (index == adt7x10_temperature && !data->valid) {
0142         /* wait for valid temperature */
0143         ret = adt7x10_temp_ready(data->regmap);
0144         if (ret) {
0145             mutex_unlock(&data->update_lock);
0146             return ret;
0147         }
0148         data->valid = true;
0149     }
0150     mutex_unlock(&data->update_lock);
0151 
0152     ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &regval);
0153     if (ret)
0154         return ret;
0155 
0156     *val = ADT7X10_REG_TO_TEMP(data, regval);
0157     return 0;
0158 }
0159 
0160 static int adt7x10_temp_write(struct adt7x10_data *data, int index, long temp)
0161 {
0162     int ret;
0163 
0164     mutex_lock(&data->update_lock);
0165     ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[index],
0166                ADT7X10_TEMP_TO_REG(temp));
0167     mutex_unlock(&data->update_lock);
0168     return ret;
0169 }
0170 
0171 static int adt7x10_hyst_read(struct adt7x10_data *data, int index, long *val)
0172 {
0173     int hyst, temp, ret;
0174 
0175     mutex_lock(&data->update_lock);
0176     ret = regmap_read(data->regmap, ADT7X10_T_HYST, &hyst);
0177     if (ret) {
0178         mutex_unlock(&data->update_lock);
0179         return ret;
0180     }
0181 
0182     ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &temp);
0183     mutex_unlock(&data->update_lock);
0184     if (ret)
0185         return ret;
0186 
0187     hyst = (hyst & ADT7X10_T_HYST_MASK) * 1000;
0188 
0189     /*
0190      * hysteresis is stored as a 4 bit offset in the device, convert it
0191      * to an absolute value
0192      */
0193     /* min has positive offset, others have negative */
0194     if (index == adt7x10_t_alarm_low)
0195         hyst = -hyst;
0196 
0197     *val = ADT7X10_REG_TO_TEMP(data, temp) - hyst;
0198     return 0;
0199 }
0200 
0201 static int adt7x10_hyst_write(struct adt7x10_data *data, long hyst)
0202 {
0203     unsigned int regval;
0204     int limit, ret;
0205 
0206     mutex_lock(&data->update_lock);
0207 
0208     /* convert absolute hysteresis value to a 4 bit delta value */
0209     ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, &regval);
0210     if (ret < 0)
0211         goto abort;
0212 
0213     limit = ADT7X10_REG_TO_TEMP(data, regval);
0214 
0215     hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
0216     regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
0217                ADT7X10_T_HYST_MASK);
0218     ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval);
0219 abort:
0220     mutex_unlock(&data->update_lock);
0221     return ret;
0222 }
0223 
0224 static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val)
0225 {
0226     unsigned int status;
0227     int ret;
0228 
0229     ret = regmap_read(data->regmap, ADT7X10_STATUS, &status);
0230     if (ret < 0)
0231         return ret;
0232 
0233     *val = !!(status & index);
0234 
0235     return 0;
0236 }
0237 
0238 static umode_t adt7x10_is_visible(const void *data,
0239                   enum hwmon_sensor_types type,
0240                   u32 attr, int channel)
0241 {
0242     switch (attr) {
0243     case hwmon_temp_max:
0244     case hwmon_temp_min:
0245     case hwmon_temp_crit:
0246     case hwmon_temp_max_hyst:
0247         return 0644;
0248     case hwmon_temp_input:
0249     case hwmon_temp_min_alarm:
0250     case hwmon_temp_max_alarm:
0251     case hwmon_temp_crit_alarm:
0252     case hwmon_temp_min_hyst:
0253     case hwmon_temp_crit_hyst:
0254         return 0444;
0255     default:
0256         break;
0257     }
0258 
0259     return 0;
0260 }
0261 
0262 static int adt7x10_read(struct device *dev, enum hwmon_sensor_types type,
0263             u32 attr, int channel, long *val)
0264 {
0265     struct adt7x10_data *data = dev_get_drvdata(dev);
0266 
0267     switch (attr) {
0268     case hwmon_temp_input:
0269         return adt7x10_temp_read(data, adt7x10_temperature, val);
0270     case hwmon_temp_max:
0271         return adt7x10_temp_read(data, adt7x10_t_alarm_high, val);
0272     case hwmon_temp_min:
0273         return adt7x10_temp_read(data, adt7x10_t_alarm_low, val);
0274     case hwmon_temp_crit:
0275         return adt7x10_temp_read(data, adt7x10_t_crit, val);
0276     case hwmon_temp_max_hyst:
0277         return adt7x10_hyst_read(data, adt7x10_t_alarm_high, val);
0278     case hwmon_temp_min_hyst:
0279         return adt7x10_hyst_read(data, adt7x10_t_alarm_low, val);
0280     case hwmon_temp_crit_hyst:
0281         return adt7x10_hyst_read(data, adt7x10_t_crit, val);
0282     case hwmon_temp_min_alarm:
0283         return adt7x10_alarm_read(data, ADT7X10_STAT_T_LOW, val);
0284     case hwmon_temp_max_alarm:
0285         return adt7x10_alarm_read(data, ADT7X10_STAT_T_HIGH, val);
0286     case hwmon_temp_crit_alarm:
0287         return adt7x10_alarm_read(data, ADT7X10_STAT_T_CRIT, val);
0288     default:
0289         return -EOPNOTSUPP;
0290     }
0291 }
0292 
0293 static int adt7x10_write(struct device *dev, enum hwmon_sensor_types type,
0294              u32 attr, int channel, long val)
0295 {
0296     struct adt7x10_data *data = dev_get_drvdata(dev);
0297 
0298     switch (attr) {
0299     case hwmon_temp_max:
0300         return adt7x10_temp_write(data, adt7x10_t_alarm_high, val);
0301     case hwmon_temp_min:
0302         return adt7x10_temp_write(data, adt7x10_t_alarm_low, val);
0303     case hwmon_temp_crit:
0304         return adt7x10_temp_write(data, adt7x10_t_crit, val);
0305     case hwmon_temp_max_hyst:
0306         return adt7x10_hyst_write(data, val);
0307     default:
0308         return -EOPNOTSUPP;
0309     }
0310 }
0311 
0312 static const struct hwmon_channel_info *adt7x10_info[] = {
0313     HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0314                HWMON_T_CRIT | HWMON_T_MAX_HYST | HWMON_T_MIN_HYST |
0315                HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
0316                HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM),
0317     NULL,
0318 };
0319 
0320 static const struct hwmon_ops adt7x10_hwmon_ops = {
0321     .is_visible = adt7x10_is_visible,
0322     .read = adt7x10_read,
0323     .write = adt7x10_write,
0324 };
0325 
0326 static const struct hwmon_chip_info adt7x10_chip_info = {
0327     .ops = &adt7x10_hwmon_ops,
0328     .info = adt7x10_info,
0329 };
0330 
0331 static void adt7x10_restore_config(void *private)
0332 {
0333     struct adt7x10_data *data = private;
0334 
0335     regmap_write(data->regmap, ADT7X10_CONFIG, data->oldconfig);
0336 }
0337 
0338 int adt7x10_probe(struct device *dev, const char *name, int irq,
0339           struct regmap *regmap)
0340 {
0341     struct adt7x10_data *data;
0342     unsigned int config;
0343     struct device *hdev;
0344     int ret;
0345 
0346     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0347     if (!data)
0348         return -ENOMEM;
0349 
0350     data->regmap = regmap;
0351 
0352     dev_set_drvdata(dev, data);
0353     mutex_init(&data->update_lock);
0354 
0355     /* configure as specified */
0356     ret = regmap_read(regmap, ADT7X10_CONFIG, &config);
0357     if (ret < 0) {
0358         dev_dbg(dev, "Can't read config? %d\n", ret);
0359         return ret;
0360     }
0361     data->oldconfig = config;
0362 
0363     /*
0364      * Set to 16 bit resolution, continous conversion and comparator mode.
0365      */
0366     data->config = data->oldconfig;
0367     data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY |
0368             ADT7X10_INT_POLARITY);
0369     data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE;
0370 
0371     if (data->config != data->oldconfig) {
0372         ret = regmap_write(regmap, ADT7X10_CONFIG, data->config);
0373         if (ret)
0374             return ret;
0375         ret = devm_add_action_or_reset(dev, adt7x10_restore_config, data);
0376         if (ret)
0377             return ret;
0378     }
0379     dev_dbg(dev, "Config %02x\n", data->config);
0380 
0381     hdev = devm_hwmon_device_register_with_info(dev, name, data,
0382                             &adt7x10_chip_info, NULL);
0383     if (IS_ERR(hdev))
0384         return PTR_ERR(hdev);
0385 
0386     if (irq > 0) {
0387         ret = devm_request_threaded_irq(dev, irq, NULL,
0388                         adt7x10_irq_handler,
0389                         IRQF_TRIGGER_FALLING |
0390                         IRQF_ONESHOT,
0391                         dev_name(dev), hdev);
0392         if (ret)
0393             return ret;
0394     }
0395 
0396     return 0;
0397 }
0398 EXPORT_SYMBOL_GPL(adt7x10_probe);
0399 
0400 #ifdef CONFIG_PM_SLEEP
0401 
0402 static int adt7x10_suspend(struct device *dev)
0403 {
0404     struct adt7x10_data *data = dev_get_drvdata(dev);
0405 
0406     return regmap_write(data->regmap, ADT7X10_CONFIG,
0407                 data->config | ADT7X10_PD);
0408 }
0409 
0410 static int adt7x10_resume(struct device *dev)
0411 {
0412     struct adt7x10_data *data = dev_get_drvdata(dev);
0413 
0414     return regmap_write(data->regmap, ADT7X10_CONFIG, data->config);
0415 }
0416 
0417 SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume);
0418 EXPORT_SYMBOL_GPL(adt7x10_dev_pm_ops);
0419 
0420 #endif /* CONFIG_PM_SLEEP */
0421 
0422 MODULE_AUTHOR("Hartmut Knaack");
0423 MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
0424 MODULE_LICENSE("GPL");