aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/temperature
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/temperature')
-rw-r--r--drivers/iio/temperature/Kconfig31
-rw-r--r--drivers/iio/temperature/Makefile3
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c45
-rw-r--r--drivers/iio/temperature/iqs620at-temp.c98
-rw-r--r--drivers/iio/temperature/ltc2983.c328
-rw-r--r--drivers/iio/temperature/max31856.c17
-rw-r--r--drivers/iio/temperature/max31865.c351
-rw-r--r--drivers/iio/temperature/maxim_thermocouple.c8
-rw-r--r--drivers/iio/temperature/mlx90614.c83
-rw-r--r--drivers/iio/temperature/mlx90632.c351
-rw-r--r--drivers/iio/temperature/tmp006.c60
-rw-r--r--drivers/iio/temperature/tmp007.c47
-rw-r--r--drivers/iio/temperature/tmp117.c185
-rw-r--r--drivers/iio/temperature/tsys01.c5
-rw-r--r--drivers/iio/temperature/tsys02d.c2
15 files changed, 1300 insertions, 314 deletions
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index e1ccb4003015..e8ed849e3b76 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -4,6 +4,16 @@
#
menu "Temperature sensors"
+config IQS620AT_TEMP
+ tristate "Azoteq IQS620AT temperature sensor"
+ depends on MFD_IQS62X || COMPILE_TEST
+ help
+ Say Y here if you want to build support for the Azoteq IQS620AT
+ temperature sensor.
+
+ To compile this driver as a module, choose M here: the module
+ will be called iqs620at-temp.
+
config LTC2983
tristate "Analog Devices Multi-Sensor Digital Temperature Measurement System"
depends on SPI
@@ -35,7 +45,6 @@ config HID_SENSOR_TEMP
tristate "HID Environmental temperature sensor"
depends on HID_SENSOR_HUB
select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
select HID_SENSOR_IIO_COMMON
select HID_SENSOR_IIO_TRIGGER
help
@@ -87,6 +96,16 @@ config TMP007
This driver can also be built as a module. If so, the module will
be called tmp007.
+config TMP117
+ tristate "TMP117 Digital temperature sensor with integrated NV memory"
+ depends on I2C
+ help
+ If you say yes here you get support for the Texas Instruments
+ TMP117 Digital temperature sensor with integrated NV memory.
+
+ This driver can also be built as a module. If so, the module will
+ be called tmp117.
+
config TSYS01
tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
depends on I2C
@@ -119,4 +138,14 @@ config MAX31856
This driver can also be built as a module. If so, the module
will be called max31856.
+config MAX31865
+ tristate "MAX31865 RTD to Digital converter"
+ depends on SPI
+ help
+ If you say yes here you get support for MAX31865
+ thermocouple sensor chip connected via SPI.
+
+ This driver can also be build as a module. If so, the module
+ will be called max31865.
+
endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index d6b850b0cf63..dd08e562ffe0 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -3,13 +3,16 @@
# Makefile for industrial I/O temperature drivers
#
+obj-$(CONFIG_IQS620AT_TEMP) += iqs620at-temp.o
obj-$(CONFIG_LTC2983) += ltc2983.o
obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
obj-$(CONFIG_MAX31856) += max31856.o
+obj-$(CONFIG_MAX31865) += max31865.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_MLX90632) += mlx90632.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
+obj-$(CONFIG_TMP117) += tmp117.o
obj-$(CONFIG_TSYS01) += tsys01.o
obj-$(CONFIG_TSYS02D) += tsys02d.o
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index eda55b9c1e9b..d40f235af1d4 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -7,9 +7,8 @@
#include <linux/hid-sensor-hub.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
-#include <linux/iio/triggered_buffer.h>
-#include <linux/iio/trigger_consumer.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -17,13 +16,20 @@
struct temperature_state {
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info temperature_attr;
- s32 temperature_data;
+ struct {
+ s32 temperature_data;
+ u64 timestamp __aligned(8);
+ } scan;
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
int value_offset;
};
+static const u32 temperature_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE,
+};
+
/* Channel definitions */
static const struct iio_chan_spec temperature_channels[] = {
{
@@ -34,7 +40,7 @@ static const struct iio_chan_spec temperature_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
},
- IIO_CHAN_SOFT_TIMESTAMP(3),
+ IIO_CHAN_SOFT_TIMESTAMP(1),
};
/* Adjust channel real bits based on report descriptor */
@@ -125,9 +131,8 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev,
struct temperature_state *temp_st = iio_priv(indio_dev);
if (atomic_read(&temp_st->common_attributes.data_ready))
- iio_push_to_buffers_with_timestamp(indio_dev,
- &temp_st->temperature_data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_timestamp(indio_dev, &temp_st->scan,
+ iio_get_time_ns(indio_dev));
return 0;
}
@@ -142,7 +147,7 @@ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev,
switch (usage_id) {
case HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE:
- temp_st->temperature_data = *(s32 *)raw_data;
+ temp_st->scan.temperature_data = *(s32 *)raw_data;
return 0;
default:
return -EINVAL;
@@ -173,14 +178,6 @@ static int temperature_parse_report(struct platform_device *pdev,
&st->temperature_attr,
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0)
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE,
- &st->common_attributes.sensitivity);
-
return ret;
}
@@ -209,7 +206,9 @@ static int hid_temperature_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_TEMPERATURE,
- &temp_st->common_attributes);
+ &temp_st->common_attributes,
+ temperature_sensitivity_addresses,
+ ARRAY_SIZE(temperature_sensitivity_addresses));
if (ret)
return ret;
@@ -225,17 +224,12 @@ static int hid_temperature_probe(struct platform_device *pdev)
indio_dev->channels = temp_chans;
indio_dev->num_channels = ARRAY_SIZE(temperature_channels);
- indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &temperature_info;
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev,
- &iio_pollfunc_store_time, NULL, NULL);
- if (ret)
- return ret;
-
atomic_set(&temp_st->common_attributes.data_ready, 0);
+
ret = hid_sensor_setup_trigger(indio_dev, name,
&temp_st->common_attributes);
if (ret)
@@ -258,7 +252,7 @@ static int hid_temperature_probe(struct platform_device *pdev)
error_remove_callback:
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
error_remove_trigger:
- hid_sensor_remove_trigger(&temp_st->common_attributes);
+ hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
return ret;
}
@@ -270,7 +264,7 @@ static int hid_temperature_remove(struct platform_device *pdev)
struct temperature_state *temp_st = iio_priv(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
- hid_sensor_remove_trigger(&temp_st->common_attributes);
+ hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
return 0;
}
@@ -298,3 +292,4 @@ module_platform_driver(hid_temperature_platform_driver);
MODULE_DESCRIPTION("HID Environmental temperature sensor");
MODULE_AUTHOR("Song Hongyan <hongyan.song@intel.com>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/temperature/iqs620at-temp.c b/drivers/iio/temperature/iqs620at-temp.c
new file mode 100644
index 000000000000..e2f878d57af7
--- /dev/null
+++ b/drivers/iio/temperature/iqs620at-temp.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620AT Temperature Sensor
+ *
+ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/iqs62x.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define IQS620_TEMP_UI_OUT 0x1A
+
+#define IQS620_TEMP_SCALE 1000
+#define IQS620_TEMP_OFFSET (-100)
+#define IQS620_TEMP_OFFSET_V3 (-40)
+
+static int iqs620_temp_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct iqs62x_core *iqs62x = iio_device_get_drvdata(indio_dev);
+ int ret;
+ __le16 val_buf;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_raw_read(iqs62x->regmap, IQS620_TEMP_UI_OUT,
+ &val_buf, sizeof(val_buf));
+ if (ret)
+ return ret;
+
+ *val = le16_to_cpu(val_buf);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = IQS620_TEMP_SCALE;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OFFSET:
+ *val = iqs62x->hw_num < IQS620_HW_NUM_V3 ? IQS620_TEMP_OFFSET
+ : IQS620_TEMP_OFFSET_V3;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info iqs620_temp_info = {
+ .read_raw = &iqs620_temp_read_raw,
+};
+
+static const struct iio_chan_spec iqs620_temp_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ },
+};
+
+static int iqs620_temp_probe(struct platform_device *pdev)
+{
+ struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
+ struct iio_dev *indio_dev;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, 0);
+ if (!indio_dev)
+ return -ENOMEM;
+
+ iio_device_set_drvdata(indio_dev, iqs62x);
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = iqs620_temp_channels;
+ indio_dev->num_channels = ARRAY_SIZE(iqs620_temp_channels);
+ indio_dev->name = iqs62x->dev_desc->dev_name;
+ indio_dev->info = &iqs620_temp_info;
+
+ return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static struct platform_driver iqs620_temp_platform_driver = {
+ .driver = {
+ .name = "iqs620at-temp",
+ },
+ .probe = iqs620_temp_probe,
+};
+module_platform_driver(iqs620_temp_platform_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS620AT Temperature Sensor");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:iqs620at-temp");
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index d39c0d6b77f1..a60ccf183687 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -12,11 +12,15 @@
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/list.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
/* register map */
#define LTC2983_STATUS_REG 0x0000
#define LTC2983_TEMP_RES_START_REG 0x0010
@@ -89,6 +93,8 @@
#define LTC2983_STATUS_START_MASK BIT(7)
#define LTC2983_STATUS_START(x) FIELD_PREP(LTC2983_STATUS_START_MASK, x)
+#define LTC2983_STATUS_UP_MASK GENMASK(7, 6)
+#define LTC2983_STATUS_UP(reg) FIELD_GET(LTC2983_STATUS_UP_MASK, reg)
#define LTC2983_STATUS_CHAN_SEL_MASK GENMASK(4, 0)
#define LTC2983_STATUS_CHAN_SEL(x) \
@@ -198,11 +204,11 @@ struct ltc2983_data {
u8 num_channels;
u8 iio_channels;
/*
- * DMA (thus cache coherency maintenance) requires the
+ * DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
* Holds the converted temperature
*/
- __be32 temp ____cacheline_aligned;
+ __be32 temp __aligned(IIO_DMA_MINALIGN);
};
struct ltc2983_sensor {
@@ -217,7 +223,7 @@ struct ltc2983_sensor {
struct ltc2983_custom_sensor {
/* raw table sensor data */
- u8 *table;
+ void *table;
size_t size;
/* address offset */
s8 offset;
@@ -375,25 +381,25 @@ static int __ltc2983_chan_custom_sensor_assign(struct ltc2983_data *st,
return regmap_bulk_write(st->regmap, reg, custom->table, custom->size);
}
-static struct ltc2983_custom_sensor *__ltc2983_custom_sensor_new(
- struct ltc2983_data *st,
- const struct device_node *np,
- const char *propname,
- const bool is_steinhart,
- const u32 resolution,
- const bool has_signed)
+static struct ltc2983_custom_sensor *
+__ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle *fn,
+ const char *propname, const bool is_steinhart,
+ const u32 resolution, const bool has_signed)
{
struct ltc2983_custom_sensor *new_custom;
- u8 index, n_entries, tbl = 0;
struct device *dev = &st->spi->dev;
/*
* For custom steinhart, the full u32 is taken. For all the others
* the MSB is discarded.
*/
- const u8 n_size = (is_steinhart == true) ? 4 : 3;
- const u8 e_size = (is_steinhart == true) ? sizeof(u32) : sizeof(u64);
+ const u8 n_size = is_steinhart ? 4 : 3;
+ u8 index, n_entries;
+ int ret;
- n_entries = of_property_count_elems_of_size(np, propname, e_size);
+ if (is_steinhart)
+ n_entries = fwnode_property_count_u32(fn, propname);
+ else
+ n_entries = fwnode_property_count_u64(fn, propname);
/* n_entries must be an even number */
if (!n_entries || (n_entries % 2) != 0) {
dev_err(dev, "Number of entries either 0 or not even\n");
@@ -407,8 +413,8 @@ static struct ltc2983_custom_sensor *__ltc2983_custom_sensor_new(
new_custom->size = n_entries * n_size;
/* check Steinhart size */
if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE) {
- dev_err(dev, "Steinhart sensors size(%zu) must be 24",
- new_custom->size);
+ dev_err(dev, "Steinhart sensors size(%zu) must be %u\n", new_custom->size,
+ LTC2983_CUSTOM_STEINHART_SIZE);
return ERR_PTR(-EINVAL);
}
/* Check space on the table. */
@@ -421,21 +427,33 @@ static struct ltc2983_custom_sensor *__ltc2983_custom_sensor_new(
}
/* allocate the table */
- new_custom->table = devm_kzalloc(dev, new_custom->size, GFP_KERNEL);
+ if (is_steinhart)
+ new_custom->table = devm_kcalloc(dev, n_entries, sizeof(u32), GFP_KERNEL);
+ else
+ new_custom->table = devm_kcalloc(dev, n_entries, sizeof(u64), GFP_KERNEL);
if (!new_custom->table)
return ERR_PTR(-ENOMEM);
- for (index = 0; index < n_entries; index++) {
- u64 temp = 0, j;
- /*
- * Steinhart sensors are configured with raw values in the
- * devicetree. For the other sensors we must convert the
- * value to raw. The odd index's correspond to temperarures
- * and always have 1/1024 of resolution. Temperatures also
- * come in kelvin, so signed values is not possible
- */
- if (!is_steinhart) {
- of_property_read_u64_index(np, propname, index, &temp);
+ /*
+ * Steinhart sensors are configured with raw values in the firmware
+ * node. For the other sensors we must convert the value to raw.
+ * The odd index's correspond to temperatures and always have 1/1024
+ * of resolution. Temperatures also come in Kelvin, so signed values
+ * are not possible.
+ */
+ if (is_steinhart) {
+ ret = fwnode_property_read_u32_array(fn, propname, new_custom->table, n_entries);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ cpu_to_be32_array(new_custom->table, new_custom->table, n_entries);
+ } else {
+ ret = fwnode_property_read_u64_array(fn, propname, new_custom->table, n_entries);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ for (index = 0; index < n_entries; index++) {
+ u64 temp = ((u64 *)new_custom->table)[index];
if ((index % 2) != 0)
temp = __convert_to_raw(temp, 1024);
@@ -443,16 +461,9 @@ static struct ltc2983_custom_sensor *__ltc2983_custom_sensor_new(
temp = __convert_to_raw_sign(temp, resolution);
else
temp = __convert_to_raw(temp, resolution);
- } else {
- u32 t32;
- of_property_read_u32_index(np, propname, index, &t32);
- temp = t32;
+ put_unaligned_be24(temp, new_custom->table + index * 3);
}
-
- for (j = 0; j < n_size; j++)
- new_custom->table[tbl++] =
- temp >> (8 * (n_size - j - 1));
}
new_custom->is_steinhart = is_steinhart;
@@ -595,13 +606,12 @@ static int ltc2983_adc_assign_chan(struct ltc2983_data *st,
return __ltc2983_chan_assign_common(st, sensor, chan_val);
}
-static struct ltc2983_sensor *ltc2983_thermocouple_new(
- const struct device_node *child,
- struct ltc2983_data *st,
- const struct ltc2983_sensor *sensor)
+static struct ltc2983_sensor *
+ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
{
struct ltc2983_thermocouple *thermo;
- struct device_node *phandle;
+ struct fwnode_handle *ref;
u32 oc_current;
int ret;
@@ -609,11 +619,10 @@ static struct ltc2983_sensor *ltc2983_thermocouple_new(
if (!thermo)
return ERR_PTR(-ENOMEM);
- if (of_property_read_bool(child, "adi,single-ended"))
+ if (fwnode_property_read_bool(child, "adi,single-ended"))
thermo->sensor_config = LTC2983_THERMOCOUPLE_SGL(1);
- ret = of_property_read_u32(child, "adi,sensor-oc-current-microamp",
- &oc_current);
+ ret = fwnode_property_read_u32(child, "adi,sensor-oc-current-microamp", &oc_current);
if (!ret) {
switch (oc_current) {
case 10:
@@ -649,20 +658,18 @@ static struct ltc2983_sensor *ltc2983_thermocouple_new(
return ERR_PTR(-EINVAL);
}
- phandle = of_parse_phandle(child, "adi,cold-junction-handle", 0);
- if (phandle) {
- int ret;
-
- ret = of_property_read_u32(phandle, "reg",
- &thermo->cold_junction_chan);
+ ref = fwnode_find_reference(child, "adi,cold-junction-handle", 0);
+ if (IS_ERR(ref)) {
+ ref = NULL;
+ } else {
+ ret = fwnode_property_read_u32(ref, "reg", &thermo->cold_junction_chan);
if (ret) {
/*
* This would be catched later but we can just return
* the error right away.
*/
dev_err(&st->spi->dev, "Property reg must be given\n");
- of_node_put(phandle);
- return ERR_PTR(-EINVAL);
+ goto fail;
}
}
@@ -674,8 +681,8 @@ static struct ltc2983_sensor *ltc2983_thermocouple_new(
propname, false,
16384, true);
if (IS_ERR(thermo->custom)) {
- of_node_put(phandle);
- return ERR_CAST(thermo->custom);
+ ret = PTR_ERR(thermo->custom);
+ goto fail;
}
}
@@ -683,37 +690,41 @@ static struct ltc2983_sensor *ltc2983_thermocouple_new(
thermo->sensor.fault_handler = ltc2983_thermocouple_fault_handler;
thermo->sensor.assign_chan = ltc2983_thermocouple_assign_chan;
- of_node_put(phandle);
+ fwnode_handle_put(ref);
return &thermo->sensor;
+
+fail:
+ fwnode_handle_put(ref);
+ return ERR_PTR(ret);
}
-static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child,
- struct ltc2983_data *st,
- const struct ltc2983_sensor *sensor)
+static struct ltc2983_sensor *
+ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
{
struct ltc2983_rtd *rtd;
int ret = 0;
struct device *dev = &st->spi->dev;
- struct device_node *phandle;
+ struct fwnode_handle *ref;
u32 excitation_current = 0, n_wires = 0;
rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
if (!rtd)
return ERR_PTR(-ENOMEM);
- phandle = of_parse_phandle(child, "adi,rsense-handle", 0);
- if (!phandle) {
+ ref = fwnode_find_reference(child, "adi,rsense-handle", 0);
+ if (IS_ERR(ref)) {
dev_err(dev, "Property adi,rsense-handle missing or invalid");
- return ERR_PTR(-EINVAL);
+ return ERR_CAST(ref);
}
- ret = of_property_read_u32(phandle, "reg", &rtd->r_sense_chan);
+ ret = fwnode_property_read_u32(ref, "reg", &rtd->r_sense_chan);
if (ret) {
dev_err(dev, "Property reg must be given\n");
goto fail;
}
- ret = of_property_read_u32(child, "adi,number-of-wires", &n_wires);
+ ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires);
if (!ret) {
switch (n_wires) {
case 2:
@@ -736,9 +747,9 @@ static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child,
}
}
- if (of_property_read_bool(child, "adi,rsense-share")) {
+ if (fwnode_property_read_bool(child, "adi,rsense-share")) {
/* Current rotation is only available with rsense sharing */
- if (of_property_read_bool(child, "adi,current-rotate")) {
+ if (fwnode_property_read_bool(child, "adi,current-rotate")) {
if (n_wires == 2 || n_wires == 3) {
dev_err(dev,
"Rotation not allowed for 2/3 Wire RTDs");
@@ -801,8 +812,8 @@ static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child,
"adi,custom-rtd",
false, 2048, false);
if (IS_ERR(rtd->custom)) {
- of_node_put(phandle);
- return ERR_CAST(rtd->custom);
+ ret = PTR_ERR(rtd->custom);
+ goto fail;
}
}
@@ -810,8 +821,8 @@ static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child,
rtd->sensor.fault_handler = ltc2983_common_fault_handler;
rtd->sensor.assign_chan = ltc2983_rtd_assign_chan;
- ret = of_property_read_u32(child, "adi,excitation-current-microamp",
- &excitation_current);
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp",
+ &excitation_current);
if (ret) {
/* default to 5uA */
rtd->excitation_current = 1;
@@ -850,23 +861,22 @@ static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child,
}
}
- of_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve);
+ fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve);
- of_node_put(phandle);
+ fwnode_handle_put(ref);
return &rtd->sensor;
fail:
- of_node_put(phandle);
+ fwnode_handle_put(ref);
return ERR_PTR(ret);
}
-static struct ltc2983_sensor *ltc2983_thermistor_new(
- const struct device_node *child,
- struct ltc2983_data *st,
- const struct ltc2983_sensor *sensor)
+static struct ltc2983_sensor *
+ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
{
struct ltc2983_thermistor *thermistor;
struct device *dev = &st->spi->dev;
- struct device_node *phandle;
+ struct fwnode_handle *ref;
u32 excitation_current = 0;
int ret = 0;
@@ -874,23 +884,23 @@ static struct ltc2983_sensor *ltc2983_thermistor_new(
if (!thermistor)
return ERR_PTR(-ENOMEM);
- phandle = of_parse_phandle(child, "adi,rsense-handle", 0);
- if (!phandle) {
+ ref = fwnode_find_reference(child, "adi,rsense-handle", 0);
+ if (IS_ERR(ref)) {
dev_err(dev, "Property adi,rsense-handle missing or invalid");
- return ERR_PTR(-EINVAL);
+ return ERR_CAST(ref);
}
- ret = of_property_read_u32(phandle, "reg", &thermistor->r_sense_chan);
+ ret = fwnode_property_read_u32(ref, "reg", &thermistor->r_sense_chan);
if (ret) {
dev_err(dev, "rsense channel must be configured...\n");
goto fail;
}
- if (of_property_read_bool(child, "adi,single-ended")) {
+ if (fwnode_property_read_bool(child, "adi,single-ended")) {
thermistor->sensor_config = LTC2983_THERMISTOR_SGL(1);
- } else if (of_property_read_bool(child, "adi,rsense-share")) {
+ } else if (fwnode_property_read_bool(child, "adi,rsense-share")) {
/* rotation is only possible if sharing rsense */
- if (of_property_read_bool(child, "adi,current-rotate"))
+ if (fwnode_property_read_bool(child, "adi,current-rotate"))
thermistor->sensor_config =
LTC2983_THERMISTOR_C_ROTATE(1);
else
@@ -924,16 +934,16 @@ static struct ltc2983_sensor *ltc2983_thermistor_new(
steinhart,
64, false);
if (IS_ERR(thermistor->custom)) {
- of_node_put(phandle);
- return ERR_CAST(thermistor->custom);
+ ret = PTR_ERR(thermistor->custom);
+ goto fail;
}
}
/* set common parameters */
thermistor->sensor.fault_handler = ltc2983_common_fault_handler;
thermistor->sensor.assign_chan = ltc2983_thermistor_assign_chan;
- ret = of_property_read_u32(child, "adi,excitation-current-nanoamp",
- &excitation_current);
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp",
+ &excitation_current);
if (ret) {
/* Auto range is not allowed for custom sensors */
if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART)
@@ -997,17 +1007,16 @@ static struct ltc2983_sensor *ltc2983_thermistor_new(
}
}
- of_node_put(phandle);
+ fwnode_handle_put(ref);
return &thermistor->sensor;
fail:
- of_node_put(phandle);
+ fwnode_handle_put(ref);
return ERR_PTR(ret);
}
-static struct ltc2983_sensor *ltc2983_diode_new(
- const struct device_node *child,
- const struct ltc2983_data *st,
- const struct ltc2983_sensor *sensor)
+static struct ltc2983_sensor *
+ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
{
struct ltc2983_diode *diode;
u32 temp = 0, excitation_current = 0;
@@ -1017,13 +1026,13 @@ static struct ltc2983_sensor *ltc2983_diode_new(
if (!diode)
return ERR_PTR(-ENOMEM);
- if (of_property_read_bool(child, "adi,single-ended"))
+ if (fwnode_property_read_bool(child, "adi,single-ended"))
diode->sensor_config = LTC2983_DIODE_SGL(1);
- if (of_property_read_bool(child, "adi,three-conversion-cycles"))
+ if (fwnode_property_read_bool(child, "adi,three-conversion-cycles"))
diode->sensor_config |= LTC2983_DIODE_3_CONV_CYCLE(1);
- if (of_property_read_bool(child, "adi,average-on"))
+ if (fwnode_property_read_bool(child, "adi,average-on"))
diode->sensor_config |= LTC2983_DIODE_AVERAGE_ON(1);
/* validate channel index */
@@ -1038,8 +1047,8 @@ static struct ltc2983_sensor *ltc2983_diode_new(
diode->sensor.fault_handler = ltc2983_common_fault_handler;
diode->sensor.assign_chan = ltc2983_diode_assign_chan;
- ret = of_property_read_u32(child, "adi,excitation-current-microamp",
- &excitation_current);
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp",
+ &excitation_current);
if (!ret) {
switch (excitation_current) {
case 10:
@@ -1062,7 +1071,7 @@ static struct ltc2983_sensor *ltc2983_diode_new(
}
}
- of_property_read_u32(child, "adi,ideal-factor-value", &temp);
+ fwnode_property_read_u32(child, "adi,ideal-factor-value", &temp);
/* 2^20 resolution */
diode->ideal_factor_value = __convert_to_raw(temp, 1048576);
@@ -1070,7 +1079,7 @@ static struct ltc2983_sensor *ltc2983_diode_new(
return &diode->sensor;
}
-static struct ltc2983_sensor *ltc2983_r_sense_new(struct device_node *child,
+static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child,
struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
@@ -1089,7 +1098,7 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct device_node *child,
return ERR_PTR(-EINVAL);
}
- ret = of_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp);
+ ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp);
if (ret) {
dev_err(&st->spi->dev, "Property adi,rsense-val-milli-ohms missing\n");
return ERR_PTR(-EINVAL);
@@ -1108,7 +1117,7 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct device_node *child,
return &rsense->sensor;
}
-static struct ltc2983_sensor *ltc2983_adc_new(struct device_node *child,
+static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child,
struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
@@ -1118,7 +1127,7 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct device_node *child,
if (!adc)
return ERR_PTR(-ENOMEM);
- if (of_property_read_bool(child, "adi,single-ended"))
+ if (fwnode_property_read_bool(child, "adi,single-ended"))
adc->single_ended = true;
if (!adc->single_ended &&
@@ -1262,49 +1271,53 @@ static irqreturn_t ltc2983_irq_handler(int irq, void *data)
static int ltc2983_parse_dt(struct ltc2983_data *st)
{
- struct device_node *child;
struct device *dev = &st->spi->dev;
+ struct fwnode_handle *child;
int ret = 0, chan = 0, channel_avail_mask = 0;
- of_property_read_u32(dev->of_node, "adi,mux-delay-config-us",
- &st->mux_delay_config);
+ device_property_read_u32(dev, "adi,mux-delay-config-us", &st->mux_delay_config);
- of_property_read_u32(dev->of_node, "adi,filter-notch-freq",
- &st->filter_notch_freq);
+ device_property_read_u32(dev, "adi,filter-notch-freq", &st->filter_notch_freq);
+
+ st->num_channels = device_get_child_node_count(dev);
+ if (!st->num_channels) {
+ dev_err(&st->spi->dev, "At least one channel must be given!");
+ return -EINVAL;
+ }
- st->num_channels = of_get_available_child_count(dev->of_node);
st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors),
GFP_KERNEL);
if (!st->sensors)
return -ENOMEM;
st->iio_channels = st->num_channels;
- for_each_available_child_of_node(dev->of_node, child) {
+ device_for_each_child_node(dev, child) {
struct ltc2983_sensor sensor;
- ret = of_property_read_u32(child, "reg", &sensor.chan);
+ ret = fwnode_property_read_u32(child, "reg", &sensor.chan);
if (ret) {
dev_err(dev, "reg property must given for child nodes\n");
- return ret;
+ goto put_child;
}
/* check if we have a valid channel */
if (sensor.chan < LTC2983_MIN_CHANNELS_NR ||
sensor.chan > LTC2983_MAX_CHANNELS_NR) {
- dev_err(dev,
- "chan:%d must be from 1 to 20\n", sensor.chan);
- return -EINVAL;
+ ret = -EINVAL;
+ dev_err(dev, "chan:%d must be from %u to %u\n", sensor.chan,
+ LTC2983_MIN_CHANNELS_NR, LTC2983_MAX_CHANNELS_NR);
+ goto put_child;
} else if (channel_avail_mask & BIT(sensor.chan)) {
+ ret = -EINVAL;
dev_err(dev, "chan:%d already in use\n", sensor.chan);
- return -EINVAL;
+ goto put_child;
}
- ret = of_property_read_u32(child, "adi,sensor-type",
- &sensor.type);
+ ret = fwnode_property_read_u32(child, "adi,sensor-type", &sensor.type);
if (ret) {
dev_err(dev,
"adi,sensor-type property must given for child nodes\n");
- return ret;
+ goto put_child;
}
dev_dbg(dev, "Create new sensor, type %u, chann %u",
@@ -1334,13 +1347,15 @@ static int ltc2983_parse_dt(struct ltc2983_data *st)
st->sensors[chan] = ltc2983_adc_new(child, st, &sensor);
} else {
dev_err(dev, "Unknown sensor type %d\n", sensor.type);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
if (IS_ERR(st->sensors[chan])) {
dev_err(dev, "Failed to create sensor %ld",
PTR_ERR(st->sensors[chan]));
- return PTR_ERR(st->sensors[chan]);
+ ret = PTR_ERR(st->sensors[chan]);
+ goto put_child;
}
/* set generic sensor parameters */
st->sensors[chan]->chan = sensor.chan;
@@ -1351,30 +1366,25 @@ static int ltc2983_parse_dt(struct ltc2983_data *st)
}
return 0;
+put_child:
+ fwnode_handle_put(child);
+ return ret;
}
static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
{
- u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0;
+ u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status;
int ret;
- unsigned long time;
- /* make sure the device is up */
- time = wait_for_completion_timeout(&st->completion,
- msecs_to_jiffies(250));
-
- if (!time) {
+ /* make sure the device is up: start bit (7) is 0 and done bit (6) is 1 */
+ ret = regmap_read_poll_timeout(st->regmap, LTC2983_STATUS_REG, status,
+ LTC2983_STATUS_UP(status) == 1, 25000,
+ 25000 * 10);
+ if (ret) {
dev_err(&st->spi->dev, "Device startup timed out\n");
- return -ETIMEDOUT;
+ return ret;
}
- st->iio_chan = devm_kzalloc(&st->spi->dev,
- st->iio_channels * sizeof(*st->iio_chan),
- GFP_KERNEL);
-
- if (!st->iio_chan)
- return -ENOMEM;
-
ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG,
LTC2983_NOTCH_FREQ_MASK,
LTC2983_NOTCH_FREQ(st->filter_notch_freq));
@@ -1462,6 +1472,7 @@ static int ltc2983_probe(struct spi_device *spi)
{
struct ltc2983_data *st;
struct iio_dev *indio_dev;
+ struct gpio_desc *gpio;
const char *name = spi_get_device_id(spi)->name;
int ret;
@@ -1485,10 +1496,27 @@ static int ltc2983_probe(struct spi_device *spi)
ret = ltc2983_parse_dt(st);
if (ret)
return ret;
- /*
- * let's request the irq now so it is used to sync the device
- * startup in ltc2983_setup()
- */
+
+ gpio = devm_gpiod_get_optional(&st->spi->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpio))
+ return PTR_ERR(gpio);
+
+ if (gpio) {
+ /* bring the device out of reset */
+ usleep_range(1000, 1200);
+ gpiod_set_value_cansleep(gpio, 0);
+ }
+
+ st->iio_chan = devm_kzalloc(&spi->dev,
+ st->iio_channels * sizeof(*st->iio_chan),
+ GFP_KERNEL);
+ if (!st->iio_chan)
+ return -ENOMEM;
+
+ ret = ltc2983_setup(st, true);
+ if (ret)
+ return ret;
+
ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler,
IRQF_TRIGGER_RISING, name, st);
if (ret) {
@@ -1496,11 +1524,6 @@ static int ltc2983_probe(struct spi_device *spi)
return ret;
}
- ret = ltc2983_setup(st, true);
- if (ret)
- return ret;
-
- indio_dev->dev.parent = &spi->dev;
indio_dev->name = name;
indio_dev->num_channels = st->iio_channels;
indio_dev->channels = st->iio_chan;
@@ -1510,7 +1533,7 @@ static int ltc2983_probe(struct spi_device *spi)
return devm_iio_device_register(&spi->dev, indio_dev);
}
-static int __maybe_unused ltc2983_resume(struct device *dev)
+static int ltc2983_resume(struct device *dev)
{
struct ltc2983_data *st = spi_get_drvdata(to_spi_device(dev));
int dummy;
@@ -1521,14 +1544,15 @@ static int __maybe_unused ltc2983_resume(struct device *dev)
return ltc2983_setup(st, false);
}
-static int __maybe_unused ltc2983_suspend(struct device *dev)
+static int ltc2983_suspend(struct device *dev)
{
struct ltc2983_data *st = spi_get_drvdata(to_spi_device(dev));
return regmap_write(st->regmap, LTC2983_STATUS_REG, LTC2983_SLEEP);
}
-static SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend, ltc2983_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend,
+ ltc2983_resume);
static const struct spi_device_id ltc2983_id_table[] = {
{ "ltc2983" },
@@ -1546,7 +1570,7 @@ static struct spi_driver ltc2983_driver = {
.driver = {
.name = "ltc2983",
.of_match_table = ltc2983_of_match,
- .pm = &ltc2983_pm_ops,
+ .pm = pm_sleep_ptr(&ltc2983_pm_ops),
},
.probe = ltc2983_probe,
.id_table = ltc2983_id_table,
diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
index b4cb21ab2e85..8307aae2cb45 100644
--- a/drivers/iio/temperature/max31856.c
+++ b/drivers/iio/temperature/max31856.c
@@ -7,13 +7,16 @@
*/
#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 <asm/unaligned.h>
#include <dt-bindings/iio/temperature/thermocouple.h>
/*
* The MSB of the register value determines whether the following byte will
@@ -168,7 +171,7 @@ static int max31856_thermocouple_read(struct max31856_data *data,
if (ret)
return ret;
/* Skip last 5 dead bits of LTCBL */
- *val = (reg_val[0] << 16 | reg_val[1] << 8 | reg_val[2]) >> 5;
+ *val = get_unaligned_be24(&reg_val[0]) >> 5;
/* Check 7th bit of LTCBH reg. value for sign*/
if (reg_val[0] & 0x80)
*val -= 0x80000;
@@ -185,7 +188,7 @@ static int max31856_thermocouple_read(struct max31856_data *data,
/* 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 = (reg_val[1] << 8 | reg_val[2]) >> 2;
+ *val = get_unaligned_be16(&reg_val[1]) >> 2;
/* As per datasheet add offset into CJTH and CJTL */
*val += offset_cjto;
/* Check 7th bit of CJTH reg. value for sign */
@@ -319,7 +322,7 @@ static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf)
fault = reg_val & faultbit;
- return sprintf(buf, "%d\n", fault);
+ return sysfs_emit(buf, "%d\n", fault);
}
static ssize_t show_fault_ovuv(struct device *dev,
@@ -343,7 +346,7 @@ static ssize_t show_filter(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max31856_data *data = iio_priv(indio_dev);
- return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
+ return sysfs_emit(buf, "%d\n", data->filter_50hz ? 50 : 60);
}
static ssize_t set_filter(struct device *dev,
@@ -416,16 +419,12 @@ static int max31856_probe(struct spi_device *spi)
spi_set_drvdata(spi, indio_dev);
indio_dev->info = &max31856_info;
- indio_dev->dev.parent = &spi->dev;
- indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = max31856_channels;
indio_dev->num_channels = ARRAY_SIZE(max31856_channels);
- ret = of_property_read_u32(spi->dev.of_node, "thermocouple-type",
- &data->thermocouple_type);
-
+ 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");
diff --git a/drivers/iio/temperature/max31865.c b/drivers/iio/temperature/max31865.c
new file mode 100644
index 000000000000..29e23652ba5a
--- /dev/null
+++ b/drivers/iio/temperature/max31865.c
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (c) Linumiz 2021
+ *
+ * max31865.c - Maxim MAX31865 RTD-to-Digital Converter sensor driver
+ *
+ * Author: Navin Sankar Velliangiri <navin@linumiz.com>
+ */
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <asm/unaligned.h>
+
+/*
+ * The MSB of the register value determines whether the following byte will
+ * be written or read. If it is 0, read will follow and if it is 1, write
+ * will follow.
+ */
+#define MAX31865_RD_WR_BIT BIT(7)
+
+#define MAX31865_CFG_VBIAS BIT(7)
+#define MAX31865_CFG_1SHOT BIT(5)
+#define MAX31865_3WIRE_RTD BIT(4)
+#define MAX31865_FAULT_STATUS_CLEAR BIT(1)
+#define MAX31865_FILTER_50HZ BIT(0)
+
+/* The MAX31865 registers */
+#define MAX31865_CFG_REG 0x00
+#define MAX31865_RTD_MSB 0x01
+#define MAX31865_FAULT_STATUS 0x07
+
+#define MAX31865_FAULT_OVUV BIT(2)
+
+static const char max31865_show_samp_freq[] = "50 60";
+
+static const struct iio_chan_spec max31865_channels[] = {
+ { /* RTD Temperature */
+ .type = IIO_TEMP,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)
+ },
+};
+
+struct max31865_data {
+ struct spi_device *spi;
+ struct mutex lock;
+ bool filter_50hz;
+ bool three_wire;
+ u8 buf[2] __aligned(IIO_DMA_MINALIGN);
+};
+
+static int max31865_read(struct max31865_data *data, u8 reg,
+ unsigned int read_size)
+{
+ return spi_write_then_read(data->spi, &reg, 1, data->buf, read_size);
+}
+
+static int max31865_write(struct max31865_data *data, size_t len)
+{
+ return spi_write(data->spi, data->buf, len);
+}
+
+static int enable_bias(struct max31865_data *data)
+{
+ u8 cfg;
+ int ret;
+
+ ret = max31865_read(data, MAX31865_CFG_REG, 1);
+ if (ret)
+ return ret;
+
+ cfg = data->buf[0];
+
+ data->buf[0] = MAX31865_CFG_REG | MAX31865_RD_WR_BIT;
+ data->buf[1] = cfg | MAX31865_CFG_VBIAS;
+
+ return max31865_write(data, 2);
+}
+
+static int disable_bias(struct max31865_data *data)
+{
+ u8 cfg;
+ int ret;
+
+ ret = max31865_read(data, MAX31865_CFG_REG, 1);
+ if (ret)
+ return ret;
+
+ cfg = data->buf[0];
+ cfg &= ~MAX31865_CFG_VBIAS;
+
+ data->buf[0] = MAX31865_CFG_REG | MAX31865_RD_WR_BIT;
+ data->buf[1] = cfg;
+
+ return max31865_write(data, 2);
+}
+
+static int max31865_rtd_read(struct max31865_data *data, int *val)
+{
+ u8 reg;
+ int ret;
+
+ /* Enable BIAS to start the conversion */
+ ret = enable_bias(data);
+ if (ret)
+ return ret;
+
+ /* wait 10.5ms before initiating the conversion */
+ msleep(11);
+
+ ret = max31865_read(data, MAX31865_CFG_REG, 1);
+ if (ret)
+ return ret;
+
+ reg = data->buf[0];
+ reg |= MAX31865_CFG_1SHOT | MAX31865_FAULT_STATUS_CLEAR;
+ data->buf[0] = MAX31865_CFG_REG | MAX31865_RD_WR_BIT;
+ data->buf[1] = reg;
+
+ ret = max31865_write(data, 2);
+ if (ret)
+ return ret;
+
+ if (data->filter_50hz) {
+ /* 50Hz filter mode requires 62.5ms to complete */
+ msleep(63);
+ } else {
+ /* 60Hz filter mode requires 52ms to complete */
+ msleep(52);
+ }
+
+ ret = max31865_read(data, MAX31865_RTD_MSB, 2);
+ if (ret)
+ return ret;
+
+ *val = get_unaligned_be16(&data->buf) >> 1;
+
+ return disable_bias(data);
+}
+
+static int max31865_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max31865_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&data->lock);
+ ret = max31865_rtd_read(data, val);
+ mutex_unlock(&data->lock);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* Temp. Data resolution is 0.03125 degree centigrade */
+ *val = 31;
+ *val2 = 250000; /* 1000 * 0.03125 */
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max31865_init(struct max31865_data *data)
+{
+ u8 cfg;
+ int ret;
+
+ ret = max31865_read(data, MAX31865_CFG_REG, 1);
+ if (ret)
+ return ret;
+
+ cfg = data->buf[0];
+
+ if (data->three_wire)
+ /* 3-wire RTD connection */
+ cfg |= MAX31865_3WIRE_RTD;
+
+ if (data->filter_50hz)
+ /* 50Hz noise rejection filter */
+ cfg |= MAX31865_FILTER_50HZ;
+
+ data->buf[0] = MAX31865_CFG_REG | MAX31865_RD_WR_BIT;
+ data->buf[1] = cfg;
+
+ return max31865_write(data, 2);
+}
+
+static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf)
+{
+ int ret;
+ bool fault;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct max31865_data *data = iio_priv(indio_dev);
+
+ ret = max31865_read(data, MAX31865_FAULT_STATUS, 1);
+ if (ret)
+ return ret;
+
+ fault = data->buf[0] & faultbit;
+
+ return sysfs_emit(buf, "%d\n", fault);
+}
+
+static ssize_t show_fault_ovuv(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return show_fault(dev, MAX31865_FAULT_OVUV, buf);
+}
+
+static ssize_t show_filter(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct max31865_data *data = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%d\n", data->filter_50hz ? 50 : 60);
+}
+
+static ssize_t set_filter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct max31865_data *data = iio_priv(indio_dev);
+ unsigned int freq;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &freq);
+ if (ret)
+ return ret;
+
+ switch (freq) {
+ case 50:
+ data->filter_50hz = true;
+ break;
+ case 60:
+ data->filter_50hz = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->lock);
+ ret = max31865_init(data);
+ mutex_unlock(&data->lock);
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(max31865_show_samp_freq);
+static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
+static IIO_DEVICE_ATTR(in_filter_notch_center_frequency, 0644,
+ show_filter, set_filter, 0);
+
+static struct attribute *max31865_attributes[] = {
+ &iio_dev_attr_fault_ovuv.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_filter_notch_center_frequency.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group max31865_group = {
+ .attrs = max31865_attributes,
+};
+
+static const struct iio_info max31865_info = {
+ .read_raw = max31865_read_raw,
+ .attrs = &max31865_group,
+};
+
+static int max31865_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct iio_dev *indio_dev;
+ struct max31865_data *data;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->spi = spi;
+ data->filter_50hz = false;
+ mutex_init(&data->lock);
+
+ indio_dev->info = &max31865_info;
+ indio_dev->name = id->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = max31865_channels;
+ indio_dev->num_channels = ARRAY_SIZE(max31865_channels);
+
+ if (device_property_read_bool(&spi->dev, "maxim,3-wire")) {
+ /* select 3 wire */
+ data->three_wire = 1;
+ } else {
+ /* select 2 or 4 wire */
+ data->three_wire = 0;
+ }
+
+ ret = max31865_init(data);
+ if (ret) {
+ dev_err(&spi->dev, "error: Failed to configure max31865\n");
+ return ret;
+ }
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id max31865_id[] = {
+ { "max31865", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, max31865_id);
+
+static const struct of_device_id max31865_of_match[] = {
+ { .compatible = "maxim,max31865" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max31865_of_match);
+
+static struct spi_driver max31865_driver = {
+ .driver = {
+ .name = "max31865",
+ .of_match_table = max31865_of_match,
+ },
+ .probe = max31865_probe,
+ .id_table = max31865_id,
+};
+module_spi_driver(max31865_driver);
+
+MODULE_AUTHOR("Navin Sankar Velliangiri <navin@linumiz.com>");
+MODULE_DESCRIPTION("Maxim MAX31865 RTD-to-Digital Converter sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c
index 8d21116c7a22..c28a7a6dea5f 100644
--- a/drivers/iio/temperature/maxim_thermocouple.c
+++ b/drivers/iio/temperature/maxim_thermocouple.c
@@ -6,12 +6,11 @@
* Author: <matt.ranostay@konsulko.com>
*/
-#include <linux/module.h>
#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -123,7 +122,7 @@ struct maxim_thermocouple_data {
struct spi_device *spi;
const struct maxim_thermocouple_chip *chip;
- u8 buffer[16] ____cacheline_aligned;
+ u8 buffer[16] __aligned(IIO_DMA_MINALIGN);
char tc_type;
};
@@ -244,7 +243,6 @@ static int maxim_thermocouple_probe(struct spi_device *spi)
indio_dev->available_scan_masks = chip->scan_masks;
indio_dev->num_channels = chip->num_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->dev.parent = &spi->dev;
data = iio_priv(indio_dev);
data->spi = spi;
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index b7c56ddf884f..8eb0f962ed25 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -79,16 +79,15 @@ struct mlx90614_data {
/* Bandwidth values for IIR filtering */
static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86};
-static IIO_CONST_ATTR(in_temp_object_filter_low_pass_3db_frequency_available,
- "0.15 0.20 0.31 0.77 0.86 1.10 1.53 7.23");
-
-static struct attribute *mlx90614_attributes[] = {
- &iio_const_attr_in_temp_object_filter_low_pass_3db_frequency_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group mlx90614_attr_group = {
- .attrs = mlx90614_attributes,
+static const int mlx90614_freqs[][2] = {
+ {0, 150000},
+ {0, 200000},
+ {0, 310000},
+ {0, 770000},
+ {0, 860000},
+ {1, 100000},
+ {1, 530000},
+ {7, 230000}
};
/*
@@ -176,11 +175,14 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client,
static int mlx90614_power_get(struct mlx90614_data *data, bool startup)
{
unsigned long now;
+ int ret;
if (!data->wakeup_gpio)
return 0;
- pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
+ if (ret < 0)
+ return ret;
if (startup) {
now = jiffies;
@@ -267,7 +269,10 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
*val = MLX90614_CONST_SCALE;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = i2c_smbus_read_word_data(data->client,
MLX90614_EMISSIVITY);
@@ -287,7 +292,10 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
FIR = 1024 */
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
mutex_unlock(&data->lock);
@@ -319,7 +327,10 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX +
val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION;
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY,
val);
@@ -331,7 +342,10 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
if (val < 0 || val2 < 0)
return -EINVAL;
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = mlx90614_iir_search(data->client,
val * 100 + val2 / 10000);
@@ -358,6 +372,22 @@ static int mlx90614_write_raw_get_fmt(struct iio_dev *indio_dev,
}
}
+static int mlx90614_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *vals = (int *)mlx90614_freqs;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = 2 * ARRAY_SIZE(mlx90614_freqs);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct iio_chan_spec mlx90614_channels[] = {
{
.type = IIO_TEMP,
@@ -374,6 +404,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_separate_available =
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
@@ -386,6 +418,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_separate_available =
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
@@ -395,7 +429,7 @@ static const struct iio_info mlx90614_info = {
.read_raw = mlx90614_read_raw,
.write_raw = mlx90614_write_raw,
.write_raw_get_fmt = mlx90614_write_raw_get_fmt,
- .attrs = &mlx90614_attr_group,
+ .read_avail = mlx90614_read_avail,
};
#ifdef CONFIG_PM
@@ -525,7 +559,6 @@ static int mlx90614_probe(struct i2c_client *client,
mlx90614_wakeup(data);
- indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mlx90614_info;
@@ -557,7 +590,7 @@ static int mlx90614_probe(struct i2c_client *client,
return iio_device_register(indio_dev);
}
-static int mlx90614_remove(struct i2c_client *client)
+static void mlx90614_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mlx90614_data *data = iio_priv(indio_dev);
@@ -570,8 +603,6 @@ static int mlx90614_remove(struct i2c_client *client)
mlx90614_sleep(data);
pm_runtime_set_suspended(&client->dev);
}
-
- return 0;
}
static const struct i2c_device_id mlx90614_id[] = {
@@ -586,7 +617,6 @@ static const struct of_device_id mlx90614_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mlx90614_of_match);
-#ifdef CONFIG_PM_SLEEP
static int mlx90614_pm_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -616,9 +646,7 @@ static int mlx90614_pm_resume(struct device *dev)
return 0;
}
-#endif
-#ifdef CONFIG_PM
static int mlx90614_pm_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -634,19 +662,18 @@ static int mlx90614_pm_runtime_resume(struct device *dev)
return mlx90614_wakeup(data);
}
-#endif
static const struct dev_pm_ops mlx90614_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume)
- SET_RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend,
- mlx90614_pm_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume)
+ RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend,
+ mlx90614_pm_runtime_resume, NULL)
};
static struct i2c_driver mlx90614_driver = {
.driver = {
.name = "mlx90614",
.of_match_table = mlx90614_of_match,
- .pm = &mlx90614_pm_ops,
+ .pm = pm_ptr(&mlx90614_pm_ops),
},
.probe = mlx90614_probe,
.remove = mlx90614_remove,
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
index eaca6ba06864..f6dec0e5f097 100644
--- a/drivers/iio/temperature/mlx90632.c
+++ b/drivers/iio/temperature/mlx90632.c
@@ -10,12 +10,15 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/math64.h>
-#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -58,6 +61,8 @@
/* Control register address - volatile */
#define MLX90632_REG_CONTROL 0x3001 /* Control Register address */
#define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */
+#define MLX90632_CFG_MTYP_MASK GENMASK(8, 4) /* Meas select Mask */
+
/* PowerModes statuses */
#define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
#define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
@@ -65,6 +70,18 @@
#define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
+/* Measurement types */
+#define MLX90632_MTYP_MEDICAL 0
+#define MLX90632_MTYP_EXTENDED 17
+
+/* Measurement type select*/
+#define MLX90632_MTYP_STATUS(ctrl_val) (ctrl_val << 4)
+#define MLX90632_MTYP_STATUS_MEDICAL MLX90632_MTYP_STATUS(MLX90632_MTYP_MEDICAL)
+#define MLX90632_MTYP_STATUS_EXTENDED MLX90632_MTYP_STATUS(MLX90632_MTYP_EXTENDED)
+
+/* I2C command register - volatile */
+#define MLX90632_REG_I2C_CMD 0x3005 /* I2C command Register address */
+
/* Device status register - volatile */
#define MLX90632_REG_STATUS 0x3fff /* Device status register */
#define MLX90632_STAT_BUSY BIT(10) /* Device busy indicator */
@@ -78,26 +95,55 @@
#define MLX90632_RAM_2(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 1)
#define MLX90632_RAM_3(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 2)
+/* Name important RAM_MEAS channels */
+#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1 MLX90632_RAM_3(17)
+#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2 MLX90632_RAM_3(18)
+#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_1 MLX90632_RAM_1(17)
+#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_2 MLX90632_RAM_2(17)
+#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_3 MLX90632_RAM_1(18)
+#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_4 MLX90632_RAM_2(18)
+#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_5 MLX90632_RAM_1(19)
+#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_6 MLX90632_RAM_2(19)
+
/* Magic constants */
#define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */
#define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */
+#define MLX90632_ID_EXTENDED 0x0505 /* EEPROM DSPv5 Extended range device id */
+#define MLX90632_ID_MASK GENMASK(14, 0) /* DSP version and device ID in EE_VERSION */
#define MLX90632_DSP_VERSION 5 /* DSP version */
#define MLX90632_DSP_MASK GENMASK(7, 0) /* DSP version in EE_VERSION */
#define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */
-#define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */
-#define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */
-#define MLX90632_MAX_MEAS_NUM 31 /**< Maximum measurements in list */
-#define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */
+#define MLX90632_REF_12 12LL /* ResCtrlRef value of Ch 1 or Ch 2 */
+#define MLX90632_REF_3 12LL /* ResCtrlRef value of Channel 3 */
+#define MLX90632_MAX_MEAS_NUM 31 /* Maximum measurements in list */
+#define MLX90632_SLEEP_DELAY_MS 3000 /* Autosleep delay */
+#define MLX90632_EXTENDED_LIMIT 27000 /* Extended mode raw value limit */
+/**
+ * struct mlx90632_data - private data for the MLX90632 device
+ * @client: I2C client of the device
+ * @lock: Internal mutex for multiple reads for single measurement
+ * @regmap: Regmap of the device
+ * @emissivity: Object emissivity from 0 to 1000 where 1000 = 1.
+ * @mtyp: Measurement type physical sensor configuration for extended range
+ * calculations
+ * @object_ambient_temperature: Ambient temperature at object (might differ of
+ * the ambient temperature of sensor.
+ * @regulator: Regulator of the device
+ */
struct mlx90632_data {
struct i2c_client *client;
- struct mutex lock; /* Multiple reads for single measurement */
+ struct mutex lock;
struct regmap *regmap;
u16 emissivity;
+ u8 mtyp;
+ u32 object_ambient_temperature;
+ struct regulator *regulator;
};
static const struct regmap_range mlx90632_volatile_reg_range[] = {
regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
+ regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
regmap_reg_range(MLX90632_RAM_1(0),
MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
@@ -113,6 +159,7 @@ static const struct regmap_range mlx90632_read_reg_range[] = {
regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
+ regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
regmap_reg_range(MLX90632_RAM_1(0),
MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
@@ -164,8 +211,17 @@ static s32 mlx90632_pwr_continuous(struct regmap *regmap)
}
/**
- * mlx90632_perform_measurement - Trigger and retrieve current measurement cycle
- * @*data: pointer to mlx90632_data object containing regmap information
+ * mlx90632_reset_delay() - Give the mlx90632 some time to reset properly
+ * If this is not done, the following I2C command(s) will not be accepted.
+ */
+static void mlx90632_reset_delay(void)
+{
+ usleep_range(150, 200);
+}
+
+/**
+ * mlx90632_perform_measurement() - Trigger and retrieve current measurement cycle
+ * @data: pointer to mlx90632_data object containing regmap information
*
* Perform a measurement and return latest measurement cycle position reported
* by sensor. This is a blocking function for 500ms, as that is default sensor
@@ -173,25 +229,19 @@ static s32 mlx90632_pwr_continuous(struct regmap *regmap)
*/
static int mlx90632_perform_measurement(struct mlx90632_data *data)
{
- int ret, tries = 100;
unsigned int reg_status;
+ int ret;
ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS,
MLX90632_STAT_DATA_RDY, 0);
if (ret < 0)
return ret;
- while (tries-- > 0) {
- ret = regmap_read(data->regmap, MLX90632_REG_STATUS,
- &reg_status);
- if (ret < 0)
- return ret;
- if (reg_status & MLX90632_STAT_DATA_RDY)
- break;
- usleep_range(10000, 11000);
- }
+ ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS, reg_status,
+ !(reg_status & MLX90632_STAT_DATA_RDY), 10000,
+ 100 * 10000);
- if (tries < 0) {
+ if (ret < 0) {
dev_err(&data->client->dev, "data not ready");
return -ETIMEDOUT;
}
@@ -199,6 +249,28 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data)
return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
}
+static int mlx90632_set_meas_type(struct regmap *regmap, u8 type)
+{
+ int ret;
+
+ if ((type != MLX90632_MTYP_MEDICAL) && (type != MLX90632_MTYP_EXTENDED))
+ return -EINVAL;
+
+ ret = regmap_write(regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD);
+ if (ret < 0)
+ return ret;
+
+ mlx90632_reset_delay();
+
+ ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL,
+ (MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK),
+ (MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT));
+ if (ret < 0)
+ return ret;
+
+ return mlx90632_pwr_continuous(regmap);
+}
+
static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
uint8_t *channel_old)
{
@@ -300,6 +372,97 @@ read_unlock:
return ret;
}
+static int mlx90632_read_ambient_raw_extended(struct regmap *regmap,
+ s16 *ambient_new_raw, s16 *ambient_old_raw)
+{
+ unsigned int read_tmp;
+ int ret;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *ambient_new_raw = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *ambient_old_raw = (s16)read_tmp;
+
+ return 0;
+}
+
+static int mlx90632_read_object_raw_extended(struct regmap *regmap, s16 *object_new_raw)
+{
+ unsigned int read_tmp;
+ s32 read;
+ int ret;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_1, &read_tmp);
+ if (ret < 0)
+ return ret;
+ read = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_2, &read_tmp);
+ if (ret < 0)
+ return ret;
+ read = read - (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_3, &read_tmp);
+ if (ret < 0)
+ return ret;
+ read = read - (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_4, &read_tmp);
+ if (ret < 0)
+ return ret;
+ read = (read + (s16)read_tmp) / 2;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_5, &read_tmp);
+ if (ret < 0)
+ return ret;
+ read = read + (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_6, &read_tmp);
+ if (ret < 0)
+ return ret;
+ read = read + (s16)read_tmp;
+
+ if (read > S16_MAX || read < S16_MIN)
+ return -ERANGE;
+
+ *object_new_raw = read;
+
+ return 0;
+}
+
+static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *object_new_raw,
+ s16 *ambient_new_raw, s16 *ambient_old_raw)
+{
+ s32 ret, meas;
+
+ mutex_lock(&data->lock);
+ ret = mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_EXTENDED);
+ if (ret < 0)
+ goto read_unlock;
+
+ ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19,
+ 50000, 800000, false, data);
+ if (ret != 0)
+ goto read_unlock;
+
+ ret = mlx90632_read_object_raw_extended(data->regmap, object_new_raw);
+ if (ret < 0)
+ goto read_unlock;
+
+ ret = mlx90632_read_ambient_raw_extended(data->regmap, ambient_new_raw, ambient_old_raw);
+
+read_unlock:
+ (void) mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_MEDICAL);
+
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
s32 *reg_value)
{
@@ -354,9 +517,23 @@ static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw,
return div64_s64((tmp << 19ULL), 1000LL);
}
+static s64 mlx90632_preprocess_temp_obj_extended(s16 object_new_raw, s16 ambient_new_raw,
+ s16 ambient_old_raw, s16 Ka)
+{
+ s64 VR_IR, kKa, tmp;
+
+ kKa = ((s64)Ka * 1000LL) >> 10ULL;
+ VR_IR = (s64)ambient_old_raw * 1000000LL +
+ kKa * div64_s64((s64)ambient_new_raw * 1000LL,
+ MLX90632_REF_3);
+ tmp = div64_s64(
+ div64_s64((s64) object_new_raw * 1000000000000LL, MLX90632_REF_12),
+ VR_IR);
+ return div64_s64(tmp << 19ULL, 1000LL);
+}
+
static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
- s32 P_T, s32 P_R, s32 P_G, s32 P_O,
- s16 Gb)
+ s32 P_T, s32 P_R, s32 P_G, s32 P_O, s16 Gb)
{
s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum;
@@ -374,11 +551,11 @@ static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
}
static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
- s64 TAdut, s32 Fa, s32 Fb,
+ s64 TAdut, s64 TAdut4, s32 Fa, s32 Fb,
s32 Ga, s16 Ha, s16 Hb,
u16 emissivity)
{
- s64 calcedKsTO, calcedKsTA, ir_Alpha, TAdut4, Alpha_corr;
+ s64 calcedKsTO, calcedKsTA, ir_Alpha, Alpha_corr;
s64 Ha_customer, Hb_customer;
Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL;
@@ -393,36 +570,66 @@ static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL);
Alpha_corr = div64_s64(Alpha_corr, 1000LL);
ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr);
- TAdut4 = (div64_s64(TAdut, 10000LL) + 27315) *
- (div64_s64(TAdut, 10000LL) + 27315) *
- (div64_s64(TAdut, 10000LL) + 27315) *
- (div64_s64(TAdut, 10000LL) + 27315);
return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4))
- 27315 - Hb_customer) * 10;
}
+static s64 mlx90632_calc_ta4(s64 TAdut, s64 scale)
+{
+ return (div64_s64(TAdut, scale) + 27315) *
+ (div64_s64(TAdut, scale) + 27315) *
+ (div64_s64(TAdut, scale) + 27315) *
+ (div64_s64(TAdut, scale) + 27315);
+}
+
static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb,
s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb,
u16 tmp_emi)
{
- s64 kTA, kTA0, TAdut;
+ s64 kTA, kTA0, TAdut, TAdut4;
s64 temp = 25000;
s8 i;
kTA = (Ea * 1000LL) >> 16LL;
kTA0 = (Eb * 1000LL) >> 8LL;
TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL;
+ TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL);
/* Iterations of calculation as described in datasheet */
for (i = 0; i < 5; ++i) {
- temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut,
+ temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TAdut4,
Fa, Fb, Ga, Ha, Hb,
tmp_emi);
}
return temp;
}
+static s32 mlx90632_calc_temp_object_extended(s64 object, s64 ambient, s64 reflected,
+ s32 Ea, s32 Eb, s32 Fa, s32 Fb, s32 Ga,
+ s16 Ha, s16 Hb, u16 tmp_emi)
+{
+ s64 kTA, kTA0, TAdut, TAdut4, Tr4, TaTr4;
+ s64 temp = 25000;
+ s8 i;
+
+ kTA = (Ea * 1000LL) >> 16LL;
+ kTA0 = (Eb * 1000LL) >> 8LL;
+ TAdut = div64_s64((ambient - kTA0) * 1000000LL, kTA) + 25 * 1000000LL;
+ Tr4 = mlx90632_calc_ta4(reflected, 10);
+ TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL);
+ TaTr4 = Tr4 - div64_s64(Tr4 - TAdut4, tmp_emi) * 1000;
+
+ /* Iterations of calculation as described in datasheet */
+ for (i = 0; i < 5; ++i) {
+ temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TaTr4,
+ Fa / 2, Fb, Ga, Ha, Hb,
+ tmp_emi);
+ }
+
+ return temp;
+}
+
static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
{
s32 ret;
@@ -470,6 +677,26 @@ static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
if (ret < 0)
return ret;
+ if (object_new_raw > MLX90632_EXTENDED_LIMIT &&
+ data->mtyp == MLX90632_MTYP_EXTENDED) {
+ ret = mlx90632_read_all_channel_extended(data, &object_new_raw,
+ &ambient_new_raw, &ambient_old_raw);
+ if (ret < 0)
+ return ret;
+
+ /* Use extended mode calculations */
+ ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
+ ambient_old_raw, Gb);
+ object = mlx90632_preprocess_temp_obj_extended(object_new_raw,
+ ambient_new_raw,
+ ambient_old_raw, Ka);
+ *val = mlx90632_calc_temp_object_extended(object, ambient,
+ data->object_ambient_temperature,
+ Ea, Eb, Fa, Fb, Ga,
+ Ha, Hb, data->emissivity);
+ return 0;
+ }
+
ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
ambient_old_raw, Gb);
object = mlx90632_preprocess_temp_obj(object_new_raw,
@@ -548,7 +775,9 @@ static int mlx90632_read_raw(struct iio_dev *indio_dev,
*val2 = data->emissivity * 1000;
}
return IIO_VAL_INT_PLUS_MICRO;
-
+ case IIO_CHAN_INFO_CALIBAMBIENT:
+ *val = data->object_ambient_temperature;
+ return IIO_VAL_INT;
default:
return -EINVAL;
}
@@ -568,6 +797,9 @@ static int mlx90632_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
data->emissivity = val * 1000 + val2 / 1000;
return 0;
+ case IIO_CHAN_INFO_CALIBAMBIENT:
+ data->object_ambient_temperature = val;
+ return 0;
default:
return -EINVAL;
}
@@ -585,7 +817,7 @@ static const struct iio_chan_spec mlx90632_channels[] = {
.modified = 1,
.channel2 = IIO_MOD_TEMP_OBJECT,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
- BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+ BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | BIT(IIO_CHAN_INFO_CALIBAMBIENT),
},
};
@@ -617,6 +849,32 @@ static int mlx90632_wakeup(struct mlx90632_data *data)
return mlx90632_pwr_continuous(data->regmap);
}
+static void mlx90632_disable_regulator(void *_data)
+{
+ struct mlx90632_data *data = _data;
+ int ret;
+
+ ret = regulator_disable(data->regulator);
+ if (ret < 0)
+ dev_err(regmap_get_device(data->regmap),
+ "Failed to disable power regulator: %d\n", ret);
+}
+
+static int mlx90632_enable_regulator(struct mlx90632_data *data)
+{
+ int ret;
+
+ ret = regulator_enable(data->regulator);
+ if (ret < 0) {
+ dev_err(regmap_get_device(data->regmap), "Failed to enable power regulator!\n");
+ return ret;
+ }
+
+ mlx90632_reset_delay();
+
+ return ret;
+}
+
static int mlx90632_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -643,15 +901,32 @@ static int mlx90632_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
mlx90632->client = client;
mlx90632->regmap = regmap;
+ mlx90632->mtyp = MLX90632_MTYP_MEDICAL;
mutex_init(&mlx90632->lock);
- indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mlx90632_info;
indio_dev->channels = mlx90632_channels;
indio_dev->num_channels = ARRAY_SIZE(mlx90632_channels);
+ mlx90632->regulator = devm_regulator_get(&client->dev, "vdd");
+ if (IS_ERR(mlx90632->regulator))
+ return dev_err_probe(&client->dev, PTR_ERR(mlx90632->regulator),
+ "failed to get vdd regulator");
+
+ ret = mlx90632_enable_regulator(mlx90632);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_add_action_or_reset(&client->dev, mlx90632_disable_regulator,
+ mlx90632);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to setup regulator cleanup action %d\n",
+ ret);
+ return ret;
+ }
+
ret = mlx90632_wakeup(mlx90632);
if (ret < 0) {
dev_err(&client->dev, "Wakeup failed: %d\n", ret);
@@ -663,15 +938,20 @@ static int mlx90632_probe(struct i2c_client *client,
dev_err(&client->dev, "read of version failed: %d\n", ret);
return ret;
}
+ read = read & MLX90632_ID_MASK;
if (read == MLX90632_ID_MEDICAL) {
dev_dbg(&client->dev,
"Detected Medical EEPROM calibration %x\n", read);
} else if (read == MLX90632_ID_CONSUMER) {
dev_dbg(&client->dev,
"Detected Consumer EEPROM calibration %x\n", read);
+ } else if (read == MLX90632_ID_EXTENDED) {
+ dev_dbg(&client->dev,
+ "Detected Extended range EEPROM calibration %x\n", read);
+ mlx90632->mtyp = MLX90632_MTYP_EXTENDED;
} else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) {
dev_dbg(&client->dev,
- "Detected Unknown EEPROM calibration %x\n", read);
+ "Detected Unknown EEPROM calibration %x\n", read);
} else {
dev_err(&client->dev,
"Wrong DSP version %x (expected %x)\n",
@@ -680,6 +960,7 @@ static int mlx90632_probe(struct i2c_client *client,
}
mlx90632->emissivity = 1000;
+ mlx90632->object_ambient_temperature = 25000; /* 25 degrees milliCelsius */
pm_runtime_disable(&client->dev);
ret = pm_runtime_set_active(&client->dev);
@@ -694,7 +975,7 @@ static int mlx90632_probe(struct i2c_client *client,
return iio_device_register(indio_dev);
}
-static int mlx90632_remove(struct i2c_client *client)
+static void mlx90632_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mlx90632_data *data = iio_priv(indio_dev);
@@ -706,8 +987,6 @@ static int mlx90632_remove(struct i2c_client *client)
pm_runtime_put_noidle(&client->dev);
mlx90632_sleep(data);
-
- return 0;
}
static const struct i2c_device_id mlx90632_id[] = {
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
index cc45d8345eb9..706a760f30b4 100644
--- a/drivers/iio/temperature/tmp006.c
+++ b/drivers/iio/temperature/tmp006.c
@@ -193,6 +193,25 @@ static bool tmp006_check_identification(struct i2c_client *client)
return mid == TMP006_MANUFACTURER_MAGIC && did == TMP006_DEVICE_MAGIC;
}
+static int tmp006_power(struct device *dev, bool up)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct tmp006_data *data = iio_priv(indio_dev);
+
+ if (up)
+ data->config |= TMP006_CONFIG_MOD_MASK;
+ else
+ data->config &= ~TMP006_CONFIG_MOD_MASK;
+
+ return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+ data->config);
+}
+
+static void tmp006_powerdown_cleanup(void *dev)
+{
+ tmp006_power(dev, false);
+}
+
static int tmp006_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -216,7 +235,6 @@ static int tmp006_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
data->client = client;
- indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tmp006_info;
@@ -229,42 +247,31 @@ static int tmp006_probe(struct i2c_client *client,
return ret;
data->config = ret;
- return iio_device_register(indio_dev);
-}
-
-static int tmp006_powerdown(struct tmp006_data *data)
-{
- return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
- data->config & ~TMP006_CONFIG_MOD_MASK);
-}
-
-static int tmp006_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ if ((ret & TMP006_CONFIG_MOD_MASK) != TMP006_CONFIG_MOD_MASK) {
+ ret = tmp006_power(&client->dev, true);
+ if (ret < 0)
+ return ret;
+ }
- iio_device_unregister(indio_dev);
- tmp006_powerdown(iio_priv(indio_dev));
+ ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup,
+ &client->dev);
+ if (ret < 0)
+ return ret;
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
-#ifdef CONFIG_PM_SLEEP
static int tmp006_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
- return tmp006_powerdown(iio_priv(indio_dev));
+ return tmp006_power(dev, false);
}
static int tmp006_resume(struct device *dev)
{
- struct tmp006_data *data = iio_priv(i2c_get_clientdata(
- to_i2c_client(dev)));
- return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
- data->config | TMP006_CONFIG_MOD_MASK);
+ return tmp006_power(dev, true);
}
-#endif
-static SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
static const struct i2c_device_id tmp006_id[] = {
{ "tmp006", 0 },
@@ -275,10 +282,9 @@ MODULE_DEVICE_TABLE(i2c, tmp006_id);
static struct i2c_driver tmp006_driver = {
.driver = {
.name = "tmp006",
- .pm = &tmp006_pm_ops,
+ .pm = pm_sleep_ptr(&tmp006_pm_ops),
},
.probe = tmp006_probe,
- .remove = tmp006_remove,
.id_table = tmp006_id,
};
module_i2c_driver(tmp006_driver);
diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c
index 7df234d96f94..f3420d8a0e35 100644
--- a/drivers/iio/temperature/tmp007.c
+++ b/drivers/iio/temperature/tmp007.c
@@ -20,7 +20,7 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/bitops.h>
-#include <linux/of.h>
+#include <linux/mod_devicetable.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -439,6 +439,13 @@ static bool tmp007_identify(struct i2c_client *client)
return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC);
}
+static void tmp007_powerdown_action_cb(void *priv)
+{
+ struct tmp007_data *data = priv;
+
+ tmp007_powerdown(data);
+}
+
static int tmp007_probe(struct i2c_client *client,
const struct i2c_device_id *tmp007_id)
{
@@ -463,7 +470,6 @@ static int tmp007_probe(struct i2c_client *client,
data->client = client;
mutex_init(&data->lock);
- indio_dev->dev.parent = &client->dev;
indio_dev->name = "tmp007";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tmp007_info;
@@ -490,6 +496,10 @@ static int tmp007_probe(struct i2c_client *client,
if (ret < 0)
return ret;
+ ret = devm_add_action_or_reset(&client->dev, tmp007_powerdown_action_cb, data);
+ if (ret)
+ return ret;
+
/*
* Only the following flags can activate ALERT pin. Data conversion/validity flags
* flags can still be polled for getting temperature data
@@ -503,7 +513,7 @@ static int tmp007_probe(struct i2c_client *client,
ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK);
if (ret < 0)
- goto error_powerdown;
+ return ret;
data->status_mask = ret;
data->status_mask |= (TMP007_STATUS_OHF | TMP007_STATUS_OLF
@@ -511,7 +521,7 @@ static int tmp007_probe(struct i2c_client *client,
ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, data->status_mask);
if (ret < 0)
- goto error_powerdown;
+ return ret;
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
@@ -520,30 +530,13 @@ static int tmp007_probe(struct i2c_client *client,
tmp007_id->name, indio_dev);
if (ret) {
dev_err(&client->dev, "irq request error %d\n", -ret);
- goto error_powerdown;
+ return ret;
}
}
- return iio_device_register(indio_dev);
-
-error_powerdown:
- tmp007_powerdown(data);
-
- return ret;
-}
-
-static int tmp007_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct tmp007_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- tmp007_powerdown(data);
-
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
-#ifdef CONFIG_PM_SLEEP
static int tmp007_suspend(struct device *dev)
{
struct tmp007_data *data = iio_priv(i2c_get_clientdata(
@@ -560,9 +553,8 @@ static int tmp007_resume(struct device *dev)
return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
data->config | TMP007_CONFIG_CONV_EN);
}
-#endif
-static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
static const struct of_device_id tmp007_of_match[] = {
{ .compatible = "ti,tmp007", },
@@ -579,11 +571,10 @@ MODULE_DEVICE_TABLE(i2c, tmp007_id);
static struct i2c_driver tmp007_driver = {
.driver = {
.name = "tmp007",
- .of_match_table = of_match_ptr(tmp007_of_match),
- .pm = &tmp007_pm_ops,
+ .of_match_table = tmp007_of_match,
+ .pm = pm_sleep_ptr(&tmp007_pm_ops),
},
.probe = tmp007_probe,
- .remove = tmp007_remove,
.id_table = tmp007_id,
};
module_i2c_driver(tmp007_driver);
diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c
new file mode 100644
index 000000000000..f9b8f2b570f6
--- /dev/null
+++ b/drivers/iio/temperature/tmp117.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Digital temperature sensor with integrated Non-volatile memory
+ * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com>
+ *
+ * Driver for the Texas Instruments TMP117 Temperature Sensor
+ * (7-bit I2C slave address (0x48 - 0x4B), changeable via ADD pins)
+ *
+ * Note: This driver assumes that the sensor has been calibrated beforehand.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+
+#include <linux/iio/iio.h>
+
+#define TMP117_REG_TEMP 0x0
+#define TMP117_REG_CFGR 0x1
+#define TMP117_REG_HIGH_LIM 0x2
+#define TMP117_REG_LOW_LIM 0x3
+#define TMP117_REG_EEPROM_UL 0x4
+#define TMP117_REG_EEPROM1 0x5
+#define TMP117_REG_EEPROM2 0x6
+#define TMP117_REG_TEMP_OFFSET 0x7
+#define TMP117_REG_EEPROM3 0x8
+#define TMP117_REG_DEVICE_ID 0xF
+
+#define TMP117_RESOLUTION_10UC 78125
+#define TMP117_DEVICE_ID 0x0117
+#define MICRODEGREE_PER_10MILLIDEGREE 10000
+
+struct tmp117_data {
+ struct i2c_client *client;
+ s16 calibbias;
+};
+
+static int tmp117_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct tmp117_data *data = iio_priv(indio_dev);
+ s32 ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = i2c_smbus_read_word_swapped(data->client,
+ TMP117_REG_TEMP);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret, 15);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_CALIBBIAS:
+ ret = i2c_smbus_read_word_swapped(data->client,
+ TMP117_REG_TEMP_OFFSET);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret, 15);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * Conversion from 10s of uC to mC
+ * as IIO reports temperature in mC
+ */
+ *val = TMP117_RESOLUTION_10UC / MICRODEGREE_PER_10MILLIDEGREE;
+ *val2 = (TMP117_RESOLUTION_10UC %
+ MICRODEGREE_PER_10MILLIDEGREE) * 100;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tmp117_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct tmp117_data *data = iio_priv(indio_dev);
+ s16 off;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ off = clamp_t(int, val, S16_MIN, S16_MAX);
+ if (off == data->calibbias)
+ return 0;
+ data->calibbias = off;
+ return i2c_smbus_write_word_swapped(data->client,
+ TMP117_REG_TEMP_OFFSET, off);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec tmp117_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static const struct iio_info tmp117_info = {
+ .read_raw = tmp117_read_raw,
+ .write_raw = tmp117_write_raw,
+};
+
+static int tmp117_identify(struct i2c_client *client)
+{
+ int dev_id;
+
+ dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
+ if (dev_id < 0)
+ return dev_id;
+ if (dev_id != TMP117_DEVICE_ID) {
+ dev_err(&client->dev, "TMP117 not found\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int tmp117_probe(struct i2c_client *client)
+{
+ struct tmp117_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EOPNOTSUPP;
+
+ ret = tmp117_identify(client);
+ if (ret < 0)
+ return ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ data->calibbias = 0;
+
+ indio_dev->name = "tmp117";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &tmp117_info;
+
+ indio_dev->channels = tmp117_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tmp117_channels);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct of_device_id tmp117_of_match[] = {
+ { .compatible = "ti,tmp117", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tmp117_of_match);
+
+static const struct i2c_device_id tmp117_id[] = {
+ { "tmp117", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp117_id);
+
+static struct i2c_driver tmp117_driver = {
+ .driver = {
+ .name = "tmp117",
+ .of_match_table = tmp117_of_match,
+ },
+ .probe_new = tmp117_probe,
+ .id_table = tmp117_id,
+};
+module_i2c_driver(tmp117_driver);
+
+MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>");
+MODULE_DESCRIPTION("TI TMP117 Temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
index d41f050c2fea..60d58ec5b063 100644
--- a/drivers/iio/temperature/tsys01.c
+++ b/drivers/iio/temperature/tsys01.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/stat.h>
@@ -160,7 +161,6 @@ static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
indio_dev->info = &tsys01_info;
indio_dev->name = dev->driver->name;
- indio_dev->dev.parent = dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = tsys01_channels;
indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
@@ -223,7 +223,7 @@ static struct i2c_driver tsys01_driver = {
.id_table = tsys01_id,
.driver = {
.name = "tsys01",
- .of_match_table = of_match_ptr(tsys01_of_match),
+ .of_match_table = tsys01_of_match,
},
};
@@ -233,3 +233,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS);
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
index 6735af400b22..49c275e4f510 100644
--- a/drivers/iio/temperature/tsys02d.c
+++ b/drivers/iio/temperature/tsys02d.c
@@ -149,7 +149,6 @@ static int tsys02d_probe(struct i2c_client *client,
indio_dev->info = &tsys02d_info;
indio_dev->name = id->name;
- indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = tsys02d_channels;
indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
@@ -188,3 +187,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS);