mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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:
commit
84dd4373d5
@ -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);
|
||||||
|
@ -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"
|
||||||
|
@ -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,
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
|
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user