#include <linux/ctype.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> #include <linux/property.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/util_macros.h> #include <linux/unaligned.h> #include <dt-bindings/iio/temperature/thermocouple.h> /* * The MSB of the register value determines whether the following byte will * be written or read. If it is 0, one or more byte reads will follow.
*/ #define MAX31856_RD_WR_BIT BIT(7)
staticint max31856_init(struct max31856_data *data)
{ int ret;
u8 reg_cr0_val, reg_cr1_val;
/* Start by changing to Off mode before making changes as * some settings are recommended to be set only when the device * is off
*/
ret = max31856_read(data, MAX31856_CR0_REG, ®_cr0_val, 1); if (ret) return ret;
reg_cr0_val &= ~MAX31856_CR0_AUTOCONVERT;
ret = max31856_write(data, MAX31856_CR0_REG, reg_cr0_val); if (ret) return ret;
/* Set thermocouple type based on dts property */
ret = max31856_read(data, MAX31856_CR1_REG, ®_cr1_val, 1); if (ret) return ret;
staticint max31856_thermocouple_read(struct max31856_data *data, struct iio_chan_spec const *chan, int *val)
{ int ret, offset_cjto;
u8 reg_val[3];
switch (chan->channel2) { case IIO_NO_MOD: /* * Multibyte Read * MAX31856_LTCBH_REG, MAX31856_LTCBM_REG, MAX31856_LTCBL_REG
*/
ret = max31856_read(data, MAX31856_LTCBH_REG, reg_val, 3); if (ret) return ret; /* Skip last 5 dead bits of LTCBL */
*val = get_unaligned_be24(®_val[0]) >> 5; /* Check 7th bit of LTCBH reg. value for sign*/ if (reg_val[0] & 0x80)
*val -= 0x80000; break;
case IIO_MOD_TEMP_AMBIENT: /* * Multibyte Read * MAX31856_CJTO_REG, MAX31856_CJTH_REG, MAX31856_CJTL_REG
*/
ret = max31856_read(data, MAX31856_CJTO_REG, reg_val, 3); if (ret) return ret; /* Get Cold Junction Temp. offset register value */
offset_cjto = reg_val[0]; /* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */
*val = get_unaligned_be16(®_val[1]) >> 2; /* As per datasheet add offset into CJTH and CJTL */
*val += offset_cjto; /* Check 7th bit of CJTH reg. value for sign */ if (reg_val[1] & 0x80)
*val -= 0x4000; break;
default: return -EINVAL;
}
ret = max31856_read(data, MAX31856_SR_REG, reg_val, 1); if (ret) return ret; /* Check for over/under voltage or open circuit fault */ if (reg_val[0] & (MAX31856_FAULT_OVUV | MAX31856_FAULT_OPEN)) return -EIO;
return ret;
}
staticint max31856_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct max31856_data *data = iio_priv(indio_dev); int ret;
switch (mask) { case IIO_CHAN_INFO_RAW:
ret = max31856_thermocouple_read(data, chan, val); if (ret) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (chan->channel2) { case IIO_MOD_TEMP_AMBIENT: /* Cold junction Temp. Data resolution is 0.015625 */
*val = 15;
*val2 = 625000; /* 1000 * 0.015625 */
ret = IIO_VAL_INT_PLUS_MICRO; break; default: /* Thermocouple Temp. Data resolution is 0.0078125 */
*val = 7;
*val2 = 812500; /* 1000 * 0.0078125) */ return IIO_VAL_INT_PLUS_MICRO;
} break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = 1 << data->averaging; return IIO_VAL_INT; case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
*val = max31856_tc_types[data->thermocouple_type]; return IIO_VAL_CHAR; default:
ret = -EINVAL; break;
}
staticint max31856_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct max31856_data *data = iio_priv(indio_dev); int msb;
switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: if (val > 16 || val < 1) return -EINVAL;
msb = fls(val) - 1; /* Round up to next 2pow if needed */ if (BIT(msb) < val)
msb++;
data->averaging = msb;
max31856_init(data); break; case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
{ int tc_type = -1; int i;
for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) { if (max31856_tc_types[i] == toupper(val)) {
tc_type = i; break;
}
} if (tc_type < 0) return -EINVAL;
ret = device_property_read_u32(&spi->dev, "thermocouple-type", &data->thermocouple_type); if (ret) {
dev_info(&spi->dev, "Could not read thermocouple type DT property, configuring as a K-Type\n");
data->thermocouple_type = THERMOCOUPLE_TYPE_K;
}
/* * no need to translate values as the supported types * have the same value as the #defines
*/ switch (data->thermocouple_type) { case THERMOCOUPLE_TYPE_B: case THERMOCOUPLE_TYPE_E: case THERMOCOUPLE_TYPE_J: case THERMOCOUPLE_TYPE_K: case THERMOCOUPLE_TYPE_N: case THERMOCOUPLE_TYPE_R: case THERMOCOUPLE_TYPE_S: case THERMOCOUPLE_TYPE_T: break; default:
dev_err(&spi->dev, "error: thermocouple-type %u not supported by max31856\n"
, data->thermocouple_type); return -EINVAL;
}
ret = max31856_init(data); if (ret) {
dev_err(&spi->dev, "error: Failed to configure max31856\n"); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.