116d60ba8SDaniel Matyas // SPDX-License-Identifier: GPL-2.0
216d60ba8SDaniel Matyas /*
316d60ba8SDaniel Matyas * max31827.c - Support for Maxim Low-Power Switch
416d60ba8SDaniel Matyas *
516d60ba8SDaniel Matyas * Copyright (c) 2023 Daniel Matyas <daniel.matyas@analog.com>
616d60ba8SDaniel Matyas */
716d60ba8SDaniel Matyas
816d60ba8SDaniel Matyas #include <linux/bitfield.h>
916d60ba8SDaniel Matyas #include <linux/bitops.h>
1016d60ba8SDaniel Matyas #include <linux/delay.h>
1116d60ba8SDaniel Matyas #include <linux/hwmon.h>
1216d60ba8SDaniel Matyas #include <linux/i2c.h>
1316d60ba8SDaniel Matyas #include <linux/mutex.h>
1416d60ba8SDaniel Matyas #include <linux/regmap.h>
1516d60ba8SDaniel Matyas
1616d60ba8SDaniel Matyas #define MAX31827_T_REG 0x0
1716d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_REG 0x2
1816d60ba8SDaniel Matyas #define MAX31827_TH_REG 0x4
1916d60ba8SDaniel Matyas #define MAX31827_TL_REG 0x6
2016d60ba8SDaniel Matyas #define MAX31827_TH_HYST_REG 0x8
2116d60ba8SDaniel Matyas #define MAX31827_TL_HYST_REG 0xA
2216d60ba8SDaniel Matyas
2316d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_1SHOT_MASK BIT(0)
2416d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_CNV_RATE_MASK GENMASK(3, 1)
2516d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK BIT(14)
2616d60ba8SDaniel Matyas #define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK BIT(15)
2716d60ba8SDaniel Matyas
2816d60ba8SDaniel Matyas #define MAX31827_12_BIT_CNV_TIME 141
2916d60ba8SDaniel Matyas
3016d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_64_HZ 0x1
3116d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_32_HZ 0x2
3216d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_16_HZ 0x3
3316d60ba8SDaniel Matyas #define MAX31827_CNV_1_DIV_4_HZ 0x4
3416d60ba8SDaniel Matyas #define MAX31827_CNV_1_HZ 0x5
3516d60ba8SDaniel Matyas #define MAX31827_CNV_4_HZ 0x6
3616d60ba8SDaniel Matyas #define MAX31827_CNV_8_HZ 0x7
3716d60ba8SDaniel Matyas
3816d60ba8SDaniel Matyas #define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16)
3916d60ba8SDaniel Matyas #define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000)
4016d60ba8SDaniel Matyas #define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0)
4116d60ba8SDaniel Matyas
4216d60ba8SDaniel Matyas struct max31827_state {
4316d60ba8SDaniel Matyas /*
4416d60ba8SDaniel Matyas * Prevent simultaneous access to the i2c client.
4516d60ba8SDaniel Matyas */
4616d60ba8SDaniel Matyas struct mutex lock;
4716d60ba8SDaniel Matyas struct regmap *regmap;
4816d60ba8SDaniel Matyas bool enable;
4916d60ba8SDaniel Matyas };
5016d60ba8SDaniel Matyas
5116d60ba8SDaniel Matyas static const struct regmap_config max31827_regmap = {
5216d60ba8SDaniel Matyas .reg_bits = 8,
5316d60ba8SDaniel Matyas .val_bits = 16,
5416d60ba8SDaniel Matyas .max_register = 0xA,
5516d60ba8SDaniel Matyas };
5616d60ba8SDaniel Matyas
write_alarm_val(struct max31827_state * st,unsigned int reg,long val)5716d60ba8SDaniel Matyas static int write_alarm_val(struct max31827_state *st, unsigned int reg,
5816d60ba8SDaniel Matyas long val)
5916d60ba8SDaniel Matyas {
6016d60ba8SDaniel Matyas unsigned int cfg;
6116d60ba8SDaniel Matyas unsigned int tmp;
6216d60ba8SDaniel Matyas int ret;
6316d60ba8SDaniel Matyas
6416d60ba8SDaniel Matyas val = MAX31827_M_DGR_TO_16_BIT(val);
6516d60ba8SDaniel Matyas
6616d60ba8SDaniel Matyas /*
6716d60ba8SDaniel Matyas * Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold
6816d60ba8SDaniel Matyas * register values are changed over I2C, the part must be in shutdown
6916d60ba8SDaniel Matyas * mode.
7016d60ba8SDaniel Matyas *
7116d60ba8SDaniel Matyas * Mutex is used to ensure, that some other process doesn't change the
7216d60ba8SDaniel Matyas * configuration register.
7316d60ba8SDaniel Matyas */
7416d60ba8SDaniel Matyas mutex_lock(&st->lock);
7516d60ba8SDaniel Matyas
7616d60ba8SDaniel Matyas if (!st->enable) {
7716d60ba8SDaniel Matyas ret = regmap_write(st->regmap, reg, val);
7816d60ba8SDaniel Matyas goto unlock;
7916d60ba8SDaniel Matyas }
8016d60ba8SDaniel Matyas
8116d60ba8SDaniel Matyas ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg);
8216d60ba8SDaniel Matyas if (ret)
8316d60ba8SDaniel Matyas goto unlock;
8416d60ba8SDaniel Matyas
8516d60ba8SDaniel Matyas tmp = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK |
8616d60ba8SDaniel Matyas MAX31827_CONFIGURATION_CNV_RATE_MASK);
8716d60ba8SDaniel Matyas ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, tmp);
8816d60ba8SDaniel Matyas if (ret)
8916d60ba8SDaniel Matyas goto unlock;
9016d60ba8SDaniel Matyas
9116d60ba8SDaniel Matyas ret = regmap_write(st->regmap, reg, val);
9216d60ba8SDaniel Matyas if (ret)
9316d60ba8SDaniel Matyas goto unlock;
9416d60ba8SDaniel Matyas
9516d60ba8SDaniel Matyas ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
9616d60ba8SDaniel Matyas
9716d60ba8SDaniel Matyas unlock:
9816d60ba8SDaniel Matyas mutex_unlock(&st->lock);
9916d60ba8SDaniel Matyas return ret;
10016d60ba8SDaniel Matyas }
10116d60ba8SDaniel Matyas
max31827_is_visible(const void * state,enum hwmon_sensor_types type,u32 attr,int channel)10216d60ba8SDaniel Matyas static umode_t max31827_is_visible(const void *state,
10316d60ba8SDaniel Matyas enum hwmon_sensor_types type, u32 attr,
10416d60ba8SDaniel Matyas int channel)
10516d60ba8SDaniel Matyas {
10616d60ba8SDaniel Matyas if (type == hwmon_temp) {
10716d60ba8SDaniel Matyas switch (attr) {
10816d60ba8SDaniel Matyas case hwmon_temp_enable:
10916d60ba8SDaniel Matyas case hwmon_temp_max:
11016d60ba8SDaniel Matyas case hwmon_temp_min:
11116d60ba8SDaniel Matyas case hwmon_temp_max_hyst:
11216d60ba8SDaniel Matyas case hwmon_temp_min_hyst:
11316d60ba8SDaniel Matyas return 0644;
11416d60ba8SDaniel Matyas case hwmon_temp_input:
11516d60ba8SDaniel Matyas case hwmon_temp_min_alarm:
11616d60ba8SDaniel Matyas case hwmon_temp_max_alarm:
11716d60ba8SDaniel Matyas return 0444;
11816d60ba8SDaniel Matyas default:
11916d60ba8SDaniel Matyas return 0;
12016d60ba8SDaniel Matyas }
12116d60ba8SDaniel Matyas } else if (type == hwmon_chip) {
12216d60ba8SDaniel Matyas if (attr == hwmon_chip_update_interval)
12316d60ba8SDaniel Matyas return 0644;
12416d60ba8SDaniel Matyas }
12516d60ba8SDaniel Matyas
12616d60ba8SDaniel Matyas return 0;
12716d60ba8SDaniel Matyas }
12816d60ba8SDaniel Matyas
max31827_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)12916d60ba8SDaniel Matyas static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
13016d60ba8SDaniel Matyas u32 attr, int channel, long *val)
13116d60ba8SDaniel Matyas {
13216d60ba8SDaniel Matyas struct max31827_state *st = dev_get_drvdata(dev);
13316d60ba8SDaniel Matyas unsigned int uval;
13416d60ba8SDaniel Matyas int ret = 0;
13516d60ba8SDaniel Matyas
13616d60ba8SDaniel Matyas switch (type) {
13716d60ba8SDaniel Matyas case hwmon_temp:
13816d60ba8SDaniel Matyas switch (attr) {
13916d60ba8SDaniel Matyas case hwmon_temp_enable:
14016d60ba8SDaniel Matyas ret = regmap_read(st->regmap,
14116d60ba8SDaniel Matyas MAX31827_CONFIGURATION_REG, &uval);
14216d60ba8SDaniel Matyas if (ret)
14316d60ba8SDaniel Matyas break;
14416d60ba8SDaniel Matyas
14516d60ba8SDaniel Matyas uval = FIELD_GET(MAX31827_CONFIGURATION_1SHOT_MASK |
14616d60ba8SDaniel Matyas MAX31827_CONFIGURATION_CNV_RATE_MASK,
14716d60ba8SDaniel Matyas uval);
14816d60ba8SDaniel Matyas *val = !!uval;
14916d60ba8SDaniel Matyas
15016d60ba8SDaniel Matyas break;
15116d60ba8SDaniel Matyas case hwmon_temp_input:
15216d60ba8SDaniel Matyas mutex_lock(&st->lock);
15316d60ba8SDaniel Matyas
15416d60ba8SDaniel Matyas if (!st->enable) {
15516d60ba8SDaniel Matyas /*
15616d60ba8SDaniel Matyas * This operation requires mutex protection,
15716d60ba8SDaniel Matyas * because the chip configuration should not
15816d60ba8SDaniel Matyas * be changed during the conversion process.
15916d60ba8SDaniel Matyas */
16016d60ba8SDaniel Matyas
16116d60ba8SDaniel Matyas ret = regmap_update_bits(st->regmap,
16216d60ba8SDaniel Matyas MAX31827_CONFIGURATION_REG,
16316d60ba8SDaniel Matyas MAX31827_CONFIGURATION_1SHOT_MASK,
16416d60ba8SDaniel Matyas 1);
16516d60ba8SDaniel Matyas if (ret) {
16616d60ba8SDaniel Matyas mutex_unlock(&st->lock);
16716d60ba8SDaniel Matyas return ret;
16816d60ba8SDaniel Matyas }
16916d60ba8SDaniel Matyas
17016d60ba8SDaniel Matyas msleep(MAX31827_12_BIT_CNV_TIME);
17116d60ba8SDaniel Matyas }
17216d60ba8SDaniel Matyas ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
17316d60ba8SDaniel Matyas
17416d60ba8SDaniel Matyas mutex_unlock(&st->lock);
17516d60ba8SDaniel Matyas
17616d60ba8SDaniel Matyas if (ret)
17716d60ba8SDaniel Matyas break;
17816d60ba8SDaniel Matyas
17916d60ba8SDaniel Matyas *val = MAX31827_16_BIT_TO_M_DGR(uval);
18016d60ba8SDaniel Matyas
18116d60ba8SDaniel Matyas break;
18216d60ba8SDaniel Matyas case hwmon_temp_max:
18316d60ba8SDaniel Matyas ret = regmap_read(st->regmap, MAX31827_TH_REG, &uval);
18416d60ba8SDaniel Matyas if (ret)
18516d60ba8SDaniel Matyas break;
18616d60ba8SDaniel Matyas
18716d60ba8SDaniel Matyas *val = MAX31827_16_BIT_TO_M_DGR(uval);
18816d60ba8SDaniel Matyas break;
18916d60ba8SDaniel Matyas case hwmon_temp_max_hyst:
19016d60ba8SDaniel Matyas ret = regmap_read(st->regmap, MAX31827_TH_HYST_REG,
19116d60ba8SDaniel Matyas &uval);
19216d60ba8SDaniel Matyas if (ret)
19316d60ba8SDaniel Matyas break;
19416d60ba8SDaniel Matyas
19516d60ba8SDaniel Matyas *val = MAX31827_16_BIT_TO_M_DGR(uval);
19616d60ba8SDaniel Matyas break;
19716d60ba8SDaniel Matyas case hwmon_temp_max_alarm:
19816d60ba8SDaniel Matyas ret = regmap_read(st->regmap,
19916d60ba8SDaniel Matyas MAX31827_CONFIGURATION_REG, &uval);
20016d60ba8SDaniel Matyas if (ret)
20116d60ba8SDaniel Matyas break;
20216d60ba8SDaniel Matyas
20316d60ba8SDaniel Matyas *val = FIELD_GET(MAX31827_CONFIGURATION_O_TEMP_STAT_MASK,
20416d60ba8SDaniel Matyas uval);
20516d60ba8SDaniel Matyas break;
20616d60ba8SDaniel Matyas case hwmon_temp_min:
20716d60ba8SDaniel Matyas ret = regmap_read(st->regmap, MAX31827_TL_REG, &uval);
20816d60ba8SDaniel Matyas if (ret)
20916d60ba8SDaniel Matyas break;
21016d60ba8SDaniel Matyas
21116d60ba8SDaniel Matyas *val = MAX31827_16_BIT_TO_M_DGR(uval);
21216d60ba8SDaniel Matyas break;
21316d60ba8SDaniel Matyas case hwmon_temp_min_hyst:
21416d60ba8SDaniel Matyas ret = regmap_read(st->regmap, MAX31827_TL_HYST_REG,
21516d60ba8SDaniel Matyas &uval);
21616d60ba8SDaniel Matyas if (ret)
21716d60ba8SDaniel Matyas break;
21816d60ba8SDaniel Matyas
21916d60ba8SDaniel Matyas *val = MAX31827_16_BIT_TO_M_DGR(uval);
22016d60ba8SDaniel Matyas break;
22116d60ba8SDaniel Matyas case hwmon_temp_min_alarm:
22216d60ba8SDaniel Matyas ret = regmap_read(st->regmap,
22316d60ba8SDaniel Matyas MAX31827_CONFIGURATION_REG, &uval);
22416d60ba8SDaniel Matyas if (ret)
22516d60ba8SDaniel Matyas break;
22616d60ba8SDaniel Matyas
22716d60ba8SDaniel Matyas *val = FIELD_GET(MAX31827_CONFIGURATION_U_TEMP_STAT_MASK,
22816d60ba8SDaniel Matyas uval);
22916d60ba8SDaniel Matyas break;
23016d60ba8SDaniel Matyas default:
23116d60ba8SDaniel Matyas ret = -EOPNOTSUPP;
23216d60ba8SDaniel Matyas break;
23316d60ba8SDaniel Matyas }
23416d60ba8SDaniel Matyas
23516d60ba8SDaniel Matyas break;
23616d60ba8SDaniel Matyas
23716d60ba8SDaniel Matyas case hwmon_chip:
23816d60ba8SDaniel Matyas if (attr == hwmon_chip_update_interval) {
23916d60ba8SDaniel Matyas ret = regmap_read(st->regmap,
24016d60ba8SDaniel Matyas MAX31827_CONFIGURATION_REG, &uval);
24116d60ba8SDaniel Matyas if (ret)
24216d60ba8SDaniel Matyas break;
24316d60ba8SDaniel Matyas
24416d60ba8SDaniel Matyas uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK,
24516d60ba8SDaniel Matyas uval);
24616d60ba8SDaniel Matyas switch (uval) {
24716d60ba8SDaniel Matyas case MAX31827_CNV_1_DIV_64_HZ:
24816d60ba8SDaniel Matyas *val = 64000;
24916d60ba8SDaniel Matyas break;
25016d60ba8SDaniel Matyas case MAX31827_CNV_1_DIV_32_HZ:
25116d60ba8SDaniel Matyas *val = 32000;
25216d60ba8SDaniel Matyas break;
25316d60ba8SDaniel Matyas case MAX31827_CNV_1_DIV_16_HZ:
25416d60ba8SDaniel Matyas *val = 16000;
25516d60ba8SDaniel Matyas break;
25616d60ba8SDaniel Matyas case MAX31827_CNV_1_DIV_4_HZ:
25716d60ba8SDaniel Matyas *val = 4000;
25816d60ba8SDaniel Matyas break;
25916d60ba8SDaniel Matyas case MAX31827_CNV_1_HZ:
26016d60ba8SDaniel Matyas *val = 1000;
26116d60ba8SDaniel Matyas break;
26216d60ba8SDaniel Matyas case MAX31827_CNV_4_HZ:
26316d60ba8SDaniel Matyas *val = 250;
26416d60ba8SDaniel Matyas break;
26516d60ba8SDaniel Matyas case MAX31827_CNV_8_HZ:
26616d60ba8SDaniel Matyas *val = 125;
26716d60ba8SDaniel Matyas break;
26816d60ba8SDaniel Matyas default:
26916d60ba8SDaniel Matyas *val = 0;
27016d60ba8SDaniel Matyas break;
27116d60ba8SDaniel Matyas }
27216d60ba8SDaniel Matyas }
27316d60ba8SDaniel Matyas break;
27416d60ba8SDaniel Matyas
27516d60ba8SDaniel Matyas default:
27616d60ba8SDaniel Matyas ret = -EOPNOTSUPP;
27716d60ba8SDaniel Matyas break;
27816d60ba8SDaniel Matyas }
27916d60ba8SDaniel Matyas
28016d60ba8SDaniel Matyas return ret;
28116d60ba8SDaniel Matyas }
28216d60ba8SDaniel Matyas
max31827_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)28316d60ba8SDaniel Matyas static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
28416d60ba8SDaniel Matyas u32 attr, int channel, long val)
28516d60ba8SDaniel Matyas {
28616d60ba8SDaniel Matyas struct max31827_state *st = dev_get_drvdata(dev);
28716d60ba8SDaniel Matyas int ret;
28816d60ba8SDaniel Matyas
28916d60ba8SDaniel Matyas switch (type) {
29016d60ba8SDaniel Matyas case hwmon_temp:
29116d60ba8SDaniel Matyas switch (attr) {
29216d60ba8SDaniel Matyas case hwmon_temp_enable:
29316d60ba8SDaniel Matyas if (val >> 1)
29416d60ba8SDaniel Matyas return -EINVAL;
29516d60ba8SDaniel Matyas
29616d60ba8SDaniel Matyas mutex_lock(&st->lock);
29716d60ba8SDaniel Matyas /**
29816d60ba8SDaniel Matyas * The chip should not be enabled while a conversion is
29916d60ba8SDaniel Matyas * performed. Neither should the chip be enabled when
30016d60ba8SDaniel Matyas * the alarm values are changed.
30116d60ba8SDaniel Matyas */
30216d60ba8SDaniel Matyas
30316d60ba8SDaniel Matyas st->enable = val;
30416d60ba8SDaniel Matyas
30516d60ba8SDaniel Matyas ret = regmap_update_bits(st->regmap,
30616d60ba8SDaniel Matyas MAX31827_CONFIGURATION_REG,
30716d60ba8SDaniel Matyas MAX31827_CONFIGURATION_1SHOT_MASK |
30816d60ba8SDaniel Matyas MAX31827_CONFIGURATION_CNV_RATE_MASK,
30916d60ba8SDaniel Matyas MAX31827_DEVICE_ENABLE(val));
31016d60ba8SDaniel Matyas
31116d60ba8SDaniel Matyas mutex_unlock(&st->lock);
31216d60ba8SDaniel Matyas
31316d60ba8SDaniel Matyas return ret;
31416d60ba8SDaniel Matyas
31516d60ba8SDaniel Matyas case hwmon_temp_max:
31616d60ba8SDaniel Matyas return write_alarm_val(st, MAX31827_TH_REG, val);
31716d60ba8SDaniel Matyas
31816d60ba8SDaniel Matyas case hwmon_temp_max_hyst:
31916d60ba8SDaniel Matyas return write_alarm_val(st, MAX31827_TH_HYST_REG, val);
32016d60ba8SDaniel Matyas
32116d60ba8SDaniel Matyas case hwmon_temp_min:
32216d60ba8SDaniel Matyas return write_alarm_val(st, MAX31827_TL_REG, val);
32316d60ba8SDaniel Matyas
32416d60ba8SDaniel Matyas case hwmon_temp_min_hyst:
32516d60ba8SDaniel Matyas return write_alarm_val(st, MAX31827_TL_HYST_REG, val);
32616d60ba8SDaniel Matyas
32716d60ba8SDaniel Matyas default:
32816d60ba8SDaniel Matyas return -EOPNOTSUPP;
32916d60ba8SDaniel Matyas }
33016d60ba8SDaniel Matyas
33116d60ba8SDaniel Matyas case hwmon_chip:
33216d60ba8SDaniel Matyas if (attr == hwmon_chip_update_interval) {
33316d60ba8SDaniel Matyas if (!st->enable)
33416d60ba8SDaniel Matyas return -EINVAL;
33516d60ba8SDaniel Matyas
33616d60ba8SDaniel Matyas switch (val) {
33716d60ba8SDaniel Matyas case 125:
33816d60ba8SDaniel Matyas val = MAX31827_CNV_8_HZ;
33916d60ba8SDaniel Matyas break;
34016d60ba8SDaniel Matyas case 250:
34116d60ba8SDaniel Matyas val = MAX31827_CNV_4_HZ;
34216d60ba8SDaniel Matyas break;
34316d60ba8SDaniel Matyas case 1000:
34416d60ba8SDaniel Matyas val = MAX31827_CNV_1_HZ;
34516d60ba8SDaniel Matyas break;
34616d60ba8SDaniel Matyas case 4000:
34716d60ba8SDaniel Matyas val = MAX31827_CNV_1_DIV_4_HZ;
34816d60ba8SDaniel Matyas break;
34916d60ba8SDaniel Matyas case 16000:
35016d60ba8SDaniel Matyas val = MAX31827_CNV_1_DIV_16_HZ;
35116d60ba8SDaniel Matyas break;
35216d60ba8SDaniel Matyas case 32000:
35316d60ba8SDaniel Matyas val = MAX31827_CNV_1_DIV_32_HZ;
35416d60ba8SDaniel Matyas break;
35516d60ba8SDaniel Matyas case 64000:
35616d60ba8SDaniel Matyas val = MAX31827_CNV_1_DIV_64_HZ;
35716d60ba8SDaniel Matyas break;
35816d60ba8SDaniel Matyas default:
35916d60ba8SDaniel Matyas return -EINVAL;
36016d60ba8SDaniel Matyas }
36116d60ba8SDaniel Matyas
36216d60ba8SDaniel Matyas val = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
36316d60ba8SDaniel Matyas val);
36416d60ba8SDaniel Matyas
36516d60ba8SDaniel Matyas return regmap_update_bits(st->regmap,
36616d60ba8SDaniel Matyas MAX31827_CONFIGURATION_REG,
36716d60ba8SDaniel Matyas MAX31827_CONFIGURATION_CNV_RATE_MASK,
36816d60ba8SDaniel Matyas val);
36916d60ba8SDaniel Matyas }
37016d60ba8SDaniel Matyas break;
37116d60ba8SDaniel Matyas
37216d60ba8SDaniel Matyas default:
37316d60ba8SDaniel Matyas return -EOPNOTSUPP;
37416d60ba8SDaniel Matyas }
37516d60ba8SDaniel Matyas
37616d60ba8SDaniel Matyas return -EOPNOTSUPP;
37716d60ba8SDaniel Matyas }
37816d60ba8SDaniel Matyas
max31827_init_client(struct max31827_state * st)37916d60ba8SDaniel Matyas static int max31827_init_client(struct max31827_state *st)
38016d60ba8SDaniel Matyas {
38116d60ba8SDaniel Matyas st->enable = true;
38216d60ba8SDaniel Matyas
38316d60ba8SDaniel Matyas return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
38416d60ba8SDaniel Matyas MAX31827_CONFIGURATION_1SHOT_MASK |
38516d60ba8SDaniel Matyas MAX31827_CONFIGURATION_CNV_RATE_MASK,
38616d60ba8SDaniel Matyas MAX31827_DEVICE_ENABLE(1));
38716d60ba8SDaniel Matyas }
38816d60ba8SDaniel Matyas
38916d60ba8SDaniel Matyas static const struct hwmon_channel_info *max31827_info[] = {
39016d60ba8SDaniel Matyas HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN |
39116d60ba8SDaniel Matyas HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM |
39216d60ba8SDaniel Matyas HWMON_T_MAX | HWMON_T_MAX_HYST |
39316d60ba8SDaniel Matyas HWMON_T_MAX_ALARM),
39416d60ba8SDaniel Matyas HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
39516d60ba8SDaniel Matyas NULL,
39616d60ba8SDaniel Matyas };
39716d60ba8SDaniel Matyas
39816d60ba8SDaniel Matyas static const struct hwmon_ops max31827_hwmon_ops = {
39916d60ba8SDaniel Matyas .is_visible = max31827_is_visible,
40016d60ba8SDaniel Matyas .read = max31827_read,
40116d60ba8SDaniel Matyas .write = max31827_write,
40216d60ba8SDaniel Matyas };
40316d60ba8SDaniel Matyas
40416d60ba8SDaniel Matyas static const struct hwmon_chip_info max31827_chip_info = {
40516d60ba8SDaniel Matyas .ops = &max31827_hwmon_ops,
40616d60ba8SDaniel Matyas .info = max31827_info,
40716d60ba8SDaniel Matyas };
40816d60ba8SDaniel Matyas
max31827_probe(struct i2c_client * client)40916d60ba8SDaniel Matyas static int max31827_probe(struct i2c_client *client)
41016d60ba8SDaniel Matyas {
41116d60ba8SDaniel Matyas struct device *dev = &client->dev;
41216d60ba8SDaniel Matyas struct device *hwmon_dev;
41316d60ba8SDaniel Matyas struct max31827_state *st;
41416d60ba8SDaniel Matyas int err;
41516d60ba8SDaniel Matyas
41616d60ba8SDaniel Matyas if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
41716d60ba8SDaniel Matyas return -EOPNOTSUPP;
41816d60ba8SDaniel Matyas
41916d60ba8SDaniel Matyas st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
42016d60ba8SDaniel Matyas if (!st)
42116d60ba8SDaniel Matyas return -ENOMEM;
42216d60ba8SDaniel Matyas
42316d60ba8SDaniel Matyas mutex_init(&st->lock);
42416d60ba8SDaniel Matyas
42516d60ba8SDaniel Matyas st->regmap = devm_regmap_init_i2c(client, &max31827_regmap);
42616d60ba8SDaniel Matyas if (IS_ERR(st->regmap))
42716d60ba8SDaniel Matyas return dev_err_probe(dev, PTR_ERR(st->regmap),
42816d60ba8SDaniel Matyas "Failed to allocate regmap.\n");
42916d60ba8SDaniel Matyas
43016d60ba8SDaniel Matyas err = max31827_init_client(st);
43116d60ba8SDaniel Matyas if (err)
43216d60ba8SDaniel Matyas return err;
43316d60ba8SDaniel Matyas
43416d60ba8SDaniel Matyas hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st,
43516d60ba8SDaniel Matyas &max31827_chip_info,
43616d60ba8SDaniel Matyas NULL);
43716d60ba8SDaniel Matyas
43816d60ba8SDaniel Matyas return PTR_ERR_OR_ZERO(hwmon_dev);
43916d60ba8SDaniel Matyas }
44016d60ba8SDaniel Matyas
44116d60ba8SDaniel Matyas static const struct i2c_device_id max31827_i2c_ids[] = {
44216d60ba8SDaniel Matyas { "max31827", 0 },
44316d60ba8SDaniel Matyas { }
44416d60ba8SDaniel Matyas };
44516d60ba8SDaniel Matyas MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids);
44616d60ba8SDaniel Matyas
44716d60ba8SDaniel Matyas static const struct of_device_id max31827_of_match[] = {
44816d60ba8SDaniel Matyas { .compatible = "adi,max31827" },
44916d60ba8SDaniel Matyas { }
45016d60ba8SDaniel Matyas };
45116d60ba8SDaniel Matyas MODULE_DEVICE_TABLE(of, max31827_of_match);
45216d60ba8SDaniel Matyas
45316d60ba8SDaniel Matyas static struct i2c_driver max31827_driver = {
45416d60ba8SDaniel Matyas .class = I2C_CLASS_HWMON,
45516d60ba8SDaniel Matyas .driver = {
45616d60ba8SDaniel Matyas .name = "max31827",
45716d60ba8SDaniel Matyas .of_match_table = max31827_of_match,
45816d60ba8SDaniel Matyas },
459*90fc660eSUwe Kleine-König .probe = max31827_probe,
46016d60ba8SDaniel Matyas .id_table = max31827_i2c_ids,
46116d60ba8SDaniel Matyas };
46216d60ba8SDaniel Matyas module_i2c_driver(max31827_driver);
46316d60ba8SDaniel Matyas
46416d60ba8SDaniel Matyas MODULE_AUTHOR("Daniel Matyas <daniel.matyas@analog.com>");
46516d60ba8SDaniel Matyas MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver");
46616d60ba8SDaniel Matyas MODULE_LICENSE("GPL");
467