diff --git a/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml index f60e06ab7d0a08..9363fa371e50d7 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml @@ -4,16 +4,19 @@ $id: http://devicetree.org/schemas/hwmon/adi,max31827.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch +title: Analog Devices MAX31827, MAX31828, MAX31829, MAX31875 Low-Power Temperature Switch maintainers: - - Daniel Matyas + - John Erasmus Mari Geronimo description: | Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch with I2C Interface https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf + Analog Devices MAX31875 Low-Power I2C Temperature Sensor in WLP Package + https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31875.pdf + properties: compatible: oneOf: @@ -22,6 +25,7 @@ properties: - enum: - adi,max31828 - adi,max31829 + - adi,max31875 - const: adi,max31827 reg: @@ -93,6 +97,16 @@ allOf: adi,fault-q: default: 4 + - if: + properties: + compatible: + contains: + const: adi,max31875 + + then: + properties: + adi,fault-q: + enum: [1, 2, 4, 6] required: - compatible diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst index 9c11a9518c6758..946398344290c7 100644 --- a/Documentation/hwmon/max31827.rst +++ b/Documentation/hwmon/max31827.rst @@ -29,9 +29,18 @@ Supported chips: Datasheet: Publicly available at the Analog Devices website + * Maxim MAX31875 + + Prefix: 'max31875' + + Addresses scanned: I2C 0x48 - 0x4f + + Datasheet: Publicly available at the Analog Devices website + Authors: - Daniel Matyas + - John Erasmus Mari Geronimo Description ----------- @@ -45,13 +54,20 @@ configured to operate in the same manner with 1 write operation to the configuration register. From here on, we will refer to all these chips as MAX31827. -MAX31827 implements a temperature sensor with a 6 WLP packaging scheme. This -sensor measures the temperature of the chip itself. +This driver also supports the MAX31875. Its fault queue is set to 1 and it has +no alarm polarity. + +MAX31827 implements a temperature sensor with a 6 WLP packaging scheme while +MAX31875 has a 4 WLP packaging scheme. This sensor measures the temperature of +the chip itself. MAX31827 has low and over temperature alarms with an effective value and a hysteresis value: -40 and -30 degrees for under temperature alarm and +100 and +90 degrees for over temperature alarm. +MAX31875 has only an over temperature alarm with an effective value and a +hysteresis value: +80 and +75 degrees. + The alarm can be configured in comparator and interrupt mode from the devicetree. In Comparator mode, the OT/UT status bits have a value of 1 when the temperature rises above the TH value or falls below TL, which is also subject to @@ -75,7 +91,8 @@ it is recommended to perform a read of the configuration/status register to clear the status bits before changing the operating mode. The conversions can be manual with the one-shot functionality and automatic with -a set frequency. When powered on, the chip measures temperatures with 1 conv/s. +a set frequency. When powered on, the MAX31827 measures temperatures with 1 +conv/s while the MAX31875 measures temperatures with 0.25 conv/s or 1 conv/4s. The conversion rate can be modified with update_interval attribute of the chip. Conversion/second = 1/update_interval. Thus, the available options according to the data sheet are: @@ -83,11 +100,13 @@ the data sheet are: - 64000 (ms) = 1 conv/64 sec - 32000 (ms) = 1 conv/32 sec - 16000 (ms) = 1 conv/16 sec -- 4000 (ms) = 1 conv/4 sec -- 1000 (ms) = 1 conv/sec (default) +- 4000 (ms) = 1 conv/4 sec (MAX31875 default) +- 1000 (ms) = 1 conv/sec (MAX31827 default) - 250 (ms) = 4 conv/sec - 125 (ms) = 8 conv/sec +The MAX31875 only supports the last four values above. + Enabling the device when it is already enabled has the side effect of setting the conversion frequency to 1 conv/s. The conversion time varies depending on the resolution. @@ -97,16 +116,16 @@ available resolutions are: - 8 bit -> 8.75 ms conversion time - 9 bit -> 17.5 ms conversion time -- 10 bit -> 35 ms conversion time -- 12 bit (default) -> 140 ms conversion time +- 10 bit (MAX31875 default) -> 35 ms conversion time +- 12 bit (MAX31827 default) -> 140 ms conversion time There is a temp1_resolution attribute which indicates the unit change in the input temperature in milli-degrees C. - 1000 mC -> 8 bit - 500 mC -> 9 bit -- 250 mC -> 10 bit -- 62 mC -> 12 bit (default) - actually this is 62.5, but the fil returns 62 +- 250 mC -> 10 bit (MAX31875 default) +- 62 mC -> 12 bit (MAX31827 default) - actually this is 62.5, but the fil returns 62 When chip is in shutdown mode and a read operation is requested, one-shot is triggered, the device waits for ms, and only after that is @@ -125,7 +144,8 @@ Bus timeout resets the I2C-compatible interface when SCL is low for more than Alarm polarity determines if the active state of the alarm is low or high. The behavior for both settings is dependent on the Fault Queue setting. The ALARM -pin is an open-drain output and requires a pullup resistor to operate. +pin is an open-drain output and requires a pullup resistor to operate. The +MAX31875 does not have this feature. The Fault Queue bits select how many consecutive temperature faults must occur before overtemperature or undertemperature faults are indicated in the diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c index 9dc1619057fa21..1653fda1f8d582 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -22,8 +22,14 @@ #define MAX31827_TH_HYST_REG 0x8 #define MAX31827_TL_HYST_REG 0xA +#define MAX31875_CONFIGURATION_REG 0x1 +#define MAX31875_TH_HYST_REG 0x2 +#define MAX31875_TH_REG 0x3 + #define MAX31827_CONFIGURATION_1SHOT_MASK BIT(0) #define MAX31827_CONFIGURATION_CNV_RATE_MASK GENMASK(3, 1) +#define MAX31827_CONFIGURATION_SHUTDOWN_MASK \ + (MAX31827_CONFIGURATION_1SHOT_MASK | MAX31827_CONFIGURATION_CNV_RATE_MASK) #define MAX31827_CONFIGURATION_PEC_EN_MASK BIT(4) #define MAX31827_CONFIGURATION_TIMEOUT_MASK BIT(5) #define MAX31827_CONFIGURATION_RESOLUTION_MASK GENMASK(7, 6) @@ -33,6 +39,13 @@ #define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK BIT(14) #define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK BIT(15) +#define MAX31875_CONFIGURATION_CNV_RATE_MASK GENMASK(2, 1) +#define MAX31875_CONFIGURATION_PEC_EN_MASK BIT(3) +#define MAX31875_CONFIGURATION_TIMEOUT_MASK BIT(4) +#define MAX31875_CONFIGURATION_RESOLUTION_MASK GENMASK(6, 5) +#define MAX31875_CONFIGURATION_SHUTDOWN_MASK BIT(8) +#define MAX31875_CONFIGURATION_FLT_Q_MASK GENMASK(12, 11) + #define MAX31827_ALRM_POL_LOW 0x0 #define MAX31827_ALRM_POL_HIGH 0x1 #define MAX31827_FLT_Q_1 0x0 @@ -43,11 +56,21 @@ #define MAX31827_10_BIT_CNV_TIME 35 #define MAX31827_12_BIT_CNV_TIME 140 -#define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16) -#define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000) -#define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0) +/* + * FIELD_PREP but no __BF_FIELD_CHECK so we can use masks from the chip_info + */ +static u32 max31827_field_prep(u32 _mask, unsigned int _val) +{ + return ((_val) << __ffs(_mask)) & (_mask); +} -enum chips { max31827 = 1, max31828, max31829 }; +/* + * FIELD_GET but no __BF_FIELD_CHECK so we can use masks from the chip_info + */ +static u32 max31827_field_get(u32 _mask, u32 _reg) +{ + return (((_reg) & (_mask)) >> __ffs(_mask)); +} enum max31827_cnv { MAX31827_CNV_1_DIV_64_HZ = 1, @@ -59,6 +82,13 @@ enum max31827_cnv { MAX31827_CNV_8_HZ, }; +enum max31875_cnv { + MAX31875_CNV_1_DIV_4_HZ, + MAX31875_CNV_1_HZ, + MAX31875_CNV_4_HZ, + MAX31875_CNV_8_HZ, +}; + static const u16 max31827_conversions[] = { [MAX31827_CNV_1_DIV_64_HZ] = 64000, [MAX31827_CNV_1_DIV_32_HZ] = 32000, @@ -69,6 +99,13 @@ static const u16 max31827_conversions[] = { [MAX31827_CNV_8_HZ] = 125, }; +static const u16 max31875_conversions[] = { + [MAX31875_CNV_1_DIV_4_HZ] = 4000, + [MAX31875_CNV_1_HZ] = 1000, + [MAX31875_CNV_4_HZ] = 250, + [MAX31875_CNV_8_HZ] = 125, +}; + enum max31827_resolution { MAX31827_RES_8_BIT = 0, MAX31827_RES_9_BIT, @@ -90,6 +127,38 @@ static const u16 max31827_conv_times[] = { [MAX31827_RES_12_BIT] = MAX31827_12_BIT_CNV_TIME, }; +struct max31827_state; +static const struct max31827_chip_info max31827; +static const struct max31827_chip_info max31828; +static const struct max31827_chip_info max31829; +static const struct max31827_chip_info max31875; + +struct max31827_chip_info { + u32 alarm_pol_default : 1; + u32 fault_q_default; + u32 resolution_default; + u32 config_reg; + u32 th_reg; + u32 th_hyst_reg; + u32 resolution_mask; + u32 timeout_mask; + u32 fault_q_mask; + u32 shutdown_mask; + u32 cnv_rate_mask; + u32 pec_en_mask; + int start_conv_idx; + const u16 *conversions; + unsigned int num_conversions; + const struct regmap_config *regmap; + const struct hwmon_chip_info *hwmon_chip_info; + unsigned int (*device_enable)(long x); + long (*is_enabled)(unsigned int x); + long (*from_16_bit_to_m_dgr)(unsigned int x); + unsigned int (*from_m_dgr_to_16_bit)(long x); + int (*shutdown)(struct max31827_state *st, unsigned int *cnv_rate); + int (*wakeup)(struct max31827_state *st, unsigned int cnv_rate); +}; + struct max31827_state { /* * Prevent simultaneous access to the i2c client. @@ -99,6 +168,7 @@ struct max31827_state { bool enable; unsigned int resolution; unsigned int update_interval; + const struct max31827_chip_info *chip_info; }; static const struct regmap_config max31827_regmap = { @@ -107,10 +177,94 @@ static const struct regmap_config max31827_regmap = { .max_register = 0xA, }; +static const struct regmap_config max31875_regmap = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 0x3, +}; + +static long max31827_16_bit_to_m_dgr(unsigned int x) +{ + return sign_extend32(x, 15) * 1000 / 16; +} + +static long max31875_16_bit_to_m_dgr(unsigned int x) +{ + return sign_extend32(x, 15) * 1000 / 256; +} + +static unsigned int max31827_m_dgr_to_16_bit(long x) +{ + return (((x) << 4) / 1000); +} + +static unsigned int max31875_m_dgr_to_16_bit(long x) +{ + return (((x) << 8) / 1000); +} + +static unsigned int max31827_device_enable(long x) +{ + return ((x) ? 0xA : 0x0); +} + +static unsigned int max31875_device_enable(long x) +{ + return FIELD_PREP(MAX31875_CONFIGURATION_SHUTDOWN_MASK, !(x)); +} + +static long max31827_is_enabled(unsigned int x) +{ + return !!(x); +} + +static long max31875_is_enabled(unsigned int x) +{ + return !(x); +} + +static int max31827_shutdown(struct max31827_state *st, unsigned int *cnv_rate) +{ + unsigned int cfg; + int ret; + + ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg); + if (ret) + return ret; + + *cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg; + cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | + MAX31827_CONFIGURATION_CNV_RATE_MASK); + + return regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); +} + +static int max31875_shutdown(struct max31827_state *st, unsigned int *cnv_rate) +{ + return regmap_update_bits(st->regmap, MAX31875_CONFIGURATION_REG, + MAX31875_CONFIGURATION_SHUTDOWN_MASK, + FIELD_PREP(MAX31875_CONFIGURATION_SHUTDOWN_MASK, + 1)); +} + +static int max31827_wakeup(struct max31827_state *st, unsigned int cnv_rate) +{ + return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_CNV_RATE_MASK, + cnv_rate); +} + +static int max31875_wakeup(struct max31827_state *st, unsigned int cnv_rate) +{ + return regmap_update_bits(st->regmap, MAX31875_CONFIGURATION_REG, + MAX31875_CONFIGURATION_SHUTDOWN_MASK, + FIELD_PREP(MAX31875_CONFIGURATION_SHUTDOWN_MASK, + 0)); +} + static int shutdown_write(struct max31827_state *st, unsigned int reg, unsigned int mask, unsigned int val) { - unsigned int cfg; unsigned int cnv_rate; int ret; @@ -132,14 +286,7 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg, goto unlock; } - ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg); - if (ret) - goto unlock; - - cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg; - cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | - MAX31827_CONFIGURATION_CNV_RATE_MASK); - ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); + ret = st->chip_info->shutdown(st, &cnv_rate); if (ret) goto unlock; @@ -151,9 +298,7 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg, if (ret) goto unlock; - ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_CNV_RATE_MASK, - cnv_rate); + ret = st->chip_info->wakeup(st, cnv_rate); unlock: mutex_unlock(&st->lock); @@ -163,7 +308,7 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg, static int write_alarm_val(struct max31827_state *st, unsigned int reg, long val) { - val = MAX31827_M_DGR_TO_16_BIT(val); + val = st->chip_info->from_m_dgr_to_16_bit(val); return shutdown_write(st, reg, 0, val); } @@ -207,14 +352,13 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, switch (attr) { case hwmon_temp_enable: ret = regmap_read(st->regmap, - MAX31827_CONFIGURATION_REG, &uval); + st->chip_info->config_reg, &uval); if (ret) break; - uval = FIELD_GET(MAX31827_CONFIGURATION_1SHOT_MASK | - MAX31827_CONFIGURATION_CNV_RATE_MASK, - uval); - *val = !!uval; + uval = max31827_field_get(st->chip_info->shutdown_mask, + uval); + *val = st->chip_info->is_enabled(uval); break; case hwmon_temp_input: @@ -228,7 +372,7 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, */ ret = regmap_update_bits(st->regmap, - MAX31827_CONFIGURATION_REG, + st->chip_info->config_reg, MAX31827_CONFIGURATION_1SHOT_MASK, 1); if (ret) { @@ -254,27 +398,27 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, if (ret) break; - *val = MAX31827_16_BIT_TO_M_DGR(uval); + *val = st->chip_info->from_16_bit_to_m_dgr(uval); break; case hwmon_temp_max: - ret = regmap_read(st->regmap, MAX31827_TH_REG, &uval); + ret = regmap_read(st->regmap, st->chip_info->th_reg, &uval); if (ret) break; - *val = MAX31827_16_BIT_TO_M_DGR(uval); + *val = st->chip_info->from_16_bit_to_m_dgr(uval); break; case hwmon_temp_max_hyst: - ret = regmap_read(st->regmap, MAX31827_TH_HYST_REG, + ret = regmap_read(st->regmap, st->chip_info->th_hyst_reg, &uval); if (ret) break; - *val = MAX31827_16_BIT_TO_M_DGR(uval); + *val = st->chip_info->from_16_bit_to_m_dgr(uval); break; case hwmon_temp_max_alarm: ret = regmap_read(st->regmap, - MAX31827_CONFIGURATION_REG, &uval); + st->chip_info->config_reg, &uval); if (ret) break; @@ -286,7 +430,7 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, if (ret) break; - *val = MAX31827_16_BIT_TO_M_DGR(uval); + *val = max31827_16_bit_to_m_dgr(uval); break; case hwmon_temp_min_hyst: ret = regmap_read(st->regmap, MAX31827_TL_HYST_REG, @@ -294,7 +438,7 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, if (ret) break; - *val = MAX31827_16_BIT_TO_M_DGR(uval); + *val = max31827_16_bit_to_m_dgr(uval); break; case hwmon_temp_min_alarm: ret = regmap_read(st->regmap, @@ -315,13 +459,13 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_chip: if (attr == hwmon_chip_update_interval) { ret = regmap_read(st->regmap, - MAX31827_CONFIGURATION_REG, &uval); + st->chip_info->config_reg, &uval); if (ret) break; - uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK, - uval); - *val = max31827_conversions[uval]; + uval = max31827_field_get(st->chip_info->cnv_rate_mask, + uval); + *val = st->chip_info->conversions[uval]; } break; @@ -337,7 +481,7 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { struct max31827_state *st = dev_get_drvdata(dev); - int res = 1; + int res = st->chip_info->start_conv_idx; int ret; switch (type) { @@ -357,20 +501,19 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, st->enable = val; ret = regmap_update_bits(st->regmap, - MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_1SHOT_MASK | - MAX31827_CONFIGURATION_CNV_RATE_MASK, - MAX31827_DEVICE_ENABLE(val)); + st->chip_info->config_reg, + st->chip_info->shutdown_mask, + st->chip_info->device_enable(val)); mutex_unlock(&st->lock); return ret; case hwmon_temp_max: - return write_alarm_val(st, MAX31827_TH_REG, val); + return write_alarm_val(st, st->chip_info->th_reg, val); case hwmon_temp_max_hyst: - return write_alarm_val(st, MAX31827_TH_HYST_REG, val); + return write_alarm_val(st, st->chip_info->th_hyst_reg, val); case hwmon_temp_min: return write_alarm_val(st, MAX31827_TL_REG, val); @@ -393,19 +536,19 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, * * This was inspired by lm73 driver. */ - while (res < ARRAY_SIZE(max31827_conversions) && - val < max31827_conversions[res]) + while (res < st->chip_info->num_conversions && + val < st->chip_info->conversions[res]) res++; - if (res == ARRAY_SIZE(max31827_conversions)) - res = ARRAY_SIZE(max31827_conversions) - 1; + if (res == st->chip_info->num_conversions) + res = st->chip_info->num_conversions - 1; - res = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK, - res); + res = max31827_field_prep(st->chip_info->cnv_rate_mask, + res); ret = regmap_update_bits(st->regmap, - MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_CNV_RATE_MASK, + st->chip_info->config_reg, + st->chip_info->cnv_rate_mask, res); if (ret) return ret; @@ -413,9 +556,10 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, st->update_interval = val; return 0; case hwmon_chip_pec: - return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_PEC_EN_MASK, - val ? MAX31827_CONFIGURATION_PEC_EN_MASK : 0); + return regmap_update_bits(st->regmap, + st->chip_info->config_reg, + st->chip_info->pec_en_mask, + val ? st->chip_info->pec_en_mask : 0); default: return -EOPNOTSUPP; } @@ -432,11 +576,11 @@ static ssize_t temp1_resolution_show(struct device *dev, unsigned int val; int ret; - ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &val); + ret = regmap_read(st->regmap, st->chip_info->config_reg, &val); if (ret) return ret; - val = FIELD_GET(MAX31827_CONFIGURATION_RESOLUTION_MASK, val); + val = max31827_field_get(st->chip_info->resolution_mask, val); return scnprintf(buf, PAGE_SIZE, "%u\n", max31827_resolutions[val]); } @@ -469,10 +613,10 @@ static ssize_t temp1_resolution_store(struct device *dev, st->resolution = idx; - ret = shutdown_write(st, MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_RESOLUTION_MASK, - FIELD_PREP(MAX31827_CONFIGURATION_RESOLUTION_MASK, - idx)); + ret = shutdown_write(st, st->chip_info->config_reg, + st->chip_info->resolution_mask, + max31827_field_prep(st->chip_info->resolution_mask, + idx)); return ret ? ret : count; } @@ -485,38 +629,31 @@ static struct attribute *max31827_attrs[] = { }; ATTRIBUTE_GROUPS(max31827); -static const struct i2c_device_id max31827_i2c_ids[] = { - { "max31827", max31827 }, - { "max31828", max31828 }, - { "max31829", max31829 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids); - static int max31827_init_client(struct max31827_state *st, struct device *dev) { struct fwnode_handle *fwnode; unsigned int res = 0; u32 data, lsb_idx; - enum chips type; bool prop; int ret; fwnode = dev_fwnode(dev); st->enable = true; - res |= MAX31827_DEVICE_ENABLE(1); + res |= st->chip_info->device_enable(1); - res |= MAX31827_CONFIGURATION_RESOLUTION_MASK; + res |= max31827_field_prep(st->chip_info->resolution_mask, + st->chip_info->resolution_default); prop = fwnode_property_read_bool(fwnode, "adi,comp-int"); res |= FIELD_PREP(MAX31827_CONFIGURATION_COMP_INT_MASK, prop); prop = fwnode_property_read_bool(fwnode, "adi,timeout-enable"); - res |= FIELD_PREP(MAX31827_CONFIGURATION_TIMEOUT_MASK, !prop); + res |= max31827_field_prep(st->chip_info->timeout_mask, !prop); - type = (enum chips)(uintptr_t)device_get_match_data(dev); + if (st->chip_info == &max31875) + goto skip_alarm_pol; if (fwnode_property_present(fwnode, "adi,alarm-pol")) { ret = fwnode_property_read_u32(fwnode, "adi,alarm-pol", &data); @@ -528,58 +665,43 @@ static int max31827_init_client(struct max31827_state *st, /* * Set default value. */ - switch (type) { - case max31827: - case max31828: - res |= FIELD_PREP(MAX31827_CONFIGURATION_ALRM_POL_MASK, - MAX31827_ALRM_POL_LOW); - break; - case max31829: - res |= FIELD_PREP(MAX31827_CONFIGURATION_ALRM_POL_MASK, - MAX31827_ALRM_POL_HIGH); - break; - default: - return -EOPNOTSUPP; - } + res |= FIELD_PREP(MAX31827_CONFIGURATION_ALRM_POL_MASK, + st->chip_info->alarm_pol_default); } +skip_alarm_pol: if (fwnode_property_present(fwnode, "adi,fault-q")) { ret = fwnode_property_read_u32(fwnode, "adi,fault-q", &data); if (ret) return ret; /* - * Convert the desired fault queue into register bits. + * Fault queue of 6 in MAX31875 has the same mapping as 8 in + * MAX31827, MAX31828 and MAX31829. */ - if (data != 0) - lsb_idx = __ffs(data); + if (st->chip_info == &max31875 && data == 6) + data = 8; - if (hweight32(data) != 1 || lsb_idx > 4) { + if (hweight32(data) != 1 || __ffs(data) > 4 || !data) { dev_err(dev, "Invalid data in adi,fault-q\n"); return -EINVAL; } - res |= FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, lsb_idx); + /* + * Convert the desired fault queue into register bits. + */ + lsb_idx = __ffs(data); + + res |= max31827_field_prep(st->chip_info->fault_q_mask, lsb_idx); } else { /* * Set default value. */ - switch (type) { - case max31827: - res |= FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, - MAX31827_FLT_Q_1); - break; - case max31828: - case max31829: - res |= FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, - MAX31827_FLT_Q_4); - break; - default: - return -EOPNOTSUPP; - } + res |= FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, + st->chip_info->fault_q_default); } - return regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, res); + return regmap_write(st->regmap, st->chip_info->config_reg, res); } static const struct hwmon_channel_info *max31827_info[] = { @@ -591,17 +713,30 @@ static const struct hwmon_channel_info *max31827_info[] = { NULL, }; +static const struct hwmon_channel_info *max31875_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | + HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_MAX_ALARM), + HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL | HWMON_C_PEC), + NULL, +}; + static const struct hwmon_ops max31827_hwmon_ops = { .is_visible = max31827_is_visible, .read = max31827_read, .write = max31827_write, }; -static const struct hwmon_chip_info max31827_chip_info = { +static const struct hwmon_chip_info max31827_hwmon_chip_info = { .ops = &max31827_hwmon_ops, .info = max31827_info, }; +static const struct hwmon_chip_info max31875_hwmon_chip_info = { + .ops = &max31827_hwmon_ops, + .info = max31875_info, +}; + static int max31827_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -616,9 +751,11 @@ static int max31827_probe(struct i2c_client *client) if (!st) return -ENOMEM; + st->chip_info = (struct max31827_chip_info *)(uintptr_t)device_get_match_data(dev); + mutex_init(&st->lock); - st->regmap = devm_regmap_init_i2c(client, &max31827_regmap); + st->regmap = devm_regmap_init_i2c(client, st->chip_info->regmap); if (IS_ERR(st->regmap)) return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to allocate regmap.\n"); @@ -632,24 +769,140 @@ static int max31827_probe(struct i2c_client *client) return err; hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st, - &max31827_chip_info, + st->chip_info->hwmon_chip_info, max31827_groups); return PTR_ERR_OR_ZERO(hwmon_dev); } +static const struct max31827_chip_info max31827 = { + .alarm_pol_default = MAX31827_ALRM_POL_LOW, + .fault_q_default = MAX31827_FLT_Q_1, + .resolution_default = MAX31827_RES_12_BIT, + .config_reg = MAX31827_CONFIGURATION_REG, + .th_reg = MAX31827_TH_REG, + .th_hyst_reg = MAX31827_TH_HYST_REG, + .resolution_mask = MAX31827_CONFIGURATION_RESOLUTION_MASK, + .timeout_mask = MAX31827_CONFIGURATION_TIMEOUT_MASK, + .fault_q_mask = MAX31827_CONFIGURATION_FLT_Q_MASK, + .shutdown_mask = MAX31827_CONFIGURATION_SHUTDOWN_MASK, + .cnv_rate_mask = MAX31827_CONFIGURATION_CNV_RATE_MASK, + .pec_en_mask = MAX31827_CONFIGURATION_PEC_EN_MASK, + .start_conv_idx = MAX31827_CNV_1_DIV_64_HZ, + .conversions = max31827_conversions, + .num_conversions = ARRAY_SIZE(max31827_conversions), + .regmap = &max31827_regmap, + .hwmon_chip_info = &max31827_hwmon_chip_info, + .device_enable = max31827_device_enable, + .is_enabled = max31827_is_enabled, + .from_16_bit_to_m_dgr = max31827_16_bit_to_m_dgr, + .from_m_dgr_to_16_bit = max31827_m_dgr_to_16_bit, + .shutdown = max31827_shutdown, + .wakeup = max31827_wakeup, +}; + +static const struct max31827_chip_info max31828 = { + .alarm_pol_default = MAX31827_ALRM_POL_LOW, + .fault_q_default = MAX31827_FLT_Q_4, + .resolution_default = MAX31827_RES_12_BIT, + .config_reg = MAX31827_CONFIGURATION_REG, + .th_reg = MAX31827_TH_REG, + .th_hyst_reg = MAX31827_TH_HYST_REG, + .resolution_mask = MAX31827_CONFIGURATION_RESOLUTION_MASK, + .timeout_mask = MAX31827_CONFIGURATION_TIMEOUT_MASK, + .fault_q_mask = MAX31827_CONFIGURATION_FLT_Q_MASK, + .shutdown_mask = MAX31827_CONFIGURATION_SHUTDOWN_MASK, + .cnv_rate_mask = MAX31827_CONFIGURATION_CNV_RATE_MASK, + .pec_en_mask = MAX31827_CONFIGURATION_PEC_EN_MASK, + .start_conv_idx = MAX31827_CNV_1_DIV_64_HZ, + .conversions = max31827_conversions, + .num_conversions = ARRAY_SIZE(max31827_conversions), + .regmap = &max31827_regmap, + .hwmon_chip_info = &max31827_hwmon_chip_info, + .device_enable = max31827_device_enable, + .is_enabled = max31827_is_enabled, + .from_16_bit_to_m_dgr = max31827_16_bit_to_m_dgr, + .from_m_dgr_to_16_bit = max31827_m_dgr_to_16_bit, + .shutdown = max31827_shutdown, + .wakeup = max31827_wakeup, +}; + +static const struct max31827_chip_info max31829 = { + .alarm_pol_default = MAX31827_ALRM_POL_HIGH, + .fault_q_default = MAX31827_FLT_Q_4, + .resolution_default = MAX31827_RES_12_BIT, + .config_reg = MAX31827_CONFIGURATION_REG, + .th_reg = MAX31827_TH_REG, + .th_hyst_reg = MAX31827_TH_HYST_REG, + .resolution_mask = MAX31827_CONFIGURATION_RESOLUTION_MASK, + .timeout_mask = MAX31827_CONFIGURATION_TIMEOUT_MASK, + .fault_q_mask = MAX31827_CONFIGURATION_FLT_Q_MASK, + .shutdown_mask = MAX31827_CONFIGURATION_SHUTDOWN_MASK, + .cnv_rate_mask = MAX31827_CONFIGURATION_CNV_RATE_MASK, + .pec_en_mask = MAX31827_CONFIGURATION_PEC_EN_MASK, + .start_conv_idx = MAX31827_CNV_1_DIV_64_HZ, + .conversions = max31827_conversions, + .num_conversions = ARRAY_SIZE(max31827_conversions), + .regmap = &max31827_regmap, + .hwmon_chip_info = &max31827_hwmon_chip_info, + .device_enable = max31827_device_enable, + .is_enabled = max31827_is_enabled, + .from_16_bit_to_m_dgr = max31827_16_bit_to_m_dgr, + .from_m_dgr_to_16_bit = max31827_m_dgr_to_16_bit, + .shutdown = max31827_shutdown, + .wakeup = max31827_wakeup, +}; + +static const struct max31827_chip_info max31875 = { + .fault_q_default = MAX31827_FLT_Q_1, + .resolution_default = MAX31827_RES_10_BIT, + .config_reg = MAX31875_CONFIGURATION_REG, + .th_reg = MAX31875_TH_REG, + .th_hyst_reg = MAX31875_TH_HYST_REG, + .resolution_mask = MAX31875_CONFIGURATION_RESOLUTION_MASK, + .timeout_mask = MAX31875_CONFIGURATION_TIMEOUT_MASK, + .fault_q_mask = MAX31875_CONFIGURATION_FLT_Q_MASK, + .shutdown_mask = MAX31875_CONFIGURATION_SHUTDOWN_MASK, + .cnv_rate_mask = MAX31875_CONFIGURATION_CNV_RATE_MASK, + .pec_en_mask = MAX31875_CONFIGURATION_PEC_EN_MASK, + .start_conv_idx = MAX31875_CNV_1_DIV_4_HZ, + .conversions = max31875_conversions, + .num_conversions = ARRAY_SIZE(max31875_conversions), + .regmap = &max31875_regmap, + .hwmon_chip_info = &max31875_hwmon_chip_info, + .device_enable = max31875_device_enable, + .is_enabled = max31875_is_enabled, + .from_16_bit_to_m_dgr = max31875_16_bit_to_m_dgr, + .from_m_dgr_to_16_bit = max31875_m_dgr_to_16_bit, + .shutdown = max31875_shutdown, + .wakeup = max31875_wakeup, +}; + +static const struct i2c_device_id max31827_i2c_ids[] = { + { "max31827", (kernel_ulong_t)&max31827 }, + { "max31828", (kernel_ulong_t)&max31828 }, + { "max31829", (kernel_ulong_t)&max31829 }, + { "max31875", (kernel_ulong_t)&max31875 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids); + static const struct of_device_id max31827_of_match[] = { { .compatible = "adi,max31827", - .data = (void *)max31827 + .data = (void *)&max31827 }, { .compatible = "adi,max31828", - .data = (void *)max31828 + .data = (void *)&max31828 }, { .compatible = "adi,max31829", - .data = (void *)max31829 + .data = (void *)&max31829 + }, + { + .compatible = "adi,max31875", + .data = (void *)&max31875 }, { } }; @@ -666,6 +919,7 @@ static struct i2c_driver max31827_driver = { }; module_i2c_driver(max31827_driver); +MODULE_AUTHOR("John Erasmus Mari Geronimo "); MODULE_AUTHOR("Daniel Matyas "); MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver"); MODULE_LICENSE("GPL");