From a7bddfe2dfce1d8859422124abe1964e0ecd386e Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Wed, 23 Oct 2019 11:26:34 +0300 Subject: [PATCH 01/43] iio: dln2-adc: fix iio_triggered_buffer_postenable() position The iio_triggered_buffer_postenable() hook should be called first to attach the poll function. The iio_triggered_buffer_predisable() hook is called last (as is it should). This change moves iio_triggered_buffer_postenable() to be called first. It adds iio_triggered_buffer_predisable() on the error paths of the postenable hook. For the predisable hook, some code-paths have been changed to make sure that the iio_triggered_buffer_predisable() hook gets called in case there is an error before it. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/adc/dln2-adc.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index 5fa78c273a25..65c7c9329b1c 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -524,6 +524,10 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev) u16 conflict; unsigned int trigger_chan; + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret) + return ret; + mutex_lock(&dln2->mutex); /* Enable ADC */ @@ -537,6 +541,7 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev) (int)conflict); ret = -EBUSY; } + iio_triggered_buffer_predisable(indio_dev); return ret; } @@ -550,6 +555,7 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev) mutex_unlock(&dln2->mutex); if (ret < 0) { dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__); + iio_triggered_buffer_predisable(indio_dev); return ret; } } else { @@ -557,12 +563,12 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev) mutex_unlock(&dln2->mutex); } - return iio_triggered_buffer_postenable(indio_dev); + return 0; } static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev) { - int ret; + int ret, ret2; struct dln2_adc *dln2 = iio_priv(indio_dev); mutex_lock(&dln2->mutex); @@ -577,12 +583,14 @@ static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev) ret = dln2_adc_set_port_enabled(dln2, false, NULL); mutex_unlock(&dln2->mutex); - if (ret < 0) { + if (ret < 0) dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__); - return ret; - } - return iio_triggered_buffer_predisable(indio_dev); + ret2 = iio_triggered_buffer_predisable(indio_dev); + if (ret == 0) + ret = ret2; + + return ret; } static const struct iio_buffer_setup_ops dln2_adc_buffer_setup_ops = { From 9b58916035a6b05256aafce4c5055805b9043cda Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Wed, 23 Oct 2019 11:27:14 +0300 Subject: [PATCH 02/43] iio: hdc100x: fix iio_triggered_buffer_{predisable,postenable} positions The iio_triggered_buffer_postenable() hook should be called first to attach the poll function and the iio_triggered_buffer_predisable() hook should be called last in the predisable hook. This change updates the driver to attach/detach the poll func in the correct order. Signed-off-by: Alexandru Ardelean Reviewed-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hdc100x.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index bfe1cdb16846..963ff043eecf 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -278,31 +278,34 @@ static int hdc100x_buffer_postenable(struct iio_dev *indio_dev) struct hdc100x_data *data = iio_priv(indio_dev); int ret; + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret) + return ret; + /* Buffer is enabled. First set ACQ Mode, then attach poll func */ mutex_lock(&data->lock); ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, HDC100X_REG_CONFIG_ACQ_MODE); mutex_unlock(&data->lock); if (ret) - return ret; + iio_triggered_buffer_predisable(indio_dev); - return iio_triggered_buffer_postenable(indio_dev); + return ret; } static int hdc100x_buffer_predisable(struct iio_dev *indio_dev) { struct hdc100x_data *data = iio_priv(indio_dev); - int ret; - - /* First detach poll func, then reset ACQ mode. OK to disable buffer */ - ret = iio_triggered_buffer_predisable(indio_dev); - if (ret) - return ret; + int ret, ret2; mutex_lock(&data->lock); ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); mutex_unlock(&data->lock); + ret2 = iio_triggered_buffer_predisable(indio_dev); + if (ret == 0) + ret = ret2; + return ret; } From 26ba6db672698641223eece20beeb59a60032eb9 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:34:56 +0200 Subject: [PATCH 03/43] iio: gyro: adis16136: check ret val for non-zero vs less-than-zero The ADIS library functions return zero on success, and negative values for error. Positive values aren't returned, but we only care about the success value (which is zero). This change is mostly needed so that the compiler won't make any inferences about some about values being potentially un-initialized. This only triggers after making some functions inline, because the compiler can better follow return paths. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16136.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 5bec7ad53d8b..d637d52d051a 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -80,19 +80,19 @@ static ssize_t adis16136_show_serial(struct file *file, ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM, &serial); - if (ret < 0) + if (ret) return ret; ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1); - if (ret < 0) + if (ret) return ret; ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2); - if (ret < 0) + if (ret) return ret; ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3); - if (ret < 0) + if (ret) return ret; len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2, @@ -116,7 +116,7 @@ static int adis16136_show_product_id(void *arg, u64 *val) ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, &prod_id); - if (ret < 0) + if (ret) return ret; *val = prod_id; @@ -134,7 +134,7 @@ static int adis16136_show_flash_count(void *arg, u64 *val) ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT, &flash_count); - if (ret < 0) + if (ret) return ret; *val = flash_count; @@ -191,7 +191,7 @@ static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) int ret; ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); - if (ret < 0) + if (ret) return ret; *freq = 32768 / (t + 1); @@ -228,7 +228,7 @@ static ssize_t adis16136_read_frequency(struct device *dev, int ret; ret = adis16136_get_freq(adis16136, &freq); - if (ret < 0) + if (ret) return ret; return sprintf(buf, "%d\n", freq); @@ -256,7 +256,7 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val) int i, ret; ret = adis16136_get_freq(adis16136, &freq); - if (ret < 0) + if (ret) return ret; for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { @@ -277,11 +277,11 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) mutex_lock(&indio_dev->mlock); ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); - if (ret < 0) + if (ret) goto err_unlock; ret = adis16136_get_freq(adis16136, &freq); - if (ret < 0) + if (ret) goto err_unlock; *val = freq / adis16136_3db_divisors[val16 & 0x07]; @@ -318,7 +318,7 @@ static int adis16136_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_CALIBBIAS: ret = adis_read_reg_32(&adis16136->adis, ADIS16136_REG_GYRO_OFF2, &val32); - if (ret < 0) + if (ret) return ret; *val = sign_extend32(val32, 31); From fe4b7f917e8fa20c1a9dd2b3f417acd3b063c880 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:34:57 +0200 Subject: [PATCH 04/43] iio: imu: adis16400: check ret val for non-zero vs less-than-zero The ADIS library functions return zero on success, and negative values for error. Positive values aren't returned, but we only care about the success value (which is zero). This change is mostly needed so that the compiler won't make any inferences about some about values being potentially un-initialized. This only triggers after making some functions inline, because the compiler can better follow return paths. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 0575ff706bd4..44e46dc96e00 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -217,16 +217,16 @@ static ssize_t adis16400_show_serial_number(struct file *file, int ret; ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1); - if (ret < 0) + if (ret) return ret; ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2); - if (ret < 0) + if (ret) return ret; ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER, &serial_number); - if (ret < 0) + if (ret) return ret; len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2, @@ -249,7 +249,7 @@ static int adis16400_show_product_id(void *arg, u64 *val) int ret; ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id); - if (ret < 0) + if (ret) return ret; *val = prod_id; @@ -266,7 +266,7 @@ static int adis16400_show_flash_count(void *arg, u64 *val) int ret; ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count); - if (ret < 0) + if (ret) return ret; *val = flash_count; @@ -327,7 +327,7 @@ static int adis16334_get_freq(struct adis16400_state *st) uint16_t t; ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); - if (ret < 0) + if (ret) return ret; t >>= ADIS16334_RATE_DIV_SHIFT; @@ -359,7 +359,7 @@ static int adis16400_get_freq(struct adis16400_state *st) uint16_t t; ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); - if (ret < 0) + if (ret) return ret; sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 52851 : 1638404; @@ -416,7 +416,7 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) } ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); - if (ret < 0) + if (ret) return ret; ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, @@ -615,7 +615,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); - if (ret < 0) { + if (ret) { mutex_unlock(&indio_dev->mlock); return ret; } @@ -626,12 +626,12 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val2 = (ret % 1000) * 1000; } mutex_unlock(&indio_dev->mlock); - if (ret < 0) + if (ret) return ret; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: ret = st->variant->get_freq(st); - if (ret < 0) + if (ret) return ret; *val = ret / 1000; *val2 = (ret % 1000) * 1000; From c754a45455bb1ba759304128063c4325205f22fb Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:34:58 +0200 Subject: [PATCH 05/43] iio: imu: adis16460: check ret val for non-zero vs less-than-zero The ADIS library functions return zero on success, and negative values for error. Positive values aren't returned, but we only care about the success value (which is zero). This change is mostly needed so that the compiler won't make any inferences about some about values being potentially un-initialized. This only triggers after making some functions inline, because the compiler can better follow return paths. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16460.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index 6aed9e84abbf..b55812521537 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -80,7 +80,7 @@ static int adis16460_show_serial_number(void *arg, u64 *val) ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_SERIAL_NUM, &serial); - if (ret < 0) + if (ret) return ret; *val = serial; @@ -98,7 +98,7 @@ static int adis16460_show_product_id(void *arg, u64 *val) ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_PROD_ID, &prod_id); - if (ret < 0) + if (ret) return ret; *val = prod_id; @@ -116,7 +116,7 @@ static int adis16460_show_flash_count(void *arg, u64 *val) ret = adis_read_reg_32(&adis16460->adis, ADIS16460_REG_FLASH_CNT, &flash_count); - if (ret < 0) + if (ret) return ret; *val = flash_count; @@ -176,7 +176,7 @@ static int adis16460_get_freq(struct iio_dev *indio_dev, int *val, int *val2) unsigned int freq; ret = adis_read_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, &t); - if (ret < 0) + if (ret) return ret; freq = 2048000 / (t + 1); From 92c7529fc1bf3e607ed90c941e55bc244e04a256 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:34:59 +0200 Subject: [PATCH 06/43] iio: imu: adis16480: check ret val for non-zero vs less-than-zero The ADIS library functions return zero on success, and negative values for error. Positive values aren't returned, but we only care about the success value (which is zero). This change is mostly needed so that the compiler won't make any inferences about some about values being potentially un-initialized. This only triggers after making some functions inline, because the compiler can better follow return paths. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index b99d73887c9f..86801f3c5f0d 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -181,7 +181,7 @@ static ssize_t adis16480_show_firmware_revision(struct file *file, int ret; ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev); - if (ret < 0) + if (ret) return ret; len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff); @@ -206,11 +206,11 @@ static ssize_t adis16480_show_firmware_date(struct file *file, int ret; ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year); - if (ret < 0) + if (ret) return ret; ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md); - if (ret < 0) + if (ret) return ret; len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", @@ -234,7 +234,7 @@ static int adis16480_show_serial_number(void *arg, u64 *val) ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM, &serial); - if (ret < 0) + if (ret) return ret; *val = serial; @@ -252,7 +252,7 @@ static int adis16480_show_product_id(void *arg, u64 *val) ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID, &prod_id); - if (ret < 0) + if (ret) return ret; *val = prod_id; @@ -270,7 +270,7 @@ static int adis16480_show_flash_count(void *arg, u64 *val) ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT, &flash_count); - if (ret < 0) + if (ret) return ret; *val = flash_count; @@ -359,7 +359,7 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) reg = ADIS16480_REG_DEC_RATE; ret = adis_read_reg_16(&st->adis, reg, &t); - if (ret < 0) + if (ret) return ret; /* @@ -462,7 +462,7 @@ static int adis16480_get_calibbias(struct iio_dev *indio_dev, ret = -EINVAL; } - if (ret < 0) + if (ret) return ret; return IIO_VAL_INT; @@ -489,7 +489,7 @@ static int adis16480_get_calibscale(struct iio_dev *indio_dev, int ret; ret = adis_read_reg_16(&st->adis, reg, &val16); - if (ret < 0) + if (ret) return ret; *scale = sign_extend32(val16, 15); @@ -535,7 +535,7 @@ static int adis16480_get_filter_freq(struct iio_dev *indio_dev, enable_mask = BIT(offset + 2); ret = adis_read_reg_16(&st->adis, reg, &val); - if (ret < 0) + if (ret) return ret; if (!(val & enable_mask)) @@ -561,7 +561,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, enable_mask = BIT(offset + 2); ret = adis_read_reg_16(&st->adis, reg, &val); - if (ret < 0) + if (ret) return ret; if (freq == 0) { @@ -937,7 +937,7 @@ static int adis16480_enable_irq(struct adis *adis, bool enable) int ret; ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); - if (ret < 0) + if (ret) return ret; val &= ~ADIS16480_DRDY_EN_MSK; @@ -1115,7 +1115,7 @@ static int adis16480_ext_clk_config(struct adis16480 *st, int ret; ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val); - if (ret < 0) + if (ret) return ret; pin = adis16480_of_get_ext_clk_pin(st, of_node); @@ -1141,7 +1141,7 @@ static int adis16480_ext_clk_config(struct adis16480 *st, val |= mode; ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); - if (ret < 0) + if (ret) return ret; return clk_prepare_enable(st->ext_clk); From 6a39ab3b195c125d3fe49d0b0b613c2e1dbbc5a2 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:35:00 +0200 Subject: [PATCH 07/43] iio: imu: adis: check ret val for non-zero vs less-than-zero The ADIS library functions return zero on success, and negative values for error. Positive values aren't returned, but we only care about the success value (which is zero). This change is mostly needed so that the compiler won't make any inferences about some about values being potentially un-initialized. This only triggers after making some functions inline, because the compiler can better follow return paths. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 1631c255deab..dc2f9e061d98 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -286,7 +286,7 @@ int adis_check_status(struct adis *adis) int i; ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status); - if (ret < 0) + if (ret) return ret; status &= adis->data->status_error_mask; From d9bbae304a3ed9bc51bf4c815dd6aa6ed0fdd118 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:35:01 +0200 Subject: [PATCH 08/43] iio: imu: adis16480: fix indentation of return statement This is just a minor indentation/alignment fix for the default case of a switch statement. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 86801f3c5f0d..d199d3d3c4bd 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -459,7 +459,7 @@ static int adis16480_get_calibbias(struct iio_dev *indio_dev, *bias = sign_extend32(val32, 31); break; default: - ret = -EINVAL; + ret = -EINVAL; } if (ret) From 52c4c732b2a6fea469790438cb08ed2de2405c3e Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:35:02 +0200 Subject: [PATCH 09/43] iio: imu: adis16480: prefer `unsigned int` over `unsigned` This is a typical checkpatch warning. The change just renames the type of the `freq` var to `unsigned int`. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index d199d3d3c4bd..b9e2695bcfad 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -350,7 +350,7 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) struct adis16480 *st = iio_priv(indio_dev); uint16_t t; int ret; - unsigned freq; + unsigned int freq; unsigned int reg; if (st->clk_mode == ADIS16480_CLK_PPS) From 9b742763d9d4195e823ae6ece760c9ed0500c1dc Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:35:03 +0200 Subject: [PATCH 10/43] iio: imu: adis16480: assign bias value only if operation succeeded This was found only after the whole thing with the inline functions, but the compiler actually found something. The value of the `bias` (in adis16480_get_calibbias()) should only be set if the read operation was successful. No actual known problem occurs as users of this function all ultimately check the return value. Hence probably not stable material. Fixes: 2f3abe6cbb6c9 ("iio:imu: Add support for the ADIS16480 and similar IMUs") Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index b9e2695bcfad..c0e7e768be41 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -451,12 +451,14 @@ static int adis16480_get_calibbias(struct iio_dev *indio_dev, case IIO_MAGN: case IIO_PRESSURE: ret = adis_read_reg_16(&st->adis, reg, &val16); - *bias = sign_extend32(val16, 15); + if (ret == 0) + *bias = sign_extend32(val16, 15); break; case IIO_ANGL_VEL: case IIO_ACCEL: ret = adis_read_reg_32(&st->adis, reg, &val32); - *bias = sign_extend32(val32, 31); + if (ret == 0) + *bias = sign_extend32(val32, 31); break; default: ret = -EINVAL; From 38262c01ead40f2b061e8b7e6abe254b538d856c Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:35:04 +0200 Subject: [PATCH 11/43] iio: imu: adis: assign read val in debugfs hook only if op successful This was also caught by the `-Wmaybe-uninitialized` warning, which (ironically as-is) it makes quite a lot of sense to do for this. The code that actually calls this function will fail to copy on the uninitialized value. Hence, patch does not need to go into stable. Fixes: 78026a6fde8f7 ("iio:imu:adis: Add debugfs register access support") Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index dc2f9e061d98..85de565a4e80 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -229,7 +229,8 @@ int adis_debugfs_reg_access(struct iio_dev *indio_dev, int ret; ret = adis_read_reg_16(adis, reg, &val16); - *readval = val16; + if (ret == 0) + *readval = val16; return ret; } else { From c49cfc227e7f49e6011d6b955145814ce13424bc Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:35:05 +0200 Subject: [PATCH 12/43] iio: imu: adis: assign value only if return code zero in read funcs The inline read functions in the ADIS library don't check the return value of the `adis_read_reg()` function and assign the value of `tmp` regardless. Fix this by checking if return value is zero and only then assigning the value of `tmp`. No known case of the callers of this function incorrectly using the value, but best to stop any potential risk here. Not suitable for stable due to no known actual bugs caused by this issue. Fixes: 57a1228a06b7a ("iio:imu:adis: Add support for 32bit registers") Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- include/linux/iio/imu/adis.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 4c53815bb729..92aae14593bf 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -129,7 +129,8 @@ static inline int adis_read_reg_16(struct adis *adis, unsigned int reg, int ret; ret = adis_read_reg(adis, reg, &tmp, 2); - *val = tmp; + if (ret == 0) + *val = tmp; return ret; } @@ -147,7 +148,8 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg, int ret; ret = adis_read_reg(adis, reg, &tmp, 4); - *val = tmp; + if (ret == 0) + *val = tmp; return ret; } From d19aeb295154ae749ca8236b6b69c41c7a7b3891 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 12:37:05 +0100 Subject: [PATCH 13/43] iio: adc: aspeed: use devm_platform_ioremap_resource Reduces boilerplate. Identified by: Coccinelle / coccicheck CHECK drivers/iio/adc/aspeed_adc.c drivers/iio/adc/aspeed_adc.c:189:1-11: WARNING: Use devm_platform_ioremap_resource for data -> base Signed-off-by: Jonathan Cameron Cc: Rick Altherr Reviewed-by: Alexandru Ardelean --- drivers/iio/adc/aspeed_adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index d3fc39df535d..1e5375235cfe 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -173,7 +173,6 @@ static int aspeed_adc_probe(struct platform_device *pdev) struct iio_dev *indio_dev; struct aspeed_adc_data *data; const struct aspeed_adc_model_data *model_data; - struct resource *res; const char *clk_parent_name; int ret; u32 adc_engine_control_reg_val; @@ -185,8 +184,7 @@ static int aspeed_adc_probe(struct platform_device *pdev) data = iio_priv(indio_dev); data->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->base = devm_ioremap_resource(&pdev->dev, res); + data->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->base)) return PTR_ERR(data->base); From 38877a376adf5d11c56bacd4b953050931c1bd0a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 13:15:38 +0100 Subject: [PATCH 14/43] iio: adc: mt6577_auxdac: use devm_platform_ioremap_resource Reduces boilerplate. Identified by coccinelle CHECK drivers/iio/adc/mt6577_auxadc.c drivers/iio/adc/mt6577_auxadc.c:257:1-18: WARNING: Use devm_platform_ioremap_resource for adc_dev -> reg_base Signed-off-by: Jonathan Cameron Cc: Zhiyong Tao Reviewed-by: Alexandru Ardelean --- drivers/iio/adc/mt6577_auxadc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index 7bbb64ca3b32..a4776d924f3a 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -237,7 +237,6 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) { struct mt6577_auxadc_device *adc_dev; unsigned long adc_clk_rate; - struct resource *res; struct iio_dev *indio_dev; int ret; @@ -253,8 +252,7 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) indio_dev->channels = mt6577_auxadc_iio_channels; indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res); + adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(adc_dev->reg_base)) { dev_err(&pdev->dev, "failed to get auxadc base address\n"); return PTR_ERR(adc_dev->reg_base); From f2d025d3f237686b1b20c323847ce6b368302b2a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 13:18:56 +0100 Subject: [PATCH 15/43] iio: adc: bcm_iproc_adc: drop a stray semicolon Found by coccinelle / coccicheck CHECK drivers/iio/adc/bcm_iproc_adc.c drivers/iio/adc/bcm_iproc_adc.c:311:3-4: Unneeded semicolon Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Raveendra Padasalagi --- drivers/iio/adc/bcm_iproc_adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 646ebdc0a8b4..5e396104ac86 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -308,7 +308,7 @@ static int iproc_adc_do_read(struct iio_dev *indio_dev, "IntMask set failed. Read will likely fail."); read_len = -EIO; goto adc_err; - }; + } } regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check); From 46e55d065394ded9c4dd5b2396a07e5810185024 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 13:25:12 +0100 Subject: [PATCH 16/43] iio: adc: cc10001: use devm_platform_ioremap_resource Reduces local boilerplate. Found by coccinelle: drivers/iio/adc/cc10001_adc.c:344:1-18: WARNING: Use devm_platform_ioremap_resource for adc_dev -> reg_base Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Naidu Tellapati --- drivers/iio/adc/cc10001_adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index f93f1d93b80d..fe9257624f16 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -310,7 +310,6 @@ static int cc10001_adc_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct cc10001_adc_device *adc_dev; unsigned long adc_clk_rate; - struct resource *res; struct iio_dev *indio_dev; unsigned long channel_map; int ret; @@ -340,8 +339,7 @@ static int cc10001_adc_probe(struct platform_device *pdev) indio_dev->info = &cc10001_adc_info; indio_dev->modes = INDIO_DIRECT_MODE; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res); + adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(adc_dev->reg_base)) { ret = PTR_ERR(adc_dev->reg_base); goto err_disable_reg; From f449aa3edd6536d03ee1ec4a4fe68c7554baf1e1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 16:27:16 +0100 Subject: [PATCH 17/43] iio: adc: ingenic: Use devm_platform_ioremap_resource Replaces local boilerplate. Identified by coccinelle. CHECK drivers/iio/adc/ingenic-adc.c drivers/iio/adc/ingenic-adc.c:449:1-10: WARNING: Use devm_platform_ioremap_resource for adc -> base Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Artur Rojek --- drivers/iio/adc/ingenic-adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 7a53c2f8d438..39c0a609fc94 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -428,7 +428,6 @@ static int ingenic_adc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct iio_dev *iio_dev; struct ingenic_adc *adc; - struct resource *mem_base; const struct ingenic_adc_soc_data *soc_data; int ret; @@ -445,8 +444,7 @@ static int ingenic_adc_probe(struct platform_device *pdev) mutex_init(&adc->aux_lock); adc->soc_data = soc_data; - mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - adc->base = devm_ioremap_resource(dev, mem_base); + adc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(adc->base)) return PTR_ERR(adc->base); From 18d031f46e9c2d9315d8eb383472f9e7b2239cbd Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 16:32:34 +0100 Subject: [PATCH 18/43] iio: adc: lpc18xx: use devm_platform_ioremap_resource Avoid local boilerplate. Identified by coccinelle CHECK drivers/iio/adc/lpc18xx_adc.c drivers/iio/adc/lpc18xx_adc.c:137:1-10: WARNING: Use devm_platform_ioremap_resource for adc -> base Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Joachim Eastwood --- drivers/iio/adc/lpc18xx_adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c index e400a95f553d..4c6ac6644dc0 100644 --- a/drivers/iio/adc/lpc18xx_adc.c +++ b/drivers/iio/adc/lpc18xx_adc.c @@ -119,7 +119,6 @@ static int lpc18xx_adc_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; struct lpc18xx_adc *adc; - struct resource *res; unsigned int clkdiv; unsigned long rate; int ret; @@ -133,8 +132,7 @@ static int lpc18xx_adc_probe(struct platform_device *pdev) adc->dev = &pdev->dev; mutex_init(&adc->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - adc->base = devm_ioremap_resource(&pdev->dev, res); + adc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(adc->base)) return PTR_ERR(adc->base); From 08cf48c7fa0b2fee2ad547e42580a9a1904061f6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 16:44:27 +0100 Subject: [PATCH 19/43] iio: adc: npcm: use devm_platform_ioremap_resource Reduces local boilerplate code. Suggested by coccinelle via coccicheck. CHECK drivers/iio/adc/npcm_adc.c drivers/iio/adc/npcm_adc.c:200:1-11: WARNING: Use devm_platform_ioremap_resource for info -> regs Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Tomer Maimon --- drivers/iio/adc/npcm_adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 910f3585fa54..a6170a37ebe8 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -183,7 +183,6 @@ static int npcm_adc_probe(struct platform_device *pdev) int irq; u32 div; u32 reg_con; - struct resource *res; struct npcm_adc *info; struct iio_dev *indio_dev; struct device *dev = &pdev->dev; @@ -196,8 +195,7 @@ static int npcm_adc_probe(struct platform_device *pdev) info->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, res); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); From 6c78cc9c4a530af6c617a7c14b5518c10bc6eadf Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 16:48:32 +0100 Subject: [PATCH 20/43] iio: adc: rcar-gyroadc: use devm_platform_ioremap_resource Avoids some local boilerplate. Suggested by coccinelle. CHECK drivers/iio/adc/rcar-gyroadc.c drivers/iio/adc/rcar-gyroadc.c:495:1-11: WARNING: Use devm_platform_ioremap_resource for priv -> regs Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Marek Vasut --- drivers/iio/adc/rcar-gyroadc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index c37f201294b2..63ce743ee7af 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -481,7 +481,6 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct rcar_gyroadc *priv; struct iio_dev *indio_dev; - struct resource *mem; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); @@ -491,8 +490,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) priv = iio_priv(indio_dev); priv->dev = dev; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = devm_ioremap_resource(dev, mem); + priv->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); From e8ad78658ecc97c7f5b6d70fc5266bc19c3bbf29 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 16:52:39 +0100 Subject: [PATCH 21/43] iio: adc: spear_adc: Use devm_platform_ioremap_resource Avoids local boilerplate doing the same thing. Suggested by coccinelle CHECK drivers/iio/adc/spear_adc.c drivers/iio/adc/spear_adc.c:283:1-22: WARNING: Use devm_platform_ioremap_resource for st -> adc_base_spear6xx Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean --- drivers/iio/adc/spear_adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index 592b97c464da..0ad536494e8f 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -260,7 +260,6 @@ static int spear_adc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct spear_adc_state *st; - struct resource *res; struct iio_dev *indio_dev = NULL; int ret = -ENODEV; int irq; @@ -279,8 +278,7 @@ static int spear_adc_probe(struct platform_device *pdev) * (e.g. SPEAr3xx). Let's provide two register base addresses * to support multi-arch kernels. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - st->adc_base_spear6xx = devm_ioremap_resource(&pdev->dev, res); + st->adc_base_spear6xx = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(st->adc_base_spear6xx)) return PTR_ERR(st->adc_base_spear6xx); From afac22e3cf9598df1ab02973f0ea70de098250da Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 17:43:49 +0100 Subject: [PATCH 22/43] iio: adc: vf610: use devm_platform_ioremap_resource Reduces boilerplate. Suggested by coccinelle CHECK drivers/iio/adc/vf610_adc.c drivers/iio/adc/vf610_adc.c:819:1-11: WARNING: Use devm_platform_ioremap_resource for info -> regs Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Fugang Duan --- drivers/iio/adc/vf610_adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 98b30475bbc6..cb7380bf07ca 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -802,7 +802,6 @@ static int vf610_adc_probe(struct platform_device *pdev) { struct vf610_adc *info; struct iio_dev *indio_dev; - struct resource *mem; int irq; int ret; @@ -815,8 +814,7 @@ static int vf610_adc_probe(struct platform_device *pdev) info = iio_priv(indio_dev); info->dev = &pdev->dev; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, mem); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); From 29ec12e29f7f6f31f0b5b8271b0a678b08e82ec1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 18:14:14 +0100 Subject: [PATCH 23/43] iio: dac: lpc18xx: Use devm_platform_ioremap_resource Reduce boilerplate. Suggested by coccinelle CHECK drivers/iio/dac/lpc18xx_dac.c drivers/iio/dac/lpc18xx_dac.c:121:1-10: WARNING: Use devm_platform_ioremap_resource for dac -> base Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean CC: Joachim Eastwood --- drivers/iio/dac/lpc18xx_dac.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index 883e84e96609..0ab357bd3633 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -106,7 +106,6 @@ static int lpc18xx_dac_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; struct lpc18xx_dac *dac; - struct resource *res; int ret; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac)); @@ -117,8 +116,7 @@ static int lpc18xx_dac_probe(struct platform_device *pdev) dac = iio_priv(indio_dev); mutex_init(&dac->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dac->base = devm_ioremap_resource(&pdev->dev, res); + dac->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dac->base)) return PTR_ERR(dac->base); From 2969c51e3a201799228f03b2838f750aaca8d104 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Oct 2019 18:17:32 +0100 Subject: [PATCH 24/43] iio: dac: vf610: Use devm_platform_ioremap_resource Reduce local boilerplate. Suggested by coccinelle CHECK drivers/iio/dac/vf610_dac.c drivers/iio/dac/vf610_dac.c:189:1-11: WARNING: Use devm_platform_ioremap_resource for info -> regs Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Cc: Sanchayan Maity --- drivers/iio/dac/vf610_dac.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index 0ec4d2609ef9..71f8a5c471c4 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -172,7 +172,6 @@ static int vf610_dac_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; struct vf610_dac *info; - struct resource *mem; int ret; indio_dev = devm_iio_device_alloc(&pdev->dev, @@ -185,8 +184,7 @@ static int vf610_dac_probe(struct platform_device *pdev) info = iio_priv(indio_dev); info->dev = &pdev->dev; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, mem); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); From a1acbc223a0c000edc5353f0710d0001772c158d Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 28 Oct 2019 17:11:47 +0100 Subject: [PATCH 25/43] dt-bindings: iio: stm32-adc: add max clock rate property Add optional dt property to tune maximum desired analog clock rate. Signed-off-by: Fabrice Gasnier Reviewed-by: Rob Herring Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt index 4c0da8c74bb2..8de933146771 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt @@ -53,6 +53,8 @@ Optional properties: analog input switches on stm32mp1. - st,syscfg: Phandle to system configuration controller. It can be used to control the analog circuitry on stm32mp1. +- st,max-clk-rate-hz: Allow to specify desired max clock rate used by analog + circuitry. Contents of a stm32 adc child node: ----------------------------------- From cb7e1b50e4e382c2c63ac0c80260db55c3a3c7ee Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 28 Oct 2019 17:11:48 +0100 Subject: [PATCH 26/43] iio: adc: stm32: allow to tune analog clock Add new optional dt property to tune analog clock prescaler. Driver looks for optional "st,max-clk-rate-hz", then computes best approximation below that rate, using ADC internal prescaler. Signed-off-by: Fabrice Gasnier Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc-core.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 20c626c289ed..6537f4f776c5 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -79,6 +79,7 @@ struct stm32_adc_priv_cfg { * @domain: irq domain reference * @aclk: clock reference for the analog circuitry * @bclk: bus clock common for all ADCs, depends on part used + * @max_clk_rate: desired maximum clock rate * @booster: booster supply reference * @vdd: vdd supply reference * @vdda: vdda analog supply reference @@ -95,6 +96,7 @@ struct stm32_adc_priv { struct irq_domain *domain; struct clk *aclk; struct clk *bclk; + u32 max_clk_rate; struct regulator *booster; struct regulator *vdd; struct regulator *vdda; @@ -141,7 +143,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, } for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { - if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz) + if ((rate / stm32f4_pclk_div[i]) <= priv->max_clk_rate) break; } if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { @@ -230,7 +232,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (ckmode) continue; - if ((rate / div) <= priv->cfg->max_clk_rate_hz) + if ((rate / div) <= priv->max_clk_rate) goto out; } } @@ -250,7 +252,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (!ckmode) continue; - if ((rate / div) <= priv->cfg->max_clk_rate_hz) + if ((rate / div) <= priv->max_clk_rate) goto out; } @@ -655,6 +657,7 @@ static int stm32_adc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; struct resource *res; + u32 max_rate; int ret; if (!pdev->dev.of_node) @@ -731,6 +734,13 @@ static int stm32_adc_probe(struct platform_device *pdev) priv->common.vref_mv = ret / 1000; dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); + ret = of_property_read_u32(pdev->dev.of_node, "st,max-clk-rate-hz", + &max_rate); + if (!ret) + priv->max_clk_rate = min(max_rate, priv->cfg->max_clk_rate_hz); + else + priv->max_clk_rate = priv->cfg->max_clk_rate_hz; + ret = priv->cfg->clk_sel(pdev, priv); if (ret < 0) goto err_hw_stop; From 59af4e206365d38fe78a94852f1f9c28f4f92c9d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 3 Nov 2019 20:47:17 +0100 Subject: [PATCH 27/43] iio: imu: st_lsm6dsx: explicitly define odr table size Introduce odr_len in st_lsm6dsx_odr_table_entry data structure in order to explicitly define odr table size and support devices with different odr table map Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 27 +++++++++++++++----- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 12 ++++----- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 37e499fe6bcf..9ffc8e06f73d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -113,7 +113,9 @@ struct st_lsm6dsx_odr { #define ST_LSM6DSX_ODR_LIST_SIZE 6 struct st_lsm6dsx_odr_table_entry { struct st_lsm6dsx_reg reg; + struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE]; + int odr_len; }; struct st_lsm6dsx_fs { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 1f28a7733fc0..a3333c215339 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -133,6 +133,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 238, 0x04 }, .odr_avl[4] = { 476, 0x05 }, .odr_avl[5] = { 952, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -145,6 +146,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 238, 0x04 }, .odr_avl[4] = { 476, 0x05 }, .odr_avl[5] = { 952, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -233,6 +235,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -245,6 +248,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -397,6 +401,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -409,6 +414,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -570,6 +576,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -582,6 +589,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -745,6 +753,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -757,6 +766,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -940,6 +950,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -952,6 +963,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -1115,6 +1127,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -1127,6 +1140,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -1350,15 +1364,16 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) int i; odr_table = &sensor->hw->settings->odr_table[sensor->id]; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) + for (i = 0; i < odr_table->odr_len; i++) { /* * ext devices can run at different odr respect to * accel sensor */ if (odr_table->odr_avl[i].hz >= odr) break; + } - if (i == ST_LSM6DSX_ODR_LIST_SIZE) + if (i == odr_table->odr_len) return -EINVAL; *val = odr_table->odr_avl[i].val; @@ -1709,13 +1724,13 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, char *buf) { struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); - enum st_lsm6dsx_sensor_id id = sensor->id; - struct st_lsm6dsx_hw *hw = sensor->hw; + const struct st_lsm6dsx_odr_table_entry *odr_table; int i, len = 0; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) + odr_table = &sensor->hw->settings->odr_table[sensor->id]; + for (i = 0; i < odr_table->odr_len; i++) len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - hw->settings->odr_table[id].odr_avl[i].hz); + odr_table->odr_avl[i].hz); buf[len - 1] = '\n'; return len; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index ea472cf6db7b..e029cc05a17f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -55,6 +55,7 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { .odr_avl[1] = { 20, 0x1 }, .odr_avl[2] = { 50, 0x2 }, .odr_avl[3] = { 100, 0x3 }, + .odr_len = 4, }, .fs_table = { .fs_avl[0] = { @@ -323,11 +324,12 @@ st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor, int i; settings = sensor->ext_info.settings; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) + for (i = 0; i < settings->odr_table.odr_len; i++) { if (settings->odr_table.odr_avl[i].hz == odr) break; + } - if (i == ST_LSM6DSX_ODR_LIST_SIZE) + if (i == settings->odr_table.odr_len) return -EINVAL; *val = settings->odr_table.odr_avl[i].val; @@ -537,12 +539,10 @@ st_lsm6dsx_shub_sampling_freq_avail(struct device *dev, int i, len = 0; settings = sensor->ext_info.settings; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) { + for (i = 0; i < settings->odr_table.odr_len; i++) { u16 val = settings->odr_table.odr_avl[i].hz; - if (val > 0) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - val); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val); } buf[len - 1] = '\n'; From fc3f6ad7f5dc6c899fbda0255865737bac88c2e0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 27 Oct 2019 19:02:30 +0100 Subject: [PATCH 28/43] iio: imu: st_lsm6dsx: fix ODR check in st_lsm6dsx_write_raw Since st_lsm6dsx i2c master controller relies on accel device as trigger and slave devices can run at different ODRs we must select an accel_odr >= slave_odr. Report real accel ODR in st_lsm6dsx_check_odr() in order to properly set sensor frequency in st_lsm6dsx_write_raw and avoid to report unsupported frequency Fixes: 6ffb55e5009ff ("iio: imu: st_lsm6dsx: introduce ST_LSM6DSX_ID_EXT sensor ids") Signed-off-by: Lorenzo Bianconi Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index a3333c215339..2f9396745bc8 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1377,8 +1377,7 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) return -EINVAL; *val = odr_table->odr_avl[i].val; - - return 0; + return odr_table->odr_avl[i].hz; } static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr, @@ -1542,8 +1541,10 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, case IIO_CHAN_INFO_SAMP_FREQ: { u8 data; - err = st_lsm6dsx_check_odr(sensor, val, &data); - if (!err) + val = st_lsm6dsx_check_odr(sensor, val, &data); + if (val < 0) + err = val; + else sensor->odr = val; break; } From f8710f0357bc36c740782c95f34ea847c75b7498 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 3 Nov 2019 20:47:18 +0100 Subject: [PATCH 29/43] iio: imu: st_lsm6dsx: express odr in mHZ Express available frequencies in mHZ in order to support even rational ODRs. This patch is need to fix an Android CTS failure Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 6 +- .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 9 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 203 +++++++++--------- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 35 +-- 4 files changed, 131 insertions(+), 122 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 9ffc8e06f73d..c605b153be41 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -106,7 +106,7 @@ struct st_lsm6dsx_sensor; struct st_lsm6dsx_hw; struct st_lsm6dsx_odr { - u16 hz; + u32 milli_hz; u8 val; }; @@ -330,7 +330,7 @@ struct st_lsm6dsx_sensor { struct st_lsm6dsx_hw *hw; u32 gain; - u16 odr; + u32 odr; u16 watermark; u8 sip; @@ -415,7 +415,7 @@ int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, enum st_lsm6dsx_fifo_mode fifo_mode); int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw); int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw); -int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val); +int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val); int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name); int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 31cd90d2c60e..d416990ae309 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -91,7 +91,7 @@ static int st_lsm6dsx_get_decimator_val(u8 val) } static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw, - u16 *max_odr, u16 *min_odr) + u32 *max_odr, u32 *min_odr) { struct st_lsm6dsx_sensor *sensor; int i; @@ -106,16 +106,17 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw, if (!(hw->enable_mask & BIT(sensor->id))) continue; - *max_odr = max_t(u16, *max_odr, sensor->odr); - *min_odr = min_t(u16, *min_odr, sensor->odr); + *max_odr = max_t(u32, *max_odr, sensor->odr); + *min_odr = min_t(u32, *min_odr, sensor->odr); } } static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw) { - u16 max_odr, min_odr, sip = 0, ts_sip = 0; const struct st_lsm6dsx_reg *ts_dec_reg; struct st_lsm6dsx_sensor *sensor; + u16 sip = 0, ts_sip = 0; + u32 max_odr, min_odr; int err = 0, i; u8 data; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 2f9396745bc8..11b2c7bc8041 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -127,12 +127,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x20, .mask = GENMASK(7, 5), }, - .odr_avl[0] = { 10, 0x01 }, - .odr_avl[1] = { 50, 0x02 }, - .odr_avl[2] = { 119, 0x03 }, - .odr_avl[3] = { 238, 0x04 }, - .odr_avl[4] = { 476, 0x05 }, - .odr_avl[5] = { 952, 0x06 }, + .odr_avl[0] = { 10000, 0x01 }, + .odr_avl[1] = { 50000, 0x02 }, + .odr_avl[2] = { 119000, 0x03 }, + .odr_avl[3] = { 238000, 0x04 }, + .odr_avl[4] = { 476000, 0x05 }, + .odr_avl[5] = { 952000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -140,12 +140,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 5), }, - .odr_avl[0] = { 15, 0x01 }, - .odr_avl[1] = { 60, 0x02 }, - .odr_avl[2] = { 119, 0x03 }, - .odr_avl[3] = { 238, 0x04 }, - .odr_avl[4] = { 476, 0x05 }, - .odr_avl[5] = { 952, 0x06 }, + .odr_avl[0] = { 14900, 0x01 }, + .odr_avl[1] = { 59500, 0x02 }, + .odr_avl[2] = { 119000, 0x03 }, + .odr_avl[3] = { 238000, 0x04 }, + .odr_avl[4] = { 476000, 0x05 }, + .odr_avl[5] = { 952000, 0x06 }, .odr_len = 6, }, }, @@ -229,12 +229,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -242,12 +242,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -395,12 +395,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -408,12 +408,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -570,12 +570,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -583,12 +583,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -747,12 +747,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -760,12 +760,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -944,12 +944,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -957,12 +957,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -1121,12 +1121,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -1134,12 +1134,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -1358,7 +1358,7 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, return 0; } -int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) +int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val) { const struct st_lsm6dsx_odr_table_entry *odr_table; int i; @@ -1369,7 +1369,7 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) * ext devices can run at different odr respect to * accel sensor */ - if (odr_table->odr_avl[i].hz >= odr) + if (odr_table->odr_avl[i].milli_hz >= odr) break; } @@ -1377,17 +1377,18 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) return -EINVAL; *val = odr_table->odr_avl[i].val; - return odr_table->odr_avl[i].hz; + return odr_table->odr_avl[i].milli_hz; } -static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr, - enum st_lsm6dsx_sensor_id id) +static int +st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u32 odr, + enum st_lsm6dsx_sensor_id id) { struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]); if (odr > 0) { if (hw->enable_mask & BIT(id)) - return max_t(u16, ref->odr, odr); + return max_t(u32, ref->odr, odr); else return odr; } else { @@ -1395,7 +1396,8 @@ static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr, } } -static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr) +static int +st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr) { struct st_lsm6dsx_sensor *ref_sensor = sensor; struct st_lsm6dsx_hw *hw = sensor->hw; @@ -1409,7 +1411,7 @@ static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr) case ST_LSM6DSX_ID_EXT1: case ST_LSM6DSX_ID_EXT2: case ST_LSM6DSX_ID_ACC: { - u16 odr; + u32 odr; int i; /* @@ -1449,7 +1451,7 @@ int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) { struct st_lsm6dsx_hw *hw = sensor->hw; - u16 odr = enable ? sensor->odr : 0; + u32 odr = enable ? sensor->odr : 0; int err; err = st_lsm6dsx_set_odr(sensor, odr); @@ -1475,7 +1477,7 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, if (err < 0) return err; - delay = 1000000 / sensor->odr; + delay = 1000000000 / sensor->odr; usleep_range(delay, 2 * delay); err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data)); @@ -1507,8 +1509,9 @@ static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, iio_device_release_direct_mode(iio_dev); break; case IIO_CHAN_INFO_SAMP_FREQ: - *val = sensor->odr; - ret = IIO_VAL_INT; + *val = sensor->odr / 1000; + *val2 = (sensor->odr % 1000) * 1000; + ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_SCALE: *val = 0; @@ -1541,6 +1544,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, case IIO_CHAN_INFO_SAMP_FREQ: { u8 data; + val = val * 1000 + val2 / 1000; val = st_lsm6dsx_check_odr(sensor, val, &data); if (val < 0) err = val; @@ -1730,8 +1734,9 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, odr_table = &sensor->hw->settings->odr_table[sensor->id]; for (i = 0; i < odr_table->odr_len; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - odr_table->odr_avl[i].hz); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%03d ", + odr_table->odr_avl[i].milli_hz / 1000, + odr_table->odr_avl[i].milli_hz % 1000); buf[len - 1] = '\n'; return len; @@ -2037,7 +2042,7 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, sensor = iio_priv(iio_dev); sensor->id = id; sensor->hw = hw; - sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz; + sensor->odr = hw->settings->odr_table[id].odr_avl[0].milli_hz; sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain; sensor->watermark = 1; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index e029cc05a17f..fa5d1001a46c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -51,10 +51,10 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { .addr = 0x60, .mask = GENMASK(3, 2), }, - .odr_avl[0] = { 10, 0x0 }, - .odr_avl[1] = { 20, 0x1 }, - .odr_avl[2] = { 50, 0x2 }, - .odr_avl[3] = { 100, 0x3 }, + .odr_avl[0] = { 10000, 0x0 }, + .odr_avl[1] = { 20000, 0x1 }, + .odr_avl[2] = { 50000, 0x2 }, + .odr_avl[3] = { 100000, 0x3 }, .odr_len = 4, }, .fs_table = { @@ -94,11 +94,11 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw) { struct st_lsm6dsx_sensor *sensor; - u16 odr; + u32 odr; sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); - odr = (hw->enable_mask & BIT(ST_LSM6DSX_ID_ACC)) ? sensor->odr : 13; - msleep((2000U / odr) + 1); + odr = (hw->enable_mask & BIT(ST_LSM6DSX_ID_ACC)) ? sensor->odr : 12500; + msleep((2000000U / odr) + 1); } /** @@ -318,14 +318,14 @@ st_lsm6dsx_shub_write_with_mask(struct st_lsm6dsx_sensor *sensor, static int st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor, - u16 odr, u16 *val) + u32 odr, u16 *val) { const struct st_lsm6dsx_ext_dev_settings *settings; int i; settings = sensor->ext_info.settings; for (i = 0; i < settings->odr_table.odr_len; i++) { - if (settings->odr_table.odr_avl[i].hz == odr) + if (settings->odr_table.odr_avl[i].milli_hz == odr) break; } @@ -337,7 +337,7 @@ st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor, } static int -st_lsm6dsx_shub_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr) +st_lsm6dsx_shub_set_odr(struct st_lsm6dsx_sensor *sensor, u32 odr) { const struct st_lsm6dsx_ext_dev_settings *settings; u16 val; @@ -442,7 +442,7 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor, if (err < 0) return err; - delay = 1000000 / sensor->odr; + delay = 1000000000 / sensor->odr; usleep_range(delay, 2 * delay); len = min_t(int, sizeof(data), ch->scan_type.realbits >> 3); @@ -482,8 +482,9 @@ st_lsm6dsx_shub_read_raw(struct iio_dev *iio_dev, iio_device_release_direct_mode(iio_dev); break; case IIO_CHAN_INFO_SAMP_FREQ: - *val = sensor->odr; - ret = IIO_VAL_INT; + *val = sensor->odr / 1000; + *val2 = (sensor->odr % 1000) * 1000; + ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_SCALE: *val = 0; @@ -514,6 +515,7 @@ st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev, case IIO_CHAN_INFO_SAMP_FREQ: { u16 data; + val = val * 1000 + val2 / 1000; err = st_lsm6dsx_shub_get_odr_val(sensor, val, &data); if (!err) sensor->odr = val; @@ -540,9 +542,10 @@ st_lsm6dsx_shub_sampling_freq_avail(struct device *dev, settings = sensor->ext_info.settings; for (i = 0; i < settings->odr_table.odr_len; i++) { - u16 val = settings->odr_table.odr_avl[i].hz; + u32 val = settings->odr_table.odr_avl[i].milli_hz; - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%03d ", + val / 1000, val % 1000); } buf[len - 1] = '\n'; @@ -607,7 +610,7 @@ st_lsm6dsx_shub_alloc_iiodev(struct st_lsm6dsx_hw *hw, sensor = iio_priv(iio_dev); sensor->id = id; sensor->hw = hw; - sensor->odr = info->odr_table.odr_avl[0].hz; + sensor->odr = info->odr_table.odr_avl[0].milli_hz; sensor->gain = info->fs_table.fs_avl[0].gain; sensor->ext_info.settings = info; sensor->ext_info.addr = i2c_addr; From 7b779f573c48e1ad6da1d6ea5f181f3ecd666bf6 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Mon, 4 Nov 2019 21:08:24 +0530 Subject: [PATCH 30/43] iio: light: add driver for veml6030 ambient light sensor veml6030 is an ambient light sensor from Vishay semiconductors. It has 16-bit resolution, supports both ambient light measurement and white channel which is more responsive to wider wavelength spectrum. It has flexible power saving, integration time and gain options. Communication with host is over I2C. Signed-off-by: Rishi Gupta Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 11 + drivers/iio/light/Makefile | 1 + drivers/iio/light/veml6030.c | 908 +++++++++++++++++++++++++++++++++++ 3 files changed, 920 insertions(+) create mode 100644 drivers/iio/light/veml6030.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index d793c1541705..9968f982fbc7 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -507,6 +507,17 @@ config VCNL4035 To compile this driver as a module, choose M here: the module will be called vcnl4035. +config VEML6030 + tristate "VEML6030 ambient light sensor" + select REGMAP_I2C + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML6030 + ambient light sensor (ALS). + + To compile this driver as a module, choose M here: the + module will be called veml6030. + config VEML6070 tristate "VEML6070 UV A light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 5d650ce46a40..c98d1cefb861 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_VCNL4035) += vcnl4035.o +obj-$(CONFIG_VEML6030) += veml6030.o obj-$(CONFIG_VEML6070) += veml6070.o obj-$(CONFIG_VL6180) += vl6180.o obj-$(CONFIG_ZOPT2201) += zopt2201.o diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c new file mode 100644 index 000000000000..aa25b87fca8f --- /dev/null +++ b/drivers/iio/light/veml6030.c @@ -0,0 +1,908 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * VEML6030 Ambient Light Sensor + * + * Copyright (c) 2019, Rishi Gupta + * + * Datasheet: https://www.vishay.com/docs/84366/veml6030.pdf + * Appnote-84367: https://www.vishay.com/docs/84367/designingveml6030.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Device registers */ +#define VEML6030_REG_ALS_CONF 0x00 +#define VEML6030_REG_ALS_WH 0x01 +#define VEML6030_REG_ALS_WL 0x02 +#define VEML6030_REG_ALS_PSM 0x03 +#define VEML6030_REG_ALS_DATA 0x04 +#define VEML6030_REG_WH_DATA 0x05 +#define VEML6030_REG_ALS_INT 0x06 + +/* Bit masks for specific functionality */ +#define VEML6030_ALS_IT GENMASK(9, 6) +#define VEML6030_PSM GENMASK(2, 1) +#define VEML6030_ALS_PERS GENMASK(5, 4) +#define VEML6030_ALS_GAIN GENMASK(12, 11) +#define VEML6030_PSM_EN BIT(0) +#define VEML6030_INT_TH_LOW BIT(15) +#define VEML6030_INT_TH_HIGH BIT(14) +#define VEML6030_ALS_INT_EN BIT(1) +#define VEML6030_ALS_SD BIT(0) + +/* + * The resolution depends on both gain and integration time. The + * cur_resolution stores one of the resolution mentioned in the + * table during startup and gets updated whenever integration time + * or gain is changed. + * + * Table 'resolution and maximum detection range' in appnote 84367 + * is visualized as a 2D array. The cur_gain stores index of gain + * in this table (0-3) while the cur_integration_time holds index + * of integration time (0-5). + */ +struct veml6030_data { + struct i2c_client *client; + struct regmap *regmap; + int cur_resolution; + int cur_gain; + int cur_integration_time; +}; + +/* Integration time available in seconds */ +static IIO_CONST_ATTR(in_illuminance_integration_time_available, + "0.025 0.05 0.1 0.2 0.4 0.8"); + +/* + * Scale is 1/gain. Value 0.125 is ALS gain x (1/8), 0.25 is + * ALS gain x (1/4), 1.0 = ALS gain x 1 and 2.0 is ALS gain x 2. + */ +static IIO_CONST_ATTR(in_illuminance_scale_available, + "0.125 0.25 1.0 2.0"); + +static struct attribute *veml6030_attributes[] = { + &iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr, + &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group veml6030_attr_group = { + .attrs = veml6030_attributes, +}; + +/* + * Persistence = 1/2/4/8 x integration time + * Minimum time for which light readings must stay above configured + * threshold to assert the interrupt. + */ +static const char * const period_values[] = { + "0.1 0.2 0.4 0.8", + "0.2 0.4 0.8 1.6", + "0.4 0.8 1.6 3.2", + "0.8 1.6 3.2 6.4", + "0.05 0.1 0.2 0.4", + "0.025 0.050 0.1 0.2" +}; + +/* + * Return list of valid period values in seconds corresponding to + * the currently active integration time. + */ +static ssize_t in_illuminance_period_available_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, reg, x; + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct veml6030_data *data = iio_priv(indio_dev); + + ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als conf register %d\n", ret); + return ret; + } + + ret = ((reg >> 6) & 0xF); + switch (ret) { + case 0: + case 1: + case 2: + case 3: + x = ret; + break; + case 8: + x = 4; + break; + case 12: + x = 5; + break; + default: + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", period_values[x]); +} + +static IIO_DEVICE_ATTR_RO(in_illuminance_period_available, 0); + +static struct attribute *veml6030_event_attributes[] = { + &iio_dev_attr_in_illuminance_period_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group veml6030_event_attr_group = { + .attrs = veml6030_event_attributes, +}; + +static int veml6030_als_pwr_on(struct veml6030_data *data) +{ + return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_SD, 0); +} + +static int veml6030_als_shut_down(struct veml6030_data *data) +{ + return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_SD, 1); +} + +static void veml6030_als_shut_down_action(void *data) +{ + veml6030_als_shut_down(data); +} + +static const struct iio_event_spec veml6030_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +/* Channel number */ +enum veml6030_chan { + CH_ALS, + CH_WHITE, +}; + +static const struct iio_chan_spec veml6030_channels[] = { + { + .type = IIO_LIGHT, + .channel = CH_ALS, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .event_spec = veml6030_event_spec, + .num_event_specs = ARRAY_SIZE(veml6030_event_spec), + }, + { + .type = IIO_INTENSITY, + .channel = CH_WHITE, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_PROCESSED), + }, +}; + +static const struct regmap_config veml6030_regmap_config = { + .name = "veml6030_regmap", + .reg_bits = 8, + .val_bits = 16, + .max_register = VEML6030_REG_ALS_INT, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int veml6030_get_intgrn_tm(struct iio_dev *indio_dev, + int *val, int *val2) +{ + int ret, reg; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als conf register %d\n", ret); + return ret; + } + + switch ((reg >> 6) & 0xF) { + case 0: + *val2 = 100000; + break; + case 1: + *val2 = 200000; + break; + case 2: + *val2 = 400000; + break; + case 3: + *val2 = 800000; + break; + case 8: + *val2 = 50000; + break; + case 12: + *val2 = 25000; + break; + default: + return -EINVAL; + } + + *val = 0; + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml6030_set_intgrn_tm(struct iio_dev *indio_dev, + int val, int val2) +{ + int ret, new_int_time, int_idx; + struct veml6030_data *data = iio_priv(indio_dev); + + if (val) + return -EINVAL; + + switch (val2) { + case 25000: + new_int_time = 0x300; + int_idx = 5; + break; + case 50000: + new_int_time = 0x200; + int_idx = 4; + break; + case 100000: + new_int_time = 0x00; + int_idx = 3; + break; + case 200000: + new_int_time = 0x40; + int_idx = 2; + break; + case 400000: + new_int_time = 0x80; + int_idx = 1; + break; + case 800000: + new_int_time = 0xC0; + int_idx = 0; + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_IT, new_int_time); + if (ret) { + dev_err(&data->client->dev, + "can't update als integration time %d\n", ret); + return ret; + } + + /* + * Cache current integration time and update resolution. For every + * increase in integration time to next level, resolution is halved + * and vice-versa. + */ + if (data->cur_integration_time < int_idx) + data->cur_resolution <<= int_idx - data->cur_integration_time; + else if (data->cur_integration_time > int_idx) + data->cur_resolution >>= data->cur_integration_time - int_idx; + + data->cur_integration_time = int_idx; + + return ret; +} + +static int veml6030_read_persistence(struct iio_dev *indio_dev, + int *val, int *val2) +{ + int ret, reg, period, x, y; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = veml6030_get_intgrn_tm(indio_dev, &x, &y); + if (ret < 0) + return ret; + + ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als conf register %d\n", ret); + } + + /* integration time multiplied by 1/2/4/8 */ + period = y * (1 << ((reg >> 4) & 0x03)); + + *val = period / 1000000; + *val2 = period % 1000000; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml6030_write_persistence(struct iio_dev *indio_dev, + int val, int val2) +{ + int ret, period, x, y; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = veml6030_get_intgrn_tm(indio_dev, &x, &y); + if (ret < 0) + return ret; + + if (!val) { + period = val2 / y; + } else { + if ((val == 1) && (val2 == 600000)) + period = 1600000 / y; + else if ((val == 3) && (val2 == 200000)) + period = 3200000 / y; + else if ((val == 6) && (val2 == 400000)) + period = 6400000 / y; + else + period = -1; + } + + if (period <= 0 || period > 8 || hweight8(period) != 1) + return -EINVAL; + + ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_PERS, (ffs(period) - 1) << 4); + if (ret) + dev_err(&data->client->dev, + "can't set persistence value %d\n", ret); + + return ret; +} + +static int veml6030_set_als_gain(struct iio_dev *indio_dev, + int val, int val2) +{ + int ret, new_gain, gain_idx; + struct veml6030_data *data = iio_priv(indio_dev); + + if (val == 0 && val2 == 125000) { + new_gain = 0x1000; /* 0x02 << 11 */ + gain_idx = 3; + } else if (val == 0 && val2 == 250000) { + new_gain = 0x1800; + gain_idx = 2; + } else if (val == 1 && val2 == 0) { + new_gain = 0x00; + gain_idx = 1; + } else if (val == 2 && val2 == 0) { + new_gain = 0x800; + gain_idx = 0; + } else { + return -EINVAL; + } + + ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_GAIN, new_gain); + if (ret) { + dev_err(&data->client->dev, + "can't set als gain %d\n", ret); + return ret; + } + + /* + * Cache currently set gain & update resolution. For every + * increase in the gain to next level, resolution is halved + * and vice-versa. + */ + if (data->cur_gain < gain_idx) + data->cur_resolution <<= gain_idx - data->cur_gain; + else if (data->cur_gain > gain_idx) + data->cur_resolution >>= data->cur_gain - gain_idx; + + data->cur_gain = gain_idx; + + return ret; +} + +static int veml6030_get_als_gain(struct iio_dev *indio_dev, + int *val, int *val2) +{ + int ret, reg; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als conf register %d\n", ret); + return ret; + } + + switch ((reg >> 11) & 0x03) { + case 0: + *val = 1; + *val2 = 0; + break; + case 1: + *val = 2; + *val2 = 0; + break; + case 2: + *val = 0; + *val2 = 125000; + break; + case 3: + *val = 0; + *val2 = 250000; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml6030_read_thresh(struct iio_dev *indio_dev, + int *val, int *val2, int dir) +{ + int ret, reg; + struct veml6030_data *data = iio_priv(indio_dev); + + if (dir == IIO_EV_DIR_RISING) + ret = regmap_read(data->regmap, VEML6030_REG_ALS_WH, ®); + else + ret = regmap_read(data->regmap, VEML6030_REG_ALS_WL, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als threshold value %d\n", ret); + return ret; + } + + *val = reg & 0xffff; + return IIO_VAL_INT; +} + +static int veml6030_write_thresh(struct iio_dev *indio_dev, + int val, int val2, int dir) +{ + int ret; + struct veml6030_data *data = iio_priv(indio_dev); + + if (val > 0xFFFF || val < 0 || val2) + return -EINVAL; + + if (dir == IIO_EV_DIR_RISING) { + ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, val); + if (ret) + dev_err(&data->client->dev, + "can't set high threshold %d\n", ret); + } else { + ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, val); + if (ret) + dev_err(&data->client->dev, + "can't set low threshold %d\n", ret); + } + + return ret; +} + +/* + * Provide both raw as well as light reading in lux. + * light (in lux) = resolution * raw reading + */ +static int veml6030_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + int ret, reg; + struct veml6030_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = &data->client->dev; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_LIGHT: + ret = regmap_read(regmap, VEML6030_REG_ALS_DATA, ®); + if (ret < 0) { + dev_err(dev, "can't read als data %d\n", ret); + return ret; + } + if (mask == IIO_CHAN_INFO_PROCESSED) { + *val = (reg * data->cur_resolution) / 10000; + *val2 = (reg * data->cur_resolution) % 10000; + return IIO_VAL_INT_PLUS_MICRO; + } + *val = reg; + return IIO_VAL_INT; + case IIO_INTENSITY: + ret = regmap_read(regmap, VEML6030_REG_WH_DATA, ®); + if (ret < 0) { + dev_err(dev, "can't read white data %d\n", ret); + return ret; + } + if (mask == IIO_CHAN_INFO_PROCESSED) { + *val = (reg * data->cur_resolution) / 10000; + *val2 = (reg * data->cur_resolution) % 10000; + return IIO_VAL_INT_PLUS_MICRO; + } + *val = reg; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_INT_TIME: + if (chan->type == IIO_LIGHT) + return veml6030_get_intgrn_tm(indio_dev, val, val2); + return -EINVAL; + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_LIGHT) + return veml6030_get_als_gain(indio_dev, val, val2); + return -EINVAL; + default: + return -EINVAL; + } +} + +static int veml6030_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + switch (chan->type) { + case IIO_LIGHT: + return veml6030_set_intgrn_tm(indio_dev, val, val2); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_LIGHT: + return veml6030_set_als_gain(indio_dev, val, val2); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int veml6030_read_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + case IIO_EV_DIR_FALLING: + return veml6030_read_thresh(indio_dev, val, val2, dir); + default: + return -EINVAL; + } + break; + case IIO_EV_INFO_PERIOD: + return veml6030_read_persistence(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +static int veml6030_write_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int val, int val2) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + return veml6030_write_thresh(indio_dev, val, val2, dir); + case IIO_EV_INFO_PERIOD: + return veml6030_write_persistence(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +static int veml6030_read_interrupt_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) +{ + int ret, reg; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als conf register %d\n", ret); + return ret; + } + + if (reg & VEML6030_ALS_INT_EN) + return 1; + else + return 0; +} + +/* + * Sensor should not be measuring light when interrupt is configured. + * Therefore correct sequence to configure interrupt functionality is: + * shut down -> enable/disable interrupt -> power on + * + * state = 1 enables interrupt, state = 0 disables interrupt + */ +static int veml6030_write_interrupt_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + int ret; + struct veml6030_data *data = iio_priv(indio_dev); + + if (state < 0 || state > 1) + return -EINVAL; + + ret = veml6030_als_shut_down(data); + if (ret < 0) { + dev_err(&data->client->dev, + "can't disable als to configure interrupt %d\n", ret); + return ret; + } + + /* enable interrupt + power on */ + ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_INT_EN | VEML6030_ALS_SD, state << 1); + if (ret) + dev_err(&data->client->dev, + "can't enable interrupt & poweron als %d\n", ret); + + return ret; +} + +static const struct iio_info veml6030_info = { + .read_raw = veml6030_read_raw, + .write_raw = veml6030_write_raw, + .read_event_value = veml6030_read_event_val, + .write_event_value = veml6030_write_event_val, + .read_event_config = veml6030_read_interrupt_config, + .write_event_config = veml6030_write_interrupt_config, + .attrs = &veml6030_attr_group, + .event_attrs = &veml6030_event_attr_group, +}; + +static const struct iio_info veml6030_info_no_irq = { + .read_raw = veml6030_read_raw, + .write_raw = veml6030_write_raw, + .attrs = &veml6030_attr_group, +}; + +static irqreturn_t veml6030_event_handler(int irq, void *private) +{ + int ret, reg, evtdir; + struct iio_dev *indio_dev = private; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als interrupt register %d\n", ret); + return IRQ_HANDLED; + } + + /* Spurious interrupt handling */ + if (!(reg & (VEML6030_INT_TH_HIGH | VEML6030_INT_TH_LOW))) + return IRQ_NONE; + + if (reg & VEML6030_INT_TH_HIGH) + evtdir = IIO_EV_DIR_RISING; + else + evtdir = IIO_EV_DIR_FALLING; + + iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, + 0, IIO_EV_TYPE_THRESH, evtdir), + iio_get_time_ns(indio_dev)); + + return IRQ_HANDLED; +} + +/* + * Set ALS gain to 1/8, integration time to 100 ms, PSM to mode 2, + * persistence to 1 x integration time and the threshold + * interrupt disabled by default. First shutdown the sensor, + * update registers and then power on the sensor. + */ +static int veml6030_hw_init(struct iio_dev *indio_dev) +{ + int ret, val; + struct veml6030_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + + ret = veml6030_als_shut_down(data); + if (ret) { + dev_err(&client->dev, "can't shutdown als %d\n", ret); + return ret; + } + + ret = regmap_write(data->regmap, VEML6030_REG_ALS_CONF, 0x1001); + if (ret) { + dev_err(&client->dev, "can't setup als configs %d\n", ret); + return ret; + } + + ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_PSM, + VEML6030_PSM | VEML6030_PSM_EN, 0x03); + if (ret) { + dev_err(&client->dev, "can't setup default PSM %d\n", ret); + return ret; + } + + ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, 0xFFFF); + if (ret) { + dev_err(&client->dev, "can't setup high threshold %d\n", ret); + return ret; + } + + ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, 0x0000); + if (ret) { + dev_err(&client->dev, "can't setup low threshold %d\n", ret); + return ret; + } + + ret = veml6030_als_pwr_on(data); + if (ret) { + dev_err(&client->dev, "can't poweron als %d\n", ret); + return ret; + } + + /* Wait 4 ms to let processor & oscillator start correctly */ + usleep_range(4000, 4002); + + /* Clear stale interrupt status bits if any during start */ + ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, &val); + if (ret < 0) { + dev_err(&client->dev, + "can't clear als interrupt status %d\n", ret); + return ret; + } + + /* Cache currently active measurement parameters */ + data->cur_gain = 3; + data->cur_resolution = 4608; + data->cur_integration_time = 3; + + return ret; +} + +static int veml6030_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct veml6030_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c adapter doesn't support plain i2c\n"); + return -EOPNOTSUPP; + } + + regmap = devm_regmap_init_i2c(client, &veml6030_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "can't setup regmap\n"); + return PTR_ERR(regmap); + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + data->regmap = regmap; + + indio_dev->dev.parent = &client->dev; + indio_dev->name = "veml6030"; + indio_dev->channels = veml6030_channels; + indio_dev->num_channels = ARRAY_SIZE(veml6030_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, veml6030_event_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "veml6030", indio_dev); + if (ret < 0) { + dev_err(&client->dev, + "irq %d request failed\n", client->irq); + return ret; + } + indio_dev->info = &veml6030_info; + } else { + indio_dev->info = &veml6030_info_no_irq; + } + + ret = veml6030_hw_init(indio_dev); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&client->dev, + veml6030_als_shut_down_action, data); + if (ret < 0) + return ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static int __maybe_unused veml6030_runtime_suspend(struct device *dev) +{ + int ret; + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct veml6030_data *data = iio_priv(indio_dev); + + ret = veml6030_als_shut_down(data); + if (ret < 0) + dev_err(&data->client->dev, "can't suspend als %d\n", ret); + + return ret; +} + +static int __maybe_unused veml6030_runtime_resume(struct device *dev) +{ + int ret; + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct veml6030_data *data = iio_priv(indio_dev); + + ret = veml6030_als_pwr_on(data); + if (ret < 0) + dev_err(&data->client->dev, "can't resume als %d\n", ret); + + return ret; +} + +static const struct dev_pm_ops veml6030_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(veml6030_runtime_suspend, + veml6030_runtime_resume, NULL) +}; + +static const struct of_device_id veml6030_of_match[] = { + { .compatible = "vishay,veml6030" }, + { } +}; +MODULE_DEVICE_TABLE(of, veml6030_of_match); + +static const struct i2c_device_id veml6030_id[] = { + { "veml6030", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, veml6030_id); + +static struct i2c_driver veml6030_driver = { + .driver = { + .name = "veml6030", + .of_match_table = veml6030_of_match, + .pm = &veml6030_pm_ops, + }, + .probe = veml6030_probe, + .id_table = veml6030_id, +}; +module_i2c_driver(veml6030_driver); + +MODULE_AUTHOR("Rishi Gupta "); +MODULE_DESCRIPTION("VEML6030 Ambient Light Sensor"); +MODULE_LICENSE("GPL v2"); From fcefddc4b735e934eda5d4a340ae7c072fdaa428 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Mon, 4 Nov 2019 21:09:00 +0530 Subject: [PATCH 31/43] dt-bindings: iio: light: add veml6030 ALS bindings This commit adds device tree bindings for veml6030 ambient light sensor. Signed-off-by: Rishi Gupta Reviewed-by: Rob Herring Signed-off-by: Jonathan Cameron --- .../bindings/iio/light/veml6030.yaml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/light/veml6030.yaml diff --git a/Documentation/devicetree/bindings/iio/light/veml6030.yaml b/Documentation/devicetree/bindings/iio/light/veml6030.yaml new file mode 100644 index 000000000000..0ff9b11f9d18 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/veml6030.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0+ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/veml6030.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: VEML6030 Ambient Light Sensor (ALS) + +maintainers: + - Rishi Gupta + +description: | + Bindings for the ambient light sensor veml6030 from Vishay + Semiconductors over an i2c interface. + + Irrespective of whether interrupt is used or not, application + can get the ALS and White channel reading from IIO raw interface. + + If the interrupts are used, application will receive an IIO event + whenever configured threshold is crossed. + + Specifications about the sensor can be found at: + https://www.vishay.com/docs/84366/veml6030.pdf + +properties: + compatible: + enum: + - vishay,veml6030 + + reg: + description: + I2C address of the device. + enum: + - 0x10 # ADDR pin pulled down + - 0x48 # ADDR pin pulled up + + interrupts: + description: + interrupt mapping for IRQ. Configure with IRQ_TYPE_LEVEL_LOW. + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + maxItems: 1 + +required: + - compatible + - reg + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + light-sensor@10 { + compatible = "vishay,veml6030"; + reg = <0x10>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + }; + }; +... From 56a8e6832874c977ea7b11a0e096031f9b4f3e11 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Mon, 4 Nov 2019 21:09:28 +0530 Subject: [PATCH 32/43] iio: documentation: light: Add veml6030 sysfs documentation The driver for veml6030 light sensor provides sysfs entries like configuring cutoff for interrupt. This commit document them. Signed-off-by: Rishi Gupta Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 680451695422..faaa2166d741 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -753,6 +753,8 @@ What: /sys/.../events/in_illuminance0_thresh_falling_value what: /sys/.../events/in_illuminance0_thresh_rising_value what: /sys/.../events/in_proximity0_thresh_falling_value what: /sys/.../events/in_proximity0_thresh_rising_value +What: /sys/.../events/in_illuminance_thresh_rising_value +What: /sys/.../events/in_illuminance_thresh_falling_value KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -972,6 +974,7 @@ What: /sys/.../events/in_activity_jogging_thresh_rising_period What: /sys/.../events/in_activity_jogging_thresh_falling_period What: /sys/.../events/in_activity_running_thresh_rising_period What: /sys/.../events/in_activity_running_thresh_falling_period +What: /sys/.../events/in_illuminance_thresh_either_period KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -1715,3 +1718,11 @@ Description: Mass concentration reading of particulate matter in ug / m3. pmX consists of particles with aerodynamic diameter less or equal to X micrometers. + +What: /sys/bus/iio/devices/iio:deviceX/events/in_illuminance_period_available +Date: November 2019 +KernelVersion: 5.4 +Contact: linux-iio@vger.kernel.org +Description: + List of valid periods (in seconds) for which the light intensity + must be above the threshold level before interrupt is asserted. From 0cdd991bbc519628ae6681a81a2bf75e375ac2d9 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Fri, 8 Nov 2019 08:25:39 +0100 Subject: [PATCH 33/43] dt-bindings: iio: dac: Migrate LTC1660 documentation to yaml Rewrite bindings to use json-schema vocabulary. Signed-off-by: Marcus Folkesson Reviewed-by: Rob Herring Signed-off-by: Jonathan Cameron --- .../bindings/iio/dac/lltc,ltc1660.yaml | 49 +++++++++++++++++++ .../devicetree/bindings/iio/dac/ltc1660.txt | 21 -------- MAINTAINERS | 2 +- 3 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml delete mode 100644 Documentation/devicetree/bindings/iio/dac/ltc1660.txt diff --git a/Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml b/Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml new file mode 100644 index 000000000000..13d005b68931 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +# Copyright 2019 Marcus Folkesson +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/bindings/iio/dac/lltc,ltc1660.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Linear Technology Micropower octal 8-Bit and 10-Bit DACs + +maintainers: + - Marcus Folkesson + +description: | + Bindings for the Linear Technology Micropower octal 8-Bit and 10-Bit DAC. + Datasheet can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/166560fa.pdf + +properties: + compatible: + enum: + - lltc,ltc1660 + - lltc,ltc1665 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 5000000 + + vref-supply: + description: Phandle to the external reference voltage supply. + +required: + - compatible + - reg + - vref-supply + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "lltc,ltc1660"; + reg = <0>; + spi-max-frequency = <5000000>; + vref-supply = <&vref_reg>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/dac/ltc1660.txt b/Documentation/devicetree/bindings/iio/dac/ltc1660.txt deleted file mode 100644 index c5b5f22d6c64..000000000000 --- a/Documentation/devicetree/bindings/iio/dac/ltc1660.txt +++ /dev/null @@ -1,21 +0,0 @@ -* Linear Technology Micropower octal 8-Bit and 10-Bit DACs - -Required properties: - - compatible: Must be one of the following: - "lltc,ltc1660" - "lltc,ltc1665" - - reg: SPI chip select number for the device - - vref-supply: Phandle to the voltage reference supply - -Recommended properties: - - spi-max-frequency: Definition as per - Documentation/devicetree/bindings/spi/spi-bus.txt. - Max frequency for this chip is 5 MHz. - -Example: -dac@0 { - compatible = "lltc,ltc1660"; - reg = <0>; - spi-max-frequency = <5000000>; - vref-supply = <&vref_reg>; -}; diff --git a/MAINTAINERS b/MAINTAINERS index 0fca3b055985..9f846e381e45 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9622,7 +9622,7 @@ LTC1660 DAC DRIVER M: Marcus Folkesson L: linux-iio@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/iio/dac/ltc1660.txt +F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml F: drivers/iio/dac/ltc1660.c LTC2983 IIO TEMPERATURE DRIVER From 6376cbe549fffb378403cee78efd26b8a2c8e450 Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Wed, 6 Nov 2019 11:47:21 +0200 Subject: [PATCH 34/43] iio: dac: ad5446: Add support for new AD5600 DAC The AD5600 is a single channel, 16-bit resolution, voltage output digital to analog converter (DAC). The AD5600 uses a 3-wire SPI interface. It is part of the AD5541 family of DACs. The ad5446 IIO driver implements support for some of these DACs (in the AD5441 family), so the change is a simple entry in this driver. Link: https://www.analog.com/media/en/technical-documentation/data-sheets/AD5600.pdf Signed-off-by: Stefan Popa Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/dac/Kconfig | 4 ++-- drivers/iio/dac/ad5446.c | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index cc42219a64f7..979070196da9 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -60,8 +60,8 @@ config AD5446 help Say yes here to build support for Analog Devices AD5300, AD5301, AD5310, AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453, - AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612, - AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs + AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5600, AD5601, AD5602, AD5611, + AD5612, AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs as well as Texas Instruments DAC081S101, DAC101S101, DAC121S101. To compile this driver as a module, choose M here: the diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 7df8b4cc295d..61c670f7fc5f 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -327,6 +327,7 @@ enum ad5446_supported_spi_device_ids { ID_AD5541A, ID_AD5512A, ID_AD5553, + ID_AD5600, ID_AD5601, ID_AD5611, ID_AD5621, @@ -381,6 +382,10 @@ static const struct ad5446_chip_info ad5446_spi_chip_info[] = { .channel = AD5446_CHANNEL(14, 16, 0), .write = ad5446_write, }, + [ID_AD5600] = { + .channel = AD5446_CHANNEL(16, 16, 0), + .write = ad5446_write, + }, [ID_AD5601] = { .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), .write = ad5446_write, @@ -448,6 +453,7 @@ static const struct spi_device_id ad5446_spi_ids[] = { {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */ {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */ {"ad5553", ID_AD5553}, + {"ad5600", ID_AD5600}, {"ad5601", ID_AD5601}, {"ad5611", ID_AD5611}, {"ad5621", ID_AD5621}, From e9a4cbcaaa391ef44d623d548ee715e77265030c Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Wed, 6 Nov 2019 09:55:33 -0800 Subject: [PATCH 35/43] iio: cros_ec_baro: set info_mask_shared_by_all_available field Field was already set for light/proximity and accelerometer/gyroscope/magnetometer sensors. Fixes: ae7b02ad2f32 ("iio: common: cros_ec_sensors: Expose cros_ec_sensors frequency range via iio sysfs") Signed-off-by: Gwendal Grignou Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/cros_ec_baro.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 2354302375de..52f53f3123b1 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -114,6 +114,7 @@ static int cros_ec_baro_write(struct iio_dev *indio_dev, static const struct iio_info cros_ec_baro_info = { .read_raw = &cros_ec_baro_read, .write_raw = &cros_ec_baro_write, + .read_avail = &cros_ec_sensors_core_read_avail, }; static int cros_ec_baro_probe(struct platform_device *pdev) @@ -149,6 +150,8 @@ static int cros_ec_baro_probe(struct platform_device *pdev) BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_FREQUENCY); + channel->info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; channel->scan_type.storagebits = CROS_EC_SENSOR_BITS; channel->scan_type.shift = 0; From ea3b263e83ed706343b935b1b239ae15ecdf176a Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 7 Nov 2019 19:43:41 +0100 Subject: [PATCH 36/43] dt-bindings: iio: imu: mpu6050: add vdd-supply inv_mpu6050 now supports an additional vdd-supply; document it. Reviewed-by: Linus Walleij Signed-off-by: Stephan Gerhold Reviewed-by: Jean-Baptiste Maneyrol Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt index 268bf7568e19..c5ee8a20af9f 100644 --- a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt +++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt @@ -21,6 +21,7 @@ Required properties: bindings. Optional properties: + - vdd-supply: regulator phandle for VDD supply - vddio-supply: regulator phandle for VDDIO supply - mount-matrix: an optional 3x3 mounting rotation matrix - i2c-gate node. These devices also support an auxiliary i2c bus. This is From 26a0ffeed95190c72da398ae9f655507dc87550f Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 7 Nov 2019 19:43:42 +0100 Subject: [PATCH 37/43] iio: imu: mpu6050: Add support for vdd-supply regulator MPU6050 has two power supply pins: VDD and VLOGIC, but the mpu6050 driver only supports enabling one of them at the moment. In some cases, they may need to be enabled separately. Add an additional "vdd-supply" that stays enabled for as long as the driver is loaded. We cannot turn off the VDD regulator during suspend as this would cause register settings (FSR, sampling rate, ...) to be lost. Signed-off-by: Stephan Gerhold Reviewed-by: Jean-Baptiste Maneyrol Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 43 +++++++++++++++++----- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 4 +- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 354030e9bed5..661a829478f5 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1140,14 +1140,14 @@ error_power_off: return result; } -static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st) +static int inv_mpu_core_enable_regulator_vddio(struct inv_mpu6050_state *st) { int result; result = regulator_enable(st->vddio_supply); if (result) { dev_err(regmap_get_device(st->map), - "Failed to enable regulator: %d\n", result); + "Failed to enable vddio regulator: %d\n", result); } else { /* Give the device a little bit of time to start up. */ usleep_range(35000, 70000); @@ -1156,21 +1156,29 @@ static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st) return result; } -static int inv_mpu_core_disable_regulator(struct inv_mpu6050_state *st) +static int inv_mpu_core_disable_regulator_vddio(struct inv_mpu6050_state *st) { int result; result = regulator_disable(st->vddio_supply); if (result) dev_err(regmap_get_device(st->map), - "Failed to disable regulator: %d\n", result); + "Failed to disable vddio regulator: %d\n", result); return result; } static void inv_mpu_core_disable_regulator_action(void *_data) { - inv_mpu_core_disable_regulator(_data); + struct inv_mpu6050_state *st = _data; + int result; + + result = regulator_disable(st->vdd_supply); + if (result) + dev_err(regmap_get_device(st->map), + "Failed to disable vdd regulator: %d\n", result); + + inv_mpu_core_disable_regulator_vddio(st); } int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, @@ -1239,6 +1247,15 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return -EINVAL; } + st->vdd_supply = devm_regulator_get(dev, "vdd"); + if (IS_ERR(st->vdd_supply)) { + if (PTR_ERR(st->vdd_supply) != -EPROBE_DEFER) + dev_err(dev, "Failed to get vdd regulator %d\n", + (int)PTR_ERR(st->vdd_supply)); + + return PTR_ERR(st->vdd_supply); + } + st->vddio_supply = devm_regulator_get(dev, "vddio"); if (IS_ERR(st->vddio_supply)) { if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER) @@ -1248,9 +1265,17 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return PTR_ERR(st->vddio_supply); } - result = inv_mpu_core_enable_regulator(st); - if (result) + result = regulator_enable(st->vdd_supply); + if (result) { + dev_err(dev, "Failed to enable vdd regulator: %d\n", result); return result; + } + + result = inv_mpu_core_enable_regulator_vddio(st); + if (result) { + regulator_disable(st->vdd_supply); + return result; + } result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action, st); @@ -1352,7 +1377,7 @@ static int inv_mpu_resume(struct device *dev) int result; mutex_lock(&st->lock); - result = inv_mpu_core_enable_regulator(st); + result = inv_mpu_core_enable_regulator_vddio(st); if (result) goto out_unlock; @@ -1370,7 +1395,7 @@ static int inv_mpu_suspend(struct device *dev) mutex_lock(&st->lock); result = inv_mpu6050_set_power_itg(st, false); - inv_mpu_core_disable_regulator(st); + inv_mpu_core_disable_regulator_vddio(st); mutex_unlock(&st->lock); return result; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 52fcf45050a5..4fcf683b9c63 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -130,7 +130,8 @@ struct inv_mpu6050_hw { * @chip_period: chip internal period estimation (~1kHz). * @it_timestamp: timestamp from previous interrupt. * @data_timestamp: timestamp for next data sample. - * @vddio_supply voltage regulator for the chip. + * @vdd_supply: VDD voltage regulator for the chip. + * @vddio_supply I/O voltage regulator for the chip. * @magn_disabled: magnetometer disabled for backward compatibility reason. * @magn_raw_to_gauss: coefficient to convert mag raw value to Gauss. * @magn_orient: magnetometer sensor chip orientation if available. @@ -154,6 +155,7 @@ struct inv_mpu6050_state { s64 chip_period; s64 it_timestamp; s64 data_timestamp; + struct regulator *vdd_supply; struct regulator *vddio_supply; bool magn_disabled; s32 magn_raw_to_gauss[3]; From 5313513d4a633dde0ae9be680bb93761591f475d Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Fri, 8 Nov 2019 08:25:30 +0100 Subject: [PATCH 38/43] dt-bindings: iio: adc: Migrate MCP3911 documentation to yaml Rewrite bindings to use json-schema vocabulary. Signed-off-by: Marcus Folkesson Reviewed-by: Rob Herring Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/mcp3911.txt | 30 -------- .../bindings/iio/adc/microchip,mcp3911.yaml | 71 +++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 72 insertions(+), 31 deletions(-) delete mode 100644 Documentation/devicetree/bindings/iio/adc/mcp3911.txt create mode 100644 Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/mcp3911.txt b/Documentation/devicetree/bindings/iio/adc/mcp3911.txt deleted file mode 100644 index 3071f48fb30b..000000000000 --- a/Documentation/devicetree/bindings/iio/adc/mcp3911.txt +++ /dev/null @@ -1,30 +0,0 @@ -* Microchip MCP3911 Dual channel analog front end (ADC) - -Required properties: - - compatible: Should be "microchip,mcp3911" - - reg: SPI chip select number for the device - -Recommended properties: - - spi-max-frequency: Definition as per - Documentation/devicetree/bindings/spi/spi-bus.txt. - Max frequency for this chip is 20MHz. - -Optional properties: - - clocks: Phandle and clock identifier for sampling clock - - interrupt-parent: Phandle to the parent interrupt controller - - interrupts: IRQ line for the ADC - - microchip,device-addr: Device address when multiple MCP3911 chips are present on the - same SPI bus. Valid values are 0-3. Defaults to 0. - - vref-supply: Phandle to the external reference voltage supply. - -Example: -adc@0 { - compatible = "microchip,mcp3911"; - reg = <0>; - interrupt-parent = <&gpio5>; - interrupts = <15 IRQ_TYPE_EDGE_RISING>; - spi-max-frequency = <20000000>; - microchip,device-addr = <0>; - vref-supply = <&vref_reg>; - clocks = <&xtal>; -}; diff --git a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml new file mode 100644 index 000000000000..881059b80d61 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +# Copyright 2019 Marcus Folkesson +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/bindings/iio/adc/microchip,mcp3911.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Microchip MCP3911 Dual channel analog front end (ADC) + +maintainers: + - Marcus Folkesson + - Kent Gustavsson + +description: | + Bindings for the Microchip MCP3911 Dual channel ADC device. Datasheet can be + found here: https://ww1.microchip.com/downloads/en/DeviceDoc/20002286C.pdf + +properties: + compatible: + enum: + - microchip,mcp3911 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 20000000 + + clocks: + description: | + Phandle and clock identifier for external sampling clock. + If not specified, the internal crystal oscillator will be used. + maxItems: 1 + + interrupts: + description: IRQ line of the ADC + maxItems: 1 + + microchip,device-addr: + description: Device address when multiple MCP3911 chips are present on the same SPI bus. + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - enum: [0, 1, 2, 3] + - default: 0 + + vref-supply: + description: | + Phandle to the external reference voltage supply. + If not specified, the internal voltage reference (1.2V) will be used. + +required: + - compatible + - reg + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "microchip,mcp3911"; + reg = <0>; + interrupt-parent = <&gpio5>; + interrupts = <15 2>; + spi-max-frequency = <20000000>; + microchip,device-addr = <0>; + vref-supply = <&vref_reg>; + clocks = <&xtal>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 9f846e381e45..3deb2c1a2afd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10734,7 +10734,7 @@ M: Kent Gustavsson L: linux-iio@vger.kernel.org S: Supported F: drivers/iio/adc/mcp3911.c -F: Documentation/devicetree/bindings/iio/adc/mcp3911.txt +F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml MICROCHIP NAND DRIVER M: Tudor Ambarus From d898f9ac542f9c60c5760cfe4b9cb10c635feb38 Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 8 Nov 2019 10:56:09 -0300 Subject: [PATCH 39/43] dt-bindings: iio: adc: Add dt-schema for AD7292 Add a devicetree schema for AD7292 monitor and control system. Signed-off-by: Marcelo Schmitt Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7292.yaml | 104 ++++++++++++++++++ MAINTAINERS | 7 ++ 2 files changed, 111 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml new file mode 100644 index 000000000000..b68be3aaf587 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7292.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7292 10-Bit Monitor and Control System + +maintainers: + - Marcelo Schmitt + +description: | + Analog Devices AD7292 10-Bit Monitor and Control System with ADC, DACs, + Temperature Sensor, and GPIOs + + Specifications about the part can be found at: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7292.pdf + +properties: + compatible: + enum: + - adi,ad7292 + + reg: + maxItems: 1 + + vref-supply: + description: | + The regulator supply for ADC and DAC reference voltage. + + spi-cpha: true + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +required: + - compatible + - reg + - spi-cpha + +patternProperties: + "^channel@[0-7]$": + type: object + description: | + Represents the external channels which are connected to the ADC. + See Documentation/devicetree/bindings/iio/adc/adc.txt. + + properties: + reg: + description: | + The channel number. It can have up to 8 channels numbered from 0 to 7. + items: + maximum: 7 + + diff-channels: + description: see Documentation/devicetree/bindings/iio/adc/adc.txt + maxItems: 1 + + required: + - reg + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + ad7292: adc@0 { + compatible = "adi,ad7292"; + reg = <0>; + spi-max-frequency = <25000000>; + vref-supply = <&adc_vref>; + spi-cpha; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + diff-channels = <0 1>; + }; + channel@2 { + reg = <2>; + }; + channel@3 { + reg = <3>; + }; + channel@4 { + reg = <4>; + }; + channel@5 { + reg = <5>; + }; + channel@6 { + reg = <6>; + }; + channel@7 { + reg = <7>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 3deb2c1a2afd..aed4c1cad9f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -901,6 +901,13 @@ S: Supported F: drivers/iio/adc/ad7124.c F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml +ANALOG DEVICES INC AD7292 DRIVER +M: Marcelo Schmitt +L: linux-iio@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml + ANALOG DEVICES INC AD7606 DRIVER M: Stefan Popa M: Beniamin Bia From 506d2e317a0a02631a74bbc4c508334c29e26eae Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 8 Nov 2019 10:56:50 -0300 Subject: [PATCH 40/43] iio: adc: Add driver support for AD7292 The AD7292 is a 10-bit monitor and control system with ADC, DACs, temperature sensor, and GPIOs. Configure AD7292 devices in direct access mode, enabling single-ended ADC readings. Datasheet: Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ad7292.pdf Signed-off-by: Marcelo Schmitt Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 10 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7292.c | 350 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 362 insertions(+) create mode 100644 drivers/iio/adc/ad7292.c diff --git a/MAINTAINERS b/MAINTAINERS index aed4c1cad9f9..d5ea4e4a4598 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -906,6 +906,7 @@ M: Marcelo Schmitt L: linux-iio@vger.kernel.org W: http://ez.analog.com/community/linux-device-drivers S: Supported +F: drivers/iio/adc/ad7292.c F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml ANALOG DEVICES INC AD7606 DRIVER diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 9554890a3200..5d8540b7b427 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -55,6 +55,16 @@ config AD7291 To compile this driver as a module, choose M here: the module will be called ad7291. +config AD7292 + tristate "Analog Devices AD7292 ADC driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD7292 + 8 Channel ADC with temperature sensor. + + To compile this driver as a module, choose M here: the + module will be called ad7292. + config AD7298 tristate "Analog Devices AD7298 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 5ecc481c2967..a1f1fbec0f87 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7124) += ad7124.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7291) += ad7291.o +obj-$(CONFIG_AD7292) += ad7292.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7923) += ad7923.o obj-$(CONFIG_AD7476) += ad7476.o diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c new file mode 100644 index 000000000000..a6798f7dfdb8 --- /dev/null +++ b/drivers/iio/adc/ad7292.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD7292 SPI ADC driver + * + * Copyright 2019 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include + +#include + +#define ADI_VENDOR_ID 0x0018 + +/* AD7292 registers definition */ +#define AD7292_REG_VENDOR_ID 0x00 +#define AD7292_REG_CONF_BANK 0x05 +#define AD7292_REG_CONV_COMM 0x0E +#define AD7292_REG_ADC_CH(x) (0x10 + (x)) + +/* AD7292 configuration bank subregisters definition */ +#define AD7292_BANK_REG_VIN_RNG0 0x10 +#define AD7292_BANK_REG_VIN_RNG1 0x11 +#define AD7292_BANK_REG_SAMP_MODE 0x12 + +#define AD7292_RD_FLAG_MSK(x) (BIT(7) | ((x) & 0x3F)) + +/* AD7292_REG_ADC_CONVERSION */ +#define AD7292_ADC_DATA_MASK GENMASK(15, 6) +#define AD7292_ADC_DATA(x) FIELD_GET(AD7292_ADC_DATA_MASK, x) + +/* AD7292_CHANNEL_SAMPLING_MODE */ +#define AD7292_CH_SAMP_MODE(reg, ch) (((reg) >> 8) & BIT(ch)) + +/* AD7292_CHANNEL_VIN_RANGE */ +#define AD7292_CH_VIN_RANGE(reg, ch) ((reg) & BIT(ch)) + +#define AD7292_VOLTAGE_CHAN(_chan) \ +{ \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .indexed = 1, \ + .channel = _chan, \ +} + +static const struct iio_chan_spec ad7292_channels[] = { + AD7292_VOLTAGE_CHAN(0), + AD7292_VOLTAGE_CHAN(1), + AD7292_VOLTAGE_CHAN(2), + AD7292_VOLTAGE_CHAN(3), + AD7292_VOLTAGE_CHAN(4), + AD7292_VOLTAGE_CHAN(5), + AD7292_VOLTAGE_CHAN(6), + AD7292_VOLTAGE_CHAN(7) +}; + +static const struct iio_chan_spec ad7292_channels_diff[] = { + { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .indexed = 1, + .differential = 1, + .channel = 0, + .channel2 = 1, + }, + AD7292_VOLTAGE_CHAN(2), + AD7292_VOLTAGE_CHAN(3), + AD7292_VOLTAGE_CHAN(4), + AD7292_VOLTAGE_CHAN(5), + AD7292_VOLTAGE_CHAN(6), + AD7292_VOLTAGE_CHAN(7) +}; + +struct ad7292_state { + struct spi_device *spi; + struct regulator *reg; + unsigned short vref_mv; + + __be16 d16 ____cacheline_aligned; + u8 d8[2]; +}; + +static int ad7292_spi_reg_read(struct ad7292_state *st, unsigned int addr) +{ + int ret; + + st->d8[0] = AD7292_RD_FLAG_MSK(addr); + + ret = spi_write_then_read(st->spi, st->d8, 1, &st->d16, 2); + if (ret < 0) + return ret; + + return be16_to_cpu(st->d16); +} + +static int ad7292_spi_subreg_read(struct ad7292_state *st, unsigned int addr, + unsigned int sub_addr, unsigned int len) +{ + unsigned int shift = 16 - (8 * len); + int ret; + + st->d8[0] = AD7292_RD_FLAG_MSK(addr); + st->d8[1] = sub_addr; + + ret = spi_write_then_read(st->spi, st->d8, 2, &st->d16, len); + if (ret < 0) + return ret; + + return (be16_to_cpu(st->d16) >> shift); +} + +static int ad7292_single_conversion(struct ad7292_state *st, + unsigned int chan_addr) +{ + int ret; + + struct spi_transfer t[] = { + { + .tx_buf = &st->d8, + .len = 4, + .delay_usecs = 6, + }, { + .rx_buf = &st->d16, + .len = 2, + }, + }; + + st->d8[0] = chan_addr; + st->d8[1] = AD7292_RD_FLAG_MSK(AD7292_REG_CONV_COMM); + + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); + + if (ret < 0) + return ret; + + return be16_to_cpu(st->d16); +} + +static int ad7292_vin_range_multiplier(struct ad7292_state *st, int channel) +{ + int samp_mode, range0, range1, factor = 1; + + /* + * Every AD7292 ADC channel may have its input range adjusted according + * to the settings at the ADC sampling mode and VIN range subregisters. + * For a given channel, the minimum input range is equal to Vref, and it + * may be increased by a multiplier factor of 2 or 4 according to the + * following rule: + * If channel is being sampled with respect to AGND: + * factor = 4 if VIN range0 and VIN range1 equal 0 + * factor = 2 if only one of VIN ranges equal 1 + * factor = 1 if both VIN range0 and VIN range1 equal 1 + * If channel is being sampled with respect to AVDD: + * factor = 4 if VIN range0 and VIN range1 equal 0 + * Behavior is undefined if any of VIN range doesn't equal 0 + */ + + samp_mode = ad7292_spi_subreg_read(st, AD7292_REG_CONF_BANK, + AD7292_BANK_REG_SAMP_MODE, 2); + + if (samp_mode < 0) + return samp_mode; + + range0 = ad7292_spi_subreg_read(st, AD7292_REG_CONF_BANK, + AD7292_BANK_REG_VIN_RNG0, 2); + + if (range0 < 0) + return range0; + + range1 = ad7292_spi_subreg_read(st, AD7292_REG_CONF_BANK, + AD7292_BANK_REG_VIN_RNG1, 2); + + if (range1 < 0) + return range1; + + if (AD7292_CH_SAMP_MODE(samp_mode, channel)) { + /* Sampling with respect to AGND */ + if (!AD7292_CH_VIN_RANGE(range0, channel)) + factor *= 2; + + if (!AD7292_CH_VIN_RANGE(range1, channel)) + factor *= 2; + + } else { + /* Sampling with respect to AVDD */ + if (AD7292_CH_VIN_RANGE(range0, channel) || + AD7292_CH_VIN_RANGE(range1, channel)) + return -EPERM; + + factor = 4; + } + + return factor; +} + +static int ad7292_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long info) +{ + struct ad7292_state *st = iio_priv(indio_dev); + unsigned int ch_addr; + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ch_addr = AD7292_REG_ADC_CH(chan->channel); + ret = ad7292_single_conversion(st, ch_addr); + if (ret < 0) + return ret; + + *val = AD7292_ADC_DATA(ret); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* + * To convert a raw value to standard units, the IIO defines + * this formula: Scaled value = (raw + offset) * scale. + * For the scale to be a correct multiplier for (raw + offset), + * it must be calculated as the input range divided by the + * number of possible distinct input values. Given the ADC data + * is 10 bit long, it may assume 2^10 distinct values. + * Hence, scale = range / 2^10. The IIO_VAL_FRACTIONAL_LOG2 + * return type indicates to the IIO API to divide *val by 2 to + * the power of *val2 when returning from read_raw. + */ + + ret = ad7292_vin_range_multiplier(st, chan->channel); + if (ret < 0) + return ret; + + *val = st->vref_mv * ret; + *val2 = 10; + return IIO_VAL_FRACTIONAL_LOG2; + default: + break; + } + return -EINVAL; +} + +static const struct iio_info ad7292_info = { + .read_raw = ad7292_read_raw, +}; + +static void ad7292_regulator_disable(void *data) +{ + struct ad7292_state *st = data; + + regulator_disable(st->reg); +} + +static int ad7292_probe(struct spi_device *spi) +{ + struct ad7292_state *st; + struct iio_dev *indio_dev; + struct device_node *child; + bool diff_channels = 0; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + + ret = ad7292_spi_reg_read(st, AD7292_REG_VENDOR_ID); + if (ret != ADI_VENDOR_ID) { + dev_err(&spi->dev, "Wrong vendor id 0x%x\n", ret); + return -EINVAL; + } + + spi_set_drvdata(spi, indio_dev); + + st->reg = devm_regulator_get_optional(&spi->dev, "vref"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) { + dev_err(&spi->dev, + "Failed to enable external vref supply\n"); + return ret; + } + + ret = devm_add_action_or_reset(&spi->dev, + ad7292_regulator_disable, st); + if (ret) { + regulator_disable(st->reg); + return ret; + } + + ret = regulator_get_voltage(st->reg); + if (ret < 0) + return ret; + + st->vref_mv = ret / 1000; + } else { + /* Use the internal voltage reference. */ + st->vref_mv = 1250; + } + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ad7292_info; + + for_each_available_child_of_node(spi->dev.of_node, child) { + diff_channels = of_property_read_bool(child, "diff-channels"); + if (diff_channels) + break; + } + + if (diff_channels) { + indio_dev->num_channels = ARRAY_SIZE(ad7292_channels_diff); + indio_dev->channels = ad7292_channels_diff; + } else { + indio_dev->num_channels = ARRAY_SIZE(ad7292_channels); + indio_dev->channels = ad7292_channels; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id ad7292_id_table[] = { + { "ad7292", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7292_id_table); + +static const struct of_device_id ad7292_of_match[] = { + { .compatible = "adi,ad7292" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ad7292_of_match); + +static struct spi_driver ad7292_driver = { + .driver = { + .name = "ad7292", + .of_match_table = ad7292_of_match, + }, + .probe = ad7292_probe, + .id_table = ad7292_id_table, +}; +module_spi_driver(ad7292_driver); + +MODULE_AUTHOR("Marcelo Schmitt "); +MODULE_DESCRIPTION("Analog Devices AD7292 ADC driver"); +MODULE_LICENSE("GPL v2"); From 731b60afcb3d318581af7f4e1ac9a66f9e12f1a5 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 18 Oct 2019 13:29:08 -0400 Subject: [PATCH 41/43] tools: iio: Correctly add make dependency for iio_utils iio tools fail to build correctly with make parallelization: $ make -s -j24 fixdep: error opening depfile: ./.iio_utils.o.d: No such file or directory make[1]: *** [/home/labbott/linux_upstream/tools/build/Makefile.build:96: iio_utils.o] Error 2 make: *** [Makefile:43: iio_event_monitor-in.o] Error 2 make: *** Waiting for unfinished jobs.... This is because iio_utils.o is used across multiple targets. Fix this by making iio_utils.o a proper dependency. Signed-off-by: Laura Abbott Signed-off-by: Jonathan Cameron --- tools/iio/Build | 1 + tools/iio/Makefile | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/iio/Build b/tools/iio/Build index f74cbda64710..8d0f3af3723f 100644 --- a/tools/iio/Build +++ b/tools/iio/Build @@ -1,3 +1,4 @@ +iio_utils-y += iio_utils.o lsiio-y += lsiio.o iio_utils.o iio_event_monitor-y += iio_event_monitor.o iio_utils.o iio_generic_buffer-y += iio_generic_buffer.o iio_utils.o diff --git a/tools/iio/Makefile b/tools/iio/Makefile index e22378dba244..3de763d9ab70 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile @@ -32,20 +32,24 @@ $(OUTPUT)include/linux/iio: ../../include/uapi/linux/iio prepare: $(OUTPUT)include/linux/iio +IIO_UTILS_IN := $(OUTPUT)iio_utils-in.o +$(IIO_UTILS_IN): prepare FORCE + $(Q)$(MAKE) $(build)=iio_utils + LSIIO_IN := $(OUTPUT)lsiio-in.o -$(LSIIO_IN): prepare FORCE +$(LSIIO_IN): prepare FORCE $(OUTPUT)iio_utils-in.o $(Q)$(MAKE) $(build)=lsiio $(OUTPUT)lsiio: $(LSIIO_IN) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ IIO_EVENT_MONITOR_IN := $(OUTPUT)iio_event_monitor-in.o -$(IIO_EVENT_MONITOR_IN): prepare FORCE +$(IIO_EVENT_MONITOR_IN): prepare FORCE $(OUTPUT)iio_utils-in.o $(Q)$(MAKE) $(build)=iio_event_monitor $(OUTPUT)iio_event_monitor: $(IIO_EVENT_MONITOR_IN) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ IIO_GENERIC_BUFFER_IN := $(OUTPUT)iio_generic_buffer-in.o -$(IIO_GENERIC_BUFFER_IN): prepare FORCE +$(IIO_GENERIC_BUFFER_IN): prepare FORCE $(OUTPUT)iio_utils-in.o $(Q)$(MAKE) $(build)=iio_generic_buffer $(OUTPUT)iio_generic_buffer: $(IIO_GENERIC_BUFFER_IN) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ From 49549cb23a2926eba70bb634e361daea0f319794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Oct 2019 17:33:48 +0100 Subject: [PATCH 42/43] iio: adis16480: Fix scales factors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the scales for the gyroscope, accelerometer and barometer. The pressure scale was just wrong. For the others, the scale factors were not taking into account that a 32bit word is being read from the device. Fixes: 7abad1063deb ("iio: adis16480: Fix scale factors") Fixes: 82e7a1b25017 ("iio: imu: adis16480: Add support for ADIS1649x family of devices") Signed-off-by: Nuno Sá Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 77 ++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index c0e7e768be41..f1d52563951c 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -622,9 +622,13 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, *val2 = (st->chip_info->temp_scale % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_PRESSURE: - *val = 0; - *val2 = 4000; /* 40ubar = 0.004 kPa */ - return IIO_VAL_INT_PLUS_MICRO; + /* + * max scale is 1310 mbar + * max raw value is 32767 shifted for 32bits + */ + *val = 131; /* 1310mbar = 131 kPa */ + *val2 = 32767 << 16; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -785,13 +789,14 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), /* - * storing the value in rad/degree and the scale in degree - * gives us the result in rad and better precession than - * storing the scale directly in rad. + * Typically we do IIO_RAD_TO_DEGREE in the denominator, which + * is exactly the same as IIO_DEGREE_TO_RAD in numerator, since + * it gives better approximation. However, in this case we + * cannot do it since it would not fit in a 32bit variable. */ - .gyro_max_val = IIO_RAD_TO_DEGREE(22887), - .gyro_max_scale = 300, - .accel_max_val = IIO_M_S_2_TO_G(21973), + .gyro_max_val = 22887 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(300), + .accel_max_val = IIO_M_S_2_TO_G(21973 << 16), .accel_max_scale = 18, .temp_scale = 5650, /* 5.65 milli degree Celsius */ .int_clk = 2460000, @@ -801,9 +806,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16480] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(22500), - .gyro_max_scale = 450, - .accel_max_val = IIO_M_S_2_TO_G(12500), + .gyro_max_val = 22500 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), + .accel_max_val = IIO_M_S_2_TO_G(12500 << 16), .accel_max_scale = 10, .temp_scale = 5650, /* 5.65 milli degree Celsius */ .int_clk = 2460000, @@ -813,9 +818,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16485] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(22500), - .gyro_max_scale = 450, - .accel_max_val = IIO_M_S_2_TO_G(20000), + .gyro_max_val = 22500 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), + .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), .accel_max_scale = 5, .temp_scale = 5650, /* 5.65 milli degree Celsius */ .int_clk = 2460000, @@ -825,9 +830,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16488] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(22500), - .gyro_max_scale = 450, - .accel_max_val = IIO_M_S_2_TO_G(22500), + .gyro_max_val = 22500 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), + .accel_max_val = IIO_M_S_2_TO_G(22500 << 16), .accel_max_scale = 18, .temp_scale = 5650, /* 5.65 milli degree Celsius */ .int_clk = 2460000, @@ -837,9 +842,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16495_1] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(20000), - .gyro_max_scale = 125, - .accel_max_val = IIO_M_S_2_TO_G(32000), + .gyro_max_val = 20000 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(125), + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 8, .temp_scale = 12500, /* 12.5 milli degree Celsius */ .int_clk = 4250000, @@ -850,9 +855,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16495_2] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(18000), - .gyro_max_scale = 450, - .accel_max_val = IIO_M_S_2_TO_G(32000), + .gyro_max_val = 18000 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 8, .temp_scale = 12500, /* 12.5 milli degree Celsius */ .int_clk = 4250000, @@ -863,9 +868,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16495_3] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(20000), - .gyro_max_scale = 2000, - .accel_max_val = IIO_M_S_2_TO_G(32000), + .gyro_max_val = 20000 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(2000), + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 8, .temp_scale = 12500, /* 12.5 milli degree Celsius */ .int_clk = 4250000, @@ -876,9 +881,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16497_1] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(20000), - .gyro_max_scale = 125, - .accel_max_val = IIO_M_S_2_TO_G(32000), + .gyro_max_val = 20000 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(125), + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 40, .temp_scale = 12500, /* 12.5 milli degree Celsius */ .int_clk = 4250000, @@ -889,9 +894,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16497_2] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(18000), - .gyro_max_scale = 450, - .accel_max_val = IIO_M_S_2_TO_G(32000), + .gyro_max_val = 18000 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 40, .temp_scale = 12500, /* 12.5 milli degree Celsius */ .int_clk = 4250000, @@ -902,9 +907,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16497_3] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), - .gyro_max_val = IIO_RAD_TO_DEGREE(20000), - .gyro_max_scale = 2000, - .accel_max_val = IIO_M_S_2_TO_G(32000), + .gyro_max_val = 20000 << 16, + .gyro_max_scale = IIO_DEGREE_TO_RAD(2000), + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 40, .temp_scale = 12500, /* 12.5 milli degree Celsius */ .int_clk = 4250000, From 4c35b7a51e2f291471f7221d112c6a45c63e83bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 28 Oct 2019 17:33:49 +0100 Subject: [PATCH 43/43] iio: adis16480: Add debugfs_reg_access entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver is defining debugfs entries by calling `adis16480_debugfs_init()`. However, those entries are attached to the iio_dev debugfs entry which won't exist if no debugfs_reg_access callback is provided. Fixes: 2f3abe6cbb6c ("iio:imu: Add support for the ADIS16480 and similar IMUs") Signed-off-by: Nuno Sá Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index f1d52563951c..078d49deebd4 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -923,6 +923,7 @@ static const struct iio_info adis16480_info = { .read_raw = &adis16480_read_raw, .write_raw = &adis16480_write_raw, .update_scan_mode = adis_update_scan_mode, + .debugfs_reg_access = adis_debugfs_reg_access, }; static int adis16480_stop_device(struct iio_dev *indio_dev)