Char/Misc driver fixes for 6.10-rc6

Here are some small driver fixes for 6.10-rc6.  Included in here are:
   - IIO driver fixes for reported issues
   - Counter driver fix for a reported problem.
 
 All of these have been in linux-next this week with no reported issues
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZoFlrA8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymiMQCgkUmsCT9KQDt+/IqClfL+A6nBvUkAn08jRwGA
 dXjTvroHgHsNCU/VXMwV
 =FcWr
 -----END PGP SIGNATURE-----

Merge tag 'char-misc-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver fixes from Greg KH:
 "Here are some small driver fixes for 6.10-rc6. Included in here are:

   - IIO driver fixes for reported issues

   - Counter driver fix for a reported problem.

  All of these have been in linux-next this week with no reported
  issues"

* tag 'char-misc-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
  counter: ti-eqep: enable clock at probe
  iio: chemical: bme680: Fix sensor data read operation
  iio: chemical: bme680: Fix overflows in compensate() functions
  iio: chemical: bme680: Fix calibration data variable
  iio: chemical: bme680: Fix pressure value output
  iio: humidity: hdc3020: fix hysteresis representation
  iio: dac: fix ad9739a random config compile error
  iio: accel: fxls8962af: select IIO_BUFFER & IIO_KFIFO_BUF
  iio: adc: ad7266: Fix variable checking bug
  iio: xilinx-ams: Don't include ams_ctrl_channels in scan_mask
This commit is contained in:
Linus Torvalds 2024-06-30 09:16:08 -07:00
commit 84dd4373d5
8 changed files with 321 additions and 86 deletions

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/counter.h> #include <linux/counter.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
@ -376,6 +377,7 @@ static int ti_eqep_probe(struct platform_device *pdev)
struct counter_device *counter; struct counter_device *counter;
struct ti_eqep_cnt *priv; struct ti_eqep_cnt *priv;
void __iomem *base; void __iomem *base;
struct clk *clk;
int err; int err;
counter = devm_counter_alloc(dev, sizeof(*priv)); counter = devm_counter_alloc(dev, sizeof(*priv));
@ -415,6 +417,10 @@ static int ti_eqep_probe(struct platform_device *pdev)
pm_runtime_enable(dev); pm_runtime_enable(dev);
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable clock\n");
err = counter_add(counter); err = counter_add(counter);
if (err < 0) { if (err < 0) {
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);

View File

@ -330,6 +330,8 @@ config DMARD10
config FXLS8962AF config FXLS8962AF
tristate tristate
depends on I2C || !I2C # cannot be built-in for modular I2C depends on I2C || !I2C # cannot be built-in for modular I2C
select IIO_BUFFER
select IIO_KFIFO_BUF
config FXLS8962AF_I2C config FXLS8962AF_I2C
tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver" tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver"

View File

@ -157,6 +157,8 @@ static int ad7266_read_raw(struct iio_dev *indio_dev,
ret = ad7266_read_single(st, val, chan->address); ret = ad7266_read_single(st, val, chan->address);
iio_device_release_direct_mode(indio_dev); iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = (*val >> 2) & 0xfff; *val = (*val >> 2) & 0xfff;
if (chan->scan_type.sign == 's') if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, *val = sign_extend32(*val,

View File

@ -414,8 +414,12 @@ static void ams_enable_channel_sequence(struct iio_dev *indio_dev)
/* Run calibration of PS & PL as part of the sequence */ /* Run calibration of PS & PL as part of the sequence */
scan_mask = BIT(0) | BIT(AMS_PS_SEQ_MAX); scan_mask = BIT(0) | BIT(AMS_PS_SEQ_MAX);
for (i = 0; i < indio_dev->num_channels; i++) for (i = 0; i < indio_dev->num_channels; i++) {
scan_mask |= BIT_ULL(indio_dev->channels[i].scan_index); const struct iio_chan_spec *chan = &indio_dev->channels[i];
if (chan->scan_index < AMS_CTRL_SEQ_BASE)
scan_mask |= BIT_ULL(chan->scan_index);
}
if (ams->ps_base) { if (ams->ps_base) {
/* put sysmon in a soft reset to change the sequence */ /* put sysmon in a soft reset to change the sequence */

View File

@ -54,7 +54,9 @@
#define BME680_NB_CONV_MASK GENMASK(3, 0) #define BME680_NB_CONV_MASK GENMASK(3, 0)
#define BME680_REG_MEAS_STAT_0 0x1D #define BME680_REG_MEAS_STAT_0 0x1D
#define BME680_NEW_DATA_BIT BIT(7)
#define BME680_GAS_MEAS_BIT BIT(6) #define BME680_GAS_MEAS_BIT BIT(6)
#define BME680_MEAS_BIT BIT(5)
/* Calibration Parameters */ /* Calibration Parameters */
#define BME680_T2_LSB_REG 0x8A #define BME680_T2_LSB_REG 0x8A

View File

@ -10,6 +10,7 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/log2.h> #include <linux/log2.h>
@ -38,7 +39,7 @@ struct bme680_calib {
s8 par_h3; s8 par_h3;
s8 par_h4; s8 par_h4;
s8 par_h5; s8 par_h5;
s8 par_h6; u8 par_h6;
s8 par_h7; s8 par_h7;
s8 par_gh1; s8 par_gh1;
s16 par_gh2; s16 par_gh2;
@ -342,10 +343,10 @@ static s16 bme680_compensate_temp(struct bme680_data *data,
if (!calib->par_t2) if (!calib->par_t2)
bme680_read_calib(data, calib); bme680_read_calib(data, calib);
var1 = (adc_temp >> 3) - (calib->par_t1 << 1); var1 = (adc_temp >> 3) - ((s32)calib->par_t1 << 1);
var2 = (var1 * calib->par_t2) >> 11; var2 = (var1 * calib->par_t2) >> 11;
var3 = ((var1 >> 1) * (var1 >> 1)) >> 12; var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
var3 = (var3 * (calib->par_t3 << 4)) >> 14; var3 = (var3 * ((s32)calib->par_t3 << 4)) >> 14;
data->t_fine = var2 + var3; data->t_fine = var2 + var3;
calc_temp = (data->t_fine * 5 + 128) >> 8; calc_temp = (data->t_fine * 5 + 128) >> 8;
@ -368,9 +369,9 @@ static u32 bme680_compensate_press(struct bme680_data *data,
var1 = (data->t_fine >> 1) - 64000; var1 = (data->t_fine >> 1) - 64000;
var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * calib->par_p6) >> 2; var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * calib->par_p6) >> 2;
var2 = var2 + (var1 * calib->par_p5 << 1); var2 = var2 + (var1 * calib->par_p5 << 1);
var2 = (var2 >> 2) + (calib->par_p4 << 16); var2 = (var2 >> 2) + ((s32)calib->par_p4 << 16);
var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
(calib->par_p3 << 5)) >> 3) + ((s32)calib->par_p3 << 5)) >> 3) +
((calib->par_p2 * var1) >> 1); ((calib->par_p2 * var1) >> 1);
var1 = var1 >> 18; var1 = var1 >> 18;
var1 = ((32768 + var1) * calib->par_p1) >> 15; var1 = ((32768 + var1) * calib->par_p1) >> 15;
@ -388,7 +389,7 @@ static u32 bme680_compensate_press(struct bme680_data *data,
var3 = ((press_comp >> 8) * (press_comp >> 8) * var3 = ((press_comp >> 8) * (press_comp >> 8) *
(press_comp >> 8) * calib->par_p10) >> 17; (press_comp >> 8) * calib->par_p10) >> 17;
press_comp += (var1 + var2 + var3 + (calib->par_p7 << 7)) >> 4; press_comp += (var1 + var2 + var3 + ((s32)calib->par_p7 << 7)) >> 4;
return press_comp; return press_comp;
} }
@ -414,7 +415,7 @@ static u32 bme680_compensate_humid(struct bme680_data *data,
(((temp_scaled * ((temp_scaled * calib->par_h5) / 100)) (((temp_scaled * ((temp_scaled * calib->par_h5) / 100))
>> 6) / 100) + (1 << 14))) >> 10; >> 6) / 100) + (1 << 14))) >> 10;
var3 = var1 * var2; var3 = var1 * var2;
var4 = calib->par_h6 << 7; var4 = (s32)calib->par_h6 << 7;
var4 = (var4 + ((temp_scaled * calib->par_h7) / 100)) >> 4; var4 = (var4 + ((temp_scaled * calib->par_h7) / 100)) >> 4;
var5 = ((var3 >> 14) * (var3 >> 14)) >> 10; var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
var6 = (var4 * var5) >> 1; var6 = (var4 * var5) >> 1;
@ -532,6 +533,43 @@ static u8 bme680_oversampling_to_reg(u8 val)
return ilog2(val) + 1; return ilog2(val) + 1;
} }
/*
* Taken from Bosch BME680 API:
* https://github.com/boschsensortec/BME68x_SensorAPI/blob/v4.4.8/bme68x.c#L490
*/
static int bme680_wait_for_eoc(struct bme680_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
unsigned int check;
int ret;
/*
* (Sum of oversampling ratios * time per oversampling) +
* TPH measurement + gas measurement + wait transition from forced mode
* + heater duration
*/
int wait_eoc_us = ((data->oversampling_temp + data->oversampling_press +
data->oversampling_humid) * 1936) + (477 * 4) +
(477 * 5) + 1000 + (data->heater_dur * 1000);
usleep_range(wait_eoc_us, wait_eoc_us + 100);
ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &check);
if (ret) {
dev_err(dev, "failed to read measurement status register.\n");
return ret;
}
if (check & BME680_MEAS_BIT) {
dev_err(dev, "Device measurement cycle incomplete.\n");
return -EBUSY;
}
if (!(check & BME680_NEW_DATA_BIT)) {
dev_err(dev, "No new data available from the device.\n");
return -ENODATA;
}
return 0;
}
static int bme680_chip_config(struct bme680_data *data) static int bme680_chip_config(struct bme680_data *data)
{ {
struct device *dev = regmap_get_device(data->regmap); struct device *dev = regmap_get_device(data->regmap);
@ -622,6 +660,10 @@ static int bme680_read_temp(struct bme680_data *data, int *val)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = bme680_wait_for_eoc(data);
if (ret)
return ret;
ret = regmap_bulk_read(data->regmap, BME680_REG_TEMP_MSB, ret = regmap_bulk_read(data->regmap, BME680_REG_TEMP_MSB,
&tmp, 3); &tmp, 3);
if (ret < 0) { if (ret < 0) {
@ -678,7 +720,7 @@ static int bme680_read_press(struct bme680_data *data,
} }
*val = bme680_compensate_press(data, adc_press); *val = bme680_compensate_press(data, adc_press);
*val2 = 100; *val2 = 1000;
return IIO_VAL_FRACTIONAL; return IIO_VAL_FRACTIONAL;
} }
@ -738,6 +780,10 @@ static int bme680_read_gas(struct bme680_data *data,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = bme680_wait_for_eoc(data);
if (ret)
return ret;
ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &check); ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &check);
if (check & BME680_GAS_MEAS_BIT) { if (check & BME680_GAS_MEAS_BIT) {
dev_err(dev, "gas measurement incomplete\n"); dev_err(dev, "gas measurement incomplete\n");

View File

@ -133,7 +133,7 @@ config AD5624R_SPI
config AD9739A config AD9739A
tristate "Analog Devices AD9739A RF DAC spi driver" tristate "Analog Devices AD9739A RF DAC spi driver"
depends on SPI || COMPILE_TEST depends on SPI
select REGMAP_SPI select REGMAP_SPI
select IIO_BACKEND select IIO_BACKEND
help help

View File

@ -19,6 +19,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/math64.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/pm.h> #include <linux/pm.h>
@ -66,8 +67,10 @@
#define HDC3020_CRC8_POLYNOMIAL 0x31 #define HDC3020_CRC8_POLYNOMIAL 0x31
#define HDC3020_MIN_TEMP -40 #define HDC3020_MIN_TEMP_MICRO -39872968
#define HDC3020_MAX_TEMP 125 #define HDC3020_MAX_TEMP_MICRO 124875639
#define HDC3020_MAX_TEMP_HYST_MICRO 164748607
#define HDC3020_MAX_HUM_MICRO 99220264
struct hdc3020_data { struct hdc3020_data {
struct i2c_client *client; struct i2c_client *client;
@ -368,6 +371,105 @@ static int hdc3020_write_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
static int hdc3020_thresh_get_temp(u16 thresh)
{
int temp;
/*
* Get the temperature threshold from 9 LSBs, shift them to get
* the truncated temperature threshold representation and
* calculate the threshold according to the formula in the
* datasheet. Result is degree celsius scaled by 65535.
*/
temp = FIELD_GET(HDC3020_THRESH_TEMP_MASK, thresh) <<
HDC3020_THRESH_TEMP_TRUNC_SHIFT;
return -2949075 + (175 * temp);
}
static int hdc3020_thresh_get_hum(u16 thresh)
{
int hum;
/*
* Get the humidity threshold from 7 MSBs, shift them to get the
* truncated humidity threshold representation and calculate the
* threshold according to the formula in the datasheet. Result is
* percent scaled by 65535.
*/
hum = FIELD_GET(HDC3020_THRESH_HUM_MASK, thresh) <<
HDC3020_THRESH_HUM_TRUNC_SHIFT;
return hum * 100;
}
static u16 hdc3020_thresh_set_temp(int s_temp, u16 curr_thresh)
{
u64 temp;
u16 thresh;
/*
* Calculate temperature threshold, shift it down to get the
* truncated threshold representation in the 9LSBs while keeping
* the current humidity threshold in the 7 MSBs.
*/
temp = (u64)(s_temp + 45000000) * 65535ULL;
temp = div_u64(temp, 1000000 * 175) >> HDC3020_THRESH_TEMP_TRUNC_SHIFT;
thresh = FIELD_PREP(HDC3020_THRESH_TEMP_MASK, temp);
thresh |= (FIELD_GET(HDC3020_THRESH_HUM_MASK, curr_thresh) <<
HDC3020_THRESH_HUM_TRUNC_SHIFT);
return thresh;
}
static u16 hdc3020_thresh_set_hum(int s_hum, u16 curr_thresh)
{
u64 hum;
u16 thresh;
/*
* Calculate humidity threshold, shift it down and up to get the
* truncated threshold representation in the 7MSBs while keeping
* the current temperature threshold in the 9 LSBs.
*/
hum = (u64)(s_hum) * 65535ULL;
hum = div_u64(hum, 1000000 * 100) >> HDC3020_THRESH_HUM_TRUNC_SHIFT;
thresh = FIELD_PREP(HDC3020_THRESH_HUM_MASK, hum);
thresh |= FIELD_GET(HDC3020_THRESH_TEMP_MASK, curr_thresh);
return thresh;
}
static
int hdc3020_thresh_clr(s64 s_thresh, s64 s_hyst, enum iio_event_direction dir)
{
s64 s_clr;
/*
* Include directions when calculation the clear value,
* since hysteresis is unsigned by definition and the
* clear value is an absolute value which is signed.
*/
if (dir == IIO_EV_DIR_RISING)
s_clr = s_thresh - s_hyst;
else
s_clr = s_thresh + s_hyst;
/* Divide by 65535 to get units of micro */
return div_s64(s_clr, 65535);
}
static int _hdc3020_write_thresh(struct hdc3020_data *data, u16 reg, u16 val)
{
u8 buf[5];
put_unaligned_be16(reg, buf);
put_unaligned_be16(val, buf + 2);
buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
return hdc3020_write_bytes(data, buf, 5);
}
static int hdc3020_write_thresh(struct iio_dev *indio_dev, static int hdc3020_write_thresh(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_type type,
@ -376,67 +478,126 @@ static int hdc3020_write_thresh(struct iio_dev *indio_dev,
int val, int val2) int val, int val2)
{ {
struct hdc3020_data *data = iio_priv(indio_dev); struct hdc3020_data *data = iio_priv(indio_dev);
u8 buf[5]; u16 reg, reg_val, reg_thresh_rd, reg_clr_rd, reg_thresh_wr, reg_clr_wr;
u64 tmp; s64 s_thresh, s_hyst, s_clr;
u16 reg; int s_val, thresh, clr, ret;
int ret;
/* Supported temperature range is from 40 to 125 degree celsius */ /* Select threshold registers */
if (val < HDC3020_MIN_TEMP || val > HDC3020_MAX_TEMP) if (dir == IIO_EV_DIR_RISING) {
return -EINVAL; reg_thresh_rd = HDC3020_R_T_RH_THRESH_HIGH;
reg_thresh_wr = HDC3020_S_T_RH_THRESH_HIGH;
/* Select threshold register */ reg_clr_rd = HDC3020_R_T_RH_THRESH_HIGH_CLR;
if (info == IIO_EV_INFO_VALUE) { reg_clr_wr = HDC3020_S_T_RH_THRESH_HIGH_CLR;
if (dir == IIO_EV_DIR_RISING)
reg = HDC3020_S_T_RH_THRESH_HIGH;
else
reg = HDC3020_S_T_RH_THRESH_LOW;
} else { } else {
if (dir == IIO_EV_DIR_RISING) reg_thresh_rd = HDC3020_R_T_RH_THRESH_LOW;
reg = HDC3020_S_T_RH_THRESH_HIGH_CLR; reg_thresh_wr = HDC3020_S_T_RH_THRESH_LOW;
else reg_clr_rd = HDC3020_R_T_RH_THRESH_LOW_CLR;
reg = HDC3020_S_T_RH_THRESH_LOW_CLR; reg_clr_wr = HDC3020_S_T_RH_THRESH_LOW_CLR;
} }
guard(mutex)(&data->lock); guard(mutex)(&data->lock);
ret = hdc3020_read_be16(data, reg); ret = hdc3020_read_be16(data, reg_thresh_rd);
if (ret < 0) if (ret < 0)
return ret; return ret;
thresh = ret;
ret = hdc3020_read_be16(data, reg_clr_rd);
if (ret < 0)
return ret;
clr = ret;
/* Scale value to include decimal part into calculations */
s_val = (val < 0) ? (val * 1000000 - val2) : (val * 1000000 + val2);
switch (chan->type) { switch (chan->type) {
case IIO_TEMP: case IIO_TEMP:
/* switch (info) {
* Calculate temperature threshold, shift it down to get the case IIO_EV_INFO_VALUE:
* truncated threshold representation in the 9LSBs while keeping s_val = max(s_val, HDC3020_MIN_TEMP_MICRO);
* the current humidity threshold in the 7 MSBs. s_val = min(s_val, HDC3020_MAX_TEMP_MICRO);
*/ reg = reg_thresh_wr;
tmp = ((u64)(((val + 45) * MICRO) + val2)) * 65535ULL; reg_val = hdc3020_thresh_set_temp(s_val, thresh);
tmp = div_u64(tmp, MICRO * 175); ret = _hdc3020_write_thresh(data, reg, reg_val);
val = tmp >> HDC3020_THRESH_TEMP_TRUNC_SHIFT; if (ret < 0)
val = FIELD_PREP(HDC3020_THRESH_TEMP_MASK, val); return ret;
val |= (FIELD_GET(HDC3020_THRESH_HUM_MASK, ret) <<
HDC3020_THRESH_HUM_TRUNC_SHIFT); /* Calculate old hysteresis */
s_thresh = (s64)hdc3020_thresh_get_temp(thresh) * 1000000;
s_clr = (s64)hdc3020_thresh_get_temp(clr) * 1000000;
s_hyst = div_s64(abs(s_thresh - s_clr), 65535);
/* Set new threshold */
thresh = reg_val;
/* Set old hysteresis */
s_val = s_hyst;
fallthrough;
case IIO_EV_INFO_HYSTERESIS:
/*
* Function hdc3020_thresh_get_temp returns temperature
* in degree celsius scaled by 65535. Scale by 1000000
* to be able to subtract scaled hysteresis value.
*/
s_thresh = (s64)hdc3020_thresh_get_temp(thresh) * 1000000;
/*
* Units of s_val are in micro degree celsius, scale by
* 65535 to get same units as s_thresh.
*/
s_val = min(abs(s_val), HDC3020_MAX_TEMP_HYST_MICRO);
s_hyst = (s64)s_val * 65535;
s_clr = hdc3020_thresh_clr(s_thresh, s_hyst, dir);
s_clr = max(s_clr, HDC3020_MIN_TEMP_MICRO);
s_clr = min(s_clr, HDC3020_MAX_TEMP_MICRO);
reg = reg_clr_wr;
reg_val = hdc3020_thresh_set_temp(s_clr, clr);
break;
default:
return -EOPNOTSUPP;
}
break; break;
case IIO_HUMIDITYRELATIVE: case IIO_HUMIDITYRELATIVE:
/* s_val = (s_val < 0) ? 0 : min(s_val, HDC3020_MAX_HUM_MICRO);
* Calculate humidity threshold, shift it down and up to get the switch (info) {
* truncated threshold representation in the 7MSBs while keeping case IIO_EV_INFO_VALUE:
* the current temperature threshold in the 9 LSBs. reg = reg_thresh_wr;
*/ reg_val = hdc3020_thresh_set_hum(s_val, thresh);
tmp = ((u64)((val * MICRO) + val2)) * 65535ULL; ret = _hdc3020_write_thresh(data, reg, reg_val);
tmp = div_u64(tmp, MICRO * 100); if (ret < 0)
val = tmp >> HDC3020_THRESH_HUM_TRUNC_SHIFT; return ret;
val = FIELD_PREP(HDC3020_THRESH_HUM_MASK, val);
val |= FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret); /* Calculate old hysteresis */
s_thresh = (s64)hdc3020_thresh_get_hum(thresh) * 1000000;
s_clr = (s64)hdc3020_thresh_get_hum(clr) * 1000000;
s_hyst = div_s64(abs(s_thresh - s_clr), 65535);
/* Set new threshold */
thresh = reg_val;
/* Try to set old hysteresis */
s_val = min(abs(s_hyst), HDC3020_MAX_HUM_MICRO);
fallthrough;
case IIO_EV_INFO_HYSTERESIS:
/*
* Function hdc3020_thresh_get_hum returns relative
* humidity in percent scaled by 65535. Scale by 1000000
* to be able to subtract scaled hysteresis value.
*/
s_thresh = (s64)hdc3020_thresh_get_hum(thresh) * 1000000;
/*
* Units of s_val are in micro percent, scale by 65535
* to get same units as s_thresh.
*/
s_hyst = (s64)s_val * 65535;
s_clr = hdc3020_thresh_clr(s_thresh, s_hyst, dir);
s_clr = max(s_clr, 0);
s_clr = min(s_clr, HDC3020_MAX_HUM_MICRO);
reg = reg_clr_wr;
reg_val = hdc3020_thresh_set_hum(s_clr, clr);
break;
default:
return -EOPNOTSUPP;
}
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
put_unaligned_be16(reg, buf); return _hdc3020_write_thresh(data, reg, reg_val);
put_unaligned_be16(val, buf + 2);
buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
return hdc3020_write_bytes(data, buf, 5);
} }
static int hdc3020_read_thresh(struct iio_dev *indio_dev, static int hdc3020_read_thresh(struct iio_dev *indio_dev,
@ -447,48 +608,60 @@ static int hdc3020_read_thresh(struct iio_dev *indio_dev,
int *val, int *val2) int *val, int *val2)
{ {
struct hdc3020_data *data = iio_priv(indio_dev); struct hdc3020_data *data = iio_priv(indio_dev);
u16 reg; u16 reg_thresh, reg_clr;
int ret; int thresh, clr, ret;
/* Select threshold register */ /* Select threshold registers */
if (info == IIO_EV_INFO_VALUE) { if (dir == IIO_EV_DIR_RISING) {
if (dir == IIO_EV_DIR_RISING) reg_thresh = HDC3020_R_T_RH_THRESH_HIGH;
reg = HDC3020_R_T_RH_THRESH_HIGH; reg_clr = HDC3020_R_T_RH_THRESH_HIGH_CLR;
else
reg = HDC3020_R_T_RH_THRESH_LOW;
} else { } else {
if (dir == IIO_EV_DIR_RISING) reg_thresh = HDC3020_R_T_RH_THRESH_LOW;
reg = HDC3020_R_T_RH_THRESH_HIGH_CLR; reg_clr = HDC3020_R_T_RH_THRESH_LOW_CLR;
else
reg = HDC3020_R_T_RH_THRESH_LOW_CLR;
} }
guard(mutex)(&data->lock); guard(mutex)(&data->lock);
ret = hdc3020_read_be16(data, reg); ret = hdc3020_read_be16(data, reg_thresh);
if (ret < 0) if (ret < 0)
return ret; return ret;
switch (chan->type) { switch (chan->type) {
case IIO_TEMP: case IIO_TEMP:
/* thresh = hdc3020_thresh_get_temp(ret);
* Get the temperature threshold from 9 LSBs, shift them to get switch (info) {
* the truncated temperature threshold representation and case IIO_EV_INFO_VALUE:
* calculate the threshold according to the formula in the *val = thresh;
* datasheet. break;
*/ case IIO_EV_INFO_HYSTERESIS:
*val = FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret); ret = hdc3020_read_be16(data, reg_clr);
*val = *val << HDC3020_THRESH_TEMP_TRUNC_SHIFT; if (ret < 0)
*val = -2949075 + (175 * (*val)); return ret;
clr = hdc3020_thresh_get_temp(ret);
*val = abs(thresh - clr);
break;
default:
return -EOPNOTSUPP;
}
*val2 = 65535; *val2 = 65535;
return IIO_VAL_FRACTIONAL; return IIO_VAL_FRACTIONAL;
case IIO_HUMIDITYRELATIVE: case IIO_HUMIDITYRELATIVE:
/* thresh = hdc3020_thresh_get_hum(ret);
* Get the humidity threshold from 7 MSBs, shift them to get the switch (info) {
* truncated humidity threshold representation and calculate the case IIO_EV_INFO_VALUE:
* threshold according to the formula in the datasheet. *val = thresh;
*/ break;
*val = FIELD_GET(HDC3020_THRESH_HUM_MASK, ret); case IIO_EV_INFO_HYSTERESIS:
*val = (*val << HDC3020_THRESH_HUM_TRUNC_SHIFT) * 100; ret = hdc3020_read_be16(data, reg_clr);
if (ret < 0)
return ret;
clr = hdc3020_thresh_get_hum(ret);
*val = abs(thresh - clr);
break;
default:
return -EOPNOTSUPP;
}
*val2 = 65535; *val2 = 65535;
return IIO_VAL_FRACTIONAL; return IIO_VAL_FRACTIONAL;
default: default: