From f26cc90a463646a2246c4c90eeaef5f5f624ea74 Mon Sep 17 00:00:00 2001 From: Jorge Harrisonn Date: Wed, 1 May 2024 18:57:23 -0300 Subject: [PATCH 001/330] iio: adc: ad7606: using claim_direct_scoped for code simplification Using iio_device_claim_direct_scoped instead of calling `iio_device _claim_direct_modeand later callingiio_device_release_direct_mode` This should make code cleaner and error handling easier Co-authored-by: Lais Nuto Signed-off-by: Lais Nuto Signed-off-by: Jorge Harrisonn Link: https://lore.kernel.org/r/20240501215724.26655-2-jorge.harrisonn@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7606.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 1928d9ae5bcf..3a417595294f 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -174,17 +174,14 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = ad7606_scan_direct(indio_dev, chan->address); - iio_device_release_direct_mode(indio_dev); - - if (ret < 0) - return ret; - *val = (short)ret; - return IIO_VAL_INT; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + ret = ad7606_scan_direct(indio_dev, chan->address); + if (ret < 0) + return ret; + *val = (short) ret; + return IIO_VAL_INT; + } + unreachable(); case IIO_CHAN_INFO_SCALE: if (st->sw_mode_en) ch = chan->address; From f8107cd6f9b9279544f6ee917919b15d95c6385c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 1 May 2024 11:19:41 +0200 Subject: [PATCH 002/330] iio: temperature: max30208: Remove an unused field in struct max30208_data In "struct max30208_data", the 'indio_dev' field is unused. Remove it. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/73f9f540ecdc7c10e833e6fc782324ae7d34ba9c.1714555144.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/max30208.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c index 48be03852cd8..720469f9dc36 100644 --- a/drivers/iio/temperature/max30208.c +++ b/drivers/iio/temperature/max30208.c @@ -34,7 +34,6 @@ struct max30208_data { struct i2c_client *client; - struct iio_dev *indio_dev; struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */ }; From 2625b8eaccae72d4f9b4992f92aaf2b7b5b89f73 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 1 May 2024 11:41:54 +0200 Subject: [PATCH 003/330] iio: multiplexer: Remove an unused field in struct mux In "struct mux", the 'indio_dev' field is unused. Remove it. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/7bb04abdc2815caf090a6c9ecab2a51d837792a7.1714556499.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jonathan Cameron --- drivers/iio/multiplexer/iio-mux.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c index edd8c69f6d2e..2953403bef53 100644 --- a/drivers/iio/multiplexer/iio-mux.c +++ b/drivers/iio/multiplexer/iio-mux.c @@ -30,7 +30,6 @@ struct mux { int cached_state; struct mux_control *control; struct iio_channel *parent; - struct iio_dev *indio_dev; struct iio_chan_spec *chan; struct iio_chan_spec_ext_info *ext_info; struct mux_child *child; From e1c313e04741ac045b1350e83d42cfc08db5e58f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 1 May 2024 13:28:50 +0200 Subject: [PATCH 004/330] iio: tmag5273: Remove some unused field in struct tmag5273_data In "struct tmag5273_data", the 'scale' and 'vcc' fields are unused. Remove them. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Reviewed-by: Gerald Loacker Link: https://lore.kernel.org/r/7bd16d7fea12c64b6b3dc3cd32839cfce145bcf3.1714562912.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/tmag5273.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index 218b1ce076c1..4187abe12784 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -118,11 +118,9 @@ struct tmag5273_data { unsigned int version; char name[16]; unsigned int conv_avg; - unsigned int scale; enum tmag5273_scale_index scale_index; unsigned int angle_measurement; struct regmap *map; - struct regulator *vcc; /* * Locks the sensor for exclusive use during a measurement (which From eef3681983e583bec87a114f4c53ed0dc8c77f1e Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 1 May 2024 14:55:17 +0200 Subject: [PATCH 005/330] iio: light: gp2ap020a00f: Remove some unused field in struct gp2ap020a00f_data In "struct gp2ap020a00f_data", the 'pdata' field is unused. Moreover the "struct gp2ap020a00f_platform_data" is defined nowhere. Neither in this file, nor in a global .h file, so it is completely pointless. So, remove it. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/57e9f29c7062d1bb846064bf6dbd7a8385a855e7.1714568099.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jonathan Cameron --- drivers/iio/light/gp2ap020a00f.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 9f41724819b6..9a476697aa1f 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -237,7 +237,6 @@ enum gp2ap020a00f_thresh_val_id { }; struct gp2ap020a00f_data { - const struct gp2ap020a00f_platform_data *pdata; struct i2c_client *client; struct mutex lock; char *buffer; From cedb9bd816694736dc27a02b123b62395205181d Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Sun, 5 May 2024 07:36:54 +0200 Subject: [PATCH 006/330] iio: imu: bmi160: add support for bmi120 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for bmi120 low power variant of bmi160. Relax failure to match ID to a warning rather than probe fail. This allows for fallback compatibles, whilst retaining a useful debugging message if they turn out not to be so compatible due to badly behaved firmware. Signed-off-by: Danila Tikhonov Co-developed-by: Barnabás Czémán Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20240505-bmi120-v3-1-15cee3d0b2ef@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bmi160/bmi160_core.c | 26 ++++++++++++++++++++------ drivers/iio/imu/bmi160/bmi160_i2c.c | 3 +++ drivers/iio/imu/bmi160/bmi160_spi.c | 3 +++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index a77f1a8348ff..90aa04d94da5 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -26,6 +26,7 @@ #include "bmi160.h" #define BMI160_REG_CHIP_ID 0x00 +#define BMI120_CHIP_ID_VAL 0xD3 #define BMI160_CHIP_ID_VAL 0xD1 #define BMI160_REG_PMU_STATUS 0x03 @@ -112,6 +113,11 @@ .ext_info = bmi160_ext_info, \ } +static const u8 bmi_chip_ids[] = { + BMI120_CHIP_ID_VAL, + BMI160_CHIP_ID_VAL, +}; + /* scan indexes follow DATA register order */ enum bmi160_scan_axis { BMI160_SCAN_EXT_MAGN_X = 0, @@ -704,6 +710,16 @@ static int bmi160_setup_irq(struct iio_dev *indio_dev, int irq, return bmi160_probe_trigger(indio_dev, irq, irq_type); } +static int bmi160_check_chip_id(const u8 chip_id) +{ + for (int i = 0; i < ARRAY_SIZE(bmi_chip_ids); i++) { + if (chip_id == bmi_chip_ids[i]) + return 0; + } + + return -ENODEV; +} + static int bmi160_chip_init(struct bmi160_data *data, bool use_spi) { int ret; @@ -737,12 +753,10 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi) dev_err(dev, "Error reading chip id\n"); goto disable_regulator; } - if (val != BMI160_CHIP_ID_VAL) { - dev_err(dev, "Wrong chip id, got %x expected %x\n", - val, BMI160_CHIP_ID_VAL); - ret = -ENODEV; - goto disable_regulator; - } + + ret = bmi160_check_chip_id(val); + if (ret) + dev_warn(dev, "Chip id not found: %x\n", val); ret = bmi160_set_mode(data, BMI160_ACCEL, true); if (ret) diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index a081305254db..d0ec5301ad9a 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -37,6 +37,7 @@ static int bmi160_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bmi160_i2c_id[] = { + {"bmi120", 0}, {"bmi160", 0}, {} }; @@ -52,12 +53,14 @@ static const struct acpi_device_id bmi160_acpi_match[] = { * the affected devices are from 2021/2022. */ {"10EC5280", 0}, + {"BMI0120", 0}, {"BMI0160", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match); static const struct of_device_id bmi160_of_match[] = { + { .compatible = "bosch,bmi120" }, { .compatible = "bosch,bmi160" }, { }, }; diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index 8b573ea99af2..9f40500132f7 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -34,18 +34,21 @@ static int bmi160_spi_probe(struct spi_device *spi) } static const struct spi_device_id bmi160_spi_id[] = { + {"bmi120", 0}, {"bmi160", 0}, {} }; MODULE_DEVICE_TABLE(spi, bmi160_spi_id); static const struct acpi_device_id bmi160_acpi_match[] = { + {"BMI0120", 0}, {"BMI0160", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match); static const struct of_device_id bmi160_of_match[] = { + { .compatible = "bosch,bmi120" }, { .compatible = "bosch,bmi160" }, { }, }; From e5073e9ccfc648c6ec4bead45b6f5d8bc3b115bf Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Sun, 5 May 2024 07:36:55 +0200 Subject: [PATCH 007/330] dt-bindings: iio: imu: bmi160: add bmi120 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document bosch,bmi120 compatible. Signed-off-by: Danila Tikhonov Signed-off-by: Barnbás Czémán Acked-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240505-bmi120-v3-2-15cee3d0b2ef@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml index 47cfba939ca6..3b0a2d8b2e91 100644 --- a/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml +++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml @@ -16,7 +16,11 @@ description: | properties: compatible: - const: bosch,bmi160 + oneOf: + - const: bosch,bmi160 + - items: + - const: bosch,bmi120 + - const: bosch,bmi160 reg: maxItems: 1 From 5acc3f971a01be48d5ff4252d8f9cdb87998cdfb Mon Sep 17 00:00:00 2001 From: Chenyuan Yang Date: Tue, 30 Apr 2024 15:44:53 +0300 Subject: [PATCH 008/330] iio: Fix the sorting functionality in iio_gts_build_avail_time_table The sorting in iio_gts_build_avail_time_table is not working as intended. It could result in an out-of-bounds access when the time is zero. Here are more details: 1. When the gts->itime_table[i].time_us is zero, e.g., the time sequence is `3, 0, 1`, the inner for-loop will not terminate and do out-of-bound writes. This is because once `times[j] > new`, the value `new` will be added in the current position and the `times[j]` will be moved to `j+1` position, which makes the if-condition always hold. Meanwhile, idx will be added one, making the loop keep running without termination and out-of-bound write. 2. If none of the gts->itime_table[i].time_us is zero, the elements will just be copied without being sorted as described in the comment "Sort times from all tables to one and remove duplicates". For more details, please refer to https://lore.kernel.org/all/6dd0d822-046c-4dd2-9532-79d7ab96ec05@gmail.com. Reported-by: Chenyuan Yang Suggested-by: Matti Vaittinen Fixes: 38416c28e168 ("iio: light: Add gain-time-scale helpers") Signed-off-by: Chenyuan Yang Co-developed-by: Matti Vaittinen Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/d501ade8c1f7b202d34c6404eda423489cab1df5.1714480171.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-gts-helper.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c index b51eb6cb766f..59d7615c0f56 100644 --- a/drivers/iio/industrialio-gts-helper.c +++ b/drivers/iio/industrialio-gts-helper.c @@ -362,17 +362,20 @@ static int iio_gts_build_avail_time_table(struct iio_gts *gts) for (i = gts->num_itime - 1; i >= 0; i--) { int new = gts->itime_table[i].time_us; - if (times[idx] < new) { + if (idx == 0 || times[idx - 1] < new) { times[idx++] = new; continue; } - for (j = 0; j <= idx; j++) { + for (j = 0; j < idx; j++) { + if (times[j] == new) + break; if (times[j] > new) { memmove(×[j + 1], ×[j], (idx - j) * sizeof(int)); times[j] = new; idx++; + break; } } } From 6de2f3a1f4bb6abb01c0922c753544ec7f349dd4 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 30 Apr 2024 15:45:21 +0300 Subject: [PATCH 009/330] iio: test: gts: test available times and gains sorting The iio_gts helpers build available times and scales tables based on the times and gains arrays given from the driver. The driver should be able to list all valid register values so that conversion from register valu to correct gain/time works for all supported register values. It might be more convenient for drivers to list these times and gains in the order where they're listed in the data-sheet than ascending order. However, for user who requests the supported scales / times it is more convenient to get the results in asscending order. Also, listing duplicated values is not meaning for the user. Hence the GTS heler should do sorting and deduplication of the scales and times when it builds the tables listing the available times/scales. Note, currently duplicated gain values aren't handled by GTS-helpers. Unsort the gain and time arrays in the test code, and add duplicates to time array in order to test the sorting and deduplicating works. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/365cc6de3c17a457db738f5fdf8dd3bd6f50d5f2.1714480171.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/test/iio-test-gts.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c index cf7ab773ea0b..5f16a7b5e6d4 100644 --- a/drivers/iio/test/iio-test-gts.c +++ b/drivers/iio/test/iio-test-gts.c @@ -70,6 +70,7 @@ */ static struct iio_gts gts; +/* Keep the gain and time tables unsorted to test the sorting */ static const struct iio_gain_sel_pair gts_test_gains[] = { GAIN_SCALE_GAIN(1, TEST_GSEL_1), GAIN_SCALE_GAIN(4, TEST_GSEL_4), @@ -79,16 +80,17 @@ static const struct iio_gain_sel_pair gts_test_gains[] = { GAIN_SCALE_GAIN(256, TEST_GSEL_256), GAIN_SCALE_GAIN(512, TEST_GSEL_512), GAIN_SCALE_GAIN(1024, TEST_GSEL_1024), - GAIN_SCALE_GAIN(2048, TEST_GSEL_2048), GAIN_SCALE_GAIN(4096, TEST_GSEL_4096), + GAIN_SCALE_GAIN(2048, TEST_GSEL_2048), #define HWGAIN_MAX 4096 }; static const struct iio_itime_sel_mul gts_test_itimes[] = { - GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8), - GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2), + GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8), + GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8), GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1), + GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), #define TIMEGAIN_MAX 8 }; #define TOTAL_GAIN_MAX (HWGAIN_MAX * TIMEGAIN_MAX) From 439ce8961bdd2e925c1f6adc82ce9fe3931e2c08 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Mon, 29 Apr 2024 21:00:37 +0200 Subject: [PATCH 010/330] iio: pressure: bmp280: Improve indentation and line wrapping Fix indentations that are not following the standards, remove extra white lines and add missing white lines. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240429190046.24252-2-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 108 ++++++++++++++++------------- drivers/iio/pressure/bmp280-spi.c | 4 +- 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 09f53d987c7d..1a3241a41768 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -52,7 +52,6 @@ */ enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD }; - enum bmp380_odr { BMP380_ODR_200HZ, BMP380_ODR_100HZ, @@ -181,18 +180,19 @@ static int bmp280_read_calib(struct bmp280_data *data) struct bmp280_calib *calib = &data->calib.bmp280; int ret; - /* Read temperature and pressure calibration values. */ ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START, - data->bmp280_cal_buf, sizeof(data->bmp280_cal_buf)); + data->bmp280_cal_buf, + sizeof(data->bmp280_cal_buf)); if (ret < 0) { dev_err(data->dev, - "failed to read temperature and pressure calibration parameters\n"); + "failed to read calibration parameters\n"); return ret; } - /* Toss the temperature and pressure calibration data into the entropy pool */ - add_device_randomness(data->bmp280_cal_buf, sizeof(data->bmp280_cal_buf)); + /* Toss calibration data into the entropy pool */ + add_device_randomness(data->bmp280_cal_buf, + sizeof(data->bmp280_cal_buf)); /* Parse temperature calibration values. */ calib->T1 = le16_to_cpu(data->bmp280_cal_buf[T1]); @@ -223,7 +223,7 @@ static int bme280_read_calib(struct bmp280_data *data) /* Load shared calibration params with bmp280 first */ ret = bmp280_read_calib(data); if (ret < 0) { - dev_err(dev, "failed to read common bmp280 calibration parameters\n"); + dev_err(dev, "failed to read calibration parameters\n"); return ret; } @@ -283,6 +283,7 @@ static int bme280_read_calib(struct bmp280_data *data) return 0; } + /* * Returns humidity in percent, resolution is 0.01 percent. Output value of * "47445" represents 47445/1024 = 46.333 %RH. @@ -305,7 +306,7 @@ static u32 bmp280_compensate_humidity(struct bmp280_data *data, var = clamp_val(var, 0, 419430400); return var >> 12; -}; +} /* * Returns temperature in DegC, resolution is 0.01 DegC. Output value of @@ -538,7 +539,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, } static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, - int val) + int val) { const int *avail = data->chip_info->oversampling_humid_avail; const int n = data->chip_info->num_oversampling_humid_avail; @@ -563,7 +564,7 @@ static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, } static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data, - int val) + int val) { const int *avail = data->chip_info->oversampling_temp_avail; const int n = data->chip_info->num_oversampling_temp_avail; @@ -588,7 +589,7 @@ static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data, } static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data, - int val) + int val) { const int *avail = data->chip_info->oversampling_press_avail; const int n = data->chip_info->num_oversampling_press_avail; @@ -772,13 +773,12 @@ static int bmp280_chip_config(struct bmp280_data *data) int ret; ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS, - BMP280_OSRS_TEMP_MASK | - BMP280_OSRS_PRESS_MASK | - BMP280_MODE_MASK, - osrs | BMP280_MODE_NORMAL); + BMP280_OSRS_TEMP_MASK | + BMP280_OSRS_PRESS_MASK | + BMP280_MODE_MASK, + osrs | BMP280_MODE_NORMAL); if (ret < 0) { - dev_err(data->dev, - "failed to write ctrl_meas register\n"); + dev_err(data->dev, "failed to write ctrl_meas register\n"); return ret; } @@ -786,8 +786,7 @@ static int bmp280_chip_config(struct bmp280_data *data) BMP280_FILTER_MASK, BMP280_FILTER_4X); if (ret < 0) { - dev_err(data->dev, - "failed to write config register\n"); + dev_err(data->dev, "failed to write config register\n"); return ret; } @@ -926,8 +925,8 @@ static int bmp380_cmd(struct bmp280_data *data, u8 cmd) } /* - * Returns temperature in Celsius degrees, resolution is 0.01º C. Output value of - * "5123" equals 51.2º C. t_fine carries fine temperature as global value. + * Returns temperature in Celsius degrees, resolution is 0.01º C. Output value + * of "5123" equals 51.2º C. t_fine carries fine temperature as global value. * * Taken from datasheet, Section Appendix 9, "Compensation formula" and repo * https://github.com/BoschSensortec/BMP3-Sensor-API. @@ -1069,7 +1068,8 @@ static int bmp380_read_calib(struct bmp280_data *data) /* Read temperature and pressure calibration data */ ret = regmap_bulk_read(data->regmap, BMP380_REG_CALIB_TEMP_START, - data->bmp380_cal_buf, sizeof(data->bmp380_cal_buf)); + data->bmp380_cal_buf, + sizeof(data->bmp380_cal_buf)); if (ret) { dev_err(data->dev, "failed to read temperature calibration parameters\n"); @@ -1077,7 +1077,8 @@ static int bmp380_read_calib(struct bmp280_data *data) } /* Toss the temperature calibration data into the entropy pool */ - add_device_randomness(data->bmp380_cal_buf, sizeof(data->bmp380_cal_buf)); + add_device_randomness(data->bmp380_cal_buf, + sizeof(data->bmp380_cal_buf)); /* Parse calibration values */ calib->T1 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_T1]); @@ -1159,7 +1160,8 @@ static int bmp380_chip_config(struct bmp280_data *data) /* Configure output data rate */ ret = regmap_update_bits_check(data->regmap, BMP380_REG_ODR, - BMP380_ODRS_MASK, data->sampling_freq, &aux); + BMP380_ODRS_MASK, data->sampling_freq, + &aux); if (ret) { dev_err(data->dev, "failed to write ODR selection register\n"); return ret; @@ -1178,12 +1180,13 @@ static int bmp380_chip_config(struct bmp280_data *data) if (change) { /* - * The configurations errors are detected on the fly during a measurement - * cycle. If the sampling frequency is too low, it's faster to reset - * the measurement loop than wait until the next measurement is due. + * The configurations errors are detected on the fly during a + * measurement cycle. If the sampling frequency is too low, it's + * faster to reset the measurement loop than wait until the next + * measurement is due. * - * Resets sensor measurement loop toggling between sleep and normal - * operating modes. + * Resets sensor measurement loop toggling between sleep and + * normal operating modes. */ ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, BMP380_MODE_MASK, @@ -1201,22 +1204,21 @@ static int bmp380_chip_config(struct bmp280_data *data) return ret; } /* - * Waits for measurement before checking configuration error flag. - * Selected longest measure time indicated in section 3.9.1 - * in the datasheet. + * Waits for measurement before checking configuration error + * flag. Selected longest measure time indicated in + * section 3.9.1 in the datasheet. */ msleep(80); /* Check config error flag */ ret = regmap_read(data->regmap, BMP380_REG_ERROR, &tmp); if (ret) { - dev_err(data->dev, - "failed to read error register\n"); + dev_err(data->dev, "failed to read error register\n"); return ret; } if (tmp & BMP380_ERR_CONF_MASK) { dev_warn(data->dev, - "sensor flagged configuration as incompatible\n"); + "sensor flagged configuration as incompatible\n"); return -EINVAL; } } @@ -1317,9 +1319,11 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write) } /* Start NVM operation sequence */ - ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_NVM_OP_SEQ_0); + ret = regmap_write(data->regmap, BMP580_REG_CMD, + BMP580_CMD_NVM_OP_SEQ_0); if (ret) { - dev_err(data->dev, "failed to send nvm operation's first sequence\n"); + dev_err(data->dev, + "failed to send nvm operation's first sequence\n"); return ret; } if (is_write) { @@ -1327,7 +1331,8 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write) ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_NVM_WRITE_SEQ_1); if (ret) { - dev_err(data->dev, "failed to send nvm write sequence\n"); + dev_err(data->dev, + "failed to send nvm write sequence\n"); return ret; } /* Datasheet says on 4.8.1.2 it takes approximately 10ms */ @@ -1338,7 +1343,8 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write) ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_NVM_READ_SEQ_1); if (ret) { - dev_err(data->dev, "failed to send nvm read sequence\n"); + dev_err(data->dev, + "failed to send nvm read sequence\n"); return ret; } /* Datasheet says on 4.8.1.1 it takes approximately 200us */ @@ -1501,8 +1507,8 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, if (ret) goto exit; - ret = regmap_bulk_read(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16, - sizeof(data->le16)); + ret = regmap_bulk_read(data->regmap, BMP580_REG_NVM_DATA_LSB, + &data->le16, sizeof(data->le16)); if (ret) { dev_err(data->dev, "error reading nvm data regs\n"); goto exit; @@ -1546,7 +1552,8 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, while (bytes >= sizeof(*buf)) { addr = bmp580_nvmem_addrs[offset / sizeof(*buf)]; - ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR, BMP580_NVM_PROG_EN | + ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR, + BMP580_NVM_PROG_EN | FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr)); if (ret) { dev_err(data->dev, "error writing nvm address\n"); @@ -1554,8 +1561,8 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, } data->le16 = cpu_to_le16(*buf++); - ret = regmap_bulk_write(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16, - sizeof(data->le16)); + ret = regmap_bulk_write(data->regmap, BMP580_REG_NVM_DATA_LSB, + &data->le16, sizeof(data->le16)); if (ret) { dev_err(data->dev, "error writing LSB NVM data regs\n"); goto exit; @@ -1662,7 +1669,8 @@ static int bmp580_chip_config(struct bmp280_data *data) BMP580_OSR_PRESS_EN; ret = regmap_update_bits_check(data->regmap, BMP580_REG_OSR_CONFIG, - BMP580_OSR_TEMP_MASK | BMP580_OSR_PRESS_MASK | + BMP580_OSR_TEMP_MASK | + BMP580_OSR_PRESS_MASK | BMP580_OSR_PRESS_EN, reg_val, &aux); if (ret) { @@ -1713,7 +1721,8 @@ static int bmp580_chip_config(struct bmp280_data *data) */ ret = regmap_read(data->regmap, BMP580_REG_EFF_OSR, &tmp); if (ret) { - dev_err(data->dev, "error reading effective OSR register\n"); + dev_err(data->dev, + "error reading effective OSR register\n"); return ret; } if (!(tmp & BMP580_EFF_OSR_VALID_ODR)) { @@ -1848,7 +1857,8 @@ static int bmp180_read_calib(struct bmp280_data *data) } /* Toss the calibration data into the entropy pool */ - add_device_randomness(data->bmp180_cal_buf, sizeof(data->bmp180_cal_buf)); + add_device_randomness(data->bmp180_cal_buf, + sizeof(data->bmp180_cal_buf)); calib->AC1 = be16_to_cpu(data->bmp180_cal_buf[AC1]); calib->AC2 = be16_to_cpu(data->bmp180_cal_buf[AC2]); @@ -1963,8 +1973,7 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) return p + ((x1 + x2 + 3791) >> 4); } -static int bmp180_read_press(struct bmp280_data *data, - int *val, int *val2) +static int bmp180_read_press(struct bmp280_data *data, int *val, int *val2) { u32 comp_press; s32 adc_press; @@ -2241,6 +2250,7 @@ static int bmp280_runtime_resume(struct device *dev) ret = regulator_bulk_enable(BMP280_NUM_SUPPLIES, data->supplies); if (ret) return ret; + usleep_range(data->start_up_time, data->start_up_time + 100); return data->chip_info->chip_config(data); } diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 4e19ea0b4d39..62b4e58104cf 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -13,7 +13,7 @@ #include "bmp280.h" static int bmp280_regmap_spi_write(void *context, const void *data, - size_t count) + size_t count) { struct spi_device *spi = to_spi_device(context); u8 buf[2]; @@ -29,7 +29,7 @@ static int bmp280_regmap_spi_write(void *context, const void *data, } static int bmp280_regmap_spi_read(void *context, const void *reg, - size_t reg_size, void *val, size_t val_size) + size_t reg_size, void *val, size_t val_size) { struct spi_device *spi = to_spi_device(context); From b23be4cd99a6f1f46963b87952632268174e62c1 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Mon, 29 Apr 2024 21:00:38 +0200 Subject: [PATCH 011/330] iio: pressure: bmp280: Use BME prefix for BME280 specifics Change the rest of the defines and function names that are used specifically by the BME280 humidity sensor to BME280 as it is done for the rest of the BMP{0,1,3,5}80 sensors. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240429190046.24252-3-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 37 +++++++++++------------ drivers/iio/pressure/bmp280-regmap.c | 8 ++--- drivers/iio/pressure/bmp280.h | 45 +++++++++++++++------------- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 1a3241a41768..edfa66953f87 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -235,14 +235,14 @@ static int bme280_read_calib(struct bmp280_data *data) * Humidity data is only available on BME280. */ - ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &tmp); + ret = regmap_read(data->regmap, BME280_REG_COMP_H1, &tmp); if (ret < 0) { dev_err(dev, "failed to read H1 comp value\n"); return ret; } calib->H1 = tmp; - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, + ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H2, &data->le16, sizeof(data->le16)); if (ret < 0) { dev_err(dev, "failed to read H2 comp value\n"); @@ -250,14 +250,14 @@ static int bme280_read_calib(struct bmp280_data *data) } calib->H2 = sign_extend32(le16_to_cpu(data->le16), 15); - ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &tmp); + ret = regmap_read(data->regmap, BME280_REG_COMP_H3, &tmp); if (ret < 0) { dev_err(dev, "failed to read H3 comp value\n"); return ret; } calib->H3 = tmp; - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, + ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H4, &data->be16, sizeof(data->be16)); if (ret < 0) { dev_err(dev, "failed to read H4 comp value\n"); @@ -266,15 +266,15 @@ static int bme280_read_calib(struct bmp280_data *data) calib->H4 = sign_extend32(((be16_to_cpu(data->be16) >> 4) & 0xff0) | (be16_to_cpu(data->be16) & 0xf), 11); - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, + ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H5, &data->le16, sizeof(data->le16)); if (ret < 0) { dev_err(dev, "failed to read H5 comp value\n"); return ret; } - calib->H5 = sign_extend32(FIELD_GET(BMP280_COMP_H5_MASK, le16_to_cpu(data->le16)), 11); + calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, le16_to_cpu(data->le16)), 11); - ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp); + ret = regmap_read(data->regmap, BME280_REG_COMP_H6, &tmp); if (ret < 0) { dev_err(dev, "failed to read H6 comp value\n"); return ret; @@ -290,7 +290,7 @@ static int bme280_read_calib(struct bmp280_data *data) * * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula". */ -static u32 bmp280_compensate_humidity(struct bmp280_data *data, +static u32 bme280_compensate_humidity(struct bmp280_data *data, s32 adc_humidity) { struct bmp280_calib *calib = &data->calib.bmp280; @@ -430,7 +430,7 @@ static int bmp280_read_press(struct bmp280_data *data, return IIO_VAL_FRACTIONAL; } -static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) +static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2) { u32 comp_humidity; s32 adc_humidity; @@ -441,7 +441,7 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) if (ret < 0) return ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, + ret = regmap_bulk_read(data->regmap, BME280_REG_HUMIDITY_MSB, &data->be16, sizeof(data->be16)); if (ret < 0) { dev_err(data->dev, "failed to read humidity\n"); @@ -454,7 +454,7 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) dev_err(data->dev, "reading humidity skipped\n"); return -EIO; } - comp_humidity = bmp280_compensate_humidity(data, adc_humidity); + comp_humidity = bme280_compensate_humidity(data, adc_humidity); *val = comp_humidity * 1000 / 1024; @@ -538,7 +538,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, return ret; } -static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, +static int bme280_write_oversampling_ratio_humid(struct bmp280_data *data, int val) { const int *avail = data->chip_info->oversampling_humid_avail; @@ -682,7 +682,7 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, mutex_lock(&data->lock); switch (chan->type) { case IIO_HUMIDITYRELATIVE: - ret = bmp280_write_oversampling_ratio_humid(data, val); + ret = bme280_write_oversampling_ratio_humid(data, val); break; case IIO_PRESSURE: ret = bmp280_write_oversampling_ratio_press(data, val); @@ -832,16 +832,15 @@ EXPORT_SYMBOL_NS(bmp280_chip_info, IIO_BMP280); static int bme280_chip_config(struct bmp280_data *data) { - u8 osrs = FIELD_PREP(BMP280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1); + u8 osrs = FIELD_PREP(BME280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1); int ret; /* * Oversampling of humidity must be set before oversampling of * temperature/pressure is set to become effective. */ - ret = regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY, - BMP280_OSRS_HUMIDITY_MASK, osrs); - + ret = regmap_update_bits(data->regmap, BME280_REG_CTRL_HUMIDITY, + BME280_OSRS_HUMIDITY_MASK, osrs); if (ret < 0) return ret; @@ -869,12 +868,12 @@ const struct bmp280_chip_info bme280_chip_info = { .oversampling_humid_avail = bmp280_oversampling_avail, .num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail), - .oversampling_humid_default = BMP280_OSRS_HUMIDITY_16X - 1, + .oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1, .chip_config = bme280_chip_config, .read_temp = bmp280_read_temp, .read_press = bmp280_read_press, - .read_humid = bmp280_read_humid, + .read_humid = bme280_read_humid, .read_calib = bme280_read_calib, }; EXPORT_SYMBOL_NS(bme280_chip_info, IIO_BMP280); diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c index 3ee56720428c..fa52839474b1 100644 --- a/drivers/iio/pressure/bmp280-regmap.c +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -45,7 +45,7 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { case BMP280_REG_CONFIG: - case BMP280_REG_CTRL_HUMIDITY: + case BME280_REG_CTRL_HUMIDITY: case BMP280_REG_CTRL_MEAS: case BMP280_REG_RESET: return true; @@ -57,8 +57,8 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case BMP280_REG_HUMIDITY_LSB: - case BMP280_REG_HUMIDITY_MSB: + case BME280_REG_HUMIDITY_LSB: + case BME280_REG_HUMIDITY_MSB: case BMP280_REG_TEMP_XLSB: case BMP280_REG_TEMP_LSB: case BMP280_REG_TEMP_MSB: @@ -167,7 +167,7 @@ const struct regmap_config bmp280_regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = BMP280_REG_HUMIDITY_LSB, + .max_register = BME280_REG_HUMIDITY_LSB, .cache_type = REGCACHE_RBTREE, .writeable_reg = bmp280_is_writeable_reg, diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index 5812a344ed8e..91d4457a9230 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -192,8 +192,6 @@ #define BMP380_PRESS_SKIPPED 0x800000 /* BMP280 specific registers */ -#define BMP280_REG_HUMIDITY_LSB 0xFE -#define BMP280_REG_HUMIDITY_MSB 0xFD #define BMP280_REG_TEMP_XLSB 0xFC #define BMP280_REG_TEMP_LSB 0xFB #define BMP280_REG_TEMP_MSB 0xFA @@ -207,15 +205,6 @@ #define BMP280_REG_CONFIG 0xF5 #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_STATUS 0xF3 -#define BMP280_REG_CTRL_HUMIDITY 0xF2 - -/* Due to non linear mapping, and data sizes we can't do a bulk read */ -#define BMP280_REG_COMP_H1 0xA1 -#define BMP280_REG_COMP_H2 0xE1 -#define BMP280_REG_COMP_H3 0xE3 -#define BMP280_REG_COMP_H4 0xE4 -#define BMP280_REG_COMP_H5 0xE5 -#define BMP280_REG_COMP_H6 0xE7 #define BMP280_REG_COMP_TEMP_START 0x88 #define BMP280_COMP_TEMP_REG_COUNT 6 @@ -223,8 +212,6 @@ #define BMP280_REG_COMP_PRESS_START 0x8E #define BMP280_COMP_PRESS_REG_COUNT 18 -#define BMP280_COMP_H5_MASK GENMASK(15, 4) - #define BMP280_CONTIGUOUS_CALIB_REGS (BMP280_COMP_TEMP_REG_COUNT + \ BMP280_COMP_PRESS_REG_COUNT) @@ -235,14 +222,6 @@ #define BMP280_FILTER_8X 3 #define BMP280_FILTER_16X 4 -#define BMP280_OSRS_HUMIDITY_MASK GENMASK(2, 0) -#define BMP280_OSRS_HUMIDITY_SKIP 0 -#define BMP280_OSRS_HUMIDITY_1X 1 -#define BMP280_OSRS_HUMIDITY_2X 2 -#define BMP280_OSRS_HUMIDITY_4X 3 -#define BMP280_OSRS_HUMIDITY_8X 4 -#define BMP280_OSRS_HUMIDITY_16X 5 - #define BMP280_OSRS_TEMP_MASK GENMASK(7, 5) #define BMP280_OSRS_TEMP_SKIP 0 #define BMP280_OSRS_TEMP_1X 1 @@ -264,6 +243,30 @@ #define BMP280_MODE_FORCED 1 #define BMP280_MODE_NORMAL 3 +/* BME280 specific registers */ +#define BME280_REG_HUMIDITY_LSB 0xFE +#define BME280_REG_HUMIDITY_MSB 0xFD + +#define BME280_REG_CTRL_HUMIDITY 0xF2 + +/* Due to non linear mapping, and data sizes we can't do a bulk read */ +#define BME280_REG_COMP_H1 0xA1 +#define BME280_REG_COMP_H2 0xE1 +#define BME280_REG_COMP_H3 0xE3 +#define BME280_REG_COMP_H4 0xE4 +#define BME280_REG_COMP_H5 0xE5 +#define BME280_REG_COMP_H6 0xE7 + +#define BME280_COMP_H5_MASK GENMASK(15, 4) + +#define BME280_OSRS_HUMIDITY_MASK GENMASK(2, 0) +#define BME280_OSRS_HUMIDITY_SKIP 0 +#define BME280_OSRS_HUMIDITY_1X 1 +#define BME280_OSRS_HUMIDITY_2X 2 +#define BME280_OSRS_HUMIDITY_4X 3 +#define BME280_OSRS_HUMIDITY_8X 4 +#define BME280_OSRS_HUMIDITY_16X 5 + /* BMP180 specific registers */ #define BMP180_REG_OUT_XLSB 0xF8 #define BMP180_REG_OUT_LSB 0xF7 From 990570dab056e9467fa73d41dd75ddb3150eb636 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Mon, 29 Apr 2024 21:00:39 +0200 Subject: [PATCH 012/330] iio: pressure: bmp280: Add identifier names in function definitions checkpatch.pl complained about missing identifier names in the input variables for some function definitions. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240429190046.24252-4-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index 91d4457a9230..fe4d3f127954 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -452,12 +452,12 @@ struct bmp280_chip_info { int num_sampling_freq_avail; int sampling_freq_default; - int (*chip_config)(struct bmp280_data *); - int (*read_temp)(struct bmp280_data *, int *, int *); - int (*read_press)(struct bmp280_data *, int *, int *); - int (*read_humid)(struct bmp280_data *, int *, int *); - int (*read_calib)(struct bmp280_data *); - int (*preinit)(struct bmp280_data *); + int (*chip_config)(struct bmp280_data *data); + int (*read_temp)(struct bmp280_data *data, int *val, int *val2); + int (*read_press)(struct bmp280_data *data, int *val, int *val2); + int (*read_humid)(struct bmp280_data *data, int *val, int *val2); + int (*read_calib)(struct bmp280_data *data); + int (*preinit)(struct bmp280_data *data); }; /* Chip infos for each variant */ @@ -476,7 +476,7 @@ extern const struct regmap_config bmp580_regmap_config; /* Probe called from different transports */ int bmp280_common_probe(struct device *dev, struct regmap *regmap, - const struct bmp280_chip_info *, + const struct bmp280_chip_info *chip_info, const char *name, int irq); From 1b5a2466b72e1afe550c8568e072f6b2af1698d5 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Mon, 29 Apr 2024 21:00:40 +0200 Subject: [PATCH 013/330] iio: pressure: bmp280: Add more intuitive name for bmp180_measure() The bmp180_measure() function essentially waits for the end of the current conversion in order to read the values from the sensors. The name bmp180_measure() could be misinterpreted because it could be translated as "measure sensor values" even though it was probably trying to say "measure time for eoc". Give a more intuitive name to this function to be less confusing. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240429190046.24252-5-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index edfa66953f87..ed49e0779d41 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -1771,7 +1771,7 @@ const struct bmp280_chip_info bmp580_chip_info = { }; EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280); -static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) +static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas) { const int conversion_time_max[] = { 4500, 7500, 13500, 25500 }; unsigned int delay_us; @@ -1820,9 +1820,9 @@ static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) { int ret; - ret = bmp180_measure(data, - FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_TEMP) | - BMP180_MEAS_SCO); + ret = bmp180_wait_for_eoc(data, + FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_TEMP) | + BMP180_MEAS_SCO); if (ret) return ret; @@ -1920,10 +1920,10 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) u8 oss = data->oversampling_press; int ret; - ret = bmp180_measure(data, - FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_PRESS) | - FIELD_PREP(BMP180_OSRS_PRESS_MASK, oss) | - BMP180_MEAS_SCO); + ret = bmp180_wait_for_eoc(data, + FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_PRESS) | + FIELD_PREP(BMP180_OSRS_PRESS_MASK, oss) | + BMP180_MEAS_SCO); if (ret) return ret; From 4391affa107d68b6c3e5222264e91bbc21793cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 8 May 2024 09:29:27 +0200 Subject: [PATCH 014/330] iio: Drop explicit initialization of struct i2c_device_id::driver_data to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These drivers don't use the driver_data member of struct i2c_device_id, so don't explicitly initialize this member. This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own. While add it, also remove commas after the sentinel entries. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240508072928.2135858-2-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl367_i2c.c | 4 ++-- drivers/iio/accel/adxl372_i2c.c | 2 +- drivers/iio/accel/bma400_i2c.c | 2 +- drivers/iio/accel/da311.c | 2 +- drivers/iio/accel/dmard06.c | 6 +++--- drivers/iio/accel/dmard09.c | 4 ++-- drivers/iio/accel/dmard10.c | 2 +- drivers/iio/accel/kxsd9-i2c.c | 4 ++-- drivers/iio/accel/mc3230.c | 2 +- drivers/iio/accel/mma7455_i2c.c | 4 ++-- drivers/iio/accel/mma7660.c | 2 +- drivers/iio/accel/mma9551.c | 2 +- drivers/iio/accel/mma9553.c | 4 ++-- drivers/iio/accel/mxc4005.c | 6 +++--- drivers/iio/accel/mxc6255.c | 4 ++-- drivers/iio/accel/stk8312.c | 4 ++-- drivers/iio/accel/stk8ba50.c | 2 +- drivers/iio/adc/ad7291.c | 2 +- drivers/iio/adc/ltc2485.c | 2 +- drivers/iio/adc/nau7802.c | 2 +- drivers/iio/adc/ti-ads7924.c | 2 +- drivers/iio/chemical/ams-iaq-core.c | 2 +- drivers/iio/chemical/bme680_i2c.c | 4 ++-- drivers/iio/chemical/ccs811.c | 2 +- drivers/iio/dac/mcp4728.c | 2 +- drivers/iio/gyro/bmg160_i2c.c | 6 +++--- drivers/iio/gyro/fxas21002c_i2c.c | 2 +- drivers/iio/gyro/itg3200_core.c | 2 +- drivers/iio/health/afe4404.c | 2 +- drivers/iio/health/max30100.c | 2 +- drivers/iio/humidity/am2315.c | 2 +- drivers/iio/humidity/hdc100x.c | 12 ++++++------ drivers/iio/humidity/si7005.c | 4 ++-- drivers/iio/humidity/si7020.c | 4 ++-- drivers/iio/imu/bmi160/bmi160_i2c.c | 4 ++-- drivers/iio/imu/bno055/bno055_i2c.c | 2 +- drivers/iio/imu/fxos8700_i2c.c | 2 +- drivers/iio/imu/kmx61.c | 2 +- drivers/iio/light/adjd_s311.c | 2 +- drivers/iio/light/adux1020.c | 2 +- drivers/iio/light/al3320a.c | 2 +- drivers/iio/light/apds9300.c | 2 +- drivers/iio/light/apds9960.c | 2 +- drivers/iio/light/bh1780.c | 4 ++-- drivers/iio/light/cm3232.c | 2 +- drivers/iio/light/cm3323.c | 2 +- drivers/iio/light/cm36651.c | 2 +- drivers/iio/light/gp2ap002.c | 4 ++-- drivers/iio/light/gp2ap020a00f.c | 2 +- drivers/iio/light/isl29028.c | 4 ++-- drivers/iio/light/isl29125.c | 2 +- drivers/iio/light/jsa1212.c | 2 +- drivers/iio/light/lv0104cs.c | 2 +- drivers/iio/light/max44000.c | 2 +- drivers/iio/light/max44009.c | 2 +- drivers/iio/light/noa1305.c | 2 +- drivers/iio/light/opt3001.c | 2 +- drivers/iio/light/pa12203001.c | 2 +- drivers/iio/light/rpr0521.c | 2 +- drivers/iio/light/si1133.c | 2 +- drivers/iio/light/stk3310.c | 6 +++--- drivers/iio/light/tcs3414.c | 2 +- drivers/iio/light/tcs3472.c | 2 +- drivers/iio/light/tsl4531.c | 2 +- drivers/iio/light/us5182d.c | 2 +- drivers/iio/light/vcnl4035.c | 2 +- drivers/iio/light/veml6030.c | 2 +- drivers/iio/light/veml6070.c | 2 +- drivers/iio/light/vl6180.c | 2 +- drivers/iio/light/zopt2201.c | 2 +- drivers/iio/magnetometer/af8133j.c | 2 +- drivers/iio/magnetometer/ak8974.c | 8 ++++---- drivers/iio/magnetometer/bmc150_magn_i2c.c | 6 +++--- drivers/iio/magnetometer/mag3110.c | 2 +- drivers/iio/magnetometer/mmc35240.c | 2 +- drivers/iio/potentiostat/lmp91000.c | 4 ++-- drivers/iio/pressure/dps310.c | 2 +- drivers/iio/pressure/hp03.c | 4 ++-- drivers/iio/pressure/icp10100.c | 2 +- drivers/iio/pressure/mpl115_i2c.c | 2 +- drivers/iio/pressure/mpl3115.c | 2 +- drivers/iio/pressure/t5403.c | 2 +- drivers/iio/pressure/zpa2326_i2c.c | 4 ++-- drivers/iio/proximity/isl29501.c | 2 +- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 6 +++--- drivers/iio/proximity/rfd77402.c | 2 +- drivers/iio/proximity/sx9500.c | 4 ++-- drivers/iio/proximity/vl53l0x-i2c.c | 2 +- drivers/iio/temperature/mlx90632.c | 2 +- drivers/iio/temperature/tmp006.c | 2 +- drivers/iio/temperature/tmp007.c | 2 +- drivers/iio/temperature/tsys01.c | 2 +- drivers/iio/temperature/tsys02d.c | 2 +- 93 files changed, 131 insertions(+), 131 deletions(-) diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index 62c74bdc0d77..deb82a43ec36 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -61,8 +61,8 @@ static int adxl367_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl367_i2c_id[] = { - { "adxl367", 0 }, - { }, + { "adxl367" }, + { } }; MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id); diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index d0690417fd36..3571cfde1c0e 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -42,7 +42,7 @@ static int adxl372_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl372_i2c_id[] = { - { "adxl372", 0 }, + { "adxl372" }, {} }; MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id); diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index adf4e3fd2e1d..c1c72f577295 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -28,7 +28,7 @@ static int bma400_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bma400_i2c_ids[] = { - { "bma400", 0 }, + { "bma400" }, { } }; MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids); diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index 8f919920ced5..94f827acdd1c 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -268,7 +268,7 @@ static int da311_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); static const struct i2c_device_id da311_i2c_id[] = { - {"da311", 0}, + { "da311" }, {} }; MODULE_DEVICE_TABLE(i2c, da311_i2c_id); diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index 2e719d60fff8..fb14894c66f9 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -201,9 +201,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume); static const struct i2c_device_id dmard06_id[] = { - { "dmard05", 0 }, - { "dmard06", 0 }, - { "dmard07", 0 }, + { "dmard05" }, + { "dmard06" }, + { "dmard07" }, { } }; MODULE_DEVICE_TABLE(i2c, dmard06_id); diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index fa98623de579..6644c1fec3e6 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -125,8 +125,8 @@ static int dmard09_probe(struct i2c_client *client) } static const struct i2c_device_id dmard09_id[] = { - { "dmard09", 0 }, - { }, + { "dmard09" }, + { } }; MODULE_DEVICE_TABLE(i2c, dmard09_id); diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 7745b6ffd1ad..35c0eefb741e 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -231,7 +231,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume); static const struct i2c_device_id dmard10_i2c_id[] = { - {"dmard10", 0}, + { "dmard10" }, {} }; MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 3bc9ee1f9db3..c4c7e2d4e98a 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -43,8 +43,8 @@ static const struct of_device_id kxsd9_of_match[] = { MODULE_DEVICE_TABLE(of, kxsd9_of_match); static const struct i2c_device_id kxsd9_i2c_id[] = { - {"kxsd9", 0}, - { }, + { "kxsd9" }, + { } }; MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id); diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index 6b87c2c9945c..caa40a14a631 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -180,7 +180,7 @@ static int mc3230_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume); static const struct i2c_device_id mc3230_i2c_id[] = { - {"mc3230", 0}, + { "mc3230" }, {} }; MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id); diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index 14f7850a22f0..36a357c8e9ed 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -32,8 +32,8 @@ static void mma7455_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id mma7455_i2c_ids[] = { - { "mma7455", 0 }, - { "mma7456", 0 }, + { "mma7455" }, + { "mma7456" }, { } }; MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids); diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index 260cbceaa151..d3febc760c4c 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -241,7 +241,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume); static const struct i2c_device_id mma7660_i2c_id[] = { - {"mma7660", 0}, + { "mma7660" }, {} }; MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 083c08f65baf..fa1799b0b0df 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -595,7 +595,7 @@ static const struct acpi_device_id mma9551_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match); static const struct i2c_device_id mma9551_id[] = { - {"mma9551", 0}, + { "mma9551" }, {} }; diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 3cbd0fd4e624..86543f34ef17 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1234,8 +1234,8 @@ static const struct acpi_device_id mma9553_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match); static const struct i2c_device_id mma9553_id[] = { - {"mma9553", 0}, - {}, + { "mma9553" }, + {} }; MODULE_DEVICE_TABLE(i2c, mma9553_id); diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index e56407b6f204..fc54a2a4693c 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -584,9 +584,9 @@ static const struct of_device_id mxc4005_of_match[] = { MODULE_DEVICE_TABLE(of, mxc4005_of_match); static const struct i2c_device_id mxc4005_id[] = { - {"mxc4005", 0}, - {"mxc6655", 0}, - { }, + { "mxc4005" }, + { "mxc6655" }, + { } }; MODULE_DEVICE_TABLE(i2c, mxc4005_id); diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index ac228128c4f9..a8abda7b2a63 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -172,8 +172,8 @@ static const struct acpi_device_id mxc6255_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match); static const struct i2c_device_id mxc6255_id[] = { - {"mxc6225", 0}, - {"mxc6255", 0}, + { "mxc6225" }, + { "mxc6255" }, { } }; MODULE_DEVICE_TABLE(i2c, mxc6255_id); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index ef0ae7672253..b3534d5751b9 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -633,8 +633,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, static const struct i2c_device_id stk8312_i2c_id[] = { /* Deprecated in favour of lowercase form */ - { "STK8312", 0 }, - { "stk8312", 0 }, + { "STK8312" }, + { "stk8312" }, {} }; MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 668edc88c89d..6d3c7f444d21 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -525,7 +525,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume); static const struct i2c_device_id stk8ba50_i2c_id[] = { - {"stk8ba50", 0}, + { "stk8ba50" }, {} }; MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index 14d02b085d3b..b59b2a51623c 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -536,7 +536,7 @@ static int ad7291_probe(struct i2c_client *client) } static const struct i2c_device_id ad7291_id[] = { - { "ad7291", 0 }, + { "ad7291" }, {} }; diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c index 859e4314cfa2..060651dd4130 100644 --- a/drivers/iio/adc/ltc2485.c +++ b/drivers/iio/adc/ltc2485.c @@ -124,7 +124,7 @@ static int ltc2485_probe(struct i2c_client *client) } static const struct i2c_device_id ltc2485_id[] = { - { "ltc2485", 0 }, + { "ltc2485" }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2485_id); diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index d9e1696df7ae..600151a62f1f 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -532,7 +532,7 @@ static int nau7802_probe(struct i2c_client *client) } static const struct i2c_device_id nau7802_i2c_id[] = { - { "nau7802", 0 }, + { "nau7802" }, { } }; MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id); diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c index afdbd04778a8..4da78302359b 100644 --- a/drivers/iio/adc/ti-ads7924.c +++ b/drivers/iio/adc/ti-ads7924.c @@ -447,7 +447,7 @@ static int ads7924_probe(struct i2c_client *client) } static const struct i2c_device_id ads7924_id[] = { - { "ads7924", 0 }, + { "ads7924" }, {} }; MODULE_DEVICE_TABLE(i2c, ads7924_id); diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c index 164facac5db6..4d605c2b9750 100644 --- a/drivers/iio/chemical/ams-iaq-core.c +++ b/drivers/iio/chemical/ams-iaq-core.c @@ -163,7 +163,7 @@ static int ams_iaqcore_probe(struct i2c_client *client) } static const struct i2c_device_id ams_iaqcore_id[] = { - { "ams-iaq-core", 0 }, + { "ams-iaq-core" }, { } }; MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id); diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index 1c7076cf91ca..7c4224d75955 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -36,8 +36,8 @@ static int bme680_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bme680_i2c_id[] = { - {"bme680", 0}, - {}, + { "bme680" }, + {} }; MODULE_DEVICE_TABLE(i2c, bme680_i2c_id); diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 87741f155c32..17d1bc518bf2 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -551,7 +551,7 @@ static void ccs811_remove(struct i2c_client *client) } static const struct i2c_device_id ccs811_id[] = { - {"ccs811", 0}, + { "ccs811" }, { } }; MODULE_DEVICE_TABLE(i2c, ccs811_id); diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c index 5113f67ddc31..c449ca949465 100644 --- a/drivers/iio/dac/mcp4728.c +++ b/drivers/iio/dac/mcp4728.c @@ -591,7 +591,7 @@ static int mcp4728_probe(struct i2c_client *client) } static const struct i2c_device_id mcp4728_id[] = { - { "mcp4728", 0 }, + { "mcp4728" }, {} }; MODULE_DEVICE_TABLE(i2c, mcp4728_id); diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 9c8e20c25e96..672d0b720f61 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -47,9 +47,9 @@ static const struct acpi_device_id bmg160_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); static const struct i2c_device_id bmg160_i2c_id[] = { - {"bmg160", 0}, - {"bmi055_gyro", 0}, - {"bmi088_gyro", 0}, + { "bmg160" }, + { "bmi055_gyro" }, + { "bmi088_gyro" }, {} }; diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c index ee7f21b718e2..b1318a1ea41b 100644 --- a/drivers/iio/gyro/fxas21002c_i2c.c +++ b/drivers/iio/gyro/fxas21002c_i2c.c @@ -39,7 +39,7 @@ static void fxas21002c_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id fxas21002c_i2c_id[] = { - { "fxas21002c", 0 }, + { "fxas21002c" }, { } }; MODULE_DEVICE_TABLE(i2c, fxas21002c_i2c_id); diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 53fb92f0ac7e..cd8a2dae56cd 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -387,7 +387,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend, itg3200_resume); static const struct i2c_device_id itg3200_id[] = { - { "itg3200", 0 }, + { "itg3200" }, { } }; MODULE_DEVICE_TABLE(i2c, itg3200_id); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 7768b07ef7a6..390fbb6effaf 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -582,7 +582,7 @@ static int afe4404_probe(struct i2c_client *client) } static const struct i2c_device_id afe4404_ids[] = { - { "afe4404", 0 }, + { "afe4404" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, afe4404_ids); diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 6236b4d96137..1dc0df21450d 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -483,7 +483,7 @@ static void max30100_remove(struct i2c_client *client) } static const struct i2c_device_id max30100_id[] = { - { "max30100", 0 }, + { "max30100" }, {} }; MODULE_DEVICE_TABLE(i2c, max30100_id); diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 37a35d1153d5..a56474be5dd2 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -253,7 +253,7 @@ static int am2315_probe(struct i2c_client *client) } static const struct i2c_device_id am2315_i2c_id[] = { - {"am2315", 0}, + { "am2315" }, {} }; MODULE_DEVICE_TABLE(i2c, am2315_i2c_id); diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 202014da2785..9b355380c9bf 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -396,12 +396,12 @@ static int hdc100x_probe(struct i2c_client *client) } static const struct i2c_device_id hdc100x_id[] = { - { "hdc100x", 0 }, - { "hdc1000", 0 }, - { "hdc1008", 0 }, - { "hdc1010", 0 }, - { "hdc1050", 0 }, - { "hdc1080", 0 }, + { "hdc100x" }, + { "hdc1000" }, + { "hdc1008" }, + { "hdc1010" }, + { "hdc1050" }, + { "hdc1080" }, { } }; MODULE_DEVICE_TABLE(i2c, hdc100x_id); diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c index 9465908cc65e..0797ece1fcba 100644 --- a/drivers/iio/humidity/si7005.c +++ b/drivers/iio/humidity/si7005.c @@ -163,8 +163,8 @@ static int si7005_probe(struct i2c_client *client) } static const struct i2c_device_id si7005_id[] = { - { "si7005", 0 }, - { "th02", 0 }, + { "si7005" }, + { "th02" }, { } }; MODULE_DEVICE_TABLE(i2c, si7005_id); diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index fb1006649328..d34a915e3d4a 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -138,8 +138,8 @@ static int si7020_probe(struct i2c_client *client) } static const struct i2c_device_id si7020_id[] = { - { "si7020", 0 }, - { "th06", 0 }, + { "si7020" }, + { "th06" }, { } }; MODULE_DEVICE_TABLE(i2c, si7020_id); diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index d0ec5301ad9a..3aa5d748f9b6 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -37,8 +37,8 @@ static int bmi160_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bmi160_i2c_id[] = { - {"bmi120", 0}, - {"bmi160", 0}, + { "bmi120" }, + { "bmi160" }, {} }; MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id); diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c index 6ecd750c6b76..cf3dd62a83ba 100644 --- a/drivers/iio/imu/bno055/bno055_i2c.c +++ b/drivers/iio/imu/bno055/bno055_i2c.c @@ -30,7 +30,7 @@ static int bno055_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bno055_i2c_id[] = { - {"bno055", 0}, + { "bno055" }, { } }; MODULE_DEVICE_TABLE(i2c, bno055_i2c_id); diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c index e99677ad96a2..2cc4a27a4527 100644 --- a/drivers/iio/imu/fxos8700_i2c.c +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -36,7 +36,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id fxos8700_i2c_id[] = { - {"fxos8700", 0}, + { "fxos8700" }, { } }; MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id); diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 7d3e061f3046..d37eca5ef761 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1505,7 +1505,7 @@ static const struct acpi_device_id kmx61_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, kmx61_acpi_match); static const struct i2c_device_id kmx61_id[] = { - {"kmx611021", 0}, + { "kmx611021" }, {} }; diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 5fd775a20176..5169f12c3eba 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -261,7 +261,7 @@ static int adjd_s311_probe(struct i2c_client *client) } static const struct i2c_device_id adjd_s311_id[] = { - { "adjd_s311", 0 }, + { "adjd_s311" }, { } }; MODULE_DEVICE_TABLE(i2c, adjd_s311_id); diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index aa4a6c78f0aa..d4eb938c3bf5 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -821,7 +821,7 @@ static int adux1020_probe(struct i2c_client *client) } static const struct i2c_device_id adux1020_id[] = { - { "adux1020", 0 }, + { "adux1020" }, {} }; MODULE_DEVICE_TABLE(i2c, adux1020_id); diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c index 105f379b9b41..497ea3fe3377 100644 --- a/drivers/iio/light/al3320a.c +++ b/drivers/iio/light/al3320a.c @@ -236,7 +236,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend, al3320a_resume); static const struct i2c_device_id al3320a_id[] = { - {"al3320a", 0}, + { "al3320a" }, {} }; MODULE_DEVICE_TABLE(i2c, al3320a_id); diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 0f978b30a232..11f2ab4ca261 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -493,7 +493,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume); static const struct i2c_device_id apds9300_id[] = { - { APDS9300_DRV_NAME, 0 }, + { APDS9300_DRV_NAME }, { } }; diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 1065a340b12b..e9e65130b6f9 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1107,7 +1107,7 @@ static const struct dev_pm_ops apds9960_pm_ops = { }; static const struct i2c_device_id apds9960_id[] = { - { "apds9960", 0 }, + { "apds9960" }, {} }; MODULE_DEVICE_TABLE(i2c, apds9960_id); diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index b84166c5fa06..475f44954f61 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -256,8 +256,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend, bh1780_runtime_resume, NULL); static const struct i2c_device_id bh1780_id[] = { - { "bh1780", 0 }, - { }, + { "bh1780" }, + { } }; MODULE_DEVICE_TABLE(i2c, bh1780_id); diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index d48a70efca69..b6288dd25bbf 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -368,7 +368,7 @@ static void cm3232_remove(struct i2c_client *client) } static const struct i2c_device_id cm3232_id[] = { - {"cm3232", 0}, + { "cm3232" }, {} }; diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 35d20207a648..79a64e2ff812 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -250,7 +250,7 @@ static int cm3323_probe(struct i2c_client *client) } static const struct i2c_device_id cm3323_id[] = { - {"cm3323", 0}, + { "cm3323" }, {} }; MODULE_DEVICE_TABLE(i2c, cm3323_id); diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 97e559acba2b..a4a1505534c0 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -713,7 +713,7 @@ static void cm36651_remove(struct i2c_client *client) } static const struct i2c_device_id cm36651_id[] = { - { "cm36651", 0 }, + { "cm36651" }, { } }; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index fec10d5e037e..7125e011a38a 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -692,8 +692,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend, gp2ap002_runtime_resume, NULL); static const struct i2c_device_id gp2ap002_id_table[] = { - { "gp2ap002", 0 }, - { }, + { "gp2ap002" }, + { } }; MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 9a476697aa1f..757383456da6 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1591,7 +1591,7 @@ static void gp2ap020a00f_remove(struct i2c_client *client) } static const struct i2c_device_id gp2ap020a00f_id[] = { - { GP2A_I2C_NAME, 0 }, + { GP2A_I2C_NAME }, { } }; diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index 5694683389be..95bfb3ffa519 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -678,8 +678,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend, isl29028_resume, NULL); static const struct i2c_device_id isl29028_id[] = { - {"isl29028", 0}, - {"isl29030", 0}, + { "isl29028" }, + { "isl29030" }, {} }; MODULE_DEVICE_TABLE(i2c, isl29028_id); diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index f1d3356d3369..59329546df58 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -327,7 +327,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume); static const struct i2c_device_id isl29125_id[] = { - { "isl29125", 0 }, + { "isl29125" }, { } }; MODULE_DEVICE_TABLE(i2c, isl29125_id); diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 869196746045..e7ba934c8e69 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -429,7 +429,7 @@ static const struct acpi_device_id jsa1212_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match); static const struct i2c_device_id jsa1212_id[] = { - { JSA1212_DRIVER_NAME, 0 }, + { JSA1212_DRIVER_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, jsa1212_id); diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c index a5445d58fddf..916109ec3217 100644 --- a/drivers/iio/light/lv0104cs.c +++ b/drivers/iio/light/lv0104cs.c @@ -510,7 +510,7 @@ static int lv0104cs_probe(struct i2c_client *client) } static const struct i2c_device_id lv0104cs_id[] = { - { "lv0104cs", 0 }, + { "lv0104cs" }, { } }; MODULE_DEVICE_TABLE(i2c, lv0104cs_id); diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index 26b464b1b650..b935976871a6 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -598,7 +598,7 @@ static int max44000_probe(struct i2c_client *client) } static const struct i2c_device_id max44000_id[] = { - {"max44000", 0}, + { "max44000" }, { } }; MODULE_DEVICE_TABLE(i2c, max44000_id); diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 61ce276e86f7..3b92362675dc 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -534,7 +534,7 @@ static const struct of_device_id max44009_of_match[] = { MODULE_DEVICE_TABLE(of, max44009_of_match); static const struct i2c_device_id max44009_id[] = { - { "max44009", 0 }, + { "max44009" }, { } }; MODULE_DEVICE_TABLE(i2c, max44009_id); diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c index 1574310020e3..596cc48c4c34 100644 --- a/drivers/iio/light/noa1305.c +++ b/drivers/iio/light/noa1305.c @@ -268,7 +268,7 @@ static const struct of_device_id noa1305_of_match[] = { MODULE_DEVICE_TABLE(of, noa1305_of_match); static const struct i2c_device_id noa1305_ids[] = { - { "noa1305", 0 }, + { "noa1305" }, { } }; MODULE_DEVICE_TABLE(i2c, noa1305_ids); diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index cb41e5ee8ec1..887c4b776a86 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -822,7 +822,7 @@ static void opt3001_remove(struct i2c_client *client) } static const struct i2c_device_id opt3001_id[] = { - { "opt3001", 0 }, + { "opt3001" }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(i2c, opt3001_id); diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index 636432c45651..b920bf82c102 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -462,7 +462,7 @@ static const struct acpi_device_id pa12203001_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); static const struct i2c_device_id pa12203001_id[] = { - { "txcpa122", 0 }, + { "txcpa122" }, {} }; diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 40d5732b5e32..78c08e0bd077 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -1109,7 +1109,7 @@ static const struct acpi_device_id rpr0521_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match); static const struct i2c_device_id rpr0521_id[] = { - {"rpr0521", 0}, + { "rpr0521" }, { } }; diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index ea2c437199c0..eeff6cc792f2 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -1055,7 +1055,7 @@ static int si1133_probe(struct i2c_client *client) } static const struct i2c_device_id si1133_ids[] = { - { "si1133", 0 }, + { "si1133" }, { } }; MODULE_DEVICE_TABLE(i2c, si1133_ids); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 08d471438175..3a03823e488a 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -683,9 +683,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume); static const struct i2c_device_id stk3310_i2c_id[] = { - {"STK3310", 0}, - {"STK3311", 0}, - {"STK3335", 0}, + { "STK3310" }, + { "STK3311" }, + { "STK3335" }, {} }; MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index dcdd85b006be..c9566615b964 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -363,7 +363,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume); static const struct i2c_device_id tcs3414_id[] = { - { "tcs3414", 0 }, + { "tcs3414" }, { } }; MODULE_DEVICE_TABLE(i2c, tcs3414_id); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 75fcf2c93717..89384dba83dd 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -599,7 +599,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, tcs3472_resume); static const struct i2c_device_id tcs3472_id[] = { - { "tcs3472", 0 }, + { "tcs3472" }, { } }; MODULE_DEVICE_TABLE(i2c, tcs3472_id); diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c index 4da7d78906d4..a5788c09ad02 100644 --- a/drivers/iio/light/tsl4531.c +++ b/drivers/iio/light/tsl4531.c @@ -227,7 +227,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume); static const struct i2c_device_id tsl4531_id[] = { - { "tsl4531", 0 }, + { "tsl4531" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl4531_id); diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 9189a1d4d7e1..de6967ac3b0b 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -955,7 +955,7 @@ static const struct acpi_device_id us5182d_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match); static const struct i2c_device_id us5182d_id[] = { - { "usd5182", 0 }, + { "usd5182" }, {} }; diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 56bbefbc0ae6..337a1332c2c6 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -653,7 +653,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4035_pm_ops, vcnl4035_runtime_suspend, vcnl4035_runtime_resume, NULL); static const struct i2c_device_id vcnl4035_id[] = { - { "vcnl4035", 0 }, + { "vcnl4035" }, { } }; MODULE_DEVICE_TABLE(i2c, vcnl4035_id); diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 043f233d9bdb..4be151308574 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -881,7 +881,7 @@ static const struct of_device_id veml6030_of_match[] = { MODULE_DEVICE_TABLE(of, veml6030_of_match); static const struct i2c_device_id veml6030_id[] = { - { "veml6030", 0 }, + { "veml6030" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6030_id); diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index d99bf3ae0fe8..f8321d346d77 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -189,7 +189,7 @@ static void veml6070_remove(struct i2c_client *client) } static const struct i2c_device_id veml6070_id[] = { - { "veml6070", 0 }, + { "veml6070" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6070_id); diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index dcadf6428a87..a1b2b3c0b4c8 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -527,7 +527,7 @@ static const struct of_device_id vl6180_of_match[] = { MODULE_DEVICE_TABLE(of, vl6180_of_match); static const struct i2c_device_id vl6180_id[] = { - { "vl6180", 0 }, + { "vl6180" }, { } }; MODULE_DEVICE_TABLE(i2c, vl6180_id); diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c index d370193a4742..327f94e447af 100644 --- a/drivers/iio/light/zopt2201.c +++ b/drivers/iio/light/zopt2201.c @@ -545,7 +545,7 @@ static int zopt2201_probe(struct i2c_client *client) } static const struct i2c_device_id zopt2201_id[] = { - { "zopt2201", 0 }, + { "zopt2201" }, { } }; MODULE_DEVICE_TABLE(i2c, zopt2201_id); diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c index 742bbdf25f08..d81d89af6283 100644 --- a/drivers/iio/magnetometer/af8133j.c +++ b/drivers/iio/magnetometer/af8133j.c @@ -505,7 +505,7 @@ static const struct of_device_id af8133j_of_match[] = { MODULE_DEVICE_TABLE(of, af8133j_of_match); static const struct i2c_device_id af8133j_id[] = { - { "af8133j", 0 }, + { "af8133j" }, { } }; MODULE_DEVICE_TABLE(i2c, af8133j_id); diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index c74d11943ec7..d802034c5402 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -1025,10 +1025,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ak8974_dev_pm_ops, ak8974_runtime_suspend, ak8974_runtime_resume, NULL); static const struct i2c_device_id ak8974_id[] = { - {"ami305", 0 }, - {"ami306", 0 }, - {"ak8974", 0 }, - {"hscdtd008a", 0 }, + { "ami305" }, + { "ami306" }, + { "ak8974" }, + { "hscdtd008a" }, {} }; MODULE_DEVICE_TABLE(i2c, ak8974_id); diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index 48d9c698f520..a28d46d59875 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -47,9 +47,9 @@ static const struct acpi_device_id bmc150_magn_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); static const struct i2c_device_id bmc150_magn_i2c_id[] = { - {"bmc150_magn", 0}, - {"bmc156_magn", 0}, - {"bmm150_magn", 0}, + { "bmc150_magn" }, + { "bmc156_magn" }, + { "bmm150_magn" }, {} }; MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index deffe3ca9004..5295dc0100e4 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -624,7 +624,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend, mag3110_resume); static const struct i2c_device_id mag3110_id[] = { - { "mag3110", 0 }, + { "mag3110" }, { } }; MODULE_DEVICE_TABLE(i2c, mag3110_id); diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 6b9f4b056191..c57932db455f 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -563,7 +563,7 @@ static const struct acpi_device_id mmc35240_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match); static const struct i2c_device_id mmc35240_id[] = { - {"mmc35240", 0}, + { "mmc35240" }, {} }; MODULE_DEVICE_TABLE(i2c, mmc35240_id); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index bd0f2c3bf2f2..c2c6b2b29867 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -405,8 +405,8 @@ static const struct of_device_id lmp91000_of_match[] = { MODULE_DEVICE_TABLE(of, lmp91000_of_match); static const struct i2c_device_id lmp91000_id[] = { - { "lmp91000", 0 }, - { "lmp91002", 0 }, + { "lmp91000" }, + { "lmp91002" }, {} }; MODULE_DEVICE_TABLE(i2c, lmp91000_id); diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 7d882e15e556..c6f44f0f4d2e 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -887,7 +887,7 @@ static int dps310_probe(struct i2c_client *client) } static const struct i2c_device_id dps310_id[] = { - { DPS310_DEV_NAME, 0 }, + { DPS310_DEV_NAME }, {} }; MODULE_DEVICE_TABLE(i2c, dps310_id); diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index 8bdb279129fa..6f7a16787143 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -266,8 +266,8 @@ static int hp03_probe(struct i2c_client *client) } static const struct i2c_device_id hp03_id[] = { - { "hp03", 0 }, - { }, + { "hp03" }, + { } }; MODULE_DEVICE_TABLE(i2c, hp03_id); diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index 2086f3ef338f..3e0bf5d31ad7 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -637,7 +637,7 @@ static const struct of_device_id icp10100_of_match[] = { MODULE_DEVICE_TABLE(of, icp10100_of_match); static const struct i2c_device_id icp10100_id[] = { - { "icp10100", 0 }, + { "icp10100" }, { } }; MODULE_DEVICE_TABLE(i2c, icp10100_id); diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c index fcbdadf4a511..0c51dc02478e 100644 --- a/drivers/iio/pressure/mpl115_i2c.c +++ b/drivers/iio/pressure/mpl115_i2c.c @@ -45,7 +45,7 @@ static int mpl115_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id mpl115_i2c_id[] = { - { "mpl115", 0 }, + { "mpl115" }, { } }; MODULE_DEVICE_TABLE(i2c, mpl115_i2c_id); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 7aa19584c340..71ded2eee060 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -318,7 +318,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume); static const struct i2c_device_id mpl3115_id[] = { - { "mpl3115", 0 }, + { "mpl3115" }, { } }; MODULE_DEVICE_TABLE(i2c, mpl3115_id); diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c index a6463c06975e..c7cb0fd816d3 100644 --- a/drivers/iio/pressure/t5403.c +++ b/drivers/iio/pressure/t5403.c @@ -251,7 +251,7 @@ static int t5403_probe(struct i2c_client *client) } static const struct i2c_device_id t5403_id[] = { - { "t5403", 0 }, + { "t5403" }, { } }; MODULE_DEVICE_TABLE(i2c, t5403_id); diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index c7fffbe7c788..4833e525c393 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -59,8 +59,8 @@ static void zpa2326_remove_i2c(struct i2c_client *client) } static const struct i2c_device_id zpa2326_i2c_ids[] = { - { "zpa2326", 0 }, - { }, + { "zpa2326" }, + { } }; MODULE_DEVICE_TABLE(i2c, zpa2326_i2c_ids); diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index 4982686fb4c3..dc66ca9bba6b 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -989,7 +989,7 @@ static int isl29501_probe(struct i2c_client *client) } static const struct i2c_device_id isl29501_id[] = { - {"isl29501", 0}, + { "isl29501" }, {} }; diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 2913d5e0fe4f..5c959730aecd 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -322,9 +322,9 @@ static void lidar_remove(struct i2c_client *client) } static const struct i2c_device_id lidar_id[] = { - {"lidar-lite-v2", 0}, - {"lidar-lite-v3", 0}, - { }, + { "lidar-lite-v2" }, + { "lidar-lite-v3" }, + { } }; MODULE_DEVICE_TABLE(i2c, lidar_id); diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index f02e83e3f15f..aff60a3c1a6f 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -308,7 +308,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume); static const struct i2c_device_id rfd77402_id[] = { - { "rfd77402", 0 }, + { "rfd77402" }, { } }; MODULE_DEVICE_TABLE(i2c, rfd77402_id); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 550e7d3cd5ee..b89d49defd7a 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -1043,8 +1043,8 @@ static const struct of_device_id sx9500_of_match[] = { MODULE_DEVICE_TABLE(of, sx9500_of_match); static const struct i2c_device_id sx9500_id[] = { - {"sx9500", 0}, - { }, + { "sx9500" }, + { } }; MODULE_DEVICE_TABLE(i2c, sx9500_id); diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index 2cea64bea909..8d4f3f849fe2 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -278,7 +278,7 @@ static int vl53l0x_probe(struct i2c_client *client) } static const struct i2c_device_id vl53l0x_id[] = { - { "vl53l0x", 0 }, + { "vl53l0x" }, { } }; MODULE_DEVICE_TABLE(i2c, vl53l0x_id); diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 8a57be108620..4676e0edde4a 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -1279,7 +1279,7 @@ static int mlx90632_probe(struct i2c_client *client) } static const struct i2c_device_id mlx90632_id[] = { - { "mlx90632", 0 }, + { "mlx90632" }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90632_id); diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index 3a3904fe138c..6d8d661f0c82 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -280,7 +280,7 @@ static const struct of_device_id tmp006_of_match[] = { MODULE_DEVICE_TABLE(of, tmp006_of_match); static const struct i2c_device_id tmp006_id[] = { - { "tmp006", 0 }, + { "tmp006" }, { } }; MODULE_DEVICE_TABLE(i2c, tmp006_id); diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index decef6896362..9bdfa9423492 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -563,7 +563,7 @@ static const struct of_device_id tmp007_of_match[] = { MODULE_DEVICE_TABLE(of, tmp007_of_match); static const struct i2c_device_id tmp007_id[] = { - { "tmp007", 0 }, + { "tmp007" }, { } }; MODULE_DEVICE_TABLE(i2c, tmp007_id); diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index 53ef56fbfe1d..9213761c5d18 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -206,7 +206,7 @@ static int tsys01_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id tsys01_id[] = { - {"tsys01", 0}, + { "tsys01" }, {} }; MODULE_DEVICE_TABLE(i2c, tsys01_id); diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index 6191db92ef9a..2b4959d6e467 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -168,7 +168,7 @@ static int tsys02d_probe(struct i2c_client *client) } static const struct i2c_device_id tsys02d_id[] = { - {"tsys02d", 0}, + { "tsys02d" }, {} }; MODULE_DEVICE_TABLE(i2c, tsys02d_id); From 081cea88a61a33c17d86270390a88b2e71c25475 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Wed, 8 May 2024 18:51:59 +0200 Subject: [PATCH 015/330] iio: pressure: bmp280: Remove dead error checks The ret value is being checked already in all the previous paths which exit in case of error, so this path can never become true. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240508165207.145554-2-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index ed49e0779d41..311a011604da 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -1350,10 +1350,6 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write) poll = 50; timeout = 400; } - if (ret) { - dev_err(data->dev, "failed to write command sequence\n"); - return -EIO; - } /* Wait until NVM is ready again */ ret = regmap_read_poll_timeout(data->regmap, BMP580_REG_STATUS, reg, From 6047c11e4ae260f3cb5c6d5be0d8c30a467be081 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Wed, 8 May 2024 18:52:00 +0200 Subject: [PATCH 016/330] iio: pressure: bmp280: Remove, add and update error messages Remove duplicate error messages, add missing error messages and update redundant ones. Add one missing error check. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240508165207.145554-3-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 55 +++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 311a011604da..0aa16fb135c1 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -222,10 +222,8 @@ static int bme280_read_calib(struct bmp280_data *data) /* Load shared calibration params with bmp280 first */ ret = bmp280_read_calib(data); - if (ret < 0) { - dev_err(dev, "failed to read calibration parameters\n"); + if (ret < 0) return ret; - } /* * Read humidity calibration values. @@ -841,8 +839,10 @@ static int bme280_chip_config(struct bmp280_data *data) */ ret = regmap_update_bits(data->regmap, BME280_REG_CTRL_HUMIDITY, BME280_OSRS_HUMIDITY_MASK, osrs); - if (ret < 0) + if (ret < 0) { + dev_err(data->dev, "failed to set humidity oversampling"); return ret; + } return bmp280_chip_config(data); } @@ -1071,7 +1071,7 @@ static int bmp380_read_calib(struct bmp280_data *data) sizeof(data->bmp380_cal_buf)); if (ret) { dev_err(data->dev, - "failed to read temperature calibration parameters\n"); + "failed to read calibration parameters\n"); return ret; } @@ -1609,20 +1609,24 @@ static int bmp580_preinit(struct bmp280_data *data) /* Post powerup sequence */ ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®); - if (ret) + if (ret) { + dev_err(data->dev, "failed to establish comms with the chip\n"); return ret; + } /* Print warn message if we don't know the chip id */ if (reg != BMP580_CHIP_ID && reg != BMP580_CHIP_ID_ALT) - dev_warn(data->dev, "preinit: unexpected chip_id\n"); + dev_warn(data->dev, "unexpected chip_id\n"); ret = regmap_read(data->regmap, BMP580_REG_STATUS, ®); - if (ret) + if (ret) { + dev_err(data->dev, "failed to read nvm status\n"); return ret; + } /* Check nvm status */ if (!(reg & BMP580_STATUS_NVM_RDY_MASK) || (reg & BMP580_STATUS_NVM_ERR_MASK)) { - dev_err(data->dev, "preinit: nvm error on powerup sequence\n"); + dev_err(data->dev, "nvm error on powerup sequence\n"); return -EIO; } @@ -1657,6 +1661,10 @@ static int bmp580_chip_config(struct bmp280_data *data) BMP580_DSP_COMP_MASK | BMP580_DSP_SHDW_IIR_TEMP_EN | BMP580_DSP_SHDW_IIR_PRESS_EN, reg_val); + if (ret) { + dev_err(data->dev, "failed to change DSP mode settings\n"); + return ret; + } /* Configure oversampling */ reg_val = FIELD_PREP(BMP580_OSR_TEMP_MASK, data->oversampling_temp) | @@ -1778,8 +1786,10 @@ static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas) reinit_completion(&data->done); ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas); - if (ret) + if (ret) { + dev_err(data->dev, "failed to write crtl_meas register\n"); return ret; + } if (data->use_eoc) { /* @@ -1802,12 +1812,16 @@ static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas) } ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl); - if (ret) + if (ret) { + dev_err(data->dev, "failed to read ctrl_meas register\n"); return ret; + } /* The value of this bit reset to "0" after conversion is complete */ - if (ctrl & BMP180_MEAS_SCO) + if (ctrl & BMP180_MEAS_SCO) { + dev_err(data->dev, "conversion didn't complete\n"); return -EIO; + } return 0; } @@ -1824,8 +1838,10 @@ static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, &data->be16, sizeof(data->be16)); - if (ret) + if (ret) { + dev_err(data->dev, "failed to read temperature\n"); return ret; + } *val = be16_to_cpu(data->be16); @@ -1840,9 +1856,10 @@ static int bmp180_read_calib(struct bmp280_data *data) ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START, data->bmp180_cal_buf, sizeof(data->bmp180_cal_buf)); - - if (ret < 0) + if (ret < 0) { + dev_err(data->dev, "failed to read calibration parameters\n"); return ret; + } /* None of the words has the value 0 or 0xFFFF */ for (i = 0; i < ARRAY_SIZE(data->bmp180_cal_buf); i++) { @@ -1925,8 +1942,10 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, data->buf, sizeof(data->buf)); - if (ret) + if (ret) { + dev_err(data->dev, "failed to read pressure\n"); return ret; + } *val = get_unaligned_be24(data->buf) >> (8 - oss); @@ -2158,8 +2177,10 @@ int bmp280_common_probe(struct device *dev, data->regmap = regmap; ret = regmap_read(regmap, data->chip_info->id_reg, &chip_id); - if (ret < 0) + if (ret < 0) { + dev_err(data->dev, "failed to read chip id\n"); return ret; + } for (i = 0; i < data->chip_info->num_chip_id; i++) { if (chip_id == data->chip_info->chip_id[i]) { From 3b3b0cf4fdd5a6dd46a6a5f4fa44528ead63a044 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Wed, 8 May 2024 18:52:01 +0200 Subject: [PATCH 017/330] iio: pressure: bmp280: Make error checks consistent The form 'if (ret)' is used in this driver in order to check for returned error values. There are also some places that 'if (ret < 0)' is used but for no specific reason. Change them to 'if (ret)' to make the driver more consistent. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240508165207.145554-4-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 0aa16fb135c1..f05ea754f53a 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -184,7 +184,7 @@ static int bmp280_read_calib(struct bmp280_data *data) ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START, data->bmp280_cal_buf, sizeof(data->bmp280_cal_buf)); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to read calibration parameters\n"); return ret; @@ -222,7 +222,7 @@ static int bme280_read_calib(struct bmp280_data *data) /* Load shared calibration params with bmp280 first */ ret = bmp280_read_calib(data); - if (ret < 0) + if (ret) return ret; /* @@ -234,7 +234,7 @@ static int bme280_read_calib(struct bmp280_data *data) */ ret = regmap_read(data->regmap, BME280_REG_COMP_H1, &tmp); - if (ret < 0) { + if (ret) { dev_err(dev, "failed to read H1 comp value\n"); return ret; } @@ -242,14 +242,14 @@ static int bme280_read_calib(struct bmp280_data *data) ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H2, &data->le16, sizeof(data->le16)); - if (ret < 0) { + if (ret) { dev_err(dev, "failed to read H2 comp value\n"); return ret; } calib->H2 = sign_extend32(le16_to_cpu(data->le16), 15); ret = regmap_read(data->regmap, BME280_REG_COMP_H3, &tmp); - if (ret < 0) { + if (ret) { dev_err(dev, "failed to read H3 comp value\n"); return ret; } @@ -257,7 +257,7 @@ static int bme280_read_calib(struct bmp280_data *data) ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H4, &data->be16, sizeof(data->be16)); - if (ret < 0) { + if (ret) { dev_err(dev, "failed to read H4 comp value\n"); return ret; } @@ -266,14 +266,14 @@ static int bme280_read_calib(struct bmp280_data *data) ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H5, &data->le16, sizeof(data->le16)); - if (ret < 0) { + if (ret) { dev_err(dev, "failed to read H5 comp value\n"); return ret; } calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, le16_to_cpu(data->le16)), 11); ret = regmap_read(data->regmap, BME280_REG_COMP_H6, &tmp); - if (ret < 0) { + if (ret) { dev_err(dev, "failed to read H6 comp value\n"); return ret; } @@ -370,7 +370,7 @@ static int bmp280_read_temp(struct bmp280_data *data, ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, data->buf, sizeof(data->buf)); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to read temperature\n"); return ret; } @@ -404,12 +404,12 @@ static int bmp280_read_press(struct bmp280_data *data, /* Read and compensate temperature so we get a reading of t_fine. */ ret = bmp280_read_temp(data, NULL, NULL); - if (ret < 0) + if (ret) return ret; ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, data->buf, sizeof(data->buf)); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to read pressure\n"); return ret; } @@ -436,12 +436,12 @@ static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2) /* Read and compensate temperature so we get a reading of t_fine. */ ret = bmp280_read_temp(data, NULL, NULL); - if (ret < 0) + if (ret) return ret; ret = regmap_bulk_read(data->regmap, BME280_REG_HUMIDITY_MSB, &data->be16, sizeof(data->be16)); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to read humidity\n"); return ret; } @@ -775,7 +775,7 @@ static int bmp280_chip_config(struct bmp280_data *data) BMP280_OSRS_PRESS_MASK | BMP280_MODE_MASK, osrs | BMP280_MODE_NORMAL); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to write ctrl_meas register\n"); return ret; } @@ -783,7 +783,7 @@ static int bmp280_chip_config(struct bmp280_data *data) ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG, BMP280_FILTER_MASK, BMP280_FILTER_4X); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to write config register\n"); return ret; } @@ -839,7 +839,7 @@ static int bme280_chip_config(struct bmp280_data *data) */ ret = regmap_update_bits(data->regmap, BME280_REG_CTRL_HUMIDITY, BME280_OSRS_HUMIDITY_MASK, osrs); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to set humidity oversampling"); return ret; } @@ -1856,7 +1856,7 @@ static int bmp180_read_calib(struct bmp280_data *data) ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START, data->bmp180_cal_buf, sizeof(data->bmp180_cal_buf)); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to read calibration parameters\n"); return ret; } @@ -2177,7 +2177,7 @@ int bmp280_common_probe(struct device *dev, data->regmap = regmap; ret = regmap_read(regmap, data->chip_info->id_reg, &chip_id); - if (ret < 0) { + if (ret) { dev_err(data->dev, "failed to read chip id\n"); return ret; } @@ -2200,7 +2200,7 @@ int bmp280_common_probe(struct device *dev, } ret = data->chip_info->chip_config(data); - if (ret < 0) + if (ret) return ret; dev_set_drvdata(dev, indio_dev); @@ -2213,7 +2213,7 @@ int bmp280_common_probe(struct device *dev, if (data->chip_info->read_calib) { ret = data->chip_info->read_calib(data); - if (ret < 0) + if (ret) return dev_err_probe(data->dev, ret, "failed to read calibration coefficients\n"); } From f0fcd87e74295150ec2f811801ef52835d30d3bf Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Wed, 8 May 2024 18:52:02 +0200 Subject: [PATCH 018/330] iio: pressure: bmp280: Use unsigned data types for raw sensor data The raw sensor data that have not been compensated yet cannot be signed values, so use unsigned ones. Also, compensated pressure values cannot be negative so use unsigned also there. Also, drop redundant cast of data->t_fine variable from s32 to s32. Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240508165207.145554-5-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 45 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index f05ea754f53a..dd5c526dacbd 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -289,13 +289,13 @@ static int bme280_read_calib(struct bmp280_data *data) * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula". */ static u32 bme280_compensate_humidity(struct bmp280_data *data, - s32 adc_humidity) + u16 adc_humidity) { struct bmp280_calib *calib = &data->calib.bmp280; s32 var; - var = ((s32)data->t_fine) - (s32)76800; - var = ((((adc_humidity << 14) - (calib->H4 << 20) - (calib->H5 * var)) + var = data->t_fine - (s32)76800; + var = (((((s32)adc_humidity << 14) - (calib->H4 << 20) - (calib->H5 * var)) + (s32)16384) >> 15) * (((((((var * calib->H6) >> 10) * (((var * (s32)calib->H3) >> 11) + (s32)32768)) >> 10) + (s32)2097152) * calib->H2 + 8192) >> 14); @@ -314,16 +314,16 @@ static u32 bme280_compensate_humidity(struct bmp280_data *data, * Taken from datasheet, Section 3.11.3, "Compensation formula". */ static s32 bmp280_compensate_temp(struct bmp280_data *data, - s32 adc_temp) + u32 adc_temp) { struct bmp280_calib *calib = &data->calib.bmp280; s32 var1, var2; - var1 = (((adc_temp >> 3) - ((s32)calib->T1 << 1)) * + var1 = (((((s32)adc_temp) >> 3) - ((s32)calib->T1 << 1)) * ((s32)calib->T2)) >> 11; - var2 = (((((adc_temp >> 4) - ((s32)calib->T1)) * - ((adc_temp >> 4) - ((s32)calib->T1))) >> 12) * - ((s32)calib->T3)) >> 14; + var2 = (((((((s32)adc_temp) >> 4) - ((s32)calib->T1)) * + ((((s32)adc_temp >> 4) - ((s32)calib->T1))) >> 12) * + ((s32)calib->T3))) >> 14; data->t_fine = var1 + var2; return (data->t_fine * 5 + 128) >> 8; @@ -337,7 +337,7 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data, * Taken from datasheet, Section 3.11.3, "Compensation formula". */ static u32 bmp280_compensate_press(struct bmp280_data *data, - s32 adc_press) + u32 adc_press) { struct bmp280_calib *calib = &data->calib.bmp280; s64 var1, var2, p; @@ -353,7 +353,7 @@ static u32 bmp280_compensate_press(struct bmp280_data *data, if (var1 == 0) return 0; - p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125; + p = ((((s64)1048576 - (s32)adc_press) << 31) - var2) * 3125; p = div64_s64(p, var1); var1 = (((s64)calib->P9) * (p >> 13) * (p >> 13)) >> 25; var2 = ((s64)(calib->P8) * p) >> 19; @@ -365,7 +365,8 @@ static u32 bmp280_compensate_press(struct bmp280_data *data, static int bmp280_read_temp(struct bmp280_data *data, int *val, int *val2) { - s32 adc_temp, comp_temp; + s32 comp_temp; + u32 adc_temp; int ret; ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, @@ -398,8 +399,7 @@ static int bmp280_read_temp(struct bmp280_data *data, static int bmp280_read_press(struct bmp280_data *data, int *val, int *val2) { - u32 comp_press; - s32 adc_press; + u32 comp_press, adc_press; int ret; /* Read and compensate temperature so we get a reading of t_fine. */ @@ -431,7 +431,7 @@ static int bmp280_read_press(struct bmp280_data *data, static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2) { u32 comp_humidity; - s32 adc_humidity; + u16 adc_humidity; int ret; /* Read and compensate temperature so we get a reading of t_fine. */ @@ -1030,8 +1030,7 @@ static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2) static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2) { - s32 comp_press; - u32 adc_press; + u32 adc_press, comp_press; int ret; /* Read and compensate for temperature so we get a reading of t_fine */ @@ -1893,12 +1892,12 @@ static int bmp180_read_calib(struct bmp280_data *data) * * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". */ -static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) +static s32 bmp180_compensate_temp(struct bmp280_data *data, u32 adc_temp) { struct bmp180_calib *calib = &data->calib.bmp180; s32 x1, x2; - x1 = ((adc_temp - calib->AC6) * calib->AC5) >> 15; + x1 = ((((s32)adc_temp) - calib->AC6) * calib->AC5) >> 15; x2 = (calib->MC << 11) / (x1 + calib->MD); data->t_fine = x1 + x2; @@ -1907,7 +1906,8 @@ static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2) { - s32 adc_temp, comp_temp; + s32 comp_temp; + u32 adc_temp; int ret; ret = bmp180_read_adc_temp(data, &adc_temp); @@ -1957,7 +1957,7 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) * * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". */ -static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) +static u32 bmp180_compensate_press(struct bmp280_data *data, u32 adc_press) { struct bmp180_calib *calib = &data->calib.bmp180; s32 oss = data->oversampling_press; @@ -1974,7 +1974,7 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) x2 = (calib->B1 * ((b6 * b6) >> 12)) >> 16; x3 = (x1 + x2 + 2) >> 2; b4 = calib->AC4 * (u32)(x3 + 32768) >> 15; - b7 = ((u32)adc_press - b3) * (50000 >> oss); + b7 = (adc_press - b3) * (50000 >> oss); if (b7 < 0x80000000) p = (b7 * 2) / b4; else @@ -1989,8 +1989,7 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) static int bmp180_read_press(struct bmp280_data *data, int *val, int *val2) { - u32 comp_press; - s32 adc_press; + u32 comp_press, adc_press; int ret; /* Read and compensate temperature so we get a reading of t_fine. */ From 5d6e6c6ec45d1bf077d42ccb759bbdb7c26778e2 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Mon, 13 May 2024 01:05:20 +0200 Subject: [PATCH 019/330] iio: pressure: bmp280: Refactorize reading functions For BMP18x, BMP28x, BME280, BMP38x the reading of the pressure value requires an update of the t_fine variable which happens through reading the temperature value. So all the bmpxxx_read_press() functions of the above sensors are internally calling the equivalent bmpxxx_read_temp() function in order to update the t_fine value. By just looking at the code this functionality is a bit hidden and is not easy to understand why those channels are not independent. This commit tries to clear these things a bit by splitting the bmpxxx_{read/compensate}_{temp/press/humid}() to the following: i. bmpxxx_read_{temp/press/humid}_adc(): read the raw value from the sensor. ii. bmpxx_calc_t_fine(): calculate the t_fine variable. iii. bmpxxx_get_t_fine(): get the t_fine variable. iv. bmpxxx_compensate_{temp/press/humid}(): compensate the adc values and return the calculated value. v. bmpxxx_read_{temp/press/humid}(): combine calls of the aforementioned functions to return the requested value. Suggested-by: Jonathan Cameron Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240512230524.53990-2-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 351 ++++++++++++++++++----------- drivers/iio/pressure/bmp280.h | 6 - 2 files changed, 224 insertions(+), 133 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index dd5c526dacbd..3bb099c55db5 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -282,6 +282,28 @@ static int bme280_read_calib(struct bmp280_data *data) return 0; } +static int bme280_read_humid_adc(struct bmp280_data *data, u16 *adc_humidity) +{ + u16 value_humidity; + int ret; + + ret = regmap_bulk_read(data->regmap, BME280_REG_HUMIDITY_MSB, + &data->be16, sizeof(data->be16)); + if (ret) { + dev_err(data->dev, "failed to read humidity\n"); + return ret; + } + + value_humidity = be16_to_cpu(data->be16); + if (value_humidity == BMP280_HUMIDITY_SKIPPED) { + dev_err(data->dev, "reading humidity skipped\n"); + return -EIO; + } + *adc_humidity = value_humidity; + + return 0; +} + /* * Returns humidity in percent, resolution is 0.01 percent. Output value of * "47445" represents 47445/1024 = 46.333 %RH. @@ -289,12 +311,12 @@ static int bme280_read_calib(struct bmp280_data *data) * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula". */ static u32 bme280_compensate_humidity(struct bmp280_data *data, - u16 adc_humidity) + u16 adc_humidity, s32 t_fine) { struct bmp280_calib *calib = &data->calib.bmp280; s32 var; - var = data->t_fine - (s32)76800; + var = t_fine - (s32)76800; var = (((((s32)adc_humidity << 14) - (calib->H4 << 20) - (calib->H5 * var)) + (s32)16384) >> 15) * (((((((var * calib->H6) >> 10) * (((var * (s32)calib->H3) >> 11) + (s32)32768)) >> 10) @@ -306,6 +328,28 @@ static u32 bme280_compensate_humidity(struct bmp280_data *data, return var >> 12; } +static int bmp280_read_temp_adc(struct bmp280_data *data, u32 *adc_temp) +{ + u32 value_temp; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read temperature\n"); + return ret; + } + + value_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf)); + if (value_temp == BMP280_TEMP_SKIPPED) { + dev_err(data->dev, "reading temperature skipped\n"); + return -EIO; + } + *adc_temp = value_temp; + + return 0; +} + /* * Returns temperature in DegC, resolution is 0.01 DegC. Output value of * "5123" equals 51.23 DegC. t_fine carries fine temperature as global @@ -313,8 +357,7 @@ static u32 bme280_compensate_humidity(struct bmp280_data *data, * * Taken from datasheet, Section 3.11.3, "Compensation formula". */ -static s32 bmp280_compensate_temp(struct bmp280_data *data, - u32 adc_temp) +static s32 bmp280_calc_t_fine(struct bmp280_data *data, u32 adc_temp) { struct bmp280_calib *calib = &data->calib.bmp280; s32 var1, var2; @@ -324,9 +367,48 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data, var2 = (((((((s32)adc_temp) >> 4) - ((s32)calib->T1)) * ((((s32)adc_temp >> 4) - ((s32)calib->T1))) >> 12) * ((s32)calib->T3))) >> 14; - data->t_fine = var1 + var2; + return var1 + var2; /* t_fine = var1 + var2 */ +} - return (data->t_fine * 5 + 128) >> 8; +static int bmp280_get_t_fine(struct bmp280_data *data, s32 *t_fine) +{ + u32 adc_temp; + int ret; + + ret = bmp280_read_temp_adc(data, &adc_temp); + if (ret) + return ret; + + *t_fine = bmp280_calc_t_fine(data, adc_temp); + + return 0; +} + +static s32 bmp280_compensate_temp(struct bmp280_data *data, u32 adc_temp) +{ + return (bmp280_calc_t_fine(data, adc_temp) * 5 + 128) / 256; +} + +static int bmp280_read_press_adc(struct bmp280_data *data, u32 *adc_press) +{ + u32 value_press; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read pressure\n"); + return ret; + } + + value_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf)); + if (value_press == BMP280_PRESS_SKIPPED) { + dev_err(data->dev, "reading pressure skipped\n"); + return -EIO; + } + *adc_press = value_press; + + return 0; } /* @@ -337,12 +419,12 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data, * Taken from datasheet, Section 3.11.3, "Compensation formula". */ static u32 bmp280_compensate_press(struct bmp280_data *data, - u32 adc_press) + u32 adc_press, s32 t_fine) { struct bmp280_calib *calib = &data->calib.bmp280; s64 var1, var2, p; - var1 = ((s64)data->t_fine) - 128000; + var1 = ((s64)t_fine) - 128000; var2 = var1 * var1 * (s64)calib->P6; var2 += (var1 * (s64)calib->P5) << 17; var2 += ((s64)calib->P4) << 35; @@ -369,58 +451,31 @@ static int bmp280_read_temp(struct bmp280_data *data, u32 adc_temp; int ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, - data->buf, sizeof(data->buf)); - if (ret) { - dev_err(data->dev, "failed to read temperature\n"); + ret = bmp280_read_temp_adc(data, &adc_temp); + if (ret) return ret; - } - adc_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf)); - if (adc_temp == BMP280_TEMP_SKIPPED) { - /* reading was skipped */ - dev_err(data->dev, "reading temperature skipped\n"); - return -EIO; - } comp_temp = bmp280_compensate_temp(data, adc_temp); - /* - * val might be NULL if we're called by the read_press routine, - * who only cares about the carry over t_fine value. - */ - if (val) { - *val = comp_temp * 10; - return IIO_VAL_INT; - } - - return 0; + *val = comp_temp * 10; + return IIO_VAL_INT; } static int bmp280_read_press(struct bmp280_data *data, int *val, int *val2) { - u32 comp_press, adc_press; + u32 comp_press, adc_press, t_fine; int ret; - /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp280_read_temp(data, NULL, NULL); + ret = bmp280_get_t_fine(data, &t_fine); if (ret) return ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, - data->buf, sizeof(data->buf)); - if (ret) { - dev_err(data->dev, "failed to read pressure\n"); + ret = bmp280_read_press_adc(data, &adc_press); + if (ret) return ret; - } - adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf)); - if (adc_press == BMP280_PRESS_SKIPPED) { - /* reading was skipped */ - dev_err(data->dev, "reading pressure skipped\n"); - return -EIO; - } - comp_press = bmp280_compensate_press(data, adc_press); + comp_press = bmp280_compensate_press(data, adc_press, t_fine); *val = comp_press; *val2 = 256000; @@ -432,27 +487,18 @@ static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2) { u32 comp_humidity; u16 adc_humidity; + s32 t_fine; int ret; - /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp280_read_temp(data, NULL, NULL); + ret = bmp280_get_t_fine(data, &t_fine); if (ret) return ret; - ret = regmap_bulk_read(data->regmap, BME280_REG_HUMIDITY_MSB, - &data->be16, sizeof(data->be16)); - if (ret) { - dev_err(data->dev, "failed to read humidity\n"); + ret = bme280_read_humid_adc(data, &adc_humidity); + if (ret) return ret; - } - adc_humidity = be16_to_cpu(data->be16); - if (adc_humidity == BMP280_HUMIDITY_SKIPPED) { - /* reading was skipped */ - dev_err(data->dev, "reading humidity skipped\n"); - return -EIO; - } - comp_humidity = bme280_compensate_humidity(data, adc_humidity); + comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine); *val = comp_humidity * 1000 / 1024; @@ -923,6 +969,28 @@ static int bmp380_cmd(struct bmp280_data *data, u8 cmd) return 0; } +static int bmp380_read_temp_adc(struct bmp280_data *data, u32 *adc_temp) +{ + u32 value_temp; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP380_REG_TEMP_XLSB, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read temperature\n"); + return ret; + } + + value_temp = get_unaligned_le24(data->buf); + if (value_temp == BMP380_TEMP_SKIPPED) { + dev_err(data->dev, "reading temperature skipped\n"); + return -EIO; + } + *adc_temp = value_temp; + + return 0; +} + /* * Returns temperature in Celsius degrees, resolution is 0.01º C. Output value * of "5123" equals 51.2º C. t_fine carries fine temperature as global value. @@ -930,9 +998,9 @@ static int bmp380_cmd(struct bmp280_data *data, u8 cmd) * Taken from datasheet, Section Appendix 9, "Compensation formula" and repo * https://github.com/BoschSensortec/BMP3-Sensor-API. */ -static s32 bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp) +static s32 bmp380_calc_t_fine(struct bmp280_data *data, u32 adc_temp) { - s64 var1, var2, var3, var4, var5, var6, comp_temp; + s64 var1, var2, var3, var4, var5, var6; struct bmp380_calib *calib = &data->calib.bmp380; var1 = ((s64) adc_temp) - (((s64) calib->T1) << 8); @@ -941,13 +1009,57 @@ static s32 bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp) var4 = var3 * ((s64) calib->T3); var5 = (var2 << 18) + var4; var6 = var5 >> 32; - data->t_fine = (s32) var6; + return (s32)var6; /* t_fine = var6 */ +} + +static int bmp380_get_t_fine(struct bmp280_data *data, s32 *t_fine) +{ + s32 adc_temp; + int ret; + + ret = bmp380_read_temp_adc(data, &adc_temp); + if (ret) + return ret; + + *t_fine = bmp380_calc_t_fine(data, adc_temp); + + return 0; +} + +static int bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp) +{ + s64 comp_temp; + s32 var6; + + var6 = bmp380_calc_t_fine(data, adc_temp); comp_temp = (var6 * 25) >> 14; comp_temp = clamp_val(comp_temp, BMP380_MIN_TEMP, BMP380_MAX_TEMP); return (s32) comp_temp; } +static int bmp380_read_press_adc(struct bmp280_data *data, u32 *adc_press) +{ + u32 value_press; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read pressure\n"); + return ret; + } + + value_press = get_unaligned_le24(data->buf); + if (value_press == BMP380_PRESS_SKIPPED) { + dev_err(data->dev, "reading pressure skipped\n"); + return -EIO; + } + *adc_press = value_press; + + return 0; +} + /* * Returns pressure in Pa as an unsigned 32 bit integer in fractional Pascal. * Output value of "9528709" represents 9528709/100 = 95287.09 Pa = 952.8709 hPa. @@ -955,27 +1067,28 @@ static s32 bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp) * Taken from datasheet, Section 9.3. "Pressure compensation" and repository * https://github.com/BoschSensortec/BMP3-Sensor-API. */ -static u32 bmp380_compensate_press(struct bmp280_data *data, u32 adc_press) +static u32 bmp380_compensate_press(struct bmp280_data *data, + u32 adc_press, s32 t_fine) { s64 var1, var2, var3, var4, var5, var6, offset, sensitivity; struct bmp380_calib *calib = &data->calib.bmp380; u32 comp_press; - var1 = (s64)data->t_fine * (s64)data->t_fine; + var1 = (s64)t_fine * (s64)t_fine; var2 = var1 >> 6; - var3 = (var2 * ((s64) data->t_fine)) >> 8; + var3 = (var2 * ((s64)t_fine)) >> 8; var4 = ((s64)calib->P8 * var3) >> 5; var5 = ((s64)calib->P7 * var1) << 4; - var6 = ((s64)calib->P6 * (s64)data->t_fine) << 22; + var6 = ((s64)calib->P6 * (s64)t_fine) << 22; offset = ((s64)calib->P5 << 47) + var4 + var5 + var6; var2 = ((s64)calib->P4 * var3) >> 5; var4 = ((s64)calib->P3 * var1) << 2; var5 = ((s64)calib->P2 - ((s64)1 << 14)) * - ((s64)data->t_fine << 21); + ((s64)t_fine << 21); sensitivity = (((s64) calib->P1 - ((s64) 1 << 14)) << 46) + var2 + var4 + var5; var1 = (sensitivity >> 24) * (s64)adc_press; - var2 = (s64)calib->P10 * (s64)data->t_fine; + var2 = (s64)calib->P10 * (s64)t_fine; var3 = var2 + ((s64)calib->P9 << 16); var4 = (var3 * (s64)adc_press) >> 13; @@ -1001,59 +1114,32 @@ static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2) u32 adc_temp; int ret; - ret = regmap_bulk_read(data->regmap, BMP380_REG_TEMP_XLSB, - data->buf, sizeof(data->buf)); - if (ret) { - dev_err(data->dev, "failed to read temperature\n"); + ret = bmp380_read_temp_adc(data, &adc_temp); + if (ret) return ret; - } - adc_temp = get_unaligned_le24(data->buf); - if (adc_temp == BMP380_TEMP_SKIPPED) { - dev_err(data->dev, "reading temperature skipped\n"); - return -EIO; - } comp_temp = bmp380_compensate_temp(data, adc_temp); - /* - * Val might be NULL if we're called by the read_press routine, - * who only cares about the carry over t_fine value. - */ - if (val) { - /* IIO reports temperatures in milli Celsius */ - *val = comp_temp * 10; - return IIO_VAL_INT; - } - - return 0; + *val = comp_temp * 10; + return IIO_VAL_INT; } static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2) { - u32 adc_press, comp_press; + u32 adc_press, comp_press, t_fine; int ret; - /* Read and compensate for temperature so we get a reading of t_fine */ - ret = bmp380_read_temp(data, NULL, NULL); + ret = bmp380_get_t_fine(data, &t_fine); if (ret) return ret; - ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB, - data->buf, sizeof(data->buf)); - if (ret) { - dev_err(data->dev, "failed to read pressure\n"); + ret = bmp380_read_press_adc(data, &adc_press); + if (ret) return ret; - } - adc_press = get_unaligned_le24(data->buf); - if (adc_press == BMP380_PRESS_SKIPPED) { - dev_err(data->dev, "reading pressure skipped\n"); - return -EIO; - } - comp_press = bmp380_compensate_press(data, adc_press); + comp_press = bmp380_compensate_press(data, adc_press, t_fine); *val = comp_press; - /* Compensated pressure is in cPa (centipascals) */ *val2 = 100000; return IIO_VAL_FRACTIONAL; @@ -1825,7 +1911,7 @@ static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas) return 0; } -static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) +static int bmp180_read_temp_adc(struct bmp280_data *data, u32 *adc_temp) { int ret; @@ -1842,7 +1928,7 @@ static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) return ret; } - *val = be16_to_cpu(data->be16); + *adc_temp = be16_to_cpu(data->be16); return 0; } @@ -1892,16 +1978,34 @@ static int bmp180_read_calib(struct bmp280_data *data) * * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". */ -static s32 bmp180_compensate_temp(struct bmp280_data *data, u32 adc_temp) + +static s32 bmp180_calc_t_fine(struct bmp280_data *data, u32 adc_temp) { struct bmp180_calib *calib = &data->calib.bmp180; s32 x1, x2; x1 = ((((s32)adc_temp) - calib->AC6) * calib->AC5) >> 15; x2 = (calib->MC << 11) / (x1 + calib->MD); - data->t_fine = x1 + x2; + return x1 + x2; /* t_fine = x1 + x2; */ +} - return (data->t_fine + 8) >> 4; +static int bmp180_get_t_fine(struct bmp280_data *data, s32 *t_fine) +{ + s32 adc_temp; + int ret; + + ret = bmp180_read_temp_adc(data, &adc_temp); + if (ret) + return ret; + + *t_fine = bmp180_calc_t_fine(data, adc_temp); + + return 0; +} + +static s32 bmp180_compensate_temp(struct bmp280_data *data, u32 adc_temp) +{ + return (bmp180_calc_t_fine(data, adc_temp) + 8) / 16; } static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2) @@ -1910,25 +2014,17 @@ static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2) u32 adc_temp; int ret; - ret = bmp180_read_adc_temp(data, &adc_temp); + ret = bmp180_read_temp_adc(data, &adc_temp); if (ret) return ret; comp_temp = bmp180_compensate_temp(data, adc_temp); - /* - * val might be NULL if we're called by the read_press routine, - * who only cares about the carry over t_fine value. - */ - if (val) { - *val = comp_temp * 100; - return IIO_VAL_INT; - } - - return 0; + *val = comp_temp * 100; + return IIO_VAL_INT; } -static int bmp180_read_adc_press(struct bmp280_data *data, int *val) +static int bmp180_read_press_adc(struct bmp280_data *data, u32 *adc_press) { u8 oss = data->oversampling_press; int ret; @@ -1947,7 +2043,7 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) return ret; } - *val = get_unaligned_be24(data->buf) >> (8 - oss); + *adc_press = get_unaligned_be24(data->buf) >> (8 - oss); return 0; } @@ -1957,7 +2053,8 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) * * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". */ -static u32 bmp180_compensate_press(struct bmp280_data *data, u32 adc_press) +static u32 bmp180_compensate_press(struct bmp280_data *data, u32 adc_press, + s32 t_fine) { struct bmp180_calib *calib = &data->calib.bmp180; s32 oss = data->oversampling_press; @@ -1965,7 +2062,7 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, u32 adc_press) s32 b3, b6; u32 b4, b7; - b6 = data->t_fine - 4000; + b6 = t_fine - 4000; x1 = (calib->B2 * (b6 * b6 >> 12)) >> 11; x2 = calib->AC2 * b6 >> 11; x3 = x1 + x2; @@ -1990,18 +2087,18 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, u32 adc_press) static int bmp180_read_press(struct bmp280_data *data, int *val, int *val2) { u32 comp_press, adc_press; + s32 t_fine; int ret; - /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp180_read_temp(data, NULL, NULL); + ret = bmp180_get_t_fine(data, &t_fine); if (ret) return ret; - ret = bmp180_read_adc_press(data, &adc_press); + ret = bmp180_read_press_adc(data, &adc_press); if (ret) return ret; - comp_press = bmp180_compensate_press(data, adc_press); + comp_press = bmp180_compensate_press(data, adc_press, t_fine); *val = comp_press; *val2 = 1000; diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index fe4d3f127954..7c30e4d523be 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -397,12 +397,6 @@ struct bmp280_data { */ int sampling_freq; - /* - * Carryover value from temperature conversion, used in pressure - * calculation. - */ - s32 t_fine; - /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. From d174ebd41280fdd3fd3b1d10c46b48d29a14c56f Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Mon, 13 May 2024 01:05:21 +0200 Subject: [PATCH 020/330] iio: pressure: bmp280: Introduce new cleanup routines Introduce new linux/cleanup.h with the guard(mutex) functionality. Suggested-by: Andy Shevchenko Suggested-by: Jonathan Cameron Signed-off-by: Vasileios Amoiridis Link: https://lore.kernel.org/r/20240512230524.53990-3-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 217 +++++++++++++++-------------- 1 file changed, 110 insertions(+), 107 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 3bb099c55db5..8d26161df2b0 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -505,6 +506,58 @@ static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2) return IIO_VAL_INT; } +static int bmp280_read_raw_impl(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bmp280_data *data = iio_priv(indio_dev); + + guard(mutex)(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + return data->chip_info->read_humid(data, val, val2); + case IIO_PRESSURE: + return data->chip_info->read_press(data, val, val2); + case IIO_TEMP: + return data->chip_info->read_temp(data, val, val2); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + *val = 1 << data->oversampling_humid; + return IIO_VAL_INT; + case IIO_PRESSURE: + *val = 1 << data->oversampling_press; + return IIO_VAL_INT; + case IIO_TEMP: + *val = 1 << data->oversampling_temp; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + if (!data->chip_info->sampling_freq_avail) + return -EINVAL; + + *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0]; + *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + if (!data->chip_info->iir_filter_coeffs_avail) + return -EINVAL; + + *val = (1 << data->iir_filter_coeff) - 1; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + static int bmp280_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -513,69 +566,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, int ret; pm_runtime_get_sync(data->dev); - mutex_lock(&data->lock); - - switch (mask) { - case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_HUMIDITYRELATIVE: - ret = data->chip_info->read_humid(data, val, val2); - break; - case IIO_PRESSURE: - ret = data->chip_info->read_press(data, val, val2); - break; - case IIO_TEMP: - ret = data->chip_info->read_temp(data, val, val2); - break; - default: - ret = -EINVAL; - break; - } - break; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - switch (chan->type) { - case IIO_HUMIDITYRELATIVE: - *val = 1 << data->oversampling_humid; - ret = IIO_VAL_INT; - break; - case IIO_PRESSURE: - *val = 1 << data->oversampling_press; - ret = IIO_VAL_INT; - break; - case IIO_TEMP: - *val = 1 << data->oversampling_temp; - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - break; - } - break; - case IIO_CHAN_INFO_SAMP_FREQ: - if (!data->chip_info->sampling_freq_avail) { - ret = -EINVAL; - break; - } - - *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0]; - *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1]; - ret = IIO_VAL_INT_PLUS_MICRO; - break; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - if (!data->chip_info->iir_filter_coeffs_avail) { - ret = -EINVAL; - break; - } - - *val = (1 << data->iir_filter_coeff) - 1; - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - break; - } - - mutex_unlock(&data->lock); + ret = bmp280_read_raw_impl(indio_dev, chan, val, val2, mask); pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); @@ -707,12 +698,13 @@ static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val) return -EINVAL; } -static int bmp280_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) +static int bmp280_write_raw_impl(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct bmp280_data *data = iio_priv(indio_dev); - int ret = 0; + + guard(mutex)(&data->lock); /* * Helper functions to update sensor running configuration. @@ -722,45 +714,36 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, */ switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - pm_runtime_get_sync(data->dev); - mutex_lock(&data->lock); switch (chan->type) { case IIO_HUMIDITYRELATIVE: - ret = bme280_write_oversampling_ratio_humid(data, val); - break; + return bme280_write_oversampling_ratio_humid(data, val); case IIO_PRESSURE: - ret = bmp280_write_oversampling_ratio_press(data, val); - break; + return bmp280_write_oversampling_ratio_press(data, val); case IIO_TEMP: - ret = bmp280_write_oversampling_ratio_temp(data, val); - break; + return bmp280_write_oversampling_ratio_temp(data, val); default: - ret = -EINVAL; - break; + return -EINVAL; } - mutex_unlock(&data->lock); - pm_runtime_mark_last_busy(data->dev); - pm_runtime_put_autosuspend(data->dev); - break; case IIO_CHAN_INFO_SAMP_FREQ: - pm_runtime_get_sync(data->dev); - mutex_lock(&data->lock); - ret = bmp280_write_sampling_frequency(data, val, val2); - mutex_unlock(&data->lock); - pm_runtime_mark_last_busy(data->dev); - pm_runtime_put_autosuspend(data->dev); - break; + return bmp280_write_sampling_frequency(data, val, val2); case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - pm_runtime_get_sync(data->dev); - mutex_lock(&data->lock); - ret = bmp280_write_iir_filter_coeffs(data, val); - mutex_unlock(&data->lock); - pm_runtime_mark_last_busy(data->dev); - pm_runtime_put_autosuspend(data->dev); - break; + return bmp280_write_iir_filter_coeffs(data, val); default: return -EINVAL; } +} + +static int bmp280_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmp280_data *data = iio_priv(indio_dev); + int ret; + + pm_runtime_get_sync(data->dev); + ret = bmp280_write_raw_impl(indio_dev, chan, val, val2, mask); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); return ret; } @@ -1551,15 +1534,14 @@ static const int bmp580_odr_table[][2] = { static const int bmp580_nvmem_addrs[] = { 0x20, 0x21, 0x22 }; -static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, - size_t bytes) +static int bmp580_nvmem_read_impl(void *priv, unsigned int offset, void *val, + size_t bytes) { struct bmp280_data *data = priv; u16 *dst = val; int ret, addr; - pm_runtime_get_sync(data->dev); - mutex_lock(&data->lock); + guard(mutex)(&data->lock); /* Set sensor in standby mode */ ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG, @@ -1601,21 +1583,31 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, exit: /* Restore chip config */ data->chip_info->chip_config(data); - mutex_unlock(&data->lock); - pm_runtime_mark_last_busy(data->dev); - pm_runtime_put_autosuspend(data->dev); return ret; } -static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, - size_t bytes) +static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct bmp280_data *data = priv; + int ret; + + pm_runtime_get_sync(data->dev); + ret = bmp580_nvmem_read_impl(priv, offset, val, bytes); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val, + size_t bytes) { struct bmp280_data *data = priv; u16 *buf = val; int ret, addr; - pm_runtime_get_sync(data->dev); - mutex_lock(&data->lock); + guard(mutex)(&data->lock); /* Set sensor in standby mode */ ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG, @@ -1666,9 +1658,20 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, exit: /* Restore chip config */ data->chip_info->chip_config(data); - mutex_unlock(&data->lock); + return ret; +} + +static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct bmp280_data *data = priv; + int ret; + + pm_runtime_get_sync(data->dev); + ret = bmp580_nvmem_write_impl(priv, offset, val, bytes); pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); + return ret; } From 56813b244e5f2ace887f04c4a69a2a0041992297 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 May 2024 11:27:47 +0200 Subject: [PATCH 021/330] w1: Add missing newline and fix typos in w1_bus_master comment - Add missing newline before @return - s/bytes/byte/ - s/handles/handle/ - s/exists/exist/ in dev_info() message Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20240527092746.263038-2-thorsten.blum@toblux.com [krzysztof: squash "w1: Fix typo in dev_info() message"] Signed-off-by: Krzysztof Kozlowski --- drivers/w1/w1.c | 2 +- include/linux/w1.h | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index afb1cc4606c5..d82e86d3ddf6 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -504,7 +504,7 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev, if (result == 0) result = count; } else { - dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family, + dev_info(dev, "Device %02x-%012llx doesn't exist\n", rn.family, (unsigned long long)rn.id); result = -EINVAL; } diff --git a/include/linux/w1.h b/include/linux/w1.h index 9a2a0ef39018..064805bfae3f 100644 --- a/include/linux/w1.h +++ b/include/linux/w1.h @@ -85,7 +85,8 @@ typedef void (*w1_slave_found_callback)(struct w1_master *, u64); * * @data: the first parameter in all the functions below * - * @read_bit: Sample the line level @return the level read (0 or 1) + * @read_bit: Sample the line level + * @return the level read (0 or 1) * * @write_bit: Sets the line level * @@ -95,7 +96,7 @@ typedef void (*w1_slave_found_callback)(struct w1_master *, u64); * touch_bit(1) = write-1 / read cycle * @return the bit read (0 or 1) * - * @read_byte: Reads a bytes. Same as 8 touch_bit(1) calls. + * @read_byte: Reads a byte. Same as 8 touch_bit(1) calls. * @return the byte read * * @write_byte: Writes a byte. Same as 8 touch_bit(x) calls. @@ -114,7 +115,7 @@ typedef void (*w1_slave_found_callback)(struct w1_master *, u64); * @set_pullup: Put out a strong pull-up pulse of the specified duration. * @return -1=Error, 0=completed * - * @search: Really nice hardware can handles the different types of ROM search + * @search: Really nice hardware can handle the different types of ROM search * w1_master* is passed to the slave found callback. * u8 is search_type, W1_SEARCH or W1_ALARM_SEARCH * From 26bf5fc86033162dbd2d5759094cbd724313d55b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 May 2024 15:49:47 +0200 Subject: [PATCH 022/330] w1: Drop allocation error message Drop the custom error message because kzalloc() already prints allocation failures. Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20240527134946.338398-2-thorsten.blum@toblux.com Signed-off-by: Krzysztof Kozlowski --- drivers/w1/w1_int.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 3a71c5eb2f83..19a0ea28e9f3 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -32,12 +32,8 @@ static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl, * We are in process context(kernel thread), so can sleep. */ dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL); - if (!dev) { - pr_err("Failed to allocate %zd bytes for new w1 device.\n", - sizeof(struct w1_master)); + if (!dev) return NULL; - } - dev->bus_master = (struct w1_bus_master *)(dev + 1); From 6392194470575de1ac0cb7223ff3bf30da94bbea Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 23 May 2024 18:30:35 -0700 Subject: [PATCH 023/330] uio: add missing MODULE_DESCRIPTION() macros Fix the 'make W=1' warnings: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_cif.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_aec.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_netx.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_mf624.o Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240523-md-drivers-uio-v2-1-5173b2ae9563@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 1 + drivers/uio/uio_aec.c | 1 + drivers/uio/uio_cif.c | 1 + drivers/uio/uio_mf624.c | 3 ++- drivers/uio/uio_netx.c | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 5ce429286ab0..20d2a55cb40b 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -1145,4 +1145,5 @@ static void __exit uio_exit(void) module_init(uio_init) module_exit(uio_exit) +MODULE_DESCRIPTION("Userspace IO core module"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c index 64eafd59e6e7..8c164e51ff9e 100644 --- a/drivers/uio/uio_aec.c +++ b/drivers/uio/uio_aec.c @@ -144,4 +144,5 @@ static struct pci_driver pci_driver = { }; module_pci_driver(pci_driver); +MODULE_DESCRIPTION("Adrienne Electronics Corp time code PCI device"); MODULE_LICENSE("GPL"); diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index 653f842a1491..1cc3b8b5a345 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c @@ -130,5 +130,6 @@ static struct pci_driver hilscher_pci_driver = { module_pci_driver(hilscher_pci_driver); MODULE_DEVICE_TABLE(pci, hilscher_pci_ids); +MODULE_DESCRIPTION("UIO Hilscher CIF card driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger"); diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c index 5065c6a073a8..790412f8dfd5 100644 --- a/drivers/uio/uio_mf624.c +++ b/drivers/uio/uio_mf624.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * UIO driver fo Humusoft MF624 DAQ card. + * UIO driver for Humusoft MF624 DAQ card. * Copyright (C) 2011 Rostislav Lisovy , * Czech Technical University in Prague */ @@ -221,5 +221,6 @@ static struct pci_driver mf624_pci_driver = { MODULE_DEVICE_TABLE(pci, mf624_pci_id); module_pci_driver(mf624_pci_driver); +MODULE_DESCRIPTION("UIO driver for Humusoft MF624 DAQ card"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Rostislav Lisovy "); diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index 2319d6de8d04..a1a58802c793 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c @@ -170,5 +170,6 @@ static struct pci_driver netx_pci_driver = { module_pci_driver(netx_pci_driver); MODULE_DEVICE_TABLE(pci, netx_pci_ids); +MODULE_DESCRIPTION("UIO driver for Hilscher NetX based fieldbus cards"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Hans J. Koch, Manuel Traut"); From ea5542c5bbfc87f572dab9fbdf932e7aeb2b7d62 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 30 May 2024 20:48:01 -0700 Subject: [PATCH 024/330] parport: add missing MODULE_DESCRIPTION() make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/parport/parport.o Add the missing MODULE_DESCRIPTION() macro invocation. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240530-parport-v1-1-09bee2ca3123@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 49c74ded8a53..b7148517e076 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -1219,4 +1219,5 @@ irqreturn_t parport_irq_handler(int irq, void *dev_id) } EXPORT_SYMBOL(parport_irq_handler); +MODULE_DESCRIPTION("Parallel-port resource manager"); MODULE_LICENSE("GPL"); From 5a71c0d1180e76d223a8266799d1ee4ba3a8e697 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 31 May 2024 15:01:14 -0700 Subject: [PATCH 025/330] dyndbg: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_dynamic_debug.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240531-md-test_dynamic_debug-v1-1-2194b477f55e@quicinc.com Signed-off-by: Greg Kroah-Hartman --- lib/test_dynamic_debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c index 8dd250ad022b..77c2a669b6af 100644 --- a/lib/test_dynamic_debug.c +++ b/lib/test_dynamic_debug.c @@ -162,4 +162,5 @@ module_init(test_dynamic_debug_init); module_exit(test_dynamic_debug_exit); MODULE_AUTHOR("Jim Cromie "); +MODULE_DESCRIPTION("Kernel module for testing dynamic_debug"); MODULE_LICENSE("GPL"); From 0d618e39763e0e2b88586cd7d40ce8419735412f Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 31 May 2024 22:21:38 -0700 Subject: [PATCH 026/330] lib/math: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in lib/math/prime_numbers.o WARNING: modpost: missing MODULE_DESCRIPTION() in lib/math/rational-test.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240531-md-lib-math-v1-1-11a3bec51ebb@quicinc.com Signed-off-by: Greg Kroah-Hartman --- lib/math/prime_numbers.c | 1 + lib/math/rational-test.c | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/math/prime_numbers.c b/lib/math/prime_numbers.c index d3b64b10da1c..9a17ee9af93a 100644 --- a/lib/math/prime_numbers.c +++ b/lib/math/prime_numbers.c @@ -311,4 +311,5 @@ module_exit(primes_exit); module_param_named(selftest, selftest_max, ulong, 0400); MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Prime number library"); MODULE_LICENSE("GPL"); diff --git a/lib/math/rational-test.c b/lib/math/rational-test.c index 01611ddff420..47486a95f088 100644 --- a/lib/math/rational-test.c +++ b/lib/math/rational-test.c @@ -53,4 +53,5 @@ static struct kunit_suite rational_test_suite = { kunit_test_suites(&rational_test_suite); +MODULE_DESCRIPTION("Rational fractions unit test"); MODULE_LICENSE("GPL v2"); From 45be81fa3b55b9da33be36f5d3d69689dc046942 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 3 Jun 2024 11:10:00 -0700 Subject: [PATCH 027/330] ppdev: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/ppdev.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240603-md-char-ppdev-v1-1-b169cb17c844@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/ppdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 58e9dcc2a308..3655aa859185 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -882,5 +882,6 @@ static void __exit ppdev_cleanup(void) module_init(ppdev_init); module_exit(ppdev_cleanup); +MODULE_DESCRIPTION("Support for user-space parallel port device drivers"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(PP_MAJOR); From a464822872f5e0e6a541c0b4971bea10421db5fa Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 3 Jun 2024 11:33:05 -0700 Subject: [PATCH 028/330] tlclk: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/tlclk.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240603-md-char-tlclk-v1-1-d395aa93da86@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/tlclk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 896a3550fba9..377bebf6c925 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -47,6 +47,7 @@ #include MODULE_AUTHOR("Sebastien Bouchard "); +MODULE_DESCRIPTION("Telecom Clock driver for Intel NetStructure(tm) MPCBL0010"); MODULE_LICENSE("GPL"); /*Hardware Reset of the PLL */ From 91f34fc54ee7d008d80607cfaafe50f416fdf160 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 3 Jun 2024 12:08:32 -0700 Subject: [PATCH 029/330] char: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/ttyprintk.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/lp.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/nvram.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240603-md-char-misc-v1-1-25d43d6f331d@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/lp.c | 1 + drivers/char/nvram.c | 1 + drivers/char/ttyprintk.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 2f171d14b9b5..5faebe0365c5 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -1123,4 +1123,5 @@ module_init(lp_init_module); module_exit(lp_cleanup_module); MODULE_ALIAS_CHARDEV_MAJOR(LP_MAJOR); +MODULE_DESCRIPTION("Generic parallel printer driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index e9f694b36871..9eff426a9286 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -540,6 +540,7 @@ static void __exit nvram_module_exit(void) module_init(nvram_module_init); module_exit(nvram_module_exit); +MODULE_DESCRIPTION("CMOS/NV-RAM driver for Linux"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(NVRAM_MINOR); MODULE_ALIAS("devname:nvram"); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 4c806a189ee5..d7f841ab4323 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -228,4 +228,5 @@ static void __exit ttyprintk_exit(void) device_initcall(ttyprintk_init); module_exit(ttyprintk_exit); +MODULE_DESCRIPTION("TTY driver to output user messages via printk"); MODULE_LICENSE("GPL"); From 312eee8f0c9927f440cf134e34db625a2976d80e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 3 Jun 2024 13:32:29 -0700 Subject: [PATCH 030/330] misc: open-dice: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/misc/open-dice.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240603-md-misc-open-dice-v1-1-ee7972ae0d39@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/open-dice.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c index 1e3eb2aa44d9..e6a61e6d9427 100644 --- a/drivers/misc/open-dice.c +++ b/drivers/misc/open-dice.c @@ -201,5 +201,6 @@ static void __exit open_dice_exit(void) module_init(open_dice_init); module_exit(open_dice_exit); +MODULE_DESCRIPTION("Driver for Open Profile for DICE."); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("David Brazdil "); From c41cc3c28730c549b78ddc9533d589c289242e63 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 30 May 2024 21:25:37 -0700 Subject: [PATCH 031/330] siox: bus-gpio: add missing MODULE_DESCRIPTION() make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/siox/siox-bus-gpio.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Acked-by: Thorsten Scherer Link: https://lore.kernel.org/r/20240530-md-siox-bus-gpio-v1-1-6a2f943ac8ad@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/siox/siox-bus-gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/siox/siox-bus-gpio.c b/drivers/siox/siox-bus-gpio.c index 9e01642e72de..d6f936464063 100644 --- a/drivers/siox/siox-bus-gpio.c +++ b/drivers/siox/siox-bus-gpio.c @@ -148,5 +148,6 @@ static struct platform_driver siox_gpio_driver = { module_platform_driver(siox_gpio_driver); MODULE_AUTHOR("Uwe Kleine-Koenig "); +MODULE_DESCRIPTION("SIOX GPIO bus driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRIVER_NAME); From c01b08a7538581d13a90d38d259673ad64bff647 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:46:54 +0300 Subject: [PATCH 032/330] misc: eeprom_93xx46: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Include mod_devicetable.h explicitly to replace the dropped of.h which included mod_devicetable.h indirectly. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 41 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 45c8ae0db8f9..bbcc9412bb4e 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -10,13 +10,15 @@ #include #include #include +#include #include #include -#include -#include +#include #include #include + #include + #include #define OP_START 0x4 @@ -422,22 +424,20 @@ static const struct spi_device_id eeprom_93xx46_spi_ids[] = { }; MODULE_DEVICE_TABLE(spi, eeprom_93xx46_spi_ids); -static int eeprom_93xx46_probe_dt(struct spi_device *spi) +static int eeprom_93xx46_probe_fw(struct device *dev) { - const struct of_device_id *of_id = - of_match_device(eeprom_93xx46_of_table, &spi->dev); - struct device_node *np = spi->dev.of_node; + const struct eeprom_93xx46_devtype_data *data; struct eeprom_93xx46_platform_data *pd; u32 tmp; int ret; - pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL); + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); if (!pd) return -ENOMEM; - ret = of_property_read_u32(np, "data-size", &tmp); + ret = device_property_read_u32(dev, "data-size", &tmp); if (ret < 0) { - dev_err(&spi->dev, "data-size property not found\n"); + dev_err(dev, "data-size property not found\n"); return ret; } @@ -446,30 +446,28 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi) } else if (tmp == 16) { pd->flags |= EE_ADDR16; } else { - dev_err(&spi->dev, "invalid data-size (%d)\n", tmp); + dev_err(dev, "invalid data-size (%d)\n", tmp); return -EINVAL; } - if (of_property_read_bool(np, "read-only")) + if (device_property_read_bool(dev, "read-only")) pd->flags |= EE_READONLY; - pd->select = devm_gpiod_get_optional(&spi->dev, "select", - GPIOD_OUT_LOW); + pd->select = devm_gpiod_get_optional(dev, "select", GPIOD_OUT_LOW); if (IS_ERR(pd->select)) return PTR_ERR(pd->select); + gpiod_set_consumer_name(pd->select, "93xx46 EEPROMs OE"); pd->prepare = select_assert; pd->finish = select_deassert; - gpiod_direction_output(pd->select, 0); - - if (of_id->data) { - const struct eeprom_93xx46_devtype_data *data = of_id->data; + data = spi_get_device_match_data(to_spi_device(dev)); + if (data) { pd->quirks = data->quirks; pd->flags |= data->flags; } - spi->dev.platform_data = pd; + dev->platform_data = pd; return 0; } @@ -478,10 +476,11 @@ static int eeprom_93xx46_probe(struct spi_device *spi) { struct eeprom_93xx46_platform_data *pd; struct eeprom_93xx46_dev *edev; + struct device *dev = &spi->dev; int err; - if (spi->dev.of_node) { - err = eeprom_93xx46_probe_dt(spi); + if (dev_fwnode(dev)) { + err = eeprom_93xx46_probe_fw(dev); if (err < 0) return err; } @@ -565,7 +564,7 @@ static void eeprom_93xx46_remove(struct spi_device *spi) static struct spi_driver eeprom_93xx46_driver = { .driver = { .name = "93xx46", - .of_match_table = of_match_ptr(eeprom_93xx46_of_table), + .of_match_table = eeprom_93xx46_of_table, }, .probe = eeprom_93xx46_probe, .remove = eeprom_93xx46_remove, From 2b82641ad0620b2d71dc05024b20f82db7e1c0b6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:46:55 +0300 Subject: [PATCH 033/330] eeprom: digsy_mtc: Fix 93xx46 driver probe failure The update to support other (bigger) types of EEPROMs broke the driver loading due to removal of the default size. Fix this by adding the respective (new) flag to the platform data. Fixes: 14374fbb3f06 ("misc: eeprom_93xx46: Add new 93c56 and 93c66 compatible strings") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240508184905.2102633-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/digsy_mtc_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c index f1f766b70965..4eddc5ba1af9 100644 --- a/drivers/misc/eeprom/digsy_mtc_eeprom.c +++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c @@ -42,7 +42,7 @@ static void digsy_mtc_op_finish(void *p) } struct eeprom_93xx46_platform_data digsy_mtc_eeprom_data = { - .flags = EE_ADDR8, + .flags = EE_ADDR8 | EE_SIZE1K, .prepare = digsy_mtc_op_prepare, .finish = digsy_mtc_op_finish, }; From c8ed97d8c3984492942ac6c63bb47794caffd4af Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:46:56 +0300 Subject: [PATCH 034/330] eeprom: digsy_mtc: Convert to use GPIO descriptors This converts the driver to use GPIO descriptors exclusively to retrieve GPIO lines. Drop the old GPIO handling in favor of the core managing it exclusively. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/digsy_mtc_eeprom.c | 46 +++++++++++--------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c index 4eddc5ba1af9..88888485e6f8 100644 --- a/drivers/misc/eeprom/digsy_mtc_eeprom.c +++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c @@ -14,13 +14,12 @@ * and delete this driver. */ -#include #include #include #include +#include #include #include -#include #define GPIO_EEPROM_CLK 216 #define GPIO_EEPROM_CS 210 @@ -29,22 +28,13 @@ #define GPIO_EEPROM_OE 255 #define EE_SPI_BUS_NUM 1 -static void digsy_mtc_op_prepare(void *p) -{ - /* enable */ - gpio_set_value(GPIO_EEPROM_OE, 0); -} +static const struct property_entry digsy_mtc_spi_properties[] = { + PROPERTY_ENTRY_U32("data-size", 8), + { } +}; -static void digsy_mtc_op_finish(void *p) -{ - /* disable */ - gpio_set_value(GPIO_EEPROM_OE, 1); -} - -struct eeprom_93xx46_platform_data digsy_mtc_eeprom_data = { - .flags = EE_ADDR8 | EE_SIZE1K, - .prepare = digsy_mtc_op_prepare, - .finish = digsy_mtc_op_finish, +static const struct software_node digsy_mtc_spi_node = { + .properties = digsy_mtc_spi_properties, }; static struct spi_gpio_platform_data eeprom_spi_gpio_data = { @@ -70,18 +60,19 @@ static struct gpiod_lookup_table eeprom_spi_gpiod_table = { "miso", GPIO_ACTIVE_HIGH), GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CS, "cs", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_OE, + "select", GPIO_ACTIVE_LOW), { }, }, }; static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = { { - .modalias = "93xx46", + .modalias = "eeprom-93xx46", .max_speed_hz = 1000000, .bus_num = EE_SPI_BUS_NUM, .chip_select = 0, .mode = SPI_MODE_0, - .platform_data = &digsy_mtc_eeprom_data, }, }; @@ -89,15 +80,18 @@ static int __init digsy_mtc_eeprom_devices_init(void) { int ret; - ret = gpio_request_one(GPIO_EEPROM_OE, GPIOF_OUT_INIT_HIGH, - "93xx46 EEPROMs OE"); - if (ret) { - pr_err("can't request gpio %d\n", GPIO_EEPROM_OE); - return ret; - } gpiod_add_lookup_table(&eeprom_spi_gpiod_table); spi_register_board_info(digsy_mtc_eeprom_info, ARRAY_SIZE(digsy_mtc_eeprom_info)); - return platform_device_register(&digsy_mtc_eeprom); + + ret = device_add_software_node(&digsy_mtc_eeprom.dev, &digsy_mtc_spi_node); + if (ret) + return ret; + + ret = platform_device_register(&digsy_mtc_eeprom); + if (ret) + device_remove_software_node(&digsy_mtc_eeprom.dev); + + return ret; } device_initcall(digsy_mtc_eeprom_devices_init); From 3aee48a8e01f98d3285a0064285b0152cdbb8a9e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:46:57 +0300 Subject: [PATCH 035/330] misc: eeprom_93xx46: Hide legacy platform data in the driver First of all, there is no user for the platform data in the kernel. Second, it needs a lot of updates to follow the modern standards of the kernel, including proper Device Tree bindings and device property handling. For now, just hide the legacy platform data in the driver's code. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 35 ++++++++++++++++++++++++----- include/linux/eeprom_93xx46.h | 32 -------------------------- 2 files changed, 29 insertions(+), 38 deletions(-) delete mode 100644 include/linux/eeprom_93xx46.h diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index bbcc9412bb4e..a5a043ddedbb 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -5,6 +5,7 @@ * (C) 2011 DENX Software Engineering, Anatolij Gustschin */ +#include #include #include #include @@ -19,7 +20,31 @@ #include -#include +struct eeprom_93xx46_platform_data { + unsigned char flags; +#define EE_ADDR8 0x01 /* 8 bit addr. cfg */ +#define EE_ADDR16 0x02 /* 16 bit addr. cfg */ +#define EE_READONLY 0x08 /* forbid writing */ +#define EE_SIZE1K 0x10 /* 1 kb of data, that is a 93xx46 */ +#define EE_SIZE2K 0x20 /* 2 kb of data, that is a 93xx56 */ +#define EE_SIZE4K 0x40 /* 4 kb of data, that is a 93xx66 */ + + unsigned int quirks; +/* Single word read transfers only; no sequential read. */ +#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ (1 << 0) +/* Instructions such as EWEN are (addrlen + 2) in length. */ +#define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH (1 << 1) +/* Add extra cycle after address during a read */ +#define EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE BIT(2) + + /* + * optional hooks to control additional logic + * before and after spi transfer. + */ + void (*prepare)(void *); + void (*finish)(void *); + struct gpio_desc *select; +}; #define OP_START 0x4 #define OP_WRITE (OP_START | 0x1) @@ -479,11 +504,9 @@ static int eeprom_93xx46_probe(struct spi_device *spi) struct device *dev = &spi->dev; int err; - if (dev_fwnode(dev)) { - err = eeprom_93xx46_probe_fw(dev); - if (err < 0) - return err; - } + err = eeprom_93xx46_probe_fw(dev); + if (err < 0) + return err; pd = spi->dev.platform_data; if (!pd) { diff --git a/include/linux/eeprom_93xx46.h b/include/linux/eeprom_93xx46.h deleted file mode 100644 index 34c2175e6a1e..000000000000 --- a/include/linux/eeprom_93xx46.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Module: eeprom_93xx46 - * platform description for 93xx46 EEPROMs. - */ -#include - -struct eeprom_93xx46_platform_data { - unsigned char flags; -#define EE_ADDR8 0x01 /* 8 bit addr. cfg */ -#define EE_ADDR16 0x02 /* 16 bit addr. cfg */ -#define EE_READONLY 0x08 /* forbid writing */ -#define EE_SIZE1K 0x10 /* 1 kb of data, that is a 93xx46 */ -#define EE_SIZE2K 0x20 /* 2 kb of data, that is a 93xx56 */ -#define EE_SIZE4K 0x40 /* 4 kb of data, that is a 93xx66 */ - - unsigned int quirks; -/* Single word read transfers only; no sequential read. */ -#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ (1 << 0) -/* Instructions such as EWEN are (addrlen + 2) in length. */ -#define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH (1 << 1) -/* Add extra cycle after address during a read */ -#define EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE BIT(2) - - /* - * optional hooks to control additional logic - * before and after spi transfer. - */ - void (*prepare)(void *); - void (*finish)(void *); - struct gpio_desc *select; -}; From 195b979955dea396e6c21bf196af06f6e5ef8c91 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:46:58 +0300 Subject: [PATCH 036/330] misc: eeprom_93xx46: Remove ->prepare() and ->finish() customisation Currently there is only one way how chip is prepared and unprepared for an operation. Drop unnecessary customisation. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-6-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 48 +++++------------------------ 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index a5a043ddedbb..b6d699c1cd39 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -37,12 +37,6 @@ struct eeprom_93xx46_platform_data { /* Add extra cycle after address during a read */ #define EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE BIT(2) - /* - * optional hooks to control additional logic - * before and after spi transfer. - */ - void (*prepare)(void *); - void (*finish)(void *); struct gpio_desc *select; }; @@ -123,8 +117,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, mutex_lock(&edev->lock); - if (edev->pdata->prepare) - edev->pdata->prepare(edev); + gpiod_set_value_cansleep(edev->pdata->select, 1); /* The opcode in front of the address is three bits. */ bits = edev->addrlen + 3; @@ -180,8 +173,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, count -= nbytes; } - if (edev->pdata->finish) - edev->pdata->finish(edev); + gpiod_set_value_cansleep(edev->pdata->select, 0); mutex_unlock(&edev->lock); @@ -222,8 +214,7 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) mutex_lock(&edev->lock); - if (edev->pdata->prepare) - edev->pdata->prepare(edev); + gpiod_set_value_cansleep(edev->pdata->select, 1); ret = spi_sync(edev->spi, &m); /* have to wait at least Tcsl ns */ @@ -232,8 +223,7 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) dev_err(&edev->spi->dev, "erase/write %sable error %d\n", is_on ? "en" : "dis", ret); - if (edev->pdata->finish) - edev->pdata->finish(edev); + gpiod_set_value_cansleep(edev->pdata->select, 0); mutex_unlock(&edev->lock); return ret; @@ -312,8 +302,7 @@ static int eeprom_93xx46_write(void *priv, unsigned int off, mutex_lock(&edev->lock); - if (edev->pdata->prepare) - edev->pdata->prepare(edev); + gpiod_set_value_cansleep(edev->pdata->select, 1); for (i = 0; i < count; i += step) { ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); @@ -324,8 +313,7 @@ static int eeprom_93xx46_write(void *priv, unsigned int off, } } - if (edev->pdata->finish) - edev->pdata->finish(edev); + gpiod_set_value_cansleep(edev->pdata->select, 0); mutex_unlock(&edev->lock); @@ -336,7 +324,6 @@ static int eeprom_93xx46_write(void *priv, unsigned int off, static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) { - struct eeprom_93xx46_platform_data *pd = edev->pdata; struct spi_message m; struct spi_transfer t; int bits, ret; @@ -368,8 +355,7 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) mutex_lock(&edev->lock); - if (edev->pdata->prepare) - edev->pdata->prepare(edev); + gpiod_set_value_cansleep(edev->pdata->select, 1); ret = spi_sync(edev->spi, &m); if (ret) @@ -377,8 +363,7 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) /* have to wait erase cycle time Tec ms */ mdelay(6); - if (pd->finish) - pd->finish(edev); + gpiod_set_value_cansleep(edev->pdata->select, 0); mutex_unlock(&edev->lock); return ret; @@ -407,20 +392,6 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev, } static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); -static void select_assert(void *context) -{ - struct eeprom_93xx46_dev *edev = context; - - gpiod_set_value_cansleep(edev->pdata->select, 1); -} - -static void select_deassert(void *context) -{ - struct eeprom_93xx46_dev *edev = context; - - gpiod_set_value_cansleep(edev->pdata->select, 0); -} - static const struct of_device_id eeprom_93xx46_of_table[] = { { .compatible = "eeprom-93xx46", .data = &at93c46_data, }, { .compatible = "atmel,at93c46", .data = &at93c46_data, }, @@ -483,9 +454,6 @@ static int eeprom_93xx46_probe_fw(struct device *dev) return PTR_ERR(pd->select); gpiod_set_consumer_name(pd->select, "93xx46 EEPROMs OE"); - pd->prepare = select_assert; - pd->finish = select_deassert; - data = spi_get_device_match_data(to_spi_device(dev)); if (data) { pd->quirks = data->quirks; From 163898508f96efaafaa87000c7c4bbf711a34bd9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:46:59 +0300 Subject: [PATCH 037/330] misc: eeprom_93xx46: Use spi_message_init_with_transfers() Replace open coded spi_message_init_with_transfers(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240508184905.2102633-7-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 34 +++++++++++------------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index b6d699c1cd39..3f885bac72c2 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -5,6 +5,7 @@ * (C) 2011 DENX Software Engineering, Anatolij Gustschin */ +#include #include #include #include @@ -124,7 +125,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, while (count) { struct spi_message m; - struct spi_transfer t[2] = { { 0 } }; + struct spi_transfer t[2] = {}; u16 cmd_addr = OP_READ << edev->addrlen; size_t nbytes = count; @@ -146,17 +147,15 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, bits += 1; } - spi_message_init(&m); - t[0].tx_buf = (char *)&cmd_addr; t[0].len = 2; t[0].bits_per_word = bits; - spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; t[1].len = count; t[1].bits_per_word = 8; - spi_message_add_tail(&t[1], &m); + + spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t)); err = spi_sync(edev->spi, &m); /* have to wait at least Tcsl ns */ @@ -183,7 +182,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) { struct spi_message m; - struct spi_transfer t; + struct spi_transfer t = {}; int bits, ret; u16 cmd_addr; @@ -204,13 +203,11 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n", is_on ? "en" : "ds", cmd_addr, bits); - spi_message_init(&m); - memset(&t, 0, sizeof(t)); - t.tx_buf = &cmd_addr; t.len = 2; t.bits_per_word = bits; - spi_message_add_tail(&t, &m); + + spi_message_init_with_transfers(&m, &t, 1); mutex_lock(&edev->lock); @@ -234,7 +231,7 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, const char *buf, unsigned off) { struct spi_message m; - struct spi_transfer t[2]; + struct spi_transfer t[2] = {}; int bits, data_len, ret; u16 cmd_addr; @@ -256,18 +253,15 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr); - spi_message_init(&m); - memset(t, 0, sizeof(t)); - t[0].tx_buf = (char *)&cmd_addr; t[0].len = 2; t[0].bits_per_word = bits; - spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; t[1].len = data_len; t[1].bits_per_word = 8; - spi_message_add_tail(&t[1], &m); + + spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t)); ret = spi_sync(edev->spi, &m); /* have to wait program cycle time Twc ms */ @@ -325,7 +319,7 @@ static int eeprom_93xx46_write(void *priv, unsigned int off, static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) { struct spi_message m; - struct spi_transfer t; + struct spi_transfer t = {}; int bits, ret; u16 cmd_addr; @@ -345,13 +339,11 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits); - spi_message_init(&m); - memset(&t, 0, sizeof(t)); - t.tx_buf = &cmd_addr; t.len = 2; t.bits_per_word = bits; - spi_message_add_tail(&t, &m); + + spi_message_init_with_transfers(&m, &t, 1); mutex_lock(&edev->lock); From 761b4cf31741b2d0beda5de4c36253b553939263 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:47:00 +0300 Subject: [PATCH 038/330] misc: eeprom_93xx46: Convert to use kstrtox() sscanf() is a heavy one and moreover requires additional boundary checks. Convert driver to use kstrtobool() in eeprom_93xx46_store_erase(). Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-8-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 3f885bac72c2..18a3b534ea73 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -366,9 +366,13 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev, const char *buf, size_t count) { struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev); - int erase = 0, ret; + bool erase; + int ret; + + ret = kstrtobool(buf, &erase); + if (ret) + return ret; - sscanf(buf, "%d", &erase); if (erase) { ret = eeprom_93xx46_ew(edev, 1); if (ret) From f5efcdfe92b0032587d1a79db45ac657798d5d44 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:47:01 +0300 Subject: [PATCH 039/330] misc: eeprom_93xx46: Replace explicit castings with proper specifiers There is no need to have an explicit casting when we can simply use the correct printf() specifier. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-9-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 18a3b534ea73..ac485b2827db 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -162,8 +162,8 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, ndelay(250); if (err) { - dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n", - nbytes, (int)off, err); + dev_err(&edev->spi->dev, "read %zu bytes at %u: err. %d\n", + nbytes, off, err); break; } @@ -274,7 +274,8 @@ static int eeprom_93xx46_write(void *priv, unsigned int off, { struct eeprom_93xx46_dev *edev = priv; char *buf = val; - int i, ret, step = 1; + int ret, step = 1; + unsigned int i; if (unlikely(off >= edev->size)) return -EFBIG; @@ -301,8 +302,7 @@ static int eeprom_93xx46_write(void *priv, unsigned int off, for (i = 0; i < count; i += step) { ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); if (ret) { - dev_err(&edev->spi->dev, "write failed at %d: %d\n", - (int)off + i, ret); + dev_err(&edev->spi->dev, "write failed at %u: %d\n", off + i, ret); break; } } From b73602bf552b6422327c453772f30e64fcb4178d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:47:02 +0300 Subject: [PATCH 040/330] misc: eeprom_93xx46: Use string_choices API instead of ternary operator Use modern string_choices API instead of manually determining the output using ternary operator. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-10-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index ac485b2827db..ad3b3bc054da 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -200,8 +201,8 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) bits += 2; } - dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n", - is_on ? "en" : "ds", cmd_addr, bits); + dev_dbg(&edev->spi->dev, "ew %s cmd 0x%04x, %d bits\n", + str_enable_disable(is_on), cmd_addr, bits); t.tx_buf = &cmd_addr; t.len = 2; @@ -217,8 +218,8 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) /* have to wait at least Tcsl ns */ ndelay(250); if (ret) - dev_err(&edev->spi->dev, "erase/write %sable error %d\n", - is_on ? "en" : "dis", ret); + dev_err(&edev->spi->dev, "erase/write %s error %d\n", + str_enable_disable(is_on), ret); gpiod_set_value_cansleep(edev->pdata->select, 0); From 83f939f4d4b91c245ff4e58422c014969f3772a6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 21:47:03 +0300 Subject: [PATCH 041/330] misc: eeprom_93xx46: Convert to DEVICE_ATTR_WO() Use DEVICE_ATTR_WO() helper instead of plain DEVICE_ATTR(), which makes the code a bit shorter and easier to read. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240508184905.2102633-11-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index ad3b3bc054da..e2221be88445 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -362,9 +362,8 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) return ret; } -static ssize_t eeprom_93xx46_store_erase(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t erase_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev); bool erase; @@ -387,7 +386,7 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev, } return count; } -static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); +static DEVICE_ATTR_WO(erase); static const struct of_device_id eeprom_93xx46_of_table[] = { { .compatible = "eeprom-93xx46", .data = &at93c46_data, }, From 10724d5d477f8baadeaa183e288d6bd872bcade2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 10 May 2024 23:14:54 +0200 Subject: [PATCH 042/330] eeprom: Drop explicit initialization of struct i2c_device_id::driver_data to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These drivers don't use the driver_data member of struct i2c_device_id, so don't explicitly initialize this member. This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240510211454.2274614-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 2 +- drivers/misc/eeprom/idt_89hpesx.c | 96 +++++++++++++++---------------- drivers/misc/eeprom/max6875.c | 2 +- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 21feebc3044c..bf4f65dc6d9a 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -52,7 +52,7 @@ static struct ee1004_bus_data { } ee1004_bus_data[EE1004_MAX_BUSSES]; static const struct i2c_device_id ee1004_ids[] = { - { "ee1004", 0 }, + { "ee1004" }, { } }; MODULE_DEVICE_TABLE(i2c, ee1004_ids); diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 327afb866b21..43421fe37d33 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -1426,58 +1426,58 @@ MODULE_DEVICE_TABLE(i2c, ee_ids); * idt_ids - supported IDT 89HPESx devices */ static const struct i2c_device_id idt_ids[] = { - { "89hpes8nt2", 0 }, - { "89hpes12nt3", 0 }, + { "89hpes8nt2" }, + { "89hpes12nt3" }, - { "89hpes24nt6ag2", 0 }, - { "89hpes32nt8ag2", 0 }, - { "89hpes32nt8bg2", 0 }, - { "89hpes12nt12g2", 0 }, - { "89hpes16nt16g2", 0 }, - { "89hpes24nt24g2", 0 }, - { "89hpes32nt24ag2", 0 }, - { "89hpes32nt24bg2", 0 }, + { "89hpes24nt6ag2" }, + { "89hpes32nt8ag2" }, + { "89hpes32nt8bg2" }, + { "89hpes12nt12g2" }, + { "89hpes16nt16g2" }, + { "89hpes24nt24g2" }, + { "89hpes32nt24ag2" }, + { "89hpes32nt24bg2" }, - { "89hpes12n3", 0 }, - { "89hpes12n3a", 0 }, - { "89hpes24n3", 0 }, - { "89hpes24n3a", 0 }, + { "89hpes12n3" }, + { "89hpes12n3a" }, + { "89hpes24n3" }, + { "89hpes24n3a" }, - { "89hpes32h8", 0 }, - { "89hpes32h8g2", 0 }, - { "89hpes48h12", 0 }, - { "89hpes48h12g2", 0 }, - { "89hpes48h12ag2", 0 }, - { "89hpes16h16", 0 }, - { "89hpes22h16", 0 }, - { "89hpes22h16g2", 0 }, - { "89hpes34h16", 0 }, - { "89hpes34h16g2", 0 }, - { "89hpes64h16", 0 }, - { "89hpes64h16g2", 0 }, - { "89hpes64h16ag2", 0 }, + { "89hpes32h8" }, + { "89hpes32h8g2" }, + { "89hpes48h12" }, + { "89hpes48h12g2" }, + { "89hpes48h12ag2" }, + { "89hpes16h16" }, + { "89hpes22h16" }, + { "89hpes22h16g2" }, + { "89hpes34h16" }, + { "89hpes34h16g2" }, + { "89hpes64h16" }, + { "89hpes64h16g2" }, + { "89hpes64h16ag2" }, - /* { "89hpes3t3", 0 }, // No SMBus-slave iface */ - { "89hpes12t3g2", 0 }, - { "89hpes24t3g2", 0 }, - /* { "89hpes4t4", 0 }, // No SMBus-slave iface */ - { "89hpes16t4", 0 }, - { "89hpes4t4g2", 0 }, - { "89hpes10t4g2", 0 }, - { "89hpes16t4g2", 0 }, - { "89hpes16t4ag2", 0 }, - { "89hpes5t5", 0 }, - { "89hpes6t5", 0 }, - { "89hpes8t5", 0 }, - { "89hpes8t5a", 0 }, - { "89hpes24t6", 0 }, - { "89hpes6t6g2", 0 }, - { "89hpes24t6g2", 0 }, - { "89hpes16t7", 0 }, - { "89hpes32t8", 0 }, - { "89hpes32t8g2", 0 }, - { "89hpes48t12", 0 }, - { "89hpes48t12g2", 0 }, + /* { "89hpes3t3" }, // No SMBus-slave iface */ + { "89hpes12t3g2" }, + { "89hpes24t3g2" }, + /* { "89hpes4t4" }, // No SMBus-slave iface */ + { "89hpes16t4" }, + { "89hpes4t4g2" }, + { "89hpes10t4g2" }, + { "89hpes16t4g2" }, + { "89hpes16t4ag2" }, + { "89hpes5t5" }, + { "89hpes6t5" }, + { "89hpes8t5" }, + { "89hpes8t5a" }, + { "89hpes24t6" }, + { "89hpes6t6g2" }, + { "89hpes24t6g2" }, + { "89hpes16t7" }, + { "89hpes32t8" }, + { "89hpes32t8g2" }, + { "89hpes48t12" }, + { "89hpes48t12g2" }, { /* END OF LIST */ } }; MODULE_DEVICE_TABLE(i2c, idt_ids); diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c index cb6b1efeafe0..6fab2ffa736b 100644 --- a/drivers/misc/eeprom/max6875.c +++ b/drivers/misc/eeprom/max6875.c @@ -183,7 +183,7 @@ static void max6875_remove(struct i2c_client *client) } static const struct i2c_device_id max6875_id[] = { - { "max6875", 0 }, + { "max6875" }, { } }; MODULE_DEVICE_TABLE(i2c, max6875_id); From a774c5d1f9c4ad43411ee4010d8eb8e60b8e60a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sanju=C3=A1n=20Garc=C3=ADa=2C=20Jorge?= Date: Thu, 23 May 2024 10:35:03 +0000 Subject: [PATCH 043/330] mcb: mcb-pci: detect IO mapped devices before requesting resources If the memory region is requested with devm_request_mem_region() for an IO mapped device it will return an error and mcb-pci will incorrectly report it with EBUSY code. Make sure we identify if the reosure is IO mapped and fail early with a correct ENOTSUPP code. Reviewed-by: Jose Javier Rodriguez Barbarin Signed-off-by: Jorge Sanjuan Garcia Link: https://lore.kernel.org/r/20240523103430.423340-1-jorge.sanjuangarcia@duagon.com Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-pci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c index 53d9202ff9a7..3b634ea318c7 100644 --- a/drivers/mcb/mcb-pci.c +++ b/drivers/mcb/mcb-pci.c @@ -45,6 +45,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) } pci_set_master(pdev); + flags = pci_resource_flags(pdev, 0); + if (flags & IORESOURCE_IO) { + ret = -ENOTSUPP; + dev_err(&pdev->dev, + "IO mapped PCI devices are not supported\n"); + goto out_disable; + } + priv->mapbase = pci_resource_start(pdev, 0); if (!priv->mapbase) { dev_err(&pdev->dev, "No PCI resource\n"); @@ -68,14 +76,6 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_disable; } - flags = pci_resource_flags(pdev, 0); - if (flags & IORESOURCE_IO) { - ret = -ENOTSUPP; - dev_err(&pdev->dev, - "IO mapped PCI devices are not supported\n"); - goto out_disable; - } - pci_set_drvdata(pdev, priv); priv->bus = mcb_alloc_bus(&pdev->dev); From f311151600dc104e6eeb0d0437582e0cf37d6962 Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 14 May 2024 15:02:17 +0300 Subject: [PATCH 044/330] iio: adc: ad7192: Use standard attribute Replace custom attribute filter_low_pass_3db_frequency_available with standard attribute. Store the available values in ad7192_state struct. The function that used to compute those values replaced by ad7192_update_filter_freq_avail(). Function ad7192_show_filter_avail() is no longer needed. Note that the initial available values are hardcoded. Also moved the mutex lock and unlock in order to protect the whole switch statement since each branch modifies the state of the device. Reviewed-by: David Lechner Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20240514120222.56488-2-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 75 ++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 7bcc7e2aa2a2..ace81e3817a1 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -190,6 +190,7 @@ struct ad7192_state { u32 mode; u32 conf; u32 scale_avail[8][2]; + u32 filter_freq_avail[4][2]; u32 oversampling_ratio_avail[4]; u8 gpocon; u8 clock_sel; @@ -473,6 +474,16 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev) st->oversampling_ratio_avail[2] = 8; st->oversampling_ratio_avail[3] = 16; + st->filter_freq_avail[0][0] = 600; + st->filter_freq_avail[1][0] = 800; + st->filter_freq_avail[2][0] = 2300; + st->filter_freq_avail[3][0] = 2720; + + st->filter_freq_avail[0][1] = 1000; + st->filter_freq_avail[1][1] = 1000; + st->filter_freq_avail[2][1] = 1000; + st->filter_freq_avail[3][1] = 1000; + return 0; } @@ -586,48 +597,24 @@ static int ad7192_get_f_adc(struct ad7192_state *st) f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); } -static void ad7192_get_available_filter_freq(struct ad7192_state *st, - int *freq) +static void ad7192_update_filter_freq_avail(struct ad7192_state *st) { unsigned int fadc; /* Formulas for filter at page 25 of the datasheet */ fadc = ad7192_compute_f_adc(st, false, true); - freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024); + st->filter_freq_avail[0][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024); fadc = ad7192_compute_f_adc(st, true, true); - freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024); + st->filter_freq_avail[1][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024); fadc = ad7192_compute_f_adc(st, false, false); - freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024); + st->filter_freq_avail[2][0] = DIV_ROUND_CLOSEST(fadc * 230, 1024); fadc = ad7192_compute_f_adc(st, true, false); - freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024); + st->filter_freq_avail[3][0] = DIV_ROUND_CLOSEST(fadc * 272, 1024); } -static ssize_t ad7192_show_filter_avail(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7192_state *st = iio_priv(indio_dev); - unsigned int freq_avail[4], i; - size_t len = 0; - - ad7192_get_available_filter_freq(st, freq_avail); - - for (i = 0; i < ARRAY_SIZE(freq_avail); i++) - len += sysfs_emit_at(buf, len, "%d.%03d ", freq_avail[i] / 1000, - freq_avail[i] % 1000); - - buf[len - 1] = '\n'; - - return len; -} - -static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available, - 0444, ad7192_show_filter_avail, NULL, 0); - static IIO_DEVICE_ATTR(bridge_switch_en, 0644, ad7192_show_bridge_switch, ad7192_set, AD7192_REG_GPOCON); @@ -637,7 +624,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644, AD7192_REG_CONF); static struct attribute *ad7192_attributes[] = { - &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, NULL }; @@ -647,7 +633,6 @@ static const struct attribute_group ad7192_attribute_group = { }; static struct attribute *ad7195_attributes[] = { - &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, &iio_dev_attr_ac_excitation_en.dev_attr.attr, NULL @@ -665,17 +650,15 @@ static unsigned int ad7192_get_temp_scale(bool unipolar) static int ad7192_set_3db_filter_freq(struct ad7192_state *st, int val, int val2) { - int freq_avail[4], i, ret, freq; + int i, ret, freq; unsigned int diff_new, diff_old; int idx = 0; diff_old = U32_MAX; freq = val * 1000 + val2; - ad7192_get_available_filter_freq(st, freq_avail); - - for (i = 0; i < ARRAY_SIZE(freq_avail); i++) { - diff_new = abs(freq - freq_avail[i]); + for (i = 0; i < ARRAY_SIZE(st->filter_freq_avail); i++) { + diff_new = abs(freq - st->filter_freq_avail[i][0]); if (diff_new < diff_old) { diff_old = diff_new; idx = i; @@ -792,10 +775,11 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, if (ret) return ret; + mutex_lock(&st->lock); + switch (mask) { case IIO_CHAN_INFO_SCALE: ret = -EINVAL; - mutex_lock(&st->lock); for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) if (val2 == st->scale_avail[i][1]) { ret = 0; @@ -809,7 +793,6 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, ad7192_calibrate_all(st); break; } - mutex_unlock(&st->lock); break; case IIO_CHAN_INFO_SAMP_FREQ: if (!val) { @@ -826,13 +809,13 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, st->mode &= ~AD7192_MODE_RATE_MASK; st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div); ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); + ad7192_update_filter_freq_avail(st); break; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000); break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: ret = -EINVAL; - mutex_lock(&st->lock); for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++) if (val == st->oversampling_ratio_avail[i]) { ret = 0; @@ -845,12 +828,14 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, 3, st->mode); break; } - mutex_unlock(&st->lock); + ad7192_update_filter_freq_avail(st); break; default: ret = -EINVAL; } + mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); return ret; @@ -888,6 +873,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev, /* Values are stored in a 2D matrix */ *length = ARRAY_SIZE(st->scale_avail) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = (int *)st->filter_freq_avail; + *type = IIO_VAL_FRACTIONAL; + *length = ARRAY_SIZE(st->filter_freq_avail) * 2; + return IIO_AVAIL_LIST; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *vals = (int *)st->oversampling_ratio_avail; @@ -956,7 +947,9 @@ static const struct iio_info ad7195_info = { BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ (_mask_all), \ .info_mask_shared_by_type_available = (_mask_type_av), \ - .info_mask_shared_by_all_available = (_mask_all_av), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ + (_mask_all_av), \ .ext_info = (_ext_info), \ .scan_index = (_si), \ .scan_type = { \ From ecec83a236db6b0966d790fd582884b510ee11a3 Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 14 May 2024 15:02:18 +0300 Subject: [PATCH 045/330] dt-bindings: iio: adc: ad7192: Add aincom supply AINCOM should actually be a supply. AINx inputs are referenced to AINCOM in pseudo-differential operation mode. AINCOM voltage represents the offset of corresponding channels. Reviewed-by: Rob Herring (Arm) Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20240514120222.56488-3-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml index 16def2985ab4..cf5c568f140a 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml @@ -41,6 +41,11 @@ properties: interrupts: maxItems: 1 + aincom-supply: + description: | + AINCOM voltage supply. Analog inputs AINx are referenced to this input + when configured for pseudo-differential operation. + dvdd-supply: description: DVdd voltage supply @@ -117,6 +122,7 @@ examples: clock-names = "mclk"; interrupts = <25 0x2>; interrupt-parent = <&gpio>; + aincom-supply = <&aincom>; dvdd-supply = <&dvdd>; avdd-supply = <&avdd>; vref-supply = <&vref>; From 2b12a52b298f41ec581efc3047792c0535dd615c Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 14 May 2024 15:02:19 +0300 Subject: [PATCH 046/330] iio: adc: ad7192: Add aincom supply AINCOM should actually be a supply. AINx inputs are referenced to AINCOM in pseudo-differential operation mode. AINCOM voltage represents the offset of corresponding channels. Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20240514120222.56488-4-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 50 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index ace81e3817a1..7160929d32c9 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -186,6 +187,7 @@ struct ad7192_state { struct regulator *vref; struct clk *mclk; u16 int_vref_mv; + u32 aincom_mv; u32 fclk; u32 mode; u32 conf; @@ -742,10 +744,24 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, *val = -(1 << (chan->scan_type.realbits - 1)); else *val = 0; + + switch (chan->type) { + case IIO_VOLTAGE: + /* + * Only applies to pseudo-differential inputs. + * AINCOM voltage has to be converted to "raw" units. + */ + if (st->aincom_mv && !chan->differential) + *val += DIV_ROUND_CLOSEST_ULL((u64)st->aincom_mv * NANO, + st->scale_avail[gain][1]); + return IIO_VAL_INT; /* Kelvin to Celsius */ - if (chan->type == IIO_TEMP) + case IIO_TEMP: *val -= 273 * ad7192_get_temp_scale(unipolar); - return IIO_VAL_INT; + return IIO_VAL_INT; + default: + return -EINVAL; + } case IIO_CHAN_INFO_SAMP_FREQ: *val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024); return IIO_VAL_INT; @@ -1052,6 +1068,7 @@ static int ad7192_probe(struct spi_device *spi) { struct ad7192_state *st; struct iio_dev *indio_dev; + struct regulator *aincom; int ret; if (!spi->irq) { @@ -1067,6 +1084,35 @@ static int ad7192_probe(struct spi_device *spi) mutex_init(&st->lock); + /* + * Regulator aincom is optional to maintain compatibility with older DT. + * Newer firmware should provide a zero volt fixed supply if wired to + * ground. + */ + aincom = devm_regulator_get_optional(&spi->dev, "aincom"); + if (IS_ERR(aincom)) { + if (PTR_ERR(aincom) != -ENODEV) + return dev_err_probe(&spi->dev, PTR_ERR(aincom), + "Failed to get AINCOM supply\n"); + + st->aincom_mv = 0; + } else { + ret = regulator_enable(aincom); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to enable specified AINCOM supply\n"); + + ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom); + if (ret) + return ret; + + ret = regulator_get_voltage(aincom); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "Device tree error, AINCOM voltage undefined\n"); + st->aincom_mv = ret / MILLI; + } + st->avdd = devm_regulator_get(&spi->dev, "avdd"); if (IS_ERR(st->avdd)) return PTR_ERR(st->avdd); From dd471a2b7759daf6bbb2fbfec4258f60e0243183 Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 14 May 2024 15:02:20 +0300 Subject: [PATCH 047/330] dt-bindings: iio: adc: Add single-channel property Devices that have both single-ended channels and differential channels cause a bit of confusion when the channels are configured in the devicetree. Clarify difference between these two types of channels for such devices by adding single-channel property alongside diff-channels. They should be mutually exclusive. Devices that have only single-ended channels can still use reg property to reference a channel like before. Suggested-by: Jonathan Cameron Signed-off-by: Alisa-Dariana Roman Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240514120222.56488-5-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/adc.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml index 36775f8f71df..0a77592f7388 100644 --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml @@ -38,6 +38,14 @@ properties: The first value specifies the positive input pin, the second specifies the negative input pin. + single-channel: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + When devices combine single-ended and differential channels, allow the + channel for a single element to be specified, independent of reg (as for + differential channels). If this and diff-channels are not present reg + shall be used instead. + settling-time-us: description: Time between enabling the channel and first stable readings. @@ -50,4 +58,15 @@ properties: device design and can interact with other characteristics such as settling time. +anyOf: + - oneOf: + - required: + - reg + - diff-channels + - required: + - reg + - single-channel + - required: + - reg + additionalProperties: true From caf7b7632b8d83d410d162221dcc5d2d16db478f Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 14 May 2024 15:02:21 +0300 Subject: [PATCH 048/330] dt-bindings: iio: adc: ad7192: Add AD7194 support Unlike the other AD719Xs, AD7194 has configurable channels. The user can dynamically configure them in the devicetree. Also add an example for AD7194 devicetree. Signed-off-by: Alisa-Dariana Roman Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240514120222.56488-6-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7192.yaml | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml index cf5c568f140a..a03da9489ed9 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml @@ -21,8 +21,15 @@ properties: - adi,ad7190 - adi,ad7192 - adi,ad7193 + - adi,ad7194 - adi,ad7195 + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + reg: maxItems: 1 @@ -89,6 +96,42 @@ properties: description: see Documentation/devicetree/bindings/iio/adc/adc.yaml type: boolean +patternProperties: + "^channel@[0-9a-f]+$": + type: object + $ref: adc.yaml + unevaluatedProperties: false + + properties: + reg: + description: The channel index. + minimum: 0 + maximum: 271 + + diff-channels: + description: + Both inputs can be connected to pins AIN1 to AIN16 by choosing the + appropriate value from 1 to 16. + items: + minimum: 1 + maximum: 16 + + single-channel: + description: + Positive input can be connected to pins AIN1 to AIN16 by choosing the + appropriate value from 1 to 16. Negative input is connected to AINCOM. + items: + minimum: 1 + maximum: 16 + + oneOf: + - required: + - reg + - diff-channels + - required: + - reg + - single-channel + required: - compatible - reg @@ -103,6 +146,17 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + enum: + - adi,ad7190 + - adi,ad7192 + - adi,ad7193 + - adi,ad7195 + then: + patternProperties: + "^channel@[0-9a-f]+$": false unevaluatedProperties: false @@ -133,3 +187,38 @@ examples: adi,burnout-currents-enable; }; }; + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7194"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <1000000>; + spi-cpol; + spi-cpha; + clocks = <&ad7192_mclk>; + clock-names = "mclk"; + interrupts = <25 0x2>; + interrupt-parent = <&gpio>; + aincom-supply = <&aincom>; + dvdd-supply = <&dvdd>; + avdd-supply = <&avdd>; + vref-supply = <&vref>; + + channel@0 { + reg = <0>; + diff-channels = <1 6>; + }; + + channel@1 { + reg = <1>; + single-channel = <1>; + }; + }; + }; From a4c514e5f0da862d7897c2316895b2fff12bddfd Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Tue, 14 May 2024 15:02:22 +0300 Subject: [PATCH 049/330] iio: adc: ad7192: Add AD7194 support Unlike the other AD719Xs, AD7194 has configurable channels. The user can dynamically configure them in the devicetree. Add sigma_delta_info member to chip_info structure. Since AD7194 is the only chip that has no channel sequencer, num_slots should remain undefined. Also modify config AD7192 description for better scaling. Signed-off-by: Alisa-Dariana Roman Link: https://lore.kernel.org/r/20240514120222.56488-7-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 11 ++- drivers/iio/adc/ad7192.c | 148 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 151 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 8db68b80b391..74fecc284f1a 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -88,12 +88,17 @@ config AD7173 called ad7173. config AD7192 - tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver" + tristate "Analog Devices AD7192 and similar ADC driver" depends on SPI select AD_SIGMA_DELTA help - Say yes here to build support for Analog Devices AD7190, - AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC). + Say yes here to build support for Analog Devices SPI analog to digital + converters (ADC): + - AD7190 + - AD7192 + - AD7193 + - AD7194 + - AD7195 If unsure, say N (but it's safe to say "Y"). To compile this driver as a module, choose M here: the diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 7160929d32c9..0789121236d6 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * AD7190 AD7192 AD7193 AD7195 SPI ADC driver + * AD7192 and similar SPI ADC driver * * Copyright 2011-2015 Analog Devices Inc. */ @@ -129,10 +129,24 @@ #define AD7193_CH_AIN8 0x480 /* AIN7 - AINCOM */ #define AD7193_CH_AINCOM 0x600 /* AINCOM - AINCOM */ +#define AD7194_CH_POS(x) (((x) - 1) << 4) +#define AD7194_CH_NEG(x) ((x) - 1) + +/* 10th bit corresponds to CON18(Pseudo) */ +#define AD7194_CH(p) (BIT(10) | AD7194_CH_POS(p)) + +#define AD7194_DIFF_CH(p, n) (AD7194_CH_POS(p) | AD7194_CH_NEG(n)) +#define AD7194_CH_TEMP 0x100 +#define AD7194_CH_BASE_NR 2 +#define AD7194_CH_AIN_START 1 +#define AD7194_CH_AIN_NR 16 +#define AD7194_CH_MAX_NR 272 + /* ID Register Bit Designations (AD7192_REG_ID) */ #define CHIPID_AD7190 0x4 #define CHIPID_AD7192 0x0 #define CHIPID_AD7193 0x2 +#define CHIPID_AD7194 0x3 #define CHIPID_AD7195 0x6 #define AD7192_ID_MASK GENMASK(3, 0) @@ -170,6 +184,7 @@ enum { ID_AD7190, ID_AD7192, ID_AD7193, + ID_AD7194, ID_AD7195, }; @@ -178,7 +193,9 @@ struct ad7192_chip_info { const char *name; const struct iio_chan_spec *channels; u8 num_channels; + const struct ad_sigma_delta_info *sigma_delta_info; const struct iio_info *info; + int (*parse_channels)(struct iio_dev *indio_dev); }; struct ad7192_state { @@ -346,6 +363,18 @@ static const struct ad_sigma_delta_info ad7192_sigma_delta_info = { .irq_flags = IRQF_TRIGGER_FALLING, }; +static const struct ad_sigma_delta_info ad7194_sigma_delta_info = { + .set_channel = ad7192_set_channel, + .append_status = ad7192_append_status, + .disable_all = ad7192_disable_all, + .set_mode = ad7192_set_mode, + .has_registers = true, + .addr_shift = 3, + .read_mask = BIT(6), + .status_ch_mask = GENMASK(3, 0), + .irq_flags = IRQF_TRIGGER_FALLING, +}; + static const struct ad_sd_calib_data ad7192_calib_arr[8] = { {AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN1}, {AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN1}, @@ -937,6 +966,14 @@ static const struct iio_info ad7192_info = { .update_scan_mode = ad7192_update_scan_mode, }; +static const struct iio_info ad7194_info = { + .read_raw = ad7192_read_raw, + .write_raw = ad7192_write_raw, + .write_raw_get_fmt = ad7192_write_raw_get_fmt, + .read_avail = ad7192_read_avail, + .validate_trigger = ad_sd_validate_trigger, +}; + static const struct iio_info ad7195_info = { .read_raw = ad7192_read_raw, .write_raw = ad7192_write_raw, @@ -1028,12 +1065,95 @@ static const struct iio_chan_spec ad7193_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(14), }; +static bool ad7194_validate_ain_channel(struct device *dev, u32 ain) +{ + return in_range(ain, AD7194_CH_AIN_START, AD7194_CH_AIN_NR); +} + +static int ad7194_parse_channels(struct iio_dev *indio_dev) +{ + struct device *dev = indio_dev->dev.parent; + struct iio_chan_spec *ad7194_channels; + const struct iio_chan_spec ad7194_chan = AD7193_CHANNEL(0, 0, 0); + const struct iio_chan_spec ad7194_chan_diff = AD7193_DIFF_CHANNEL(0, 0, 0, 0); + const struct iio_chan_spec ad7194_chan_temp = AD719x_TEMP_CHANNEL(0, 0); + const struct iio_chan_spec ad7194_chan_timestamp = IIO_CHAN_SOFT_TIMESTAMP(0); + unsigned int num_channels, index = 0; + u32 ain[2]; + int ret; + + num_channels = device_get_child_node_count(dev); + if (num_channels > AD7194_CH_MAX_NR) + return dev_err_probe(dev, -EINVAL, "Too many channels: %u\n", + num_channels); + + num_channels += AD7194_CH_BASE_NR; + + ad7194_channels = devm_kcalloc(dev, num_channels, + sizeof(*ad7194_channels), GFP_KERNEL); + if (!ad7194_channels) + return -ENOMEM; + + indio_dev->channels = ad7194_channels; + indio_dev->num_channels = num_channels; + + device_for_each_child_node_scoped(dev, child) { + ret = fwnode_property_read_u32_array(child, "diff-channels", + ain, ARRAY_SIZE(ain)); + if (ret == 0) { + if (!ad7194_validate_ain_channel(dev, ain[0])) + return dev_err_probe(dev, -EINVAL, + "Invalid AIN channel: %u\n", + ain[0]); + + if (!ad7194_validate_ain_channel(dev, ain[1])) + return dev_err_probe(dev, -EINVAL, + "Invalid AIN channel: %u\n", + ain[1]); + + *ad7194_channels = ad7194_chan_diff; + ad7194_channels->scan_index = index++; + ad7194_channels->channel = ain[0]; + ad7194_channels->channel2 = ain[1]; + ad7194_channels->address = AD7194_DIFF_CH(ain[0], ain[1]); + } else { + ret = fwnode_property_read_u32(child, "single-channel", + &ain[0]); + if (ret) + return dev_err_probe(dev, ret, + "Missing channel property\n"); + + if (!ad7194_validate_ain_channel(dev, ain[0])) + return dev_err_probe(dev, -EINVAL, + "Invalid AIN channel: %u\n", + ain[0]); + + *ad7194_channels = ad7194_chan; + ad7194_channels->scan_index = index++; + ad7194_channels->channel = ain[0]; + ad7194_channels->address = AD7194_CH(ain[0]); + } + ad7194_channels++; + } + + *ad7194_channels = ad7194_chan_temp; + ad7194_channels->scan_index = index++; + ad7194_channels->address = AD7194_CH_TEMP; + ad7194_channels++; + + *ad7194_channels = ad7194_chan_timestamp; + ad7194_channels->scan_index = index; + + return 0; +} + static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { [ID_AD7190] = { .chip_id = CHIPID_AD7190, .name = "ad7190", .channels = ad7192_channels, .num_channels = ARRAY_SIZE(ad7192_channels), + .sigma_delta_info = &ad7192_sigma_delta_info, .info = &ad7192_info, }, [ID_AD7192] = { @@ -1041,6 +1161,7 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { .name = "ad7192", .channels = ad7192_channels, .num_channels = ARRAY_SIZE(ad7192_channels), + .sigma_delta_info = &ad7192_sigma_delta_info, .info = &ad7192_info, }, [ID_AD7193] = { @@ -1048,13 +1169,22 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { .name = "ad7193", .channels = ad7193_channels, .num_channels = ARRAY_SIZE(ad7193_channels), + .sigma_delta_info = &ad7192_sigma_delta_info, .info = &ad7192_info, }, + [ID_AD7194] = { + .chip_id = CHIPID_AD7194, + .name = "ad7194", + .info = &ad7194_info, + .sigma_delta_info = &ad7194_sigma_delta_info, + .parse_channels = ad7194_parse_channels, + }, [ID_AD7195] = { .chip_id = CHIPID_AD7195, .name = "ad7195", .channels = ad7192_channels, .num_channels = ARRAY_SIZE(ad7192_channels), + .sigma_delta_info = &ad7192_sigma_delta_info, .info = &ad7195_info, }, }; @@ -1161,11 +1291,17 @@ static int ad7192_probe(struct spi_device *spi) st->chip_info = spi_get_device_match_data(spi); indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = st->chip_info->num_channels; indio_dev->info = st->chip_info->info; + if (st->chip_info->parse_channels) { + ret = st->chip_info->parse_channels(indio_dev); + if (ret) + return ret; + } else { + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + } - ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info); + ret = ad_sd_init(&st->sd, indio_dev, spi, st->chip_info->sigma_delta_info); if (ret) return ret; @@ -1202,6 +1338,7 @@ static const struct of_device_id ad7192_of_match[] = { { .compatible = "adi,ad7190", .data = &ad7192_chip_info_tbl[ID_AD7190] }, { .compatible = "adi,ad7192", .data = &ad7192_chip_info_tbl[ID_AD7192] }, { .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] }, + { .compatible = "adi,ad7194", .data = &ad7192_chip_info_tbl[ID_AD7194] }, { .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] }, {} }; @@ -1211,6 +1348,7 @@ static const struct spi_device_id ad7192_ids[] = { { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] }, { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] }, { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] }, + { "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] }, { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] }, {} }; @@ -1227,6 +1365,6 @@ static struct spi_driver ad7192_driver = { module_spi_driver(ad7192_driver); MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC"); +MODULE_DESCRIPTION("Analog Devices AD7192 and similar ADC"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); From 1568f94f29dd6b0e33a9123c432214b5756ad708 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 23 May 2024 00:04:55 +0100 Subject: [PATCH 050/330] iio: accel: bmi088: remove unused struct 'bmi088_scale_info' 'bmi088_scale_info' has been unused since the original commit c19ae6be7555 ("iio: accel: Add support for the Bosch-Sensortec BMI088"). Remove it. Signed-off-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20240522230457.478156-2-linux@treblig.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmi088-accel-core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c index 4d989708e6c3..469a1255d93c 100644 --- a/drivers/iio/accel/bmi088-accel-core.c +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -114,11 +114,6 @@ enum bmi088_odr_modes { BMI088_ACCEL_MODE_ODR_1600 = 0xc, }; -struct bmi088_scale_info { - int scale; - u8 reg_range; -}; - struct bmi088_accel_chip_info { const char *name; u8 chip_id; From 64741cb5acfb8a1cf1c4a61ec0d8cd1310ceca90 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 23 May 2024 00:04:56 +0100 Subject: [PATCH 051/330] iio: adc: pac1934: remove unused struct 'samp_rate_mapping' 'samp_rate_mapping' has been unused since the original commit 0fb528c8255b ("iio: adc: adding support for PAC193x"). Remove it. Signed-off-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20240522230457.478156-3-linux@treblig.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/pac1934.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index 456f12faa348..ae24a27805ab 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -227,11 +227,6 @@ struct pac1934_features { const char *name; }; -struct samp_rate_mapping { - u16 samp_rate; - u8 shift2value; -}; - static const unsigned int samp_rate_map_tbl[] = { [PAC1934_SAMP_1024SPS] = 1024, [PAC1934_SAMP_256SPS] = 256, From 4d8c7da08be5ef48ef0c3d4ea1a25733b03d626a Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 23 May 2024 00:04:57 +0100 Subject: [PATCH 052/330] iio: light: rohm-bu27034: remove unused struct 'bu27034_result' 'bu27034_result' is unused since the original commit e52afbd61039 ("iio: light: ROHM BU27034 Ambient Light Sensor"). Remove it. Signed-off-by: Dr. David Alan Gilbert Acked-by: Matti Vaittinen Link: https://lore.kernel.org/r/20240522230457.478156-4-linux@treblig.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/rohm-bu27034.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c index bf3de853a811..4937bf6fa046 100644 --- a/drivers/iio/light/rohm-bu27034.c +++ b/drivers/iio/light/rohm-bu27034.c @@ -223,12 +223,6 @@ struct bu27034_data { } scan; }; -struct bu27034_result { - u16 ch0; - u16 ch1; - u16 ch2; -}; - static const struct regmap_range bu27034_volatile_ranges[] = { { .range_min = BU27034_REG_SYSTEM_CONTROL, From 709aeedcc7cfadb2f9c3ac29b0cda337c6b57b7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= Date: Tue, 21 May 2024 17:34:51 +0200 Subject: [PATCH 053/330] iio: light: stk3310: relax failure to match id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relax failure to match ID to a warning rather than probe fail. This add abilty to use other compatible variants when chip id is not defined in the driver. Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20240521-stk3311-v1-1-07a4966b355a@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 3a03823e488a..c2dd42664681 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -477,8 +477,7 @@ static int stk3310_init(struct iio_dev *indio_dev) chipid != STK3311_CHIP_ID_VAL && chipid != STK3311X_CHIP_ID_VAL && chipid != STK3335_CHIP_ID_VAL) { - dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid); - return -ENODEV; + dev_warn(&client->dev, "unknown chip id: 0x%x\n", chipid); } state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS; From 745712c7bb1f8eaf00cf3b5a49c3c13bd7805597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= Date: Tue, 21 May 2024 17:34:52 +0200 Subject: [PATCH 054/330] iio: light: stk3310: make chip id check expandable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify chip id check for support easier additions for compatible variants. Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20240521-stk3311-v1-2-07a4966b355a@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index c2dd42664681..56627332c3d6 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -81,6 +81,13 @@ static const struct reg_field stk3310_reg_field_flag_psint = static const struct reg_field stk3310_reg_field_flag_nf = REG_FIELD(STK3310_REG_FLAG, 0, 0); +static const u8 stk3310_chip_ids[] = { + STK3310_CHIP_ID_VAL, + STK3311X_CHIP_ID_VAL, + STK3311_CHIP_ID_VAL, + STK3335_CHIP_ID_VAL, +}; + /* Estimate maximum proximity values with regard to measurement scale. */ static const int stk3310_ps_max[4] = { STK3310_PS_MAX_VAL / 640, @@ -197,6 +204,16 @@ static const struct attribute_group stk3310_attribute_group = { .attrs = stk3310_attributes }; +static int stk3310_check_chip_id(const u8 chip_id) +{ + for (int i = 0; i < ARRAY_SIZE(stk3310_chip_ids); i++) { + if (chip_id == stk3310_chip_ids[i]) + return 0; + } + + return -ENODEV; +} + static int stk3310_get_index(const int table[][2], int table_size, int val, int val2) { @@ -473,12 +490,9 @@ static int stk3310_init(struct iio_dev *indio_dev) if (ret < 0) return ret; - if (chipid != STK3310_CHIP_ID_VAL && - chipid != STK3311_CHIP_ID_VAL && - chipid != STK3311X_CHIP_ID_VAL && - chipid != STK3335_CHIP_ID_VAL) { + ret = stk3310_check_chip_id(chipid); + if (ret < 0) dev_warn(&client->dev, "unknown chip id: 0x%x\n", chipid); - } state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS; ret = stk3310_set_state(data, state); From cba37c2e532dc234cc8ea1894f130ca39948d4a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= Date: Tue, 21 May 2024 17:34:53 +0200 Subject: [PATCH 055/330] iio: light: stk3310: support more stk3311 variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for more stk3311 variants like stk3311-a and stk3311-s34, they are register compatible but they have different chip ids. Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20240521-stk3311-v1-3-07a4966b355a@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 56627332c3d6..e3470d6743ef 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -37,6 +37,8 @@ #define STK3310_CHIP_ID_VAL 0x13 #define STK3311_CHIP_ID_VAL 0x1D +#define STK3311A_CHIP_ID_VAL 0x15 +#define STK3311S34_CHIP_ID_VAL 0x1E #define STK3311X_CHIP_ID_VAL 0x12 #define STK3335_CHIP_ID_VAL 0x51 #define STK3310_PSINT_EN 0x01 @@ -83,6 +85,8 @@ static const struct reg_field stk3310_reg_field_flag_nf = static const u8 stk3310_chip_ids[] = { STK3310_CHIP_ID_VAL, + STK3311A_CHIP_ID_VAL, + STK3311S34_CHIP_ID_VAL, STK3311X_CHIP_ID_VAL, STK3311_CHIP_ID_VAL, STK3335_CHIP_ID_VAL, From 7a8e7f13f99b31c85b77b362cb7b7a23fead11d3 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Wed, 22 May 2024 14:54:05 +0200 Subject: [PATCH 056/330] iio: adc: ad9467: use DMA safe buffer for spi Make sure we use a DMA safe buffer (IIO_DMA_MINALIGN) for all the spi transfers. Only relevant for writes since for reads spi_write_then_read() is used which does not require DMA safe buffers. Also note that for consistency, ad9467_spi_read() is also taking struct ad9467_state as a parameter (even if not really needed). Fixes: ad6797120238 ("iio: adc: ad9467: add support AD9467 ADC") Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240522-dev-ad9467-dma-v2-1-a37bec463632@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad9467.c | 65 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index e85b763b9ffc..3571cfe0f9cc 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -141,9 +141,10 @@ struct ad9467_state { struct gpio_desc *pwrdown_gpio; /* ensure consistent state obtained on multiple related accesses */ struct mutex lock; + u8 buf[3] __aligned(IIO_DMA_MINALIGN); }; -static int ad9467_spi_read(struct spi_device *spi, unsigned int reg) +static int ad9467_spi_read(struct ad9467_state *st, unsigned int reg) { unsigned char tbuf[2], rbuf[1]; int ret; @@ -151,7 +152,7 @@ static int ad9467_spi_read(struct spi_device *spi, unsigned int reg) tbuf[0] = 0x80 | (reg >> 8); tbuf[1] = reg & 0xFF; - ret = spi_write_then_read(spi, + ret = spi_write_then_read(st->spi, tbuf, ARRAY_SIZE(tbuf), rbuf, ARRAY_SIZE(rbuf)); @@ -161,35 +162,32 @@ static int ad9467_spi_read(struct spi_device *spi, unsigned int reg) return rbuf[0]; } -static int ad9467_spi_write(struct spi_device *spi, unsigned int reg, +static int ad9467_spi_write(struct ad9467_state *st, unsigned int reg, unsigned int val) { - unsigned char buf[3]; + st->buf[0] = reg >> 8; + st->buf[1] = reg & 0xFF; + st->buf[2] = val; - buf[0] = reg >> 8; - buf[1] = reg & 0xFF; - buf[2] = val; - - return spi_write(spi, buf, ARRAY_SIZE(buf)); + return spi_write(st->spi, st->buf, ARRAY_SIZE(st->buf)); } static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { struct ad9467_state *st = iio_priv(indio_dev); - struct spi_device *spi = st->spi; int ret; if (!readval) { guard(mutex)(&st->lock); - ret = ad9467_spi_write(spi, reg, writeval); + ret = ad9467_spi_write(st, reg, writeval); if (ret) return ret; - return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER, + return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER, AN877_ADC_TRANSFER_SYNC); } - ret = ad9467_spi_read(spi, reg); + ret = ad9467_spi_read(st, reg); if (ret < 0) return ret; *readval = ret; @@ -295,7 +293,7 @@ static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2) unsigned int i, vref_val; int ret; - ret = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF); + ret = ad9467_spi_read(st, AN877_ADC_REG_VREF); if (ret < 0) return ret; @@ -330,31 +328,31 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2) continue; guard(mutex)(&st->lock); - ret = ad9467_spi_write(st->spi, AN877_ADC_REG_VREF, + ret = ad9467_spi_write(st, AN877_ADC_REG_VREF, info->scale_table[i][1]); if (ret < 0) return ret; - return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER, AN877_ADC_TRANSFER_SYNC); } return -EINVAL; } -static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) +static int ad9467_outputmode_set(struct ad9467_state *st, unsigned int mode) { int ret; - ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode); + ret = ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_MODE, mode); if (ret < 0) return ret; - return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER, + return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER, AN877_ADC_TRANSFER_SYNC); } -static int ad9647_calibrate_prepare(const struct ad9467_state *st) +static int ad9647_calibrate_prepare(struct ad9467_state *st) { struct iio_backend_data_fmt data = { .enable = false, @@ -362,17 +360,17 @@ static int ad9647_calibrate_prepare(const struct ad9467_state *st) unsigned int c; int ret; - ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO, + ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO, AN877_ADC_TESTMODE_PN9_SEQ); if (ret) return ret; - ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + ret = ad9467_spi_write(st, AN877_ADC_REG_TRANSFER, AN877_ADC_TRANSFER_SYNC); if (ret) return ret; - ret = ad9467_outputmode_set(st->spi, st->info->default_output_mode); + ret = ad9467_outputmode_set(st, st->info->default_output_mode); if (ret) return ret; @@ -390,7 +388,7 @@ static int ad9647_calibrate_prepare(const struct ad9467_state *st) return iio_backend_chan_enable(st->back, 0); } -static int ad9647_calibrate_polarity_set(const struct ad9467_state *st, +static int ad9647_calibrate_polarity_set(struct ad9467_state *st, bool invert) { enum iio_backend_sample_trigger trigger; @@ -401,7 +399,7 @@ static int ad9647_calibrate_polarity_set(const struct ad9467_state *st, if (invert) phase |= AN877_ADC_INVERT_DCO_CLK; - return ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_PHASE, + return ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_PHASE, phase); } @@ -437,19 +435,18 @@ static unsigned int ad9467_find_optimal_point(const unsigned long *calib_map, return cnt; } -static int ad9467_calibrate_apply(const struct ad9467_state *st, - unsigned int val) +static int ad9467_calibrate_apply(struct ad9467_state *st, unsigned int val) { unsigned int lane; int ret; if (st->info->has_dco) { - ret = ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_DELAY, + ret = ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_DELAY, val); if (ret) return ret; - return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER, AN877_ADC_TRANSFER_SYNC); } @@ -462,7 +459,7 @@ static int ad9467_calibrate_apply(const struct ad9467_state *st, return 0; } -static int ad9647_calibrate_stop(const struct ad9467_state *st) +static int ad9647_calibrate_stop(struct ad9467_state *st) { struct iio_backend_data_fmt data = { .sign_extend = true, @@ -487,16 +484,16 @@ static int ad9647_calibrate_stop(const struct ad9467_state *st) } mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; - ret = ad9467_outputmode_set(st->spi, mode); + ret = ad9467_outputmode_set(st, mode); if (ret) return ret; - ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO, + ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO, AN877_ADC_TESTMODE_OFF); if (ret) return ret; - return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER, AN877_ADC_TRANSFER_SYNC); } @@ -846,7 +843,7 @@ static int ad9467_probe(struct spi_device *spi) if (ret) return ret; - id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID); + id = ad9467_spi_read(st, AN877_ADC_REG_CHIP_ID); if (id != st->info->id) { dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", id, st->info->id); From fefbc4a5d60da4b5367313d5d8ac1f777f2fb2a8 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Wed, 22 May 2024 14:54:06 +0200 Subject: [PATCH 057/330] iio: adc: ad9467: change struct members padding Using tabs and maintaining the start of the variables aligned is a pain and may lead to lot's of unrelated changes when adding new members. Hence, let's change things now and just have a simple space. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240522-dev-ad9467-dma-v2-2-a37bec463632@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad9467.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 3571cfe0f9cc..ec11437cac7e 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -107,27 +107,27 @@ #define AD9647_MAX_TEST_POINTS 32 struct ad9467_chip_info { - const char *name; - unsigned int id; - const struct iio_chan_spec *channels; - unsigned int num_channels; - const unsigned int (*scale_table)[2]; - int num_scales; - unsigned long max_rate; - unsigned int default_output_mode; - unsigned int vref_mask; - unsigned int num_lanes; + const char *name; + unsigned int id; + const struct iio_chan_spec *channels; + unsigned int num_channels; + const unsigned int (*scale_table)[2]; + int num_scales; + unsigned long max_rate; + unsigned int default_output_mode; + unsigned int vref_mask; + unsigned int num_lanes; /* data clock output */ - bool has_dco; + bool has_dco; }; struct ad9467_state { - const struct ad9467_chip_info *info; - struct iio_backend *back; - struct spi_device *spi; - struct clk *clk; - unsigned int output_mode; - unsigned int (*scales)[2]; + const struct ad9467_chip_info *info; + struct iio_backend *back; + struct spi_device *spi; + struct clk *clk; + unsigned int output_mode; + unsigned int (*scales)[2]; /* * Times 2 because we may also invert the signal polarity and run the * calibration again. For some reference on the test points (ad9265) see: @@ -138,10 +138,10 @@ struct ad9467_state { * at the io delay control section. */ DECLARE_BITMAP(calib_map, AD9647_MAX_TEST_POINTS * 2); - struct gpio_desc *pwrdown_gpio; + struct gpio_desc *pwrdown_gpio; /* ensure consistent state obtained on multiple related accesses */ - struct mutex lock; - u8 buf[3] __aligned(IIO_DMA_MINALIGN); + struct mutex lock; + u8 buf[3] __aligned(IIO_DMA_MINALIGN); }; static int ad9467_spi_read(struct ad9467_state *st, unsigned int reg) From 0fbce5d171e489cd21a67773331716c9cc752890 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 22 May 2024 17:01:36 +0200 Subject: [PATCH 058/330] dt-bindings: iio: dac: fix ad3552r gain parameter names The adi,gain-scaling-p/n values are an inverted log2, so initial naming was set correctly, but the driver uses just adi,gain-scaling-p/n, and if fdt is created accordingly with the fdt bindings documentation, driver fails the probe. Observing that: - the Linux driver is the only consumer, - there are no upstreamed dts nodes related to ad3552r, the fix to the documentation side is preferred and less-risk. Fixes: b0a96c5f599e ("dt-bindings: iio: dac: Add adi,ad3552r.yaml") Signed-off-by: Angelo Dureghello Reviewed-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240522150141.1776196-2-adureghello@baylibre.org Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/dac/adi,ad3552r.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml index 96340a05754c..b4a5542060eb 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml @@ -92,13 +92,13 @@ patternProperties: maximum: 511 minimum: -511 - adi,gain-scaling-p-inv-log2: - description: GainP = 1 / ( 2 ^ adi,gain-scaling-p-inv-log2) + adi,gain-scaling-p: + description: GainP = 1 / ( 2 ^ adi,gain-scaling-p) $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2, 3] - adi,gain-scaling-n-inv-log2: - description: GainN = 1 / ( 2 ^ adi,gain-scaling-n-inv-log2) + adi,gain-scaling-n: + description: GainN = 1 / ( 2 ^ adi,gain-scaling-n) $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2, 3] @@ -107,8 +107,8 @@ patternProperties: required: - adi,gain-offset - - adi,gain-scaling-p-inv-log2 - - adi,gain-scaling-n-inv-log2 + - adi,gain-scaling-p + - adi,gain-scaling-n - adi,rfb-ohms required: @@ -208,8 +208,8 @@ examples: reg = <1>; custom-output-range-config { adi,gain-offset = <5>; - adi,gain-scaling-p-inv-log2 = <1>; - adi,gain-scaling-n-inv-log2 = <2>; + adi,gain-scaling-p = <1>; + adi,gain-scaling-n = <2>; adi,rfb-ohms = <1>; }; }; From 80ea2007638017b18b0a900e605d7804aaf8d1ae Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 22 May 2024 17:01:37 +0200 Subject: [PATCH 059/330] dt-bindings: iio: dac: add ad35xxr single output variants Add support for ad3541r and ad3551r single output variants. Signed-off-by: Angelo Dureghello Reviewed-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240522150141.1776196-3-adureghello@baylibre.org Signed-off-by: Jonathan Cameron --- .../bindings/iio/dac/adi,ad3552r.yaml | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml index b4a5542060eb..0ea15d198001 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml @@ -13,13 +13,17 @@ maintainers: description: | Bindings for the Analog Devices AD3552R DAC device and similar. Datasheet can be found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad3541r.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/ad3542r.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad3551r.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/ad3552r.pdf properties: compatible: enum: + - adi,ad3541r - adi,ad3542r + - adi,ad3551r - adi,ad3552r reg: @@ -128,7 +132,9 @@ allOf: properties: compatible: contains: - const: adi,ad3542r + enum: + - adi,ad3541r + - adi,ad3542r then: patternProperties: "^channel@([0-1])$": @@ -158,7 +164,9 @@ allOf: properties: compatible: contains: - const: adi,ad3552r + enum: + - adi,ad3551r + - adi,ad3552r then: patternProperties: "^channel@([0-1])$": @@ -182,6 +190,21 @@ allOf: - const: -10000000 - const: 10000000 + - if: + properties: + compatible: + contains: + enum: + - adi,ad3541r + - adi,ad3551r + then: + properties: + channel@1: false + channel@0: + properties: + reg: + const: 0 + required: - compatible - reg From 2334d5e0b7af8912f140e1df16bd94fb3ab98578 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 22 May 2024 17:01:38 +0200 Subject: [PATCH 060/330] iio: dac: ad3552r: add model data structure Add a "model data" structure to keep useful hardware-related information as from datasheet, avoiding id-based conditional choices later on. Removed id-based checks and filled model-specific structures with device specific features, In particular, num_hw_channels is introduced to keep the number of hardware implemented channels, since 1-channel versions of the DACs are added in this same patchset. Signed-off-by: Angelo Dureghello Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240522150141.1776196-4-adureghello@baylibre.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 98 +++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index 8aa942896b5b..d637a8722f17 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -261,7 +261,17 @@ struct ad3552r_ch_data { bool range_override; }; +struct ad3552r_model_data { + const char *model_name; + enum ad3542r_id chip_id; + unsigned int num_hw_channels; + const s32 (*ranges_table)[2]; + int num_ranges; + bool requires_output_range; +}; + struct ad3552r_desc { + const struct ad3552r_model_data *model_data; /* Used to look the spi bus for atomic operations where needed */ struct mutex lock; struct gpio_desc *gpio_reset; @@ -271,7 +281,6 @@ struct ad3552r_desc { struct iio_chan_spec channels[AD3552R_NUM_CH + 1]; unsigned long enabled_ch; unsigned int num_ch; - enum ad3542r_id chip_id; }; static const u16 addr_mask_map[][2] = { @@ -745,13 +754,8 @@ static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch) } else { /* Normal range */ idx = dac->ch_data[ch].range; - if (dac->chip_id == AD3542R_ID) { - v_min = ad3542r_ch_ranges[idx][0]; - v_max = ad3542r_ch_ranges[idx][1]; - } else { - v_min = ad3552r_ch_ranges[idx][0]; - v_max = ad3552r_ch_ranges[idx][1]; - } + v_min = dac->model_data->ranges_table[idx][0]; + v_max = dac->model_data->ranges_table[idx][1]; } /* @@ -775,22 +779,14 @@ static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch) dac->ch_data[ch].offset_dec = div_s64(tmp, span); } -static int ad3552r_find_range(u16 id, s32 *vals) +static int ad3552r_find_range(const struct ad3552r_model_data *model_data, + s32 *vals) { - int i, len; - const s32 (*ranges)[2]; + int i; - if (id == AD3542R_ID) { - len = ARRAY_SIZE(ad3542r_ch_ranges); - ranges = ad3542r_ch_ranges; - } else { - len = ARRAY_SIZE(ad3552r_ch_ranges); - ranges = ad3552r_ch_ranges; - } - - for (i = 0; i < len; i++) - if (vals[0] == ranges[i][0] * 1000 && - vals[1] == ranges[i][1] * 1000) + for (i = 0; i < model_data->num_ranges; i++) + if (vals[0] == model_data->ranges_table[i][0] * 1000 && + vals[1] == model_data->ranges_table[i][1] * 1000) return i; return -EINVAL; @@ -940,10 +936,10 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) if (err) return dev_err_probe(dev, err, "mandatory reg property missing\n"); - if (ch >= AD3552R_NUM_CH) + if (ch >= dac->model_data->num_hw_channels) return dev_err_probe(dev, -EINVAL, "reg must be less than %d\n", - AD3552R_NUM_CH); + dac->model_data->num_hw_channels); if (fwnode_property_present(child, "adi,output-range-microvolt")) { err = fwnode_property_read_u32_array(child, @@ -954,7 +950,7 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return dev_err_probe(dev, err, "adi,output-range-microvolt property could not be parsed\n"); - err = ad3552r_find_range(dac->chip_id, vals); + err = ad3552r_find_range(dac->model_data, vals); if (err < 0) return dev_err_probe(dev, err, "Invalid adi,output-range-microvolt value\n"); @@ -967,9 +963,10 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return err; dac->ch_data[ch].range = val; - } else if (dac->chip_id == AD3542R_ID) { + } else if (dac->model_data->requires_output_range) { return dev_err_probe(dev, -EINVAL, - "adi,output-range-microvolt is required for ad3542r\n"); + "adi,output-range-microvolt is required for %s\n", + dac->model_data->model_name); } else { err = ad3552r_configure_custom_gain(dac, child, ch); if (err) @@ -989,7 +986,8 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) } /* Disable unused channels */ - for_each_clear_bit(ch, &dac->enabled_ch, AD3552R_NUM_CH) { + for_each_clear_bit(ch, &dac->enabled_ch, + dac->model_data->num_hw_channels) { err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN, ch, 1); if (err) @@ -1032,7 +1030,7 @@ static int ad3552r_init(struct ad3552r_desc *dac) } id |= val << 8; - if (id != dac->chip_id) { + if (id != dac->model_data->chip_id) { dev_err(&dac->spi->dev, "Product id not matching\n"); return -ENODEV; } @@ -1042,7 +1040,6 @@ static int ad3552r_init(struct ad3552r_desc *dac) static int ad3552r_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); struct ad3552r_desc *dac; struct iio_dev *indio_dev; int err; @@ -1053,7 +1050,9 @@ static int ad3552r_probe(struct spi_device *spi) dac = iio_priv(indio_dev); dac->spi = spi; - dac->chip_id = id->driver_data; + dac->model_data = spi_get_device_match_data(spi); + if (!dac->model_data) + return -EINVAL; mutex_init(&dac->lock); @@ -1062,10 +1061,7 @@ static int ad3552r_probe(struct spi_device *spi) return err; /* Config triggered buffer device */ - if (dac->chip_id == AD3552R_ID) - indio_dev->name = "ad3552r"; - else - indio_dev->name = "ad3542r"; + indio_dev->name = dac->model_data->model_name; indio_dev->dev.parent = &spi->dev; indio_dev->info = &ad3552r_iio_info; indio_dev->num_channels = dac->num_ch; @@ -1083,16 +1079,40 @@ static int ad3552r_probe(struct spi_device *spi) return devm_iio_device_register(&spi->dev, indio_dev); } +static const struct ad3552r_model_data ad3542r_model_data = { + .model_name = "ad3542r", + .chip_id = AD3542R_ID, + .num_hw_channels = 2, + .ranges_table = ad3542r_ch_ranges, + .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges), + .requires_output_range = true, +}; + +static const struct ad3552r_model_data ad3552r_model_data = { + .model_name = "ad3552r", + .chip_id = AD3552R_ID, + .num_hw_channels = 2, + .ranges_table = ad3552r_ch_ranges, + .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges), + .requires_output_range = false, +}; + static const struct spi_device_id ad3552r_id[] = { - { "ad3542r", AD3542R_ID }, - { "ad3552r", AD3552R_ID }, + { + .name = "ad3542r", + .driver_data = (kernel_ulong_t)&ad3542r_model_data + }, + { + .name = "ad3552r", + .driver_data = (kernel_ulong_t)&ad3552r_model_data + }, { } }; MODULE_DEVICE_TABLE(spi, ad3552r_id); static const struct of_device_id ad3552r_of_match[] = { - { .compatible = "adi,ad3542r"}, - { .compatible = "adi,ad3552r"}, + { .compatible = "adi,ad3542r", .data = &ad3542r_model_data }, + { .compatible = "adi,ad3552r", .data = &ad3552r_model_data }, { } }; MODULE_DEVICE_TABLE(of, ad3552r_of_match); From ea1c94d785b180ddf0c5933ed1c1b483a06b33b5 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 22 May 2024 17:01:39 +0200 Subject: [PATCH 061/330] iio: dac: ad3552r: add support for ad3541r and ad3551r Add support for single-output DAC variants. Signed-off-by: Angelo Dureghello Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240522150141.1776196-5-adureghello@baylibre.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index d637a8722f17..f573a6ad9326 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -140,7 +140,9 @@ enum ad3552r_ch_vref_select { }; enum ad3542r_id { + AD3541R_ID = 0x400b, AD3542R_ID = 0x4009, + AD3551R_ID = 0x400a, AD3552R_ID = 0x4008, }; @@ -1079,6 +1081,15 @@ static int ad3552r_probe(struct spi_device *spi) return devm_iio_device_register(&spi->dev, indio_dev); } +static const struct ad3552r_model_data ad3541r_model_data = { + .model_name = "ad3541r", + .chip_id = AD3541R_ID, + .num_hw_channels = 1, + .ranges_table = ad3542r_ch_ranges, + .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges), + .requires_output_range = true, +}; + static const struct ad3552r_model_data ad3542r_model_data = { .model_name = "ad3542r", .chip_id = AD3542R_ID, @@ -1088,6 +1099,15 @@ static const struct ad3552r_model_data ad3542r_model_data = { .requires_output_range = true, }; +static const struct ad3552r_model_data ad3551r_model_data = { + .model_name = "ad3551r", + .chip_id = AD3551R_ID, + .num_hw_channels = 1, + .ranges_table = ad3552r_ch_ranges, + .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges), + .requires_output_range = false, +}; + static const struct ad3552r_model_data ad3552r_model_data = { .model_name = "ad3552r", .chip_id = AD3552R_ID, @@ -1098,10 +1118,18 @@ static const struct ad3552r_model_data ad3552r_model_data = { }; static const struct spi_device_id ad3552r_id[] = { + { + .name = "ad3541r", + .driver_data = (kernel_ulong_t)&ad3541r_model_data + }, { .name = "ad3542r", .driver_data = (kernel_ulong_t)&ad3542r_model_data }, + { + .name = "ad3551r", + .driver_data = (kernel_ulong_t)&ad3551r_model_data + }, { .name = "ad3552r", .driver_data = (kernel_ulong_t)&ad3552r_model_data @@ -1111,7 +1139,9 @@ static const struct spi_device_id ad3552r_id[] = { MODULE_DEVICE_TABLE(spi, ad3552r_id); static const struct of_device_id ad3552r_of_match[] = { + { .compatible = "adi,ad3541r", .data = &ad3541r_model_data }, { .compatible = "adi,ad3542r", .data = &ad3542r_model_data }, + { .compatible = "adi,ad3551r", .data = &ad3551r_model_data }, { .compatible = "adi,ad3552r", .data = &ad3552r_model_data }, { } }; From d421302a910c63e541ebc9755b38956d135a6603 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 22 May 2024 17:01:40 +0200 Subject: [PATCH 062/330] iio: dac: ad3552r: change AD3552R_NUM_CH define name After model data and num_hw_channles introduction, we have: ad3552r_desc, num_ch: used to keep channel number set in fdt, ad35xxr_model_data, num_hw_channels: for max channel checks, AD3552R_NUM_CH: just actually used to define the max array size on allocated arrays. Renaming AD3552R_NUM_CH to a more consistent name, as AD3552R_MAX_CH. Signed-off-by: Angelo Dureghello Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240522150141.1776196-6-adureghello@baylibre.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index f573a6ad9326..dac5b60cbd5e 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -117,7 +117,7 @@ #define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3) /* Useful defines */ -#define AD3552R_NUM_CH 2 +#define AD3552R_MAX_CH 2 #define AD3552R_MASK_CH(ch) BIT(ch) #define AD3552R_MASK_ALL_CH GENMASK(1, 0) #define AD3552R_MAX_REG_SIZE 3 @@ -279,8 +279,8 @@ struct ad3552r_desc { struct gpio_desc *gpio_reset; struct gpio_desc *gpio_ldac; struct spi_device *spi; - struct ad3552r_ch_data ch_data[AD3552R_NUM_CH]; - struct iio_chan_spec channels[AD3552R_NUM_CH + 1]; + struct ad3552r_ch_data ch_data[AD3552R_MAX_CH]; + struct iio_chan_spec channels[AD3552R_MAX_CH + 1]; unsigned long enabled_ch; unsigned int num_ch; }; @@ -539,7 +539,7 @@ static int32_t ad3552r_trigger_hw_ldac(struct gpio_desc *ldac) static int ad3552r_write_all_channels(struct ad3552r_desc *dac, u8 *data) { int err, len; - u8 addr, buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE + 1]; + u8 addr, buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE + 1]; addr = AD3552R_REG_ADDR_CH_INPUT_24B(1); /* CH1 */ @@ -597,7 +597,7 @@ static irqreturn_t ad3552r_trigger_handler(int irq, void *p) struct iio_buffer *buf = indio_dev->buffer; struct ad3552r_desc *dac = iio_priv(indio_dev); /* Maximum size of a scan */ - u8 buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE]; + u8 buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE]; int err; memset(buff, 0, sizeof(buff)); From c1db755b6a229d1a5d7d3cb5371e82855874398c Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Wed, 22 May 2024 17:01:41 +0200 Subject: [PATCH 063/330] iio: dac: ad3552r: uniform structure names Use same driver file name (ad3552r) for structure names used for all variants. Signed-off-by: Angelo Dureghello Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240522150141.1776196-7-adureghello@baylibre.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index dac5b60cbd5e..ddc6c262f801 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -139,7 +139,7 @@ enum ad3552r_ch_vref_select { AD3552R_EXTERNAL_VREF_PIN_INPUT }; -enum ad3542r_id { +enum ad3552r_id { AD3541R_ID = 0x400b, AD3542R_ID = 0x4009, AD3551R_ID = 0x400a, @@ -265,7 +265,7 @@ struct ad3552r_ch_data { struct ad3552r_model_data { const char *model_name; - enum ad3542r_id chip_id; + enum ad3552r_id chip_id; unsigned int num_hw_channels; const s32 (*ranges_table)[2]; int num_ranges; From 28cf9cbe68298c64857974bca394f150b9e57b60 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 23 May 2024 14:24:10 -0500 Subject: [PATCH 064/330] iio: adc: sort Makefile The Makefile for IIO ADC drivers is intended to be sorted alphabetically. I can be tricky to keep it sorted when adding new drivers when not all of the existing drivers are sorted. So let's sort everything now to make it easier to keep it sorted in the future. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240523192412.3220547-1-dlechner@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Makefile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index edb32ce2af02..6a8c2da0e707 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_AD7280) += ad7280a.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 obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o @@ -29,6 +28,7 @@ obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o +obj-$(CONFIG_AD7923) += ad7923.o obj-$(CONFIG_AD7944) += ad7944.o obj-$(CONFIG_AD7949) += ad7949.o obj-$(CONFIG_AD799X) += ad799x.o @@ -90,42 +90,43 @@ obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_NPCM_ADC) += npcm_adc.o obj-$(CONFIG_PAC1934) += pac1934.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o +obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_RRADC) += qcom-spmi-rradc.o -obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o -obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o +obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o +obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o -obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o +obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o -obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o -obj-$(CONFIG_SUN20I_GPADC) += sun20i-gpadc-iio.o obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o obj-$(CONFIG_STM32_ADC) += stm32-adc.o -obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o +obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o obj-$(CONFIG_STMPE_ADC) += stmpe-adc.o +obj-$(CONFIG_SUN20I_GPADC) += sun20i-gpadc-iio.o +obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o -obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o +obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o +obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o +obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o -obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o -obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TI_LMP92064) += ti-lmp92064.o obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o @@ -134,7 +135,6 @@ obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o obj-$(CONFIG_VF610_ADC) += vf610_adc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o +obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o -obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o -obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o From 33c33a961ba659b2001d461395e4a95d6d30673f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 24 May 2024 15:38:04 -0500 Subject: [PATCH 065/330] iio: adc: ad7944: remove unused parameter In the ad7944 driver, the ad7944_convert_and_acquire() had an unused `chan` parameter. This patch removes the parameter. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240524-iio-ad7944-remove-unused-parameter-v1-1-fd824d7122a0@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 4602ab5ed2a6..e2cb64cef476 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -259,7 +259,6 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc /** * ad7944_convert_and_acquire - Perform a single conversion and acquisition * @adc: The ADC device structure - * @chan: The channel specification * Return: 0 on success, a negative error code on failure * * Perform a conversion and acquisition of a single sample using the @@ -268,8 +267,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc * Upon successful return adc->sample.raw will contain the conversion result * (or adc->chain_mode_buf if the device is using chain mode). */ -static int ad7944_convert_and_acquire(struct ad7944_adc *adc, - const struct iio_chan_spec *chan) +static int ad7944_convert_and_acquire(struct ad7944_adc *adc) { int ret; @@ -291,7 +289,7 @@ static int ad7944_single_conversion(struct ad7944_adc *adc, { int ret; - ret = ad7944_convert_and_acquire(adc, chan); + ret = ad7944_convert_and_acquire(adc); if (ret) return ret; @@ -361,7 +359,7 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p) struct ad7944_adc *adc = iio_priv(indio_dev); int ret; - ret = ad7944_convert_and_acquire(adc, &indio_dev->channels[0]); + ret = ad7944_convert_and_acquire(adc); if (ret) goto out; From 5c3266385e4f27c69c03bcbfa68339b49be91c56 Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Thu, 23 May 2024 19:47:36 +0200 Subject: [PATCH 066/330] iio: imu: bmi323: Use iio read_acpi_mount_matrix() helper bmi150-accel and bmi323-imu are declared in an almost identical way in the ACPI and in some devices such as the Asus RC71L the "ROTM" property can be found: parse and use the ACPI-defined mount-matrix. Co-developed-by: Luke D. Jones Co-developed-by: Jonathan LoBue Signed-off-by: Denis Benato Link: https://lore.kernel.org/r/20240523174736.16692-2-benato.denis96@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bmi323/bmi323_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c index 5d42ab9b176a..b391e5e701b1 100644 --- a/drivers/iio/imu/bmi323/bmi323_core.c +++ b/drivers/iio/imu/bmi323/bmi323_core.c @@ -2083,9 +2083,11 @@ int bmi323_core_probe(struct device *dev) if (ret) return -EINVAL; - ret = iio_read_mount_matrix(dev, &data->orientation); - if (ret) - return ret; + if (!iio_read_acpi_mount_matrix(dev, &data->orientation, "ROTM")) { + ret = iio_read_mount_matrix(dev, &data->orientation); + if (ret) + return ret; + } indio_dev->name = "bmi323-imu"; indio_dev->info = &bmi323_info; From e2261b4a4de2804698935eb44f98dc897e1c44c3 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 30 May 2024 12:28:34 +0300 Subject: [PATCH 067/330] iio: frequency: adrf6780: rm clk provider include The driver has no clock provider implementation, therefore remove the include. Fixes: 63aaf6d06d87 ("iio: frequency: adrf6780: add support for ADRF6780") Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20240530092835.36892-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/adrf6780.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c index b4defb82f37e..3f46032c9275 100644 --- a/drivers/iio/frequency/adrf6780.c +++ b/drivers/iio/frequency/adrf6780.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From 9be46ec5606e6e1aa4b9c6086762ed82f34ceaae Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 29 May 2024 17:00:55 +0100 Subject: [PATCH 068/330] staging: iio: adt7316: remove unused struct 'adt7316_limit_regs' 'adt7316_limit_regs' has never been used since the original commit 35f6b6b86ede ("staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver"). The comment above it is a copy-and-paste from a different struct. Remove both the struct and the comment. Reviewed-by: Nuno Sa Signed-off-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20240529160055.28489-1-linux@treblig.org Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 79467f056a05..f4260786d50a 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -209,15 +209,6 @@ struct adt7316_chip_info { #define ADT7316_TEMP_AIN_INT_MASK \ (ADT7316_TEMP_INT_MASK) -/* - * struct adt7316_chip_info - chip specific information - */ - -struct adt7316_limit_regs { - u16 data_high; - u16 data_low; -}; - static ssize_t adt7316_show_enabled(struct device *dev, struct device_attribute *attr, char *buf) From 202b89f4b778d86a940f693785600acaccca6a2b Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 31 May 2024 11:41:54 +0200 Subject: [PATCH 069/330] iio: adc: adi-axi-adc: don't allow concurrent enable/disable calls Add proper mutex guards as we should not be able to disable the core in the middle of enabling it. Note there's no need to rush in backporting this as the only user of the backend does not do anything crazy.. Fixes: 794ef0e57854 ("iio: adc: adi-axi-adc: move to backend framework") Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240531-dev-axi-adc-drp-v3-1-e3fa79447c67@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 0cf0d81358fd..bf51d619ebbc 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -85,6 +85,7 @@ static int axi_adc_enable(struct iio_backend *back) struct adi_axi_adc_state *st = iio_backend_get_priv(back); int ret; + guard(mutex)(&st->lock); ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, ADI_AXI_REG_RSTN_MMCM_RSTN); if (ret) @@ -99,6 +100,7 @@ static void axi_adc_disable(struct iio_backend *back) { struct adi_axi_adc_state *st = iio_backend_get_priv(back); + guard(mutex)(&st->lock); regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); } From 70a0e10f8ab62ba82b080347ca0a119e14e964c9 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 31 May 2024 11:41:55 +0200 Subject: [PATCH 070/330] iio: adc: adi-axi-adc: make sure DRP is locked on enable When enabling the core, make sure DRP (Dynamic Reconfiguration Port) is locked. Most of the designs don't really use it but we still get the lock bit set. So let's do it all the time so the code is generic. While at it reduce the timeout time to 1 microsecond as it seems to be enough and goes in line with what we have on the similar DAC core (adi-axi-dac). Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240531-dev-axi-adc-drp-v3-2-e3fa79447c67@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index bf51d619ebbc..0f8bd1d75131 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -42,6 +42,9 @@ #define ADI_AXI_ADC_REG_CTRL 0x0044 #define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1) +#define ADI_AXI_ADC_REG_DRP_STATUS 0x0074 +#define ADI_AXI_ADC_DRP_LOCKED BIT(17) + /* ADC Channel controls */ #define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40) @@ -83,6 +86,7 @@ struct adi_axi_adc_state { static int axi_adc_enable(struct iio_backend *back) { struct adi_axi_adc_state *st = iio_backend_get_priv(back); + unsigned int __val; int ret; guard(mutex)(&st->lock); @@ -91,7 +95,17 @@ static int axi_adc_enable(struct iio_backend *back) if (ret) return ret; - fsleep(10000); + /* + * Make sure the DRP (Dynamic Reconfiguration Port) is locked. Not all + * designs really use it but if they don't we still get the lock bit + * set. So let's do it all the time so the code is generic. + */ + ret = regmap_read_poll_timeout(st->regmap, ADI_AXI_ADC_REG_DRP_STATUS, + __val, __val & ADI_AXI_ADC_DRP_LOCKED, + 100, 1000); + if (ret) + return ret; + return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); } From c4ea781c20e2d10a2de5005dbf6e24f1cc676b09 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 28 May 2024 16:20:28 +0200 Subject: [PATCH 071/330] dt-bindings: iio: adc: Add binding for AD7380 ADCs This adds a binding specification for the Analog Devices Inc. AD7380 family of ADCs. Signed-off-by: David Lechner Signed-off-by: Julien Stephan Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240528-adding-new-ad738x-driver-v7-1-4cd70a4c12c8@baylibre.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7380.yaml | 82 +++++++++++++++++++ MAINTAINERS | 9 ++ 2 files changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml new file mode 100644 index 000000000000..5e1ee0ebe0a2 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7380.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices Simultaneous Sampling Analog to Digital Converters + +maintainers: + - Michael Hennerich + - Nuno Sá + +description: | + * https://www.analog.com/en/products/ad7380.html + * https://www.analog.com/en/products/ad7381.html + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,ad7380 + - adi,ad7381 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 80000000 + spi-cpol: true + spi-cpha: true + + vcc-supply: + description: A 3V to 3.6V supply that powers the chip. + + vlogic-supply: + description: + A 1.65V to 3.6V supply for the logic pins. + + refio-supply: + description: + A 2.5V to 3.3V supply for the external reference voltage. When omitted, + the internal 2.5V reference is used. + + interrupts: + description: + When the device is using 1-wire mode, this property is used to optionally + specify the ALERT interrupt. + maxItems: 1 + +required: + - compatible + - reg + - vcc-supply + - vlogic-supply + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7380"; + reg = <0>; + + spi-cpol; + spi-cpha; + spi-max-frequency = <80000000>; + + interrupts = <27 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + vcc-supply = <&supply_3_3V>; + vlogic-supply = <&supply_3_3V>; + refio-supply = <&supply_2_5V>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index d6c90161c7bf..c1e62fd354b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -439,6 +439,15 @@ W: http://wiki.analog.com/AD7142 W: https://ez.analog.com/linux-software-drivers F: drivers/input/misc/ad714x.c +AD738X ADC DRIVER (AD7380/1/2/4) +M: Michael Hennerich +M: Nuno Sá +R: David Lechner +S: Supported +W: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad738x +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml + AD7877 TOUCHSCREEN DRIVER M: Michael Hennerich S: Supported From b095217c104bca87d5e24c147b3e37cae921c441 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 28 May 2024 16:20:29 +0200 Subject: [PATCH 072/330] iio: adc: ad7380: new driver for AD7380 ADCs This adds a new driver for the AD7380 family ADCs. The driver currently implements basic support for the AD7380, AD7381, 2-channel differential ADCs. Support for additional single-ended, pseudo-differential and 4-channel chips that use the same register map as well as additional features of the chip will be added in future patches. [Julien Stephan: fix rx/tx buffer for regmap access] [Julien Stephan: fix scale issue] [Julien Stephan: use the new iio_device_claim_direct_scoped instead of iio_device_claim_direct_mode] Co-developed-by: Stefan Popa Signed-off-by: Stefan Popa Reviewed-by: Nuno Sa Signed-off-by: David Lechner [Julien Stephan: add datasheet links of supported parts] Signed-off-by: Julien Stephan Link: https://lore.kernel.org/r/20240528-adding-new-ad738x-driver-v7-2-4cd70a4c12c8@baylibre.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 16 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7380.c | 438 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 456 insertions(+) create mode 100644 drivers/iio/adc/ad7380.c diff --git a/MAINTAINERS b/MAINTAINERS index c1e62fd354b5..bff979a507ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -447,6 +447,7 @@ S: Supported W: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad738x W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml +F: drivers/iio/adc/ad7380.c AD7877 TOUCHSCREEN DRIVER M: Michael Hennerich diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 74fecc284f1a..5030319249c5 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -160,6 +160,22 @@ config AD7298 To compile this driver as a module, choose M here: the module will be called ad7298. +config AD7380 + tristate "Analog Devices AD7380 ADC driver" + depends on SPI_MASTER + select IIO_BUFFER + select IIO_TRIGGER + select IIO_TRIGGERED_BUFFER + help + AD7380 is a family of simultaneous sampling ADCs that share the same + SPI register map and have similar pinouts. + + Say yes here to build support for Analog Devices AD7380 ADC and + similar chips. + + To compile this driver as a module, choose M here: the module will be + called ad7380. + config AD7476 tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 6a8c2da0e707..37ac689a0209 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7292) += ad7292.o obj-$(CONFIG_AD7298) += ad7298.o +obj-$(CONFIG_AD7380) += ad7380.o obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c new file mode 100644 index 000000000000..dac7e11755ff --- /dev/null +++ b/drivers/iio/adc/ad7380.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD738x Simultaneous Sampling SAR ADCs + * + * Copyright 2017 Analog Devices Inc. + * Copyright 2024 BayLibre, SAS + * + * Datasheets of supported parts: + * ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* 2.5V internal reference voltage */ +#define AD7380_INTERNAL_REF_MV 2500 + +/* reading and writing registers is more reliable at lower than max speed */ +#define AD7380_REG_WR_SPEED_HZ 10000000 + +#define AD7380_REG_WR BIT(15) +#define AD7380_REG_REGADDR GENMASK(14, 12) +#define AD7380_REG_DATA GENMASK(11, 0) + +#define AD7380_REG_ADDR_NOP 0x0 +#define AD7380_REG_ADDR_CONFIG1 0x1 +#define AD7380_REG_ADDR_CONFIG2 0x2 +#define AD7380_REG_ADDR_ALERT 0x3 +#define AD7380_REG_ADDR_ALERT_LOW_TH 0x4 +#define AD7380_REG_ADDR_ALERT_HIGH_TH 0x5 + +#define AD7380_CONFIG1_OS_MODE BIT(9) +#define AD7380_CONFIG1_OSR GENMASK(8, 6) +#define AD7380_CONFIG1_CRC_W BIT(5) +#define AD7380_CONFIG1_CRC_R BIT(4) +#define AD7380_CONFIG1_ALERTEN BIT(3) +#define AD7380_CONFIG1_RES BIT(2) +#define AD7380_CONFIG1_REFSEL BIT(1) +#define AD7380_CONFIG1_PMODE BIT(0) + +#define AD7380_CONFIG2_SDO2 GENMASK(9, 8) +#define AD7380_CONFIG2_SDO BIT(8) +#define AD7380_CONFIG2_RESET GENMASK(7, 0) + +#define AD7380_CONFIG2_RESET_SOFT 0x3C +#define AD7380_CONFIG2_RESET_HARD 0xFF + +#define AD7380_ALERT_LOW_TH GENMASK(11, 0) +#define AD7380_ALERT_HIGH_TH GENMASK(11, 0) + +struct ad7380_chip_info { + const char *name; + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +#define AD7380_CHANNEL(index, bits) { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .indexed = 1, \ + .differential = 1, \ + .channel = 2 * (index), \ + .channel2 = 2 * (index) + 1, \ + .scan_index = (index), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define DEFINE_AD7380_2_CHANNEL(name, bits) \ +static const struct iio_chan_spec name[] = { \ + AD7380_CHANNEL(0, bits), \ + AD7380_CHANNEL(1, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(2), \ +} + +DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16); +DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14); + +/* Since this is simultaneous sampling, we don't allow individual channels. */ +static const unsigned long ad7380_2_channel_scan_masks[] = { + GENMASK(1, 0), + 0 +}; + +static const struct ad7380_chip_info ad7380_chip_info = { + .name = "ad7380", + .channels = ad7380_channels, + .num_channels = ARRAY_SIZE(ad7380_channels), +}; + +static const struct ad7380_chip_info ad7381_chip_info = { + .name = "ad7381", + .channels = ad7381_channels, + .num_channels = ARRAY_SIZE(ad7381_channels), +}; + +struct ad7380_state { + const struct ad7380_chip_info *chip_info; + struct spi_device *spi; + struct regmap *regmap; + unsigned int vref_mv; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * Make the buffer large enough for 2 16-bit samples and one 64-bit + * aligned 64 bit timestamp. + */ + struct { + u16 raw[2]; + + s64 ts __aligned(8); + } scan_data __aligned(IIO_DMA_MINALIGN); + u16 tx; + u16 rx; +}; + +static int ad7380_regmap_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct ad7380_state *st = context; + struct spi_transfer xfer = { + .speed_hz = AD7380_REG_WR_SPEED_HZ, + .bits_per_word = 16, + .len = 2, + .tx_buf = &st->tx, + }; + + st->tx = FIELD_PREP(AD7380_REG_WR, 1) | + FIELD_PREP(AD7380_REG_REGADDR, reg) | + FIELD_PREP(AD7380_REG_DATA, val); + + return spi_sync_transfer(st->spi, &xfer, 1); +} + +static int ad7380_regmap_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct ad7380_state *st = context; + struct spi_transfer xfers[] = { + { + .speed_hz = AD7380_REG_WR_SPEED_HZ, + .bits_per_word = 16, + .len = 2, + .tx_buf = &st->tx, + .cs_change = 1, + .cs_change_delay = { + .value = 10, /* t[CSH] */ + .unit = SPI_DELAY_UNIT_NSECS, + }, + }, { + .speed_hz = AD7380_REG_WR_SPEED_HZ, + .bits_per_word = 16, + .len = 2, + .rx_buf = &st->rx, + }, + }; + int ret; + + st->tx = FIELD_PREP(AD7380_REG_WR, 0) | + FIELD_PREP(AD7380_REG_REGADDR, reg) | + FIELD_PREP(AD7380_REG_DATA, 0); + + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); + if (ret < 0) + return ret; + + *val = FIELD_GET(AD7380_REG_DATA, st->rx); + + return 0; +} + +static const struct regmap_config ad7380_regmap_config = { + .reg_bits = 3, + .val_bits = 12, + .reg_read = ad7380_regmap_reg_read, + .reg_write = ad7380_regmap_reg_write, + .max_register = AD7380_REG_ADDR_ALERT_HIGH_TH, + .can_sleep = true, +}; + +static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg, + u32 writeval, u32 *readval) +{ + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + struct ad7380_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + else + return regmap_write(st->regmap, reg, writeval); + } + unreachable(); +} + +static irqreturn_t ad7380_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7380_state *st = iio_priv(indio_dev); + struct spi_transfer xfer = { + .bits_per_word = st->chip_info->channels[0].scan_type.realbits, + .len = 4, + .rx_buf = st->scan_data.raw, + }; + int ret; + + ret = spi_sync_transfer(st->spi, &xfer, 1); + if (ret) + goto out; + + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_data, + pf->timestamp); + +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ad7380_read_direct(struct ad7380_state *st, + struct iio_chan_spec const *chan, int *val) +{ + struct spi_transfer xfers[] = { + /* toggle CS (no data xfer) to trigger a conversion */ + { + .speed_hz = AD7380_REG_WR_SPEED_HZ, + .bits_per_word = chan->scan_type.realbits, + .delay = { + .value = 190, /* t[CONVERT] */ + .unit = SPI_DELAY_UNIT_NSECS, + }, + .cs_change = 1, + .cs_change_delay = { + .value = 10, /* t[CSH] */ + .unit = SPI_DELAY_UNIT_NSECS, + }, + }, + /* then read both channels */ + { + .speed_hz = AD7380_REG_WR_SPEED_HZ, + .bits_per_word = chan->scan_type.realbits, + .rx_buf = st->scan_data.raw, + .len = 4, + }, + }; + int ret; + + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); + if (ret < 0) + return ret; + + *val = sign_extend32(st->scan_data.raw[chan->scan_index], + chan->scan_type.realbits - 1); + + return IIO_VAL_INT; +} + +static int ad7380_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct ad7380_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + return ad7380_read_direct(st, chan, val); + } + unreachable(); + case IIO_CHAN_INFO_SCALE: + /* + * According to the datasheet, the LSB size for fully differential ADC is + * (2 × VREF) / 2^N, where N is the ADC resolution (i.e realbits) + */ + *val = st->vref_mv; + *val2 = chan->scan_type.realbits - 1; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info ad7380_info = { + .read_raw = &ad7380_read_raw, + .debugfs_reg_access = &ad7380_debugfs_reg_access, +}; + +static int ad7380_init(struct ad7380_state *st, struct regulator *vref) +{ + int ret; + + /* perform hard reset */ + ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2, + AD7380_CONFIG2_RESET, + FIELD_PREP(AD7380_CONFIG2_RESET, + AD7380_CONFIG2_RESET_HARD)); + if (ret < 0) + return ret; + + /* select internal or external reference voltage */ + ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG1, + AD7380_CONFIG1_REFSEL, + FIELD_PREP(AD7380_CONFIG1_REFSEL, + vref ? 1 : 0)); + if (ret < 0) + return ret; + + /* SPI 1-wire mode */ + return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2, + AD7380_CONFIG2_SDO, + FIELD_PREP(AD7380_CONFIG2_SDO, 1)); +} + +static void ad7380_regulator_disable(void *p) +{ + regulator_disable(p); +} + +static int ad7380_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad7380_state *st; + struct regulator *vref; + 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; + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n"); + + vref = devm_regulator_get_optional(&spi->dev, "refio"); + if (IS_ERR(vref)) { + if (PTR_ERR(vref) != -ENODEV) + return dev_err_probe(&spi->dev, PTR_ERR(vref), + "Failed to get refio regulator\n"); + + vref = NULL; + } + + /* + * If there is no REFIO supply, then it means that we are using + * the internal 2.5V reference, otherwise REFIO is reference voltage. + */ + if (vref) { + ret = regulator_enable(vref); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, + ad7380_regulator_disable, vref); + if (ret) + return ret; + + ret = regulator_get_voltage(vref); + if (ret < 0) + return ret; + + st->vref_mv = ret / 1000; + } else { + st->vref_mv = AD7380_INTERNAL_REF_MV; + } + + st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + "failed to allocate register map\n"); + + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + indio_dev->name = st->chip_info->name; + indio_dev->info = &ad7380_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->available_scan_masks = ad7380_2_channel_scan_masks; + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + iio_pollfunc_store_time, + ad7380_trigger_handler, NULL); + if (ret) + return ret; + + ret = ad7380_init(st, vref); + if (ret) + return ret; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ad7380_of_match_table[] = { + { .compatible = "adi,ad7380", .data = &ad7380_chip_info }, + { .compatible = "adi,ad7381", .data = &ad7381_chip_info }, + { } +}; + +static const struct spi_device_id ad7380_id_table[] = { + { "ad7380", (kernel_ulong_t)&ad7380_chip_info }, + { "ad7381", (kernel_ulong_t)&ad7381_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad7380_id_table); + +static struct spi_driver ad7380_driver = { + .driver = { + .name = "ad7380", + .of_match_table = ad7380_of_match_table, + }, + .probe = ad7380_probe, + .id_table = ad7380_id_table, +}; +module_spi_driver(ad7380_driver); + +MODULE_AUTHOR("Stefan Popa "); +MODULE_DESCRIPTION("Analog Devices AD738x ADC driver"); +MODULE_LICENSE("GPL"); From 6b2c80194e151d8ce41849f97a6ca13c8ca30a32 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 28 May 2024 16:20:30 +0200 Subject: [PATCH 073/330] dt-bindings: iio: adc: ad7380: add pseudo-differential parts Adding AD7383 and AD7384 compatible parts that are pseudo-differential. Pseudo-differential require common mode voltage supplies, so add them conditionally Signed-off-by: David Lechner Signed-off-by: Julien Stephan Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240528-adding-new-ad738x-driver-v7-3-4cd70a4c12c8@baylibre.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7380.yaml | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml index 5e1ee0ebe0a2..de3d28a021ae 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml @@ -13,6 +13,8 @@ maintainers: description: | * https://www.analog.com/en/products/ad7380.html * https://www.analog.com/en/products/ad7381.html + * https://www.analog.com/en/products/ad7383.html + * https://www.analog.com/en/products/ad7384.html $ref: /schemas/spi/spi-peripheral-props.yaml# @@ -21,6 +23,8 @@ properties: enum: - adi,ad7380 - adi,ad7381 + - adi,ad7383 + - adi,ad7384 reg: maxItems: 1 @@ -42,6 +46,16 @@ properties: A 2.5V to 3.3V supply for the external reference voltage. When omitted, the internal 2.5V reference is used. + aina-supply: + description: + The common mode voltage supply for the AINA- pin on pseudo-differential + chips. + + ainb-supply: + description: + The common mode voltage supply for the AINB- pin on pseudo-differential + chips. + interrupts: description: When the device is using 1-wire mode, this property is used to optionally @@ -56,6 +70,24 @@ required: unevaluatedProperties: false +allOf: + # pseudo-differential chips require common mode voltage supplies, + # true differential chips don't use them + - if: + properties: + compatible: + enum: + - adi,ad7383 + - adi,ad7384 + then: + required: + - aina-supply + - ainb-supply + else: + properties: + aina-supply: false + ainb-supply: false + examples: - | #include From 2920b6ee6d69ed874b8cc60e5a0b930aca102e18 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 28 May 2024 16:20:31 +0200 Subject: [PATCH 074/330] iio: adc: ad7380: add support for pseudo-differential parts Add support for AD7383, AD7384 pseudo-differential compatible parts. Pseudo differential parts require common mode voltage supplies so add the support for them and add the support of IIO_CHAN_INFO_OFFSET to retrieve the offset Signed-off-by: David Lechner Signed-off-by: Julien Stephan Link: https://lore.kernel.org/r/20240528-adding-new-ad738x-driver-v7-4-4cd70a4c12c8@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7380.c | 110 +++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index dac7e11755ff..4ad283cf970d 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -7,6 +7,7 @@ * * Datasheets of supported parts: * ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf + * ad7383/4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-7384.pdf */ #include @@ -66,16 +67,19 @@ struct ad7380_chip_info { const char *name; const struct iio_chan_spec *channels; unsigned int num_channels; + const char * const *vcm_supplies; + unsigned int num_vcm_supplies; }; -#define AD7380_CHANNEL(index, bits) { \ +#define AD7380_CHANNEL(index, bits, diff) { \ .type = IIO_VOLTAGE, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + ((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .indexed = 1, \ - .differential = 1, \ - .channel = 2 * (index), \ - .channel2 = 2 * (index) + 1, \ + .differential = (diff), \ + .channel = (diff) ? (2 * (index)) : (index), \ + .channel2 = (diff) ? (2 * (index) + 1) : 0, \ .scan_index = (index), \ .scan_type = { \ .sign = 's', \ @@ -85,15 +89,23 @@ struct ad7380_chip_info { }, \ } -#define DEFINE_AD7380_2_CHANNEL(name, bits) \ -static const struct iio_chan_spec name[] = { \ - AD7380_CHANNEL(0, bits), \ - AD7380_CHANNEL(1, bits), \ - IIO_CHAN_SOFT_TIMESTAMP(2), \ +#define DEFINE_AD7380_2_CHANNEL(name, bits, diff) \ +static const struct iio_chan_spec name[] = { \ + AD7380_CHANNEL(0, bits, diff), \ + AD7380_CHANNEL(1, bits, diff), \ + IIO_CHAN_SOFT_TIMESTAMP(2), \ } -DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16); -DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14); +/* fully differential */ +DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1); +DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1); +/* pseudo differential */ +DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0); +DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0); + +static const char * const ad7380_2_channel_vcm_supplies[] = { + "aina", "ainb", +}; /* Since this is simultaneous sampling, we don't allow individual channels. */ static const unsigned long ad7380_2_channel_scan_masks[] = { @@ -113,11 +125,28 @@ static const struct ad7380_chip_info ad7381_chip_info = { .num_channels = ARRAY_SIZE(ad7381_channels), }; +static const struct ad7380_chip_info ad7383_chip_info = { + .name = "ad7383", + .channels = ad7383_channels, + .num_channels = ARRAY_SIZE(ad7383_channels), + .vcm_supplies = ad7380_2_channel_vcm_supplies, + .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), +}; + +static const struct ad7380_chip_info ad7384_chip_info = { + .name = "ad7384", + .channels = ad7384_channels, + .num_channels = ARRAY_SIZE(ad7384_channels), + .vcm_supplies = ad7380_2_channel_vcm_supplies, + .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), +}; + struct ad7380_state { const struct ad7380_chip_info *chip_info; struct spi_device *spi; struct regmap *regmap; unsigned int vref_mv; + unsigned int vcm_mv[2]; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -288,13 +317,24 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, unreachable(); case IIO_CHAN_INFO_SCALE: /* - * According to the datasheet, the LSB size for fully differential ADC is - * (2 × VREF) / 2^N, where N is the ADC resolution (i.e realbits) + * According to the datasheet, the LSB size is: + * * (2 × VREF) / 2^N, for differential chips + * * VREF / 2^N, for pseudo-differential chips + * where N is the ADC resolution (i.e realbits) */ *val = st->vref_mv; - *val2 = chan->scan_type.realbits - 1; + *val2 = chan->scan_type.realbits - chan->differential; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + /* + * According to IIO ABI, offset is applied before scale, + * so offset is: vcm_mv / scale + */ + *val = st->vcm_mv[chan->channel] * (1 << chan->scan_type.realbits) + / st->vref_mv; + + return IIO_VAL_INT; default: return -EINVAL; } @@ -341,7 +381,7 @@ static int ad7380_probe(struct spi_device *spi) struct iio_dev *indio_dev; struct ad7380_state *st; struct regulator *vref; - int ret; + int ret, i; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) @@ -385,6 +425,40 @@ static int ad7380_probe(struct spi_device *spi) st->vref_mv = AD7380_INTERNAL_REF_MV; } + if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv)) + return dev_err_probe(&spi->dev, -EINVAL, + "invalid number of VCM supplies\n"); + + /* + * pseudo-differential chips have common mode supplies for the negative + * input pin. + */ + for (i = 0; i < st->chip_info->num_vcm_supplies; i++) { + struct regulator *vcm; + + vcm = devm_regulator_get(&spi->dev, + st->chip_info->vcm_supplies[i]); + if (IS_ERR(vcm)) + return dev_err_probe(&spi->dev, PTR_ERR(vcm), + "Failed to get %s regulator\n", + st->chip_info->vcm_supplies[i]); + + ret = regulator_enable(vcm); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, + ad7380_regulator_disable, vcm); + if (ret) + return ret; + + ret = regulator_get_voltage(vcm); + if (ret < 0) + return ret; + + st->vcm_mv[i] = ret / 1000; + } + st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config); if (IS_ERR(st->regmap)) return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), @@ -413,12 +487,16 @@ static int ad7380_probe(struct spi_device *spi) static const struct of_device_id ad7380_of_match_table[] = { { .compatible = "adi,ad7380", .data = &ad7380_chip_info }, { .compatible = "adi,ad7381", .data = &ad7381_chip_info }, + { .compatible = "adi,ad7383", .data = &ad7383_chip_info }, + { .compatible = "adi,ad7384", .data = &ad7384_chip_info }, { } }; static const struct spi_device_id ad7380_id_table[] = { { "ad7380", (kernel_ulong_t)&ad7380_chip_info }, { "ad7381", (kernel_ulong_t)&ad7381_chip_info }, + { "ad7383", (kernel_ulong_t)&ad7383_chip_info }, + { "ad7384", (kernel_ulong_t)&ad7384_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7380_id_table); From baa781e1d84f2165c480c28d2c286e465d3fb2e1 Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Tue, 28 May 2024 16:20:32 +0200 Subject: [PATCH 075/330] iio: adc: ad7380: prepare for parts with more channels The current driver supports only parts with 2 channels. In order to prepare the support of new compatible ADCs with more channels, this commit: - defines MAX_NUM_CHANNEL to specify the maximum number of channels currently supported by the driver - adds available_scan_mask member in ad7380_chip_info structure - fixes spi xfer struct len depending on number of channels - fixes scan_data.raw buffer size to handle more channels - adds a timing specifications structure in ad7380_chip_info structure Signed-off-by: Julien Stephan Link: https://lore.kernel.org/r/20240528-adding-new-ad738x-driver-v7-5-4cd70a4c12c8@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7380.c | 43 ++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index 4ad283cf970d..790d08c90ad0 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -27,6 +27,7 @@ #include #include +#define MAX_NUM_CHANNELS 2 /* 2.5V internal reference voltage */ #define AD7380_INTERNAL_REF_MV 2500 @@ -63,12 +64,19 @@ #define AD7380_ALERT_LOW_TH GENMASK(11, 0) #define AD7380_ALERT_HIGH_TH GENMASK(11, 0) +#define T_CONVERT_NS 190 /* conversion time */ +struct ad7380_timing_specs { + const unsigned int t_csh_ns; /* CS minimum high time */ +}; + struct ad7380_chip_info { const char *name; const struct iio_chan_spec *channels; unsigned int num_channels; const char * const *vcm_supplies; unsigned int num_vcm_supplies; + const unsigned long *available_scan_masks; + const struct ad7380_timing_specs *timing_specs; }; #define AD7380_CHANNEL(index, bits, diff) { \ @@ -113,16 +121,24 @@ static const unsigned long ad7380_2_channel_scan_masks[] = { 0 }; +static const struct ad7380_timing_specs ad7380_timing = { + .t_csh_ns = 10, +}; + static const struct ad7380_chip_info ad7380_chip_info = { .name = "ad7380", .channels = ad7380_channels, .num_channels = ARRAY_SIZE(ad7380_channels), + .available_scan_masks = ad7380_2_channel_scan_masks, + .timing_specs = &ad7380_timing, }; static const struct ad7380_chip_info ad7381_chip_info = { .name = "ad7381", .channels = ad7381_channels, .num_channels = ARRAY_SIZE(ad7381_channels), + .available_scan_masks = ad7380_2_channel_scan_masks, + .timing_specs = &ad7380_timing, }; static const struct ad7380_chip_info ad7383_chip_info = { @@ -131,6 +147,8 @@ static const struct ad7380_chip_info ad7383_chip_info = { .num_channels = ARRAY_SIZE(ad7383_channels), .vcm_supplies = ad7380_2_channel_vcm_supplies, .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), + .available_scan_masks = ad7380_2_channel_scan_masks, + .timing_specs = &ad7380_timing, }; static const struct ad7380_chip_info ad7384_chip_info = { @@ -139,6 +157,8 @@ static const struct ad7380_chip_info ad7384_chip_info = { .num_channels = ARRAY_SIZE(ad7384_channels), .vcm_supplies = ad7380_2_channel_vcm_supplies, .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies), + .available_scan_masks = ad7380_2_channel_scan_masks, + .timing_specs = &ad7380_timing, }; struct ad7380_state { @@ -146,15 +166,16 @@ struct ad7380_state { struct spi_device *spi; struct regmap *regmap; unsigned int vref_mv; - unsigned int vcm_mv[2]; + unsigned int vcm_mv[MAX_NUM_CHANNELS]; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. - * Make the buffer large enough for 2 16-bit samples and one 64-bit + * Make the buffer large enough for MAX_NUM_CHANNELS 16-bit samples and one 64-bit * aligned 64 bit timestamp. + * As MAX_NUM_CHANNELS is 2 the layout of the structure is the same for all parts */ struct { - u16 raw[2]; + u16 raw[MAX_NUM_CHANNELS]; s64 ts __aligned(8); } scan_data __aligned(IIO_DMA_MINALIGN); @@ -192,7 +213,7 @@ static int ad7380_regmap_reg_read(void *context, unsigned int reg, .tx_buf = &st->tx, .cs_change = 1, .cs_change_delay = { - .value = 10, /* t[CSH] */ + .value = st->chip_info->timing_specs->t_csh_ns, .unit = SPI_DELAY_UNIT_NSECS, }, }, { @@ -247,7 +268,8 @@ static irqreturn_t ad7380_trigger_handler(int irq, void *p) struct ad7380_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { .bits_per_word = st->chip_info->channels[0].scan_type.realbits, - .len = 4, + .len = (st->chip_info->num_channels - 1) * + BITS_TO_BYTES(st->chip_info->channels->scan_type.storagebits), .rx_buf = st->scan_data.raw, }; int ret; @@ -274,21 +296,22 @@ static int ad7380_read_direct(struct ad7380_state *st, .speed_hz = AD7380_REG_WR_SPEED_HZ, .bits_per_word = chan->scan_type.realbits, .delay = { - .value = 190, /* t[CONVERT] */ + .value = T_CONVERT_NS, .unit = SPI_DELAY_UNIT_NSECS, }, .cs_change = 1, .cs_change_delay = { - .value = 10, /* t[CSH] */ + .value = st->chip_info->timing_specs->t_csh_ns, .unit = SPI_DELAY_UNIT_NSECS, }, }, - /* then read both channels */ + /* then read all channels */ { .speed_hz = AD7380_REG_WR_SPEED_HZ, .bits_per_word = chan->scan_type.realbits, .rx_buf = st->scan_data.raw, - .len = 4, + .len = (st->chip_info->num_channels - 1) * + ((chan->scan_type.storagebits > 16) ? 4 : 2), }, }; int ret; @@ -469,7 +492,7 @@ static int ad7380_probe(struct spi_device *spi) indio_dev->name = st->chip_info->name; indio_dev->info = &ad7380_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->available_scan_masks = ad7380_2_channel_scan_masks; + indio_dev->available_scan_masks = st->chip_info->available_scan_masks; ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, iio_pollfunc_store_time, From 1a291cc8ee17d1473a8ebf2ce2a5b49b0461b8fb Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Tue, 28 May 2024 16:20:33 +0200 Subject: [PATCH 076/330] dt-bindings: iio: adc: ad7380: add support for ad738x-4 4 channels variants Add compatible support for ad7380/1/3/4-4 parts which are 4 channels variants from ad7380/1/3/4 Signed-off-by: Julien Stephan Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240528-adding-new-ad738x-driver-v7-6-4cd70a4c12c8@baylibre.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7380.yaml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml index de3d28a021ae..899b777017ce 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml @@ -15,6 +15,10 @@ description: | * https://www.analog.com/en/products/ad7381.html * https://www.analog.com/en/products/ad7383.html * https://www.analog.com/en/products/ad7384.html + * https://www.analog.com/en/products/ad7380-4.html + * https://www.analog.com/en/products/ad7381-4.html + * https://www.analog.com/en/products/ad7383-4.html + * https://www.analog.com/en/products/ad7384-4.html $ref: /schemas/spi/spi-peripheral-props.yaml# @@ -25,6 +29,10 @@ properties: - adi,ad7381 - adi,ad7383 - adi,ad7384 + - adi,ad7380-4 + - adi,ad7381-4 + - adi,ad7383-4 + - adi,ad7384-4 reg: maxItems: 1 @@ -56,6 +64,16 @@ properties: The common mode voltage supply for the AINB- pin on pseudo-differential chips. + ainc-supply: + description: + The common mode voltage supply for the AINC- pin on pseudo-differential + chips. + + aind-supply: + description: + The common mode voltage supply for the AIND- pin on pseudo-differential + chips. + interrupts: description: When the device is using 1-wire mode, this property is used to optionally @@ -79,6 +97,8 @@ allOf: enum: - adi,ad7383 - adi,ad7384 + - adi,ad7383-4 + - adi,ad7384-4 then: required: - aina-supply @@ -87,6 +107,20 @@ allOf: properties: aina-supply: false ainb-supply: false + - if: + properties: + compatible: + enum: + - adi,ad7383-4 + - adi,ad7384-4 + then: + required: + - ainc-supply + - aind-supply + else: + properties: + ainc-supply: false + aind-supply: false examples: - | From 737413da870452c38fccd88108d4418d9cc94a9b Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Tue, 28 May 2024 16:20:34 +0200 Subject: [PATCH 077/330] iio: adc: ad7380: add support for ad738x-4 4 channels variants Add support for ad7380/1/2/3-4 parts which are 4 channels variants from ad7380/1/2/3 Signed-off-by: Julien Stephan Link: https://lore.kernel.org/r/20240528-adding-new-ad738x-driver-v7-7-4cd70a4c12c8@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7380.c | 77 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index 790d08c90ad0..6b0b1b0be363 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -8,6 +8,9 @@ * Datasheets of supported parts: * ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf * ad7383/4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-7384.pdf + * ad7380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7380-4.pdf + * ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf + * ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf */ #include @@ -27,7 +30,7 @@ #include #include -#define MAX_NUM_CHANNELS 2 +#define MAX_NUM_CHANNELS 4 /* 2.5V internal reference voltage */ #define AD7380_INTERNAL_REF_MV 2500 @@ -104,27 +107,53 @@ static const struct iio_chan_spec name[] = { \ IIO_CHAN_SOFT_TIMESTAMP(2), \ } +#define DEFINE_AD7380_4_CHANNEL(name, bits, diff) \ +static const struct iio_chan_spec name[] = { \ + AD7380_CHANNEL(0, bits, diff), \ + AD7380_CHANNEL(1, bits, diff), \ + AD7380_CHANNEL(2, bits, diff), \ + AD7380_CHANNEL(3, bits, diff), \ + IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + /* fully differential */ DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1); DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1); +DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1); +DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1); /* pseudo differential */ DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0); DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0); +DEFINE_AD7380_4_CHANNEL(ad7383_4_channels, 16, 0); +DEFINE_AD7380_4_CHANNEL(ad7384_4_channels, 14, 0); static const char * const ad7380_2_channel_vcm_supplies[] = { "aina", "ainb", }; +static const char * const ad7380_4_channel_vcm_supplies[] = { + "aina", "ainb", "ainc", "aind", +}; + /* Since this is simultaneous sampling, we don't allow individual channels. */ static const unsigned long ad7380_2_channel_scan_masks[] = { GENMASK(1, 0), 0 }; +static const unsigned long ad7380_4_channel_scan_masks[] = { + GENMASK(3, 0), + 0 +}; + static const struct ad7380_timing_specs ad7380_timing = { .t_csh_ns = 10, }; +static const struct ad7380_timing_specs ad7380_4_timing = { + .t_csh_ns = 20, +}; + static const struct ad7380_chip_info ad7380_chip_info = { .name = "ad7380", .channels = ad7380_channels, @@ -161,6 +190,42 @@ static const struct ad7380_chip_info ad7384_chip_info = { .timing_specs = &ad7380_timing, }; +static const struct ad7380_chip_info ad7380_4_chip_info = { + .name = "ad7380-4", + .channels = ad7380_4_channels, + .num_channels = ARRAY_SIZE(ad7380_4_channels), + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + +static const struct ad7380_chip_info ad7381_4_chip_info = { + .name = "ad7381-4", + .channels = ad7381_4_channels, + .num_channels = ARRAY_SIZE(ad7381_4_channels), + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + +static const struct ad7380_chip_info ad7383_4_chip_info = { + .name = "ad7383-4", + .channels = ad7383_4_channels, + .num_channels = ARRAY_SIZE(ad7383_4_channels), + .vcm_supplies = ad7380_4_channel_vcm_supplies, + .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies), + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + +static const struct ad7380_chip_info ad7384_4_chip_info = { + .name = "ad7384-4", + .channels = ad7384_4_channels, + .num_channels = ARRAY_SIZE(ad7384_4_channels), + .vcm_supplies = ad7380_4_channel_vcm_supplies, + .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies), + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + struct ad7380_state { const struct ad7380_chip_info *chip_info; struct spi_device *spi; @@ -172,7 +237,7 @@ struct ad7380_state { * transfer buffers to live in their own cache lines. * Make the buffer large enough for MAX_NUM_CHANNELS 16-bit samples and one 64-bit * aligned 64 bit timestamp. - * As MAX_NUM_CHANNELS is 2 the layout of the structure is the same for all parts + * As MAX_NUM_CHANNELS is 4 the layout of the structure is the same for all parts */ struct { u16 raw[MAX_NUM_CHANNELS]; @@ -512,6 +577,10 @@ static const struct of_device_id ad7380_of_match_table[] = { { .compatible = "adi,ad7381", .data = &ad7381_chip_info }, { .compatible = "adi,ad7383", .data = &ad7383_chip_info }, { .compatible = "adi,ad7384", .data = &ad7384_chip_info }, + { .compatible = "adi,ad7380-4", .data = &ad7380_4_chip_info }, + { .compatible = "adi,ad7381-4", .data = &ad7381_4_chip_info }, + { .compatible = "adi,ad7383-4", .data = &ad7383_4_chip_info }, + { .compatible = "adi,ad7384-4", .data = &ad7384_4_chip_info }, { } }; @@ -520,6 +589,10 @@ static const struct spi_device_id ad7380_id_table[] = { { "ad7381", (kernel_ulong_t)&ad7381_chip_info }, { "ad7383", (kernel_ulong_t)&ad7383_chip_info }, { "ad7384", (kernel_ulong_t)&ad7384_chip_info }, + { "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info }, + { "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info }, + { "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info }, + { "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7380_id_table); From fd7179ece035417f44f7ecff086d6df674d8a5bd Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 30 May 2024 10:14:08 -0500 Subject: [PATCH 078/330] iio: introduce struct iio_scan_type This gives the channel scan_type a named type so that it can be used to simplify code in later commits. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240530-iio-add-support-for-multiple-scan-types-v3-1-cbc4acea2cfa@baylibre.com Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 55e2b22086a1..19de573a944a 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -173,6 +173,27 @@ struct iio_event_spec { unsigned long mask_shared_by_all; }; +/** + * struct iio_scan_type - specification for channel data format in buffer + * @sign: 's' or 'u' to specify signed or unsigned + * @realbits: Number of valid bits of data + * @storagebits: Realbits + padding + * @shift: Shift right by this before masking out realbits. + * @repeat: Number of times real/storage bits repeats. When the + * repeat element is more than 1, then the type element in + * sysfs will show a repeat value. Otherwise, the number + * of repetitions is omitted. + * @endianness: little or big endian + */ +struct iio_scan_type { + char sign; + u8 realbits; + u8 storagebits; + u8 shift; + u8 repeat; + enum iio_endian endianness; +}; + /** * struct iio_chan_spec - specification of a single channel * @type: What type of measurement is the channel making. @@ -184,17 +205,6 @@ struct iio_event_spec { * @scan_index: Monotonic index to give ordering in scans when read * from a buffer. * @scan_type: struct describing the scan type - * @scan_type.sign: 's' or 'u' to specify signed or unsigned - * @scan_type.realbits: Number of valid bits of data - * @scan_type.storagebits: Realbits + padding - * @scan_type.shift: Shift right by this before masking out - * realbits. - * @scan_type.repeat: Number of times real/storage bits repeats. - * When the repeat element is more than 1, then - * the type element in sysfs will show a repeat - * value. Otherwise, the number of repetitions - * is omitted. - * @scan_type.endianness: little or big endian * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_separate_available: What availability information is to be @@ -245,14 +255,7 @@ struct iio_chan_spec { int channel2; unsigned long address; int scan_index; - struct { - char sign; - u8 realbits; - u8 storagebits; - u8 shift; - u8 repeat; - enum iio_endian endianness; - } scan_type; + struct iio_scan_type scan_type; long info_mask_separate; long info_mask_separate_available; long info_mask_shared_by_type; From 7758562898033a3bd98a24d2a541c930b0fc98e6 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 30 May 2024 10:14:09 -0500 Subject: [PATCH 079/330] iio: buffer: use struct iio_scan_type to simplify code By using struct iio_scan_type, we can simplify the code by removing lots of duplicate pointer dereferences. This make the code a bit easier to read. This also prepares for a future where channels may have more than one scan_type. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240530-iio-add-support-for-multiple-scan-types-v3-2-cbc4acea2cfa@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 48 ++++++++++++++++++------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index cec58a604d73..08103a9e77f7 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -366,7 +366,8 @@ static ssize_t iio_show_fixed_type(struct device *dev, char *buf) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u8 type = this_attr->c->scan_type.endianness; + const struct iio_scan_type *scan_type = &this_attr->c->scan_type; + u8 type = scan_type->endianness; if (type == IIO_CPU) { #ifdef __LITTLE_ENDIAN @@ -375,21 +376,21 @@ static ssize_t iio_show_fixed_type(struct device *dev, type = IIO_BE; #endif } - if (this_attr->c->scan_type.repeat > 1) + if (scan_type->repeat > 1) return sysfs_emit(buf, "%s:%c%d/%dX%d>>%u\n", iio_endian_prefix[type], - this_attr->c->scan_type.sign, - this_attr->c->scan_type.realbits, - this_attr->c->scan_type.storagebits, - this_attr->c->scan_type.repeat, - this_attr->c->scan_type.shift); + scan_type->sign, + scan_type->realbits, + scan_type->storagebits, + scan_type->repeat, + scan_type->shift); else return sysfs_emit(buf, "%s:%c%d/%d>>%u\n", iio_endian_prefix[type], - this_attr->c->scan_type.sign, - this_attr->c->scan_type.realbits, - this_attr->c->scan_type.storagebits, - this_attr->c->scan_type.shift); + scan_type->sign, + scan_type->realbits, + scan_type->storagebits, + scan_type->shift); } static ssize_t iio_scan_el_show(struct device *dev, @@ -694,12 +695,16 @@ static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, unsigned int scan_index) { const struct iio_chan_spec *ch; + const struct iio_scan_type *scan_type; unsigned int bytes; ch = iio_find_channel_from_si(indio_dev, scan_index); - bytes = ch->scan_type.storagebits / 8; - if (ch->scan_type.repeat > 1) - bytes *= ch->scan_type.repeat; + scan_type = &ch->scan_type; + bytes = scan_type->storagebits / 8; + + if (scan_type->repeat > 1) + bytes *= scan_type->repeat; + return bytes; } @@ -1616,18 +1621,21 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, if (channels) { /* new magic */ for (i = 0; i < indio_dev->num_channels; i++) { + const struct iio_scan_type *scan_type; + if (channels[i].scan_index < 0) continue; + scan_type = &channels[i].scan_type; + /* Verify that sample bits fit into storage */ - if (channels[i].scan_type.storagebits < - channels[i].scan_type.realbits + - channels[i].scan_type.shift) { + if (scan_type->storagebits < + scan_type->realbits + scan_type->shift) { dev_err(&indio_dev->dev, "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n", - i, channels[i].scan_type.storagebits, - channels[i].scan_type.realbits, - channels[i].scan_type.shift); + i, scan_type->storagebits, + scan_type->realbits, + scan_type->shift); ret = -EINVAL; goto error_cleanup_dynamic; } From d8f2bb50845f2797f594ffe3cac9417abff4d7b0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 30 May 2024 10:14:10 -0500 Subject: [PATCH 080/330] iio: add support for multiple scan types per channel This adds new fields to the iio_channel structure to support multiple scan types per channel. This is useful for devices that support multiple resolution modes or other modes that require different data formats of the raw data. To make use of this, drivers need to implement the new callback get_current_scan_type() to resolve the scan type for a given channel based on the current state of the driver. There is a new scan_type_ext field in the iio_channel structure that should be used to store the scan types for any channel that has more than one. There is also a new flag has_ext_scan_type that acts as a type discriminator for the scan_type/ext_scan_type union. A union is used so that we don't grow the size of the iio_channel structure and also makes it clear that scan_type and ext_scan_type are mutually exclusive. The buffer code is the only code in the IIO core code that is using the scan_type field. This patch updates the buffer code to use the new iio_channel_validate_scan_type() function to ensure it is returning the correct scan type for the current state of the device when reading the sysfs attributes. The buffer validation code is also update to validate any additional scan types that are set in the scan_type_ext field. Part of that code is refactored to a new function to avoid duplication. Some userspace tools may need to be updated to re-read the scan type after writing any other attribute. During testing, we noticed that we had to restart iiod to get it to re-read the scan type after enabling oversampling on the ad7380 driver. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240530-iio-add-support-for-multiple-scan-types-v3-3-cbc4acea2cfa@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 99 ++++++++++++++++++++++++------- include/linux/iio/iio.h | 55 ++++++++++++++++- 2 files changed, 132 insertions(+), 22 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 08103a9e77f7..0138b21b244f 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -365,9 +365,16 @@ static ssize_t iio_show_fixed_type(struct device *dev, struct device_attribute *attr, char *buf) { + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - const struct iio_scan_type *scan_type = &this_attr->c->scan_type; - u8 type = scan_type->endianness; + const struct iio_scan_type *scan_type; + u8 type; + + scan_type = iio_get_current_scan_type(indio_dev, this_attr->c); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + type = scan_type->endianness; if (type == IIO_CPU) { #ifdef __LITTLE_ENDIAN @@ -691,15 +698,18 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr, return sysfs_emit(buf, "%d\n", iio_buffer_is_active(buffer)); } -static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, - unsigned int scan_index) +static int iio_storage_bytes_for_si(struct iio_dev *indio_dev, + unsigned int scan_index) { const struct iio_chan_spec *ch; const struct iio_scan_type *scan_type; unsigned int bytes; ch = iio_find_channel_from_si(indio_dev, scan_index); - scan_type = &ch->scan_type; + scan_type = iio_get_current_scan_type(indio_dev, ch); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + bytes = scan_type->storagebits / 8; if (scan_type->repeat > 1) @@ -708,7 +718,7 @@ static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, return bytes; } -static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) +static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); @@ -726,6 +736,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, for_each_set_bit(i, mask, indio_dev->masklength) { length = iio_storage_bytes_for_si(indio_dev, i); + if (length < 0) + return length; + bytes = ALIGN(bytes, length); bytes += length; largest = max(largest, length); @@ -733,6 +746,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, if (timestamp) { length = iio_storage_bytes_for_timestamp(indio_dev); + if (length < 0) + return length; + bytes = ALIGN(bytes, length); bytes += length; largest = max(largest, length); @@ -1012,14 +1028,22 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, indio_dev->masklength, in_ind + 1); while (in_ind != out_ind) { - length = iio_storage_bytes_for_si(indio_dev, in_ind); + ret = iio_storage_bytes_for_si(indio_dev, in_ind); + if (ret < 0) + goto error_clear_mux_table; + + length = ret; /* Make sure we are aligned */ in_loc = roundup(in_loc, length) + length; in_ind = find_next_bit(indio_dev->active_scan_mask, indio_dev->masklength, in_ind + 1); } - length = iio_storage_bytes_for_si(indio_dev, in_ind); + ret = iio_storage_bytes_for_si(indio_dev, in_ind); + if (ret < 0) + goto error_clear_mux_table; + + length = ret; out_loc = roundup(out_loc, length); in_loc = roundup(in_loc, length); ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); @@ -1030,7 +1054,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, } /* Relies on scan_timestamp being last */ if (buffer->scan_timestamp) { - length = iio_storage_bytes_for_timestamp(indio_dev); + ret = iio_storage_bytes_for_timestamp(indio_dev); + if (ret < 0) + goto error_clear_mux_table; + + length = ret; out_loc = roundup(out_loc, length); in_loc = roundup(in_loc, length); ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); @@ -1597,6 +1625,22 @@ static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp } } +static int iio_channel_validate_scan_type(struct device *dev, int ch, + const struct iio_scan_type *scan_type) +{ + /* Verify that sample bits fit into storage */ + if (scan_type->storagebits < scan_type->realbits + scan_type->shift) { + dev_err(dev, + "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n", + ch, scan_type->storagebits, + scan_type->realbits, + scan_type->shift); + return -EINVAL; + } + + return 0; +} + static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, struct iio_dev *indio_dev, int index) @@ -1626,18 +1670,33 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, if (channels[i].scan_index < 0) continue; - scan_type = &channels[i].scan_type; + if (channels[i].has_ext_scan_type) { + int j; - /* Verify that sample bits fit into storage */ - if (scan_type->storagebits < - scan_type->realbits + scan_type->shift) { - dev_err(&indio_dev->dev, - "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n", - i, scan_type->storagebits, - scan_type->realbits, - scan_type->shift); - ret = -EINVAL; - goto error_cleanup_dynamic; + /* + * get_current_scan_type is required when using + * extended scan types. + */ + if (!indio_dev->info->get_current_scan_type) { + ret = -EINVAL; + goto error_cleanup_dynamic; + } + + for (j = 0; j < channels[i].num_ext_scan_type; j++) { + scan_type = &channels[i].ext_scan_type[j]; + + ret = iio_channel_validate_scan_type( + &indio_dev->dev, i, scan_type); + if (ret) + goto error_cleanup_dynamic; + } + } else { + scan_type = &channels[i].scan_type; + + ret = iio_channel_validate_scan_type( + &indio_dev->dev, i, scan_type); + if (ret) + goto error_cleanup_dynamic; } ret = iio_buffer_add_channel_sysfs(indio_dev, buffer, diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 19de573a944a..894309294182 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -204,7 +204,13 @@ struct iio_scan_type { * @address: Driver specific identifier. * @scan_index: Monotonic index to give ordering in scans when read * from a buffer. - * @scan_type: struct describing the scan type + * @scan_type: struct describing the scan type - mutually exclusive + * with ext_scan_type. + * @ext_scan_type: Used in rare cases where there is more than one scan + * format for a channel. When this is used, the flag + * has_ext_scan_type must be set and the driver must + * implement get_current_scan_type in struct iio_info. + * @num_ext_scan_type: Number of elements in ext_scan_type. * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_separate_available: What availability information is to be @@ -248,6 +254,7 @@ struct iio_scan_type { * attributes but not for event codes. * @output: Channel is output. * @differential: Channel is differential. + * @has_ext_scan_type: True if ext_scan_type is used instead of scan_type. */ struct iio_chan_spec { enum iio_chan_type type; @@ -255,7 +262,13 @@ struct iio_chan_spec { int channel2; unsigned long address; int scan_index; - struct iio_scan_type scan_type; + union { + struct iio_scan_type scan_type; + struct { + const struct iio_scan_type *ext_scan_type; + unsigned int num_ext_scan_type; + }; + }; long info_mask_separate; long info_mask_separate_available; long info_mask_shared_by_type; @@ -273,6 +286,7 @@ struct iio_chan_spec { unsigned indexed:1; unsigned output:1; unsigned differential:1; + unsigned has_ext_scan_type:1; }; @@ -435,6 +449,9 @@ struct iio_trigger; /* forward declaration */ * for better event identification. * @validate_trigger: function to validate the trigger when the * current trigger gets changed. + * @get_current_scan_type: must be implemented by drivers that use ext_scan_type + * in the channel spec to return the index of the currently + * active ext_scan type for a channel. * @update_scan_mode: function to configure device and scan buffer when * channels have changed * @debugfs_reg_access: function to read or write register value of device @@ -519,6 +536,8 @@ struct iio_info { int (*validate_trigger)(struct iio_dev *indio_dev, struct iio_trigger *trig); + int (*get_current_scan_type)(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan); int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask); int (*debugfs_reg_access)(struct iio_dev *indio_dev, @@ -804,6 +823,38 @@ static inline bool iio_read_acpi_mount_matrix(struct device *dev, } #endif +/** + * iio_get_current_scan_type - Get the current scan type for a channel + * @indio_dev: the IIO device to get the scan type for + * @chan: the channel to get the scan type for + * + * Most devices only have one scan type per channel and can just access it + * directly without calling this function. Core IIO code and drivers that + * implement ext_scan_type in the channel spec should use this function to + * get the current scan type for a channel. + * + * Returns: the current scan type for the channel or error. + */ +static inline const struct iio_scan_type +*iio_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + int ret; + + if (chan->has_ext_scan_type) { + ret = indio_dev->info->get_current_scan_type(indio_dev, chan); + if (ret < 0) + return ERR_PTR(ret); + + if (ret >= chan->num_ext_scan_type) + return ERR_PTR(-EINVAL); + + return &chan->ext_scan_type[ret]; + } + + return &chan->scan_type; +} + ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, From 99d46eecf98fe9af4573363fcb5c8d8d36ce875e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 30 May 2024 10:14:11 -0500 Subject: [PATCH 081/330] iio: adc: ad7380: use spi_optimize_message() This changes the AD7380 to use spi_optimize_message() to optimize buffered reads. This changes both direct reads and buffered reads to use the same spi_message. This has some (welcome) side effects. The first is that in buffered reads, the timestamp will now correspond to the same sample rather than the previous sample. The second is that direct reads now use the same SPI bus speed as buffered reads. This reduces CPU usage of the IRQ thread from around 25% to around 20% when sampling at 10 kHz on a ZedBoard. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240530-iio-add-support-for-multiple-scan-types-v3-4-cbc4acea2cfa@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7380.c | 70 ++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index 6b0b1b0be363..006496807de9 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -232,6 +232,9 @@ struct ad7380_state { struct regmap *regmap; unsigned int vref_mv; unsigned int vcm_mv[MAX_NUM_CHANNELS]; + /* xfers, message an buffer for reading sample data */ + struct spi_transfer xfer[2]; + struct spi_message msg; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -331,15 +334,9 @@ static irqreturn_t ad7380_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7380_state *st = iio_priv(indio_dev); - struct spi_transfer xfer = { - .bits_per_word = st->chip_info->channels[0].scan_type.realbits, - .len = (st->chip_info->num_channels - 1) * - BITS_TO_BYTES(st->chip_info->channels->scan_type.storagebits), - .rx_buf = st->scan_data.raw, - }; int ret; - ret = spi_sync_transfer(st->spi, &xfer, 1); + ret = spi_sync(st->spi, &st->msg); if (ret) goto out; @@ -355,33 +352,9 @@ out: static int ad7380_read_direct(struct ad7380_state *st, struct iio_chan_spec const *chan, int *val) { - struct spi_transfer xfers[] = { - /* toggle CS (no data xfer) to trigger a conversion */ - { - .speed_hz = AD7380_REG_WR_SPEED_HZ, - .bits_per_word = chan->scan_type.realbits, - .delay = { - .value = T_CONVERT_NS, - .unit = SPI_DELAY_UNIT_NSECS, - }, - .cs_change = 1, - .cs_change_delay = { - .value = st->chip_info->timing_specs->t_csh_ns, - .unit = SPI_DELAY_UNIT_NSECS, - }, - }, - /* then read all channels */ - { - .speed_hz = AD7380_REG_WR_SPEED_HZ, - .bits_per_word = chan->scan_type.realbits, - .rx_buf = st->scan_data.raw, - .len = (st->chip_info->num_channels - 1) * - ((chan->scan_type.storagebits > 16) ? 4 : 2), - }, - }; int ret; - ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); + ret = spi_sync(st->spi, &st->msg); if (ret < 0) return ret; @@ -464,6 +437,11 @@ static void ad7380_regulator_disable(void *p) regulator_disable(p); } +static void ad7380_unoptimize_msg(void *msg) +{ + spi_unoptimize_message(msg); +} + static int ad7380_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -552,6 +530,34 @@ static int ad7380_probe(struct spi_device *spi) return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), "failed to allocate register map\n"); + /* + * Setting up a low latency read for getting sample data. Used for both + * direct read an triggered buffer. + */ + + /* toggle CS (no data xfer) to trigger a conversion */ + st->xfer[0].delay.value = T_CONVERT_NS; + st->xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS; + st->xfer[0].cs_change = 1; + st->xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns; + st->xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + + /* then do a second xfer to read the data */ + st->xfer[1].bits_per_word = st->chip_info->channels[0].scan_type.realbits; + st->xfer[1].rx_buf = st->scan_data.raw; + st->xfer[1].len = BITS_TO_BYTES(st->chip_info->channels[0].scan_type.storagebits) + * (st->chip_info->num_channels - 1); + + spi_message_init_with_transfers(&st->msg, st->xfer, ARRAY_SIZE(st->xfer)); + + ret = spi_optimize_message(st->spi, &st->msg); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, ad7380_unoptimize_msg, &st->msg); + if (ret) + return ret; + indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; indio_dev->name = st->chip_info->name; From 15b08012852f40ce89c3237a557b68397916685e Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Thu, 30 May 2024 10:14:12 -0500 Subject: [PATCH 082/330] iio: adc: ad7380: add oversampling support ad7380x(-4) parts are able to do oversampling to increase accuracy. This chips supports a normal oversampling mode and a rolling mode and also allows enabling and disabling extra resolution bits when oversampling is enabled. We have intentionally left out the rolling mode for now as there is not a compelling use case for it. User can process a captured data buffer to get the same effect. We are also currently not supporting changing the oversampling mode independently of the resolution bits. The resolution boost feature can only be enabled when oversampling is enabled and oversampling is not as useful without the resolution boost. So for now we consider the features tightly coupled. When oversampling is enabled, the resolution boost is enabled and when oversampling is disabled, the resolution boost is disabled. Since the resolution boost feature causes 16-bit chips to now have 18-bit data which means the storagebits has to change from 16 to 32 bits, we use the new ext_scan_type feature to allow changing the scan_type at runtime based on if the resolution boost is enabled or not. SPI message optimization has to be moved since now some of the xfer parameters change based on the resolution boost mode. A few neighboring comments are also fixed up while we are touching this code. Signed-off-by: Julien Stephan Co-developed-by: David Lechner Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240530-iio-add-support-for-multiple-scan-types-v3-5-cbc4acea2cfa@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7380.c | 305 +++++++++++++++++++++++++++++++++------ 1 file changed, 260 insertions(+), 45 deletions(-) diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index 006496807de9..7568cd0a2b32 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -13,6 +13,7 @@ * ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf */ +#include #include #include #include @@ -68,6 +69,9 @@ #define AD7380_ALERT_HIGH_TH GENMASK(11, 0) #define T_CONVERT_NS 190 /* conversion time */ +#define T_CONVERT_0_NS 10 /* 1st conversion start time (oversampling) */ +#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */ + struct ad7380_timing_specs { const unsigned int t_csh_ns; /* CS minimum high time */ }; @@ -82,22 +86,59 @@ struct ad7380_chip_info { const struct ad7380_timing_specs *timing_specs; }; +enum { + AD7380_SCAN_TYPE_NORMAL, + AD7380_SCAN_TYPE_RESOLUTION_BOOST, +}; + +/* Extended scan types for 14-bit chips. */ +static const struct iio_scan_type ad7380_scan_type_14[] = { + [AD7380_SCAN_TYPE_NORMAL] = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + .endianness = IIO_CPU + }, + [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU + }, +}; + +/* Extended scan types for 16-bit chips. */ +static const struct iio_scan_type ad7380_scan_type_16[] = { + [AD7380_SCAN_TYPE_NORMAL] = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU + }, + [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = { + .sign = 's', + .realbits = 18, + .storagebits = 32, + .endianness = IIO_CPU + }, +}; + #define AD7380_CHANNEL(index, bits, diff) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .indexed = 1, \ .differential = (diff), \ .channel = (diff) ? (2 * (index)) : (index), \ .channel2 = (diff) ? (2 * (index) + 1) : 0, \ .scan_index = (index), \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .endianness = IIO_CPU, \ - }, \ + .has_ext_scan_type = 1, \ + .ext_scan_type = ad7380_scan_type_##bits, \ + .num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits),\ } #define DEFINE_AD7380_2_CHANNEL(name, bits, diff) \ @@ -154,6 +195,15 @@ static const struct ad7380_timing_specs ad7380_4_timing = { .t_csh_ns = 20, }; +/* + * Available oversampling ratios. The indices correspond with the bit value + * expected by the chip. The available ratios depend on the averaging mode, + * only normal averaging is supported for now. + */ +static const int ad7380_oversampling_ratios[] = { + 1, 2, 4, 8, 16, 32, +}; + static const struct ad7380_chip_info ad7380_chip_info = { .name = "ad7380", .channels = ad7380_channels, @@ -230,23 +280,23 @@ struct ad7380_state { const struct ad7380_chip_info *chip_info; struct spi_device *spi; struct regmap *regmap; + unsigned int oversampling_ratio; + bool resolution_boost_enabled; unsigned int vref_mv; unsigned int vcm_mv[MAX_NUM_CHANNELS]; /* xfers, message an buffer for reading sample data */ struct spi_transfer xfer[2]; struct spi_message msg; /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - * Make the buffer large enough for MAX_NUM_CHANNELS 16-bit samples and one 64-bit - * aligned 64 bit timestamp. - * As MAX_NUM_CHANNELS is 4 the layout of the structure is the same for all parts + * DMA (thus cache coherency maintenance) requires the transfer buffers + * to live in their own cache lines. + * + * Make the buffer large enough for MAX_NUM_CHANNELS 32-bit samples and + * one 64-bit aligned 64-bit timestamp. */ - struct { - u16 raw[MAX_NUM_CHANNELS]; - - s64 ts __aligned(8); - } scan_data __aligned(IIO_DMA_MINALIGN); + u8 scan_data[ALIGN(MAX_NUM_CHANNELS * sizeof(u32), sizeof(s64)) + + sizeof(s64)] __aligned(IIO_DMA_MINALIGN); + /* buffers for reading/writing registers */ u16 tx; u16 rx; }; @@ -329,6 +379,69 @@ static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg, unreachable(); } +/** + * ad7380_update_xfers - update the SPI transfers base on the current scan type + * @st: device instance specific state + * @scan_type: current scan type + */ +static void ad7380_update_xfers(struct ad7380_state *st, + const struct iio_scan_type *scan_type) +{ + /* + * First xfer only triggers conversion and has to be long enough for + * all conversions to complete, which can be multiple conversion in the + * case of oversampling. Technically T_CONVERT_X_NS is lower for some + * chips, but we use the maximum value for simplicity for now. + */ + if (st->oversampling_ratio > 1) + st->xfer[0].delay.value = T_CONVERT_0_NS + T_CONVERT_X_NS * + (st->oversampling_ratio - 1); + else + st->xfer[0].delay.value = T_CONVERT_NS; + + st->xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS; + + /* + * Second xfer reads all channels. Data size depends on if resolution + * boost is enabled or not. + */ + st->xfer[1].bits_per_word = scan_type->realbits; + st->xfer[1].len = BITS_TO_BYTES(scan_type->storagebits) * + (st->chip_info->num_channels - 1); +} + +static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad7380_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type; + + /* + * Currently, we always read all channels at the same time. The scan_type + * is the same for all channels, so we just pass the first channel. + */ + scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + ad7380_update_xfers(st, scan_type); + + return spi_optimize_message(st->spi, &st->msg); +} + +static int ad7380_triggered_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad7380_state *st = iio_priv(indio_dev); + + spi_unoptimize_message(&st->msg); + + return 0; +} + +static const struct iio_buffer_setup_ops ad7380_buffer_setup_ops = { + .preenable = ad7380_triggered_buffer_preenable, + .postdisable = ad7380_triggered_buffer_postdisable, +}; + static irqreturn_t ad7380_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -349,17 +462,23 @@ out: return IRQ_HANDLED; } -static int ad7380_read_direct(struct ad7380_state *st, - struct iio_chan_spec const *chan, int *val) +static int ad7380_read_direct(struct ad7380_state *st, unsigned int scan_index, + const struct iio_scan_type *scan_type, int *val) { int ret; + ad7380_update_xfers(st, scan_type); + ret = spi_sync(st->spi, &st->msg); if (ret < 0) return ret; - *val = sign_extend32(st->scan_data.raw[chan->scan_index], - chan->scan_type.realbits - 1); + if (scan_type->storagebits > 16) + *val = sign_extend32(*(u32 *)(st->scan_data + 4 * scan_index), + scan_type->realbits - 1); + else + *val = sign_extend32(*(u16 *)(st->scan_data + 2 * scan_index), + scan_type->realbits - 1); return IIO_VAL_INT; } @@ -369,11 +488,18 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long info) { struct ad7380_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type; + + scan_type = iio_get_current_scan_type(indio_dev, chan); + + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); switch (info) { case IIO_CHAN_INFO_RAW: iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - return ad7380_read_direct(st, chan, val); + return ad7380_read_direct(st, chan->scan_index, + scan_type, val); } unreachable(); case IIO_CHAN_INFO_SCALE: @@ -384,7 +510,7 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, * where N is the ADC resolution (i.e realbits) */ *val = st->vref_mv; - *val2 = chan->scan_type.realbits - chan->differential; + *val2 = scan_type->realbits - chan->differential; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: @@ -392,17 +518,118 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, * According to IIO ABI, offset is applied before scale, * so offset is: vcm_mv / scale */ - *val = st->vcm_mv[chan->channel] * (1 << chan->scan_type.realbits) + *val = st->vcm_mv[chan->channel] * (1 << scan_type->realbits) / st->vref_mv; + return IIO_VAL_INT; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling_ratio; + return IIO_VAL_INT; default: return -EINVAL; } } +static int ad7380_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = ad7380_oversampling_ratios; + *length = ARRAY_SIZE(ad7380_oversampling_ratios); + *type = IIO_VAL_INT; + + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +/** + * ad7380_osr_to_regval - convert ratio to OSR register value + * @ratio: ratio to check + * + * Check if ratio is present in the list of available ratios and return the + * corresponding value that needs to be written to the register to select that + * ratio. + * + * Returns: register value (0 to 7) or -EINVAL if there is not an exact match + */ +static int ad7380_osr_to_regval(int ratio) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ad7380_oversampling_ratios); i++) { + if (ratio == ad7380_oversampling_ratios[i]) + return i; + } + + return -EINVAL; +} + +static int ad7380_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ad7380_state *st = iio_priv(indio_dev); + int ret, osr, boost; + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + osr = ad7380_osr_to_regval(val); + if (osr < 0) + return osr; + + /* always enable resolution boost when oversampling is enabled */ + boost = osr > 0 ? 1 : 0; + + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + ret = regmap_update_bits(st->regmap, + AD7380_REG_ADDR_CONFIG1, + AD7380_CONFIG1_OSR | AD7380_CONFIG1_RES, + FIELD_PREP(AD7380_CONFIG1_OSR, osr) | + FIELD_PREP(AD7380_CONFIG1_RES, boost)); + + if (ret) + return ret; + + st->oversampling_ratio = val; + st->resolution_boost_enabled = boost; + + /* + * Perform a soft reset. This will flush the oversampling + * block and FIFO but will maintain the content of the + * configurable registers. + */ + return regmap_update_bits(st->regmap, + AD7380_REG_ADDR_CONFIG2, + AD7380_CONFIG2_RESET, + FIELD_PREP(AD7380_CONFIG2_RESET, + AD7380_CONFIG2_RESET_SOFT)); + } + unreachable(); + default: + return -EINVAL; + } +} + +static int ad7380_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad7380_state *st = iio_priv(indio_dev); + + return st->resolution_boost_enabled ? AD7380_SCAN_TYPE_RESOLUTION_BOOST + : AD7380_SCAN_TYPE_NORMAL; +} + static const struct iio_info ad7380_info = { .read_raw = &ad7380_read_raw, + .read_avail = &ad7380_read_avail, + .write_raw = &ad7380_write_raw, + .get_current_scan_type = &ad7380_get_current_scan_type, .debugfs_reg_access = &ad7380_debugfs_reg_access, }; @@ -426,6 +653,9 @@ static int ad7380_init(struct ad7380_state *st, struct regulator *vref) if (ret < 0) return ret; + /* This is the default value after reset. */ + st->oversampling_ratio = 1; + /* SPI 1-wire mode */ return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2, AD7380_CONFIG2_SDO, @@ -437,11 +667,6 @@ static void ad7380_regulator_disable(void *p) regulator_disable(p); } -static void ad7380_unoptimize_msg(void *msg) -{ - spi_unoptimize_message(msg); -} - static int ad7380_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -532,32 +757,21 @@ static int ad7380_probe(struct spi_device *spi) /* * Setting up a low latency read for getting sample data. Used for both - * direct read an triggered buffer. + * direct read an triggered buffer. Additional fields will be set up in + * ad7380_update_xfers() based on the current state of the driver at the + * time of the read. */ /* toggle CS (no data xfer) to trigger a conversion */ - st->xfer[0].delay.value = T_CONVERT_NS; - st->xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS; st->xfer[0].cs_change = 1; st->xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns; st->xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; /* then do a second xfer to read the data */ - st->xfer[1].bits_per_word = st->chip_info->channels[0].scan_type.realbits; - st->xfer[1].rx_buf = st->scan_data.raw; - st->xfer[1].len = BITS_TO_BYTES(st->chip_info->channels[0].scan_type.storagebits) - * (st->chip_info->num_channels - 1); + st->xfer[1].rx_buf = st->scan_data; spi_message_init_with_transfers(&st->msg, st->xfer, ARRAY_SIZE(st->xfer)); - ret = spi_optimize_message(st->spi, &st->msg); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&spi->dev, ad7380_unoptimize_msg, &st->msg); - if (ret) - return ret; - indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; indio_dev->name = st->chip_info->name; @@ -567,7 +781,8 @@ static int ad7380_probe(struct spi_device *spi) ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, iio_pollfunc_store_time, - ad7380_trigger_handler, NULL); + ad7380_trigger_handler, + &ad7380_buffer_setup_ops); if (ret) return ret; From 6859fba8c1481df1a0daae1405ee14f04f5952d3 Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:10 +0300 Subject: [PATCH 083/330] dt-bindings: iio: imu: Add ADIS16501 compatibles Add ADIS16501 compatible. Similarly to other ADIS1650X devices, ADIS16501 supports sync-mode values [0,2]. There are two differences between ADIS16501 and ADIS16477-2: - ADIS16501 does not support pulse sync mode - the delta velocity scale value is different Acked-by: Conor Dooley Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-2-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml index 9b7ad609f7db..db52e7063116 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml @@ -30,6 +30,7 @@ properties: - adi,adis16467-2 - adi,adis16467-3 - adi,adis16500 + - adi,adis16501 - adi,adis16505-1 - adi,adis16505-2 - adi,adis16505-3 @@ -90,6 +91,7 @@ allOf: contains: enum: - adi,adis16500 + - adi,adis16501 - adi,adis16505-1 - adi,adis16505-2 - adi,adis16505-3 From 64c65fac71b09d4d0edc24af4cfbb5123dad6f6b Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:11 +0300 Subject: [PATCH 084/330] drivers: iio: imu: Add support for ADIS16501 Add support for ADIS16501 device in already existing ADIS16475 driver. Reviewed-by: Nuno Sa Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-3-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/Kconfig | 4 ++-- drivers/iio/imu/adis16475.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 52a155ff3250..782fb80e44c2 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -36,8 +36,8 @@ config ADIS16475 select IIO_ADIS_LIB_BUFFER if IIO_BUFFER help Say yes here to build support for Analog Devices ADIS16470, ADIS16475, - ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505, ADIS16507 inertial - sensors. + ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16501, ADIS16505, + ADIS16507 inertial sensors. To compile this driver as a module, choose M here: the module will be called adis16475. diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 060a21c70460..8dc22d01246a 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -661,6 +661,7 @@ enum adis16475_variant { ADIS16467_2, ADIS16467_3, ADIS16500, + ADIS16501, ADIS16505_1, ADIS16505_2, ADIS16505_3, @@ -980,6 +981,25 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts), }, + [ADIS16501] = { + .name = "adis16501", + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, + .gyro_max_val = 1, + .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), + .accel_max_val = 1, + .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), + .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 125, + .int_clk = 2000, + .max_dec = 1999, + .sync = adis16475_sync_mode, + /* pulse sync not supported */ + .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, + .adis_data = ADIS16475_DATA(16501, &adis1650x_timeouts), + }, [ADIS16505_1] = { .name = "adis16505-1", .num_channels = ARRAY_SIZE(adis16477_channels), @@ -1484,6 +1504,8 @@ static const struct of_device_id adis16475_of_match[] = { .data = &adis16475_chip_info[ADIS16467_3] }, { .compatible = "adi,adis16500", .data = &adis16475_chip_info[ADIS16500] }, + { .compatible = "adi,adis16501", + .data = &adis16475_chip_info[ADIS16501] }, { .compatible = "adi,adis16505-1", .data = &adis16475_chip_info[ADIS16505_1] }, { .compatible = "adi,adis16505-2", @@ -1515,6 +1537,7 @@ static const struct spi_device_id adis16475_ids[] = { { "adis16467-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] }, { "adis16467-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] }, { "adis16500", (kernel_ulong_t)&adis16475_chip_info[ADIS16500] }, + { "adis16501", (kernel_ulong_t)&adis16475_chip_info[ADIS16501] }, { "adis16505-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] }, { "adis16505-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] }, { "adis16505-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] }, From b6e6aca6c2b1b53fb4db4b672eaa2722a75aa6a2 Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:12 +0300 Subject: [PATCH 085/330] iio: imu: adis_buffer: Add buffer setup API with buffer attributes Add new API called devm_adis_setup_buffer_and_trigger_with_attrs() which also takes buffer attributes as a parameter. Rewrite devm_adis_setup_buffer_and_trigger() implementation such that it calls devm_adis_setup_buffer_and_trigger_with_attrs() with buffer attributes parameter NULL Reviewed-by: Nuno Sa Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-4-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 32 ++++++++++++++++++-------------- include/linux/iio/imu/adis.h | 20 ++++++++++++++++---- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 928933027ae3..871b78b225e2 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -175,31 +175,36 @@ static void adis_buffer_cleanup(void *arg) } /** - * devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for - * the managed adis device + * devm_adis_setup_buffer_and_trigger_with_attrs() - Sets up buffer and trigger + * for the managed adis device with buffer attributes. * @adis: The adis device * @indio_dev: The IIO device - * @trigger_handler: Optional trigger handler, may be NULL. + * @trigger_handler: Trigger handler: should handle the buffer readings. + * @ops: Optional buffer setup functions, may be NULL. + * @buffer_attrs: Extra buffer attributes. * * Returns 0 on success, a negative error code otherwise. * - * This function sets up the buffer and trigger for a adis devices. If - * 'trigger_handler' is NULL the default trigger handler will be used. The - * default trigger handler will simply read the registers assigned to the - * currently active channels. + * This function sets up the buffer (with buffer setup functions and extra + * buffer attributes) and trigger for a adis devices with buffer attributes. */ int -devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, - irq_handler_t trigger_handler) +devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis, struct iio_dev *indio_dev, + irq_handler_t trigger_handler, + const struct iio_buffer_setup_ops *ops, + const struct iio_dev_attr **buffer_attrs) { int ret; if (!trigger_handler) trigger_handler = adis_trigger_handler; - ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev, - &iio_pollfunc_store_time, - trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup_ext(&adis->spi->dev, indio_dev, + &iio_pollfunc_store_time, + trigger_handler, + IIO_BUFFER_DIRECTION_IN, + ops, + buffer_attrs); if (ret) return ret; @@ -212,5 +217,4 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup, adis); } -EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger, IIO_ADISLIB); - +EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger_with_attrs, IIO_ADISLIB); diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 8898966bc0f0..0fe3a2f63033 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -21,6 +21,7 @@ #define ADIS_REG_PAGE_ID 0x00 struct adis; +struct iio_dev_attr; /** * struct adis_timeouts - ADIS chip variant timeouts @@ -515,11 +516,19 @@ int adis_single_conversion(struct iio_dev *indio_dev, #define ADIS_ROT_CHAN(mod, addr, si, info_sep, info_all, bits) \ ADIS_MOD_CHAN(IIO_ROT, mod, addr, si, info_sep, info_all, bits) +#define devm_adis_setup_buffer_and_trigger(adis, indio_dev, trigger_handler) \ + devm_adis_setup_buffer_and_trigger_with_attrs((adis), (indio_dev), \ + (trigger_handler), NULL, \ + NULL) + #ifdef CONFIG_IIO_ADIS_LIB_BUFFER int -devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, - irq_handler_t trigger_handler); +devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis, + struct iio_dev *indio_dev, + irq_handler_t trigger_handler, + const struct iio_buffer_setup_ops *ops, + const struct iio_dev_attr **buffer_attrs); int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev); @@ -529,8 +538,11 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, #else /* CONFIG_IIO_BUFFER */ static inline int -devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, - irq_handler_t trigger_handler) +devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis, + struct iio_dev *indio_dev, + irq_handler_t trigger_handler, + const struct iio_buffer_setup_ops *ops, + const struct iio_dev_attr **buffer_attrs) { return 0; } From 880b1b1fbef5e6dc6bbcdb25311b9a030adf5a4e Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:13 +0300 Subject: [PATCH 086/330] iio: imu: adis16475: Create push single sample API Create push single sample API reposnsible for pushing a single sample into the buffer. This is a preparation patch for FIFO support where more than one sample has to be pushed in the trigger handler. Reviewed-by: Nuno Sa Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-5-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 8dc22d01246a..d7e71d302f78 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -1207,9 +1207,8 @@ static void adis16475_burst32_check(struct adis16475 *st) } } -static irqreturn_t adis16475_trigger_handler(int irq, void *p) +static int adis16475_push_single_sample(struct iio_poll_func *pf) { - struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16475 *st = iio_priv(indio_dev); struct adis *adis = &st->adis; @@ -1298,6 +1297,15 @@ check_burst32: * array. */ adis16475_burst32_check(st); + return ret; +} + +static irqreturn_t adis16475_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + + adis16475_push_single_sample(pf); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; From f5657c7751d73db8d88c6eee556dce6534620a1f Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:14 +0300 Subject: [PATCH 087/330] drivers: iio: imu: adis16475: generic computation for sample rate Currently adis16475 supports a sample rate between 1900 and 2100 Hz. This patch changes the setting of sample rate from hardcoded values to a generic computation based on the internal clock frequency. This is a preparatory patch for adding support for adis1657x family devices which allow sample rates between 3900 and 4100 Hz. Reviewed-by: Nuno Sa Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-6-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 39 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index d7e71d302f78..4b66cf308f22 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -310,6 +310,9 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) u16 dec; int ret; u32 sample_rate = st->clk_freq; + /* The optimal sample rate for the supported IMUs is between int_clk - 100 and int_clk + 100. */ + u32 max_sample_rate = st->info->int_clk * 1000 + 100000; + u32 min_sample_rate = st->info->int_clk * 1000 - 100000; if (!freq) return -EINVAL; @@ -317,8 +320,9 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) adis_dev_lock(&st->adis); /* * When using sync scaled mode, the input clock needs to be scaled so that we have - * an IMU sample rate between (optimally) 1900 and 2100. After this, we can use the - * decimation filter to lower the sampling rate in order to get what the user wants. + * an IMU sample rate between (optimally) int_clk - 100 and int_clk + 100. + * After this, we can use the decimation filter to lower the sampling rate in order + * to get what the user wants. * Optimally, the user sample rate is a multiple of both the IMU sample rate and * the input clock. Hence, calculating the sync_scale dynamically gives us better * chances of achieving a perfect/integer value for DEC_RATE. The math here is: @@ -336,23 +340,24 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) * solution. In this case, we get the highest multiple of the input clock * lower than the IMU max sample rate. */ - if (scaled_rate > 2100000) - scaled_rate = 2100000 / st->clk_freq * st->clk_freq; + if (scaled_rate > max_sample_rate) + scaled_rate = max_sample_rate / st->clk_freq * st->clk_freq; else - scaled_rate = 2100000 / scaled_rate * scaled_rate; + scaled_rate = max_sample_rate / scaled_rate * scaled_rate; /* * This is not an hard requirement but it's not advised to run the IMU - * with a sample rate lower than 1900Hz due to possible undersampling - * issues. However, there are users that might really want to take the risk. - * Hence, we provide a module parameter for them. If set, we allow sample - * rates lower than 1.9KHz. By default, we won't allow this and we just roundup - * the rate to the next multiple of the input clock bigger than 1.9KHz. This - * is done like this as in some cases (when DEC_RATE is 0) might give - * us the closest value to the one desired by the user... + * with a sample rate lower than internal clock frequency, due to possible + * undersampling issues. However, there are users that might really want + * to take the risk. Hence, we provide a module parameter for them. If set, + * we allow sample rates lower than internal clock frequency. + * By default, we won't allow this and we just roundup the rate to the next + * multiple of the input clock. This is done like this as in some cases + * (when DEC_RATE is 0) might give us the closest value to the one desired + * by the user... */ - if (scaled_rate < 1900000 && !low_rate_allow) - scaled_rate = roundup(1900000, st->clk_freq); + if (scaled_rate < min_sample_rate && !low_rate_allow) + scaled_rate = roundup(min_sample_rate, st->clk_freq); sync_scale = scaled_rate / st->clk_freq; ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale); @@ -1317,6 +1322,7 @@ static int adis16475_config_sync_mode(struct adis16475 *st) struct device *dev = &st->adis.spi->dev; const struct adis16475_sync *sync; u32 sync_mode; + u16 max_sample_rate = st->info->int_clk + 100; u16 val; /* default to internal clk */ @@ -1357,10 +1363,9 @@ static int adis16475_config_sync_mode(struct adis16475 *st) /* * In sync scaled mode, the IMU sample rate is the clk_freq * sync_scale. * Hence, default the IMU sample rate to the highest multiple of the input - * clock lower than the IMU max sample rate. The optimal range is - * 1900-2100 sps... + * clock lower than the IMU max sample rate. */ - up_scale = 2100 / st->clk_freq; + up_scale = max_sample_rate / st->clk_freq; ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, From 01724ce2d9405b2246bbb69701c74880eb56a34b Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:15 +0300 Subject: [PATCH 088/330] iio: imu: adis_trigger: Allow level interrupts for FIFO readings Currently, adis library allows configuration only for edge interrupts, needed for data ready sampling. This patch removes the restriction for level interrupts for devices which have FIFO support. Furthermore, in case of devices which have FIFO support, devm_request_threaded_irq is used for interrupt allocation, to avoid flooding the processor with the FIFO watermark level interrupt, which is active until enough data has been read from the FIFO. Reviewed-by: Nuno Sa Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-7-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_trigger.c | 37 ++++++++++++++++++++++++---------- include/linux/iio/imu/adis.h | 1 + 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index f890bf842db8..a8740b043cfe 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -34,17 +34,24 @@ static int adis_validate_irq_flag(struct adis *adis) if (adis->data->unmasked_drdy) adis->irq_flag |= IRQF_NO_AUTOEN; /* - * Typically this devices have data ready either on the rising edge or - * on the falling edge of the data ready pin. This checks enforces that - * one of those is set in the drivers... It defaults to - * IRQF_TRIGGER_RISING for backward compatibility with devices that - * don't support changing the pin polarity. + * Typically adis devices without FIFO have data ready either on the + * rising edge or on the falling edge of the data ready pin. + * IMU devices with FIFO support have the watermark pin level driven + * either high or low when the FIFO is filled with the desired number + * of samples. + * It defaults to IRQF_TRIGGER_RISING for backward compatibility with + * devices that don't support changing the pin polarity. */ if (direction == IRQF_TRIGGER_NONE) { adis->irq_flag |= IRQF_TRIGGER_RISING; return 0; } else if (direction != IRQF_TRIGGER_RISING && - direction != IRQF_TRIGGER_FALLING) { + direction != IRQF_TRIGGER_FALLING && !adis->data->has_fifo) { + dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n", + adis->irq_flag); + return -EINVAL; + } else if (direction != IRQF_TRIGGER_HIGH && + direction != IRQF_TRIGGER_LOW && adis->data->has_fifo) { dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n", adis->irq_flag); return -EINVAL; @@ -77,11 +84,19 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (ret) return ret; - ret = devm_request_irq(&adis->spi->dev, adis->spi->irq, - &iio_trigger_generic_data_rdy_poll, - adis->irq_flag, - indio_dev->name, - adis->trig); + if (adis->data->has_fifo) + ret = devm_request_threaded_irq(&adis->spi->dev, adis->spi->irq, + NULL, + &iio_trigger_generic_data_rdy_poll, + adis->irq_flag | IRQF_ONESHOT, + indio_dev->name, + adis->trig); + else + ret = devm_request_irq(&adis->spi->dev, adis->spi->irq, + &iio_trigger_generic_data_rdy_poll, + adis->irq_flag, + indio_dev->name, + adis->trig); if (ret) return ret; diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 0fe3a2f63033..4bb0a53cf7ea 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -85,6 +85,7 @@ struct adis_data { bool unmasked_drdy; bool has_paging; + bool has_fifo; unsigned int burst_reg_cmd; unsigned int burst_len; From c6900c9a931852952e4e316e82a92657a93c0dbd Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:16 +0300 Subject: [PATCH 089/330] iio: imu: adis16475: Re-define ADIS16475_DATA Re-define ADIS16475_DATA such that it takes _burst_max_len, _burst_max_speed_hz and _has_fifo as parameters. Also, do a preparatory rename operation for ADIS16475_BURST32_MAX_DATA to ADIS16475_BURST32_MAX_DATA_NO_TS32 to be able to differentiate in the future between devices which are using 16-bit or 32-bit timestamp size in burst mode. Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-8-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 141 +++++++++++++++++++++++------------- 1 file changed, 92 insertions(+), 49 deletions(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 4b66cf308f22..2daa799604c7 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -65,7 +65,7 @@ #define ADIS16500_BURST32_MASK BIT(9) #define ADIS16500_BURST32(x) FIELD_PREP(ADIS16500_BURST32_MASK, x) /* number of data elements in burst mode */ -#define ADIS16475_BURST32_MAX_DATA 32 +#define ADIS16475_BURST32_MAX_DATA_NO_TS32 32 #define ADIS16475_BURST_MAX_DATA 20 #define ADIS16475_MAX_SCAN_DATA 20 /* spi max speed in brust mode */ @@ -695,32 +695,33 @@ static const char * const adis16475_status_error_msgs[] = { [ADIS16475_DIAG_STAT_CLK] = "Clock error", }; -#define ADIS16475_DATA(_prod_id, _timeouts) \ -{ \ - .msc_ctrl_reg = ADIS16475_REG_MSG_CTRL, \ - .glob_cmd_reg = ADIS16475_REG_GLOB_CMD, \ - .diag_stat_reg = ADIS16475_REG_DIAG_STAT, \ - .prod_id_reg = ADIS16475_REG_PROD_ID, \ - .prod_id = (_prod_id), \ - .self_test_mask = BIT(2), \ - .self_test_reg = ADIS16475_REG_GLOB_CMD, \ - .cs_change_delay = 16, \ - .read_delay = 5, \ - .write_delay = 5, \ - .status_error_msgs = adis16475_status_error_msgs, \ - .status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) | \ - BIT(ADIS16475_DIAG_STAT_FLASH_MEM) | \ - BIT(ADIS16475_DIAG_STAT_SPI) | \ - BIT(ADIS16475_DIAG_STAT_STANDBY) | \ - BIT(ADIS16475_DIAG_STAT_SENSOR) | \ - BIT(ADIS16475_DIAG_STAT_MEMORY) | \ - BIT(ADIS16475_DIAG_STAT_CLK), \ - .unmasked_drdy = true, \ - .timeouts = (_timeouts), \ - .burst_reg_cmd = ADIS16475_REG_GLOB_CMD, \ - .burst_len = ADIS16475_BURST_MAX_DATA, \ - .burst_max_len = ADIS16475_BURST32_MAX_DATA, \ - .burst_max_speed_hz = ADIS16475_BURST_MAX_SPEED \ +#define ADIS16475_DATA(_prod_id, _timeouts, _burst_max_len, _burst_max_speed_hz, _has_fifo) \ +{ \ + .msc_ctrl_reg = ADIS16475_REG_MSG_CTRL, \ + .glob_cmd_reg = ADIS16475_REG_GLOB_CMD, \ + .diag_stat_reg = ADIS16475_REG_DIAG_STAT, \ + .prod_id_reg = ADIS16475_REG_PROD_ID, \ + .prod_id = (_prod_id), \ + .self_test_mask = BIT(2), \ + .self_test_reg = ADIS16475_REG_GLOB_CMD, \ + .cs_change_delay = 16, \ + .read_delay = 5, \ + .write_delay = 5, \ + .status_error_msgs = adis16475_status_error_msgs, \ + .status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) | \ + BIT(ADIS16475_DIAG_STAT_FLASH_MEM) | \ + BIT(ADIS16475_DIAG_STAT_SPI) | \ + BIT(ADIS16475_DIAG_STAT_STANDBY) | \ + BIT(ADIS16475_DIAG_STAT_SENSOR) | \ + BIT(ADIS16475_DIAG_STAT_MEMORY) | \ + BIT(ADIS16475_DIAG_STAT_CLK), \ + .unmasked_drdy = true, \ + .has_fifo = _has_fifo, \ + .timeouts = (_timeouts), \ + .burst_reg_cmd = ADIS16475_REG_GLOB_CMD, \ + .burst_len = ADIS16475_BURST_MAX_DATA, \ + .burst_max_len = _burst_max_len, \ + .burst_max_speed_hz = _burst_max_speed_hz \ } static const struct adis16475_sync adis16475_sync_mode[] = { @@ -758,7 +759,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16470, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16470, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16475_1] = { .name = "adis16475-1", @@ -775,7 +778,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16475_2] = { .name = "adis16475-2", @@ -792,7 +797,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16475_3] = { .name = "adis16475-3", @@ -809,7 +816,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16477_1] = { .name = "adis16477-1", @@ -827,7 +836,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16477_2] = { .name = "adis16477-2", @@ -845,7 +856,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16477_3] = { .name = "adis16477-3", @@ -863,7 +876,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16465_1] = { .name = "adis16465-1", @@ -880,7 +895,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16465_2] = { .name = "adis16465-2", @@ -897,7 +914,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16465_3] = { .name = "adis16465-3", @@ -914,7 +933,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16467_1] = { .name = "adis16467-1", @@ -931,7 +952,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16467_2] = { .name = "adis16467-2", @@ -948,7 +971,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16467_3] = { .name = "adis16467-3", @@ -965,7 +990,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts), + .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16500] = { .name = "adis16500", @@ -984,7 +1011,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16501] = { .name = "adis16501", @@ -1003,7 +1032,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16501, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16501, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16505_1] = { .name = "adis16505-1", @@ -1022,7 +1053,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16505_2] = { .name = "adis16505-2", @@ -1041,7 +1074,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16505_3] = { .name = "adis16505-3", @@ -1060,7 +1095,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16507_1] = { .name = "adis16507-1", @@ -1079,7 +1116,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16507_2] = { .name = "adis16507-2", @@ -1098,7 +1137,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, [ADIS16507_3] = { .name = "adis16507-3", @@ -1117,7 +1158,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, - .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), + .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts, + ADIS16475_BURST32_MAX_DATA_NO_TS32, + ADIS16475_BURST_MAX_SPEED, false), }, }; @@ -1158,7 +1201,7 @@ static bool adis16475_validate_crc(const u8 *buffer, u16 crc, { int i; /* extra 6 elements for low gyro and accel */ - const u16 sz = burst32 ? ADIS16475_BURST32_MAX_DATA : + const u16 sz = burst32 ? ADIS16475_BURST32_MAX_DATA_NO_TS32 : ADIS16475_BURST_MAX_DATA; for (i = 0; i < sz - 2; i++) From 647a2c81fe7bcb7ac2fdbbc085d00456e027b32b Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:17 +0300 Subject: [PATCH 090/330] dt-bindings: iio: imu: Add ADIS1657X family devices compatibles Add ADIS1657X family devices compatibles and specify the according maximum SPI baudrate. Similarly to other ADIS1650X devices, ADIS1657X supports sync-mode values [0,2]. Each newly added device has a different angular velocity/linear acceleration/ delta velocity scale combination, as follows: Accel dynamic range sensitivity: - 262144000 LSB/g: ADIS16575 - 52428800 LSB/g: ADIS16576, ADIS16577 Gyro dynamic range sensitivity: - 2621440 LSB/deg/sec: ADIS1575-2, ADIS1576-2, ADIS1577-2 - 655360 LSB/deg/sec: ADIS1575-3, ADIS1576-3, ADIS1577-3 Delta velocity sensitivity: - 2^15/100 LSB/m/sec: ADIS16575 - 2^15/125 LSB/m/sec: ADIS16576 - 2^15/400 LSB/m/sec: ADIS16577 Each ADIS1657X device supports FIFO usage and a sample-rate of 4.1KHz, meanwhile the already existing devices do not support FIFO usage and have a maximum sample-rate of 2.1KHz. Reviewed-by: Conor Dooley Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-9-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/imu/adi,adis16475.yaml | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml index db52e7063116..9d185f7bfdcb 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml @@ -37,6 +37,12 @@ properties: - adi,adis16507-1 - adi,adis16507-2 - adi,adis16507-3 + - adi,adis16575-2 + - adi,adis16575-3 + - adi,adis16576-2 + - adi,adis16576-3 + - adi,adis16577-2 + - adi,adis16577-3 reg: maxItems: 1 @@ -98,6 +104,12 @@ allOf: - adi,adis16507-1 - adi,adis16507-2 - adi,adis16507-3 + - adi,adis16575-2 + - adi,adis16575-3 + - adi,adis16576-2 + - adi,adis16576-3 + - adi,adis16577-2 + - adi,adis16577-3 then: properties: @@ -114,6 +126,23 @@ allOf: dependencies: adi,sync-mode: [ clocks ] + - if: + properties: + compatible: + contains: + enum: + - adi,adis16575-2 + - adi,adis16575-3 + - adi,adis16576-2 + - adi,adis16576-3 + - adi,adis16577-2 + - adi,adis16577-3 + + then: + properties: + spi-max-frequency: + maximum: 15000000 + unevaluatedProperties: false examples: From f95920baa0666758ca87977ab6d853e8bc24961c Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Mon, 27 May 2024 17:26:18 +0300 Subject: [PATCH 091/330] drivers: iio: imu: Add support for adis1657x family Add support for ADIS1657X family devices in already exiting ADIS16475 driver. Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240527142618.275897-10-ramona.bolboaca13@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 612 +++++++++++++++++++++++++++++++++--- 1 file changed, 561 insertions(+), 51 deletions(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 2daa799604c7..cf73c6f46c79 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,8 @@ FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MASK, x) #define ADIS16475_SYNC_MODE_MASK GENMASK(4, 2) #define ADIS16475_SYNC_MODE(x) FIELD_PREP(ADIS16475_SYNC_MODE_MASK, x) +#define ADIS16575_SYNC_4KHZ_MASK BIT(11) +#define ADIS16575_SYNC_4KHZ(x) FIELD_PREP(ADIS16575_SYNC_4KHZ_MASK, x) #define ADIS16475_REG_UP_SCALE 0x62 #define ADIS16475_REG_DEC_RATE 0x64 #define ADIS16475_REG_GLOB_CMD 0x68 @@ -66,14 +69,31 @@ #define ADIS16500_BURST32(x) FIELD_PREP(ADIS16500_BURST32_MASK, x) /* number of data elements in burst mode */ #define ADIS16475_BURST32_MAX_DATA_NO_TS32 32 +#define ADIS16575_BURST32_DATA_TS32 34 #define ADIS16475_BURST_MAX_DATA 20 #define ADIS16475_MAX_SCAN_DATA 20 /* spi max speed in brust mode */ #define ADIS16475_BURST_MAX_SPEED 1000000 +#define ADIS16575_BURST_MAX_SPEED 8000000 #define ADIS16475_LSB_DEC_MASK 0 #define ADIS16475_LSB_FIR_MASK 1 #define ADIS16500_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0) #define ADIS16500_BURST_DATA_SEL_1_CHN_MASK GENMASK(12, 7) +#define ADIS16575_MAX_FIFO_WM 511UL +#define ADIS16475_REG_FIFO_CTRL 0x5A +#define ADIS16575_WM_LVL_MASK GENMASK(15, 4) +#define ADIS16575_WM_LVL(x) FIELD_PREP(ADIS16575_WM_LVL_MASK, x) +#define ADIS16575_WM_POL_MASK BIT(3) +#define ADIS16575_WM_POL(x) FIELD_PREP(ADIS16575_WM_POL_MASK, x) +#define ADIS16575_WM_EN_MASK BIT(2) +#define ADIS16575_WM_EN(x) FIELD_PREP(ADIS16575_WM_EN_MASK, x) +#define ADIS16575_OVERFLOW_MASK BIT(1) +#define ADIS16575_STOP_ENQUEUE FIELD_PREP(ADIS16575_OVERFLOW_MASK, 0) +#define ADIS16575_OVERWRITE_OLDEST FIELD_PREP(ADIS16575_OVERFLOW_MASK, 1) +#define ADIS16575_FIFO_EN_MASK BIT(0) +#define ADIS16575_FIFO_EN(x) FIELD_PREP(ADIS16575_FIFO_EN_MASK, x) +#define ADIS16575_FIFO_FLUSH_CMD BIT(5) +#define ADIS16575_REG_FIFO_CNT 0x3C enum { ADIS16475_SYNC_DIRECT = 1, @@ -95,6 +115,8 @@ struct adis16475_chip_info { const char *name; #define ADIS16475_HAS_BURST32 BIT(0) #define ADIS16475_HAS_BURST_DELTA_DATA BIT(1) +#define ADIS16475_HAS_TIMESTAMP32 BIT(2) +#define ADIS16475_NEEDS_BURST_REQUEST BIT(3) const long flags; u32 num_channels; u32 gyro_max_val; @@ -116,6 +138,7 @@ struct adis16475 { bool burst32; unsigned long lsb_flag; u16 sync_mode; + u16 fifo_watermark; /* Alignment needed for the timestamp */ __be16 data[ADIS16475_MAX_SCAN_DATA] __aligned(8); }; @@ -442,6 +465,124 @@ static int adis16475_set_filter(struct adis16475 *st, const u32 filter) return 0; } +static ssize_t adis16475_get_fifo_enabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adis16475 *st = iio_priv(indio_dev); + int ret; + u16 val; + + ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%lu\n", FIELD_GET(ADIS16575_FIFO_EN_MASK, val)); +} + +static ssize_t adis16475_get_fifo_watermark(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adis16475 *st = iio_priv(indio_dev); + int ret; + u16 val; + + ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%lu\n", FIELD_GET(ADIS16575_WM_LVL_MASK, val) + 1); +} + +static ssize_t hwfifo_watermark_min_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "1\n"); +} + +static ssize_t hwfifo_watermark_max_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%lu\n", ADIS16575_MAX_FIFO_WM); +} + +static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0); +static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0); +static IIO_DEVICE_ATTR(hwfifo_watermark, 0444, + adis16475_get_fifo_watermark, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, + adis16475_get_fifo_enabled, NULL, 0); + +static const struct iio_dev_attr *adis16475_fifo_attributes[] = { + &iio_dev_attr_hwfifo_watermark_min, + &iio_dev_attr_hwfifo_watermark_max, + &iio_dev_attr_hwfifo_watermark, + &iio_dev_attr_hwfifo_enabled, + NULL +}; + +static int adis16475_buffer_postenable(struct iio_dev *indio_dev) +{ + struct adis16475 *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + + return adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL, + ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(1)); +} + +static int adis16475_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct adis16475 *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + int ret; + + adis_dev_lock(&st->adis); + + ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL, + ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0)); + if (ret) + goto unlock; + + ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD, + ADIS16575_FIFO_FLUSH_CMD); + +unlock: + adis_dev_unlock(&st->adis); + return ret; +} + +static const struct iio_buffer_setup_ops adis16475_buffer_ops = { + .postenable = adis16475_buffer_postenable, + .postdisable = adis16475_buffer_postdisable, +}; + +static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val) +{ + struct adis16475 *st = iio_priv(indio_dev); + int ret; + u16 wm_lvl; + + adis_dev_lock(&st->adis); + + val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM); + + wm_lvl = ADIS16575_WM_LVL(val - 1); + ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl); + if (ret) + goto unlock; + + st->fifo_watermark = val; + +unlock: + adis_dev_unlock(&st->adis); + return ret; +} + static const u32 adis16475_calib_regs[] = { [ADIS16475_SCAN_GYRO_X] = ADIS16475_REG_X_GYRO_BIAS_L, [ADIS16475_SCAN_GYRO_Y] = ADIS16475_REG_Y_GYRO_BIAS_L, @@ -651,6 +792,22 @@ static const struct iio_chan_spec adis16475_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(7) }; +static const struct iio_chan_spec adis16575_channels[] = { + ADIS16475_GYRO_CHANNEL(X), + ADIS16475_GYRO_CHANNEL(Y), + ADIS16475_GYRO_CHANNEL(Z), + ADIS16475_ACCEL_CHANNEL(X), + ADIS16475_ACCEL_CHANNEL(Y), + ADIS16475_ACCEL_CHANNEL(Z), + ADIS16475_TEMP_CHANNEL(), + ADIS16475_DELTANG_CHAN(X), + ADIS16475_DELTANG_CHAN(Y), + ADIS16475_DELTANG_CHAN(Z), + ADIS16475_DELTVEL_CHAN(X), + ADIS16475_DELTVEL_CHAN(Y), + ADIS16475_DELTVEL_CHAN(Z), +}; + enum adis16475_variant { ADIS16470, ADIS16475_1, @@ -673,6 +830,12 @@ enum adis16475_variant { ADIS16507_1, ADIS16507_2, ADIS16507_3, + ADIS16575_2, + ADIS16575_3, + ADIS16576_2, + ADIS16576_3, + ADIS16577_2, + ADIS16577_3, }; enum { @@ -731,6 +894,12 @@ static const struct adis16475_sync adis16475_sync_mode[] = { { ADIS16475_SYNC_PULSE, 1000, 2100 }, }; +static const struct adis16475_sync adis16575_sync_mode[] = { + { ADIS16475_SYNC_OUTPUT }, + { ADIS16475_SYNC_DIRECT, 1900, 4100 }, + { ADIS16475_SYNC_SCALED, 1, 400 }, +}; + static const struct adis_timeout adis16475_timeouts = { .reset_ms = 200, .sw_reset_ms = 200, @@ -1162,6 +1331,144 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { ADIS16475_BURST32_MAX_DATA_NO_TS32, ADIS16475_BURST_MAX_SPEED, false), }, + [ADIS16575_2] = { + .name = "adis16575-2", + .num_channels = ARRAY_SIZE(adis16575_channels), + .channels = adis16575_channels, + .gyro_max_val = 1, + .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), + .accel_max_val = 8, + .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16), + .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(450), + .deltvel_max_val = 100, + .int_clk = 4000, + .max_dec = 3999, + .sync = adis16575_sync_mode, + .num_sync = ARRAY_SIZE(adis16575_sync_mode), + .flags = ADIS16475_HAS_BURST32 | + ADIS16475_HAS_BURST_DELTA_DATA | + ADIS16475_NEEDS_BURST_REQUEST | + ADIS16475_HAS_TIMESTAMP32, + .adis_data = ADIS16475_DATA(16575, &adis16475_timeouts, + ADIS16575_BURST32_DATA_TS32, + ADIS16575_BURST_MAX_SPEED, true), + }, + [ADIS16575_3] = { + .name = "adis16575-3", + .num_channels = ARRAY_SIZE(adis16575_channels), + .channels = adis16575_channels, + .gyro_max_val = 1, + .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), + .accel_max_val = 8, + .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16), + .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2000), + .deltvel_max_val = 100, + .int_clk = 4000, + .max_dec = 3999, + .sync = adis16575_sync_mode, + .num_sync = ARRAY_SIZE(adis16575_sync_mode), + .flags = ADIS16475_HAS_BURST32 | + ADIS16475_HAS_BURST_DELTA_DATA | + ADIS16475_NEEDS_BURST_REQUEST | + ADIS16475_HAS_TIMESTAMP32, + .adis_data = ADIS16475_DATA(16575, &adis16475_timeouts, + ADIS16575_BURST32_DATA_TS32, + ADIS16575_BURST_MAX_SPEED, true), + }, + [ADIS16576_2] = { + .name = "adis16576-2", + .num_channels = ARRAY_SIZE(adis16575_channels), + .channels = adis16575_channels, + .gyro_max_val = 1, + .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), + .accel_max_val = 40, + .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16), + .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(450), + .deltvel_max_val = 125, + .int_clk = 4000, + .max_dec = 3999, + .sync = adis16575_sync_mode, + .num_sync = ARRAY_SIZE(adis16575_sync_mode), + .flags = ADIS16475_HAS_BURST32 | + ADIS16475_HAS_BURST_DELTA_DATA | + ADIS16475_NEEDS_BURST_REQUEST | + ADIS16475_HAS_TIMESTAMP32, + .adis_data = ADIS16475_DATA(16576, &adis16475_timeouts, + ADIS16575_BURST32_DATA_TS32, + ADIS16575_BURST_MAX_SPEED, true), + }, + [ADIS16576_3] = { + .name = "adis16576-3", + .num_channels = ARRAY_SIZE(adis16575_channels), + .channels = adis16575_channels, + .gyro_max_val = 1, + .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), + .accel_max_val = 40, + .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16), + .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2000), + .deltvel_max_val = 125, + .int_clk = 4000, + .max_dec = 3999, + .sync = adis16575_sync_mode, + .num_sync = ARRAY_SIZE(adis16575_sync_mode), + .flags = ADIS16475_HAS_BURST32 | + ADIS16475_HAS_BURST_DELTA_DATA | + ADIS16475_NEEDS_BURST_REQUEST | + ADIS16475_HAS_TIMESTAMP32, + .adis_data = ADIS16475_DATA(16576, &adis16475_timeouts, + ADIS16575_BURST32_DATA_TS32, + ADIS16575_BURST_MAX_SPEED, true), + }, + [ADIS16577_2] = { + .name = "adis16577-2", + .num_channels = ARRAY_SIZE(adis16575_channels), + .channels = adis16575_channels, + .gyro_max_val = 1, + .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), + .accel_max_val = 40, + .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16), + .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(450), + .deltvel_max_val = 400, + .int_clk = 4000, + .max_dec = 3999, + .sync = adis16575_sync_mode, + .num_sync = ARRAY_SIZE(adis16575_sync_mode), + .flags = ADIS16475_HAS_BURST32 | + ADIS16475_HAS_BURST_DELTA_DATA | + ADIS16475_NEEDS_BURST_REQUEST | + ADIS16475_HAS_TIMESTAMP32, + .adis_data = ADIS16475_DATA(16577, &adis16475_timeouts, + ADIS16575_BURST32_DATA_TS32, + ADIS16575_BURST_MAX_SPEED, true), + }, + [ADIS16577_3] = { + .name = "adis16577-3", + .num_channels = ARRAY_SIZE(adis16575_channels), + .channels = adis16575_channels, + .gyro_max_val = 1, + .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), + .accel_max_val = 40, + .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16), + .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2000), + .deltvel_max_val = 400, + .int_clk = 4000, + .max_dec = 3999, + .sync = adis16575_sync_mode, + .num_sync = ARRAY_SIZE(adis16575_sync_mode), + .flags = ADIS16475_HAS_BURST32 | + ADIS16475_HAS_BURST_DELTA_DATA | + ADIS16475_NEEDS_BURST_REQUEST | + ADIS16475_HAS_TIMESTAMP32, + .adis_data = ADIS16475_DATA(16577, &adis16475_timeouts, + ADIS16575_BURST32_DATA_TS32, + ADIS16575_BURST_MAX_SPEED, true), + }, }; static int adis16475_update_scan_mode(struct iio_dev *indio_dev, @@ -1196,15 +1503,20 @@ static const struct iio_info adis16475_info = { .debugfs_reg_access = adis_debugfs_reg_access, }; +static const struct iio_info adis16575_info = { + .read_raw = &adis16475_read_raw, + .write_raw = &adis16475_write_raw, + .update_scan_mode = adis16475_update_scan_mode, + .debugfs_reg_access = adis_debugfs_reg_access, + .hwfifo_set_watermark = adis16475_set_watermark, +}; + static bool adis16475_validate_crc(const u8 *buffer, u16 crc, - const bool burst32) + u16 burst_size, u16 start_idx) { int i; - /* extra 6 elements for low gyro and accel */ - const u16 sz = burst32 ? ADIS16475_BURST32_MAX_DATA_NO_TS32 : - ADIS16475_BURST_MAX_DATA; - for (i = 0; i < sz - 2; i++) + for (i = start_idx; i < burst_size - 2; i++) crc -= buffer[i]; return crc == 0; @@ -1214,10 +1526,14 @@ static void adis16475_burst32_check(struct adis16475 *st) { int ret; struct adis *adis = &st->adis; + u8 timestamp32 = 0; if (!(st->info->flags & ADIS16475_HAS_BURST32)) return; + if (st->info->flags & ADIS16475_HAS_TIMESTAMP32) + timestamp32 = 1; + if (st->lsb_flag && !st->burst32) { const u16 en = ADIS16500_BURST32(1); @@ -1231,9 +1547,12 @@ static void adis16475_burst32_check(struct adis16475 *st) /* * In 32-bit mode we need extra 2 bytes for all gyro * and accel channels. + * If the device has 32-bit timestamp value we need 2 extra + * bytes for it. */ - adis->burst_extra_len = 6 * sizeof(u16); - adis->xfer[1].len += 6 * sizeof(u16); + adis->burst_extra_len = (6 + timestamp32) * sizeof(u16); + adis->xfer[1].len += (6 + timestamp32) * sizeof(u16); + dev_dbg(&adis->spi->dev, "Enable burst32 mode, xfer:%d", adis->xfer[1].len); @@ -1249,7 +1568,7 @@ static void adis16475_burst32_check(struct adis16475 *st) /* Remove the extra bits */ adis->burst_extra_len = 0; - adis->xfer[1].len -= 6 * sizeof(u16); + adis->xfer[1].len -= (6 + timestamp32) * sizeof(u16); dev_dbg(&adis->spi->dev, "Disable burst32 mode, xfer:%d\n", adis->xfer[1].len); } @@ -1264,20 +1583,29 @@ static int adis16475_push_single_sample(struct iio_poll_func *pf) __be16 *buffer; u16 crc; bool valid; + u8 crc_offset = 9; + u16 burst_size = ADIS16475_BURST_MAX_DATA; + u16 start_idx = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 2 : 0; + /* offset until the first element after gyro and accel */ const u8 offset = st->burst32 ? 13 : 7; + if (st->burst32) { + crc_offset = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 16 : 15; + burst_size = adis->data->burst_max_len; + } + ret = spi_sync(adis->spi, &adis->msg); if (ret) - goto check_burst32; + return ret; buffer = adis->buffer; - crc = be16_to_cpu(buffer[offset + 2]); - valid = adis16475_validate_crc(adis->buffer, crc, st->burst32); + crc = be16_to_cpu(buffer[crc_offset]); + valid = adis16475_validate_crc(adis->buffer, crc, burst_size, start_idx); if (!valid) { dev_err(&adis->spi->dev, "Invalid crc\n"); - goto check_burst32; + return -EINVAL; } for_each_set_bit(bit, indio_dev->active_scan_mask, @@ -1337,23 +1665,123 @@ static int adis16475_push_single_sample(struct iio_poll_func *pf) } } + /* There might not be a timestamp option for some devices. */ iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp); -check_burst32: - /* - * We only check the burst mode at the end of the current capture since - * it takes a full data ready cycle for the device to update the burst - * array. - */ - adis16475_burst32_check(st); - return ret; + + return 0; } static irqreturn_t adis16475_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; + struct adis16475 *st = iio_priv(indio_dev); adis16475_push_single_sample(pf); + /* + * We only check the burst mode at the end of the current capture since + * it takes a full data ready cycle for the device to update the burst + * array. + */ + adis16475_burst32_check(st); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +/* + * This function updates the first tx byte from the adis message based on the + * given burst request. + */ +static void adis16575_update_msg_for_burst(struct adis *adis, u8 burst_req) +{ + unsigned int burst_max_length; + u8 *tx; + + if (adis->data->burst_max_len) + burst_max_length = adis->data->burst_max_len; + else + burst_max_length = adis->data->burst_len + adis->burst_extra_len; + + tx = adis->buffer + burst_max_length; + tx[0] = ADIS_READ_REG(burst_req); +} + +static int adis16575_custom_burst_read(struct iio_poll_func *pf, u8 burst_req) +{ + struct iio_dev *indio_dev = pf->indio_dev; + struct adis16475 *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + + adis16575_update_msg_for_burst(adis, burst_req); + + if (burst_req) + return spi_sync(adis->spi, &adis->msg); + + return adis16475_push_single_sample(pf); +} + +/* + * This handler is meant to be used for devices which support burst readings + * from FIFO (namely devices from adis1657x family). + * In order to pop the FIFO the 0x68 0x00 FIFO pop burst request has to be sent. + * If the previous device command was not a FIFO pop burst request, the FIFO pop + * burst request will simply pop the FIFO without returning valid data. + * For the nth consecutive burst request, thedevice will send the data popped + * with the (n-1)th consecutive burst request. + * In order to read the data which was popped previously, without popping the + * FIFO, the 0x00 0x00 burst request has to be sent. + * If after a 0x68 0x00 FIFO pop burst request, there is any other device access + * different from a 0x68 0x00 or a 0x00 0x00 burst request, the FIFO data popped + * previously will be lost. + */ +static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adis16475 *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + int ret; + u16 fifo_cnt, i; + + adis_dev_lock(&st->adis); + + ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt); + if (ret) + goto unlock; + + /* + * If no sample is available, nothing can be read. This can happen if + * a the used trigger has a higher frequency than the selected sample rate. + */ + if (!fifo_cnt) + goto unlock; + + /* + * First burst request - FIFO pop: popped data will be returned in the + * next burst request. + */ + ret = adis16575_custom_burst_read(pf, adis->data->burst_reg_cmd); + if (ret) + goto unlock; + + for (i = 0; i < fifo_cnt - 1; i++) { + ret = adis16475_push_single_sample(pf); + if (ret) + goto unlock; + } + + /* FIFO read without popping */ + ret = adis16575_custom_burst_read(pf, 0); + +unlock: + /* + * We only check the burst mode at the end of the current capture since + * reading data from registers will impact the FIFO reading. + */ + adis16475_burst32_check(st); + adis_dev_unlock(&st->adis); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -1368,6 +1796,15 @@ static int adis16475_config_sync_mode(struct adis16475 *st) u16 max_sample_rate = st->info->int_clk + 100; u16 val; + /* if available, enable 4khz internal clock */ + if (st->info->int_clk == 4000) { + ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL, + ADIS16575_SYNC_4KHZ_MASK, + (u16)ADIS16575_SYNC_4KHZ(1)); + if (ret) + return ret; + } + /* default to internal clk */ st->clk_freq = st->info->int_clk * 1000; @@ -1446,34 +1883,69 @@ static int adis16475_config_irq_pin(struct adis16475 *st) u8 polarity; struct spi_device *spi = st->adis.spi; - /* - * It is possible to configure the data ready polarity. Furthermore, we - * need to update the adis struct if we want data ready as active low. - */ irq_type = irq_get_trigger_type(spi->irq); - if (irq_type == IRQ_TYPE_EDGE_RISING) { - polarity = 1; - st->adis.irq_flag = IRQF_TRIGGER_RISING; - } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { - polarity = 0; - st->adis.irq_flag = IRQF_TRIGGER_FALLING; - } else { - dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n", - irq_type); - return -EINVAL; - } - val = ADIS16475_MSG_CTRL_DR_POL(polarity); - ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL, - ADIS16475_MSG_CTRL_DR_POL_MASK, val); - if (ret) - return ret; - /* - * There is a delay writing to any bits written to the MSC_CTRL - * register. It should not be bigger than 200us, so 250 should be more - * than enough! - */ - usleep_range(250, 260); + if (st->adis.data->has_fifo) { + /* + * It is possible to configure the fifo watermark pin polarity. + * Furthermore, we need to update the adis struct if we want the + * watermark pin active low. + */ + if (irq_type == IRQ_TYPE_LEVEL_HIGH) { + polarity = 1; + st->adis.irq_flag = IRQF_TRIGGER_HIGH; + } else if (irq_type == IRQ_TYPE_LEVEL_LOW) { + polarity = 0; + st->adis.irq_flag = IRQF_TRIGGER_LOW; + } else { + dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n", + irq_type); + return -EINVAL; + } + + /* Configure the watermark pin polarity. */ + val = ADIS16575_WM_POL(polarity); + ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, + ADIS16575_WM_POL_MASK, val); + if (ret) + return ret; + + /* Enable watermark interrupt pin. */ + ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, + ADIS16575_WM_EN_MASK, + (u16)ADIS16575_WM_EN(1)); + if (ret) + return ret; + + } else { + /* + * It is possible to configure the data ready polarity. Furthermore, we + * need to update the adis struct if we want data ready as active low. + */ + if (irq_type == IRQ_TYPE_EDGE_RISING) { + polarity = 1; + st->adis.irq_flag = IRQF_TRIGGER_RISING; + } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { + polarity = 0; + st->adis.irq_flag = IRQF_TRIGGER_FALLING; + } else { + dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n", + irq_type); + return -EINVAL; + } + + val = ADIS16475_MSG_CTRL_DR_POL(polarity); + ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL, + ADIS16475_MSG_CTRL_DR_POL_MASK, val); + if (ret) + return ret; + /* + * There is a delay writing to any bits written to the MSC_CTRL + * register. It should not be bigger than 200us, so 250 should be more + * than enough! + */ + usleep_range(250, 260); + } return 0; } @@ -1484,6 +1956,7 @@ static int adis16475_probe(struct spi_device *spi) struct iio_dev *indio_dev; struct adis16475 *st; int ret; + u16 val; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) @@ -1502,7 +1975,10 @@ static int adis16475_probe(struct spi_device *spi) indio_dev->name = st->info->name; indio_dev->channels = st->info->channels; indio_dev->num_channels = st->info->num_channels; - indio_dev->info = &adis16475_info; + if (st->adis.data->has_fifo) + indio_dev->info = &adis16575_info; + else + indio_dev->info = &adis16475_info; indio_dev->modes = INDIO_DIRECT_MODE; ret = __adis_initial_startup(&st->adis); @@ -1517,10 +1993,26 @@ static int adis16475_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, - adis16475_trigger_handler); - if (ret) - return ret; + if (st->adis.data->has_fifo) { + ret = devm_adis_setup_buffer_and_trigger_with_attrs(&st->adis, indio_dev, + adis16475_trigger_handler_with_fifo, + &adis16475_buffer_ops, + adis16475_fifo_attributes); + if (ret) + return ret; + + /* Update overflow behavior to always overwrite the oldest sample. */ + val = ADIS16575_OVERWRITE_OLDEST; + ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, + ADIS16575_OVERFLOW_MASK, val); + if (ret) + return ret; + } else { + ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, + adis16475_trigger_handler); + if (ret) + return ret; + } ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret) @@ -1574,6 +2066,18 @@ static const struct of_device_id adis16475_of_match[] = { .data = &adis16475_chip_info[ADIS16507_2] }, { .compatible = "adi,adis16507-3", .data = &adis16475_chip_info[ADIS16507_3] }, + { .compatible = "adi,adis16575-2", + .data = &adis16475_chip_info[ADIS16575_2] }, + { .compatible = "adi,adis16575-3", + .data = &adis16475_chip_info[ADIS16575_3] }, + { .compatible = "adi,adis16576-2", + .data = &adis16475_chip_info[ADIS16576_2] }, + { .compatible = "adi,adis16576-3", + .data = &adis16475_chip_info[ADIS16576_3] }, + { .compatible = "adi,adis16577-2", + .data = &adis16475_chip_info[ADIS16577_2] }, + { .compatible = "adi,adis16577-3", + .data = &adis16475_chip_info[ADIS16577_3] }, { }, }; MODULE_DEVICE_TABLE(of, adis16475_of_match); @@ -1600,6 +2104,12 @@ static const struct spi_device_id adis16475_ids[] = { { "adis16507-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] }, { "adis16507-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] }, { "adis16507-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] }, + { "adis16575-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] }, + { "adis16575-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] }, + { "adis16576-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] }, + { "adis16576-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] }, + { "adis16577-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] }, + { "adis16577-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] }, { } }; MODULE_DEVICE_TABLE(spi, adis16475_ids); From 8c0a438fa037fde88eeeb415e1ac77e133ee6930 Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Tue, 28 May 2024 17:24:04 +0300 Subject: [PATCH 092/330] iio: adis16480: make the burst_max_speed configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this, we can pass the maxixum spi burst speed to the 'ADIS16480_DATA()' macro. This is in preparation to support new devices that have a different speed than the one used so far. Co-developed-by: Nuno Sá Signed-off-by: Ramona Gradinariu Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240528142409.239187-2-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 84 +++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index b40a55bba30c..bc6cbd00cd4b 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -107,8 +107,6 @@ #define ADIS16495_BURST_ID 0xA5A5 /* total number of segments in burst */ #define ADIS16495_BURST_MAX_DATA 20 -/* spi max speed in burst mode */ -#define ADIS16495_BURST_MAX_SPEED 6000000 #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) @@ -872,33 +870,33 @@ static const char * const adis16480_status_error_msgs[] = { static int adis16480_enable_irq(struct adis *adis, bool enable); -#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len) \ -{ \ - .diag_stat_reg = ADIS16480_REG_DIAG_STS, \ - .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \ - .prod_id_reg = ADIS16480_REG_PROD_ID, \ - .prod_id = (_prod_id), \ - .has_paging = true, \ - .read_delay = 5, \ - .write_delay = 5, \ - .self_test_mask = BIT(1), \ - .self_test_reg = ADIS16480_REG_GLOB_CMD, \ - .status_error_msgs = adis16480_status_error_msgs, \ - .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \ - BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \ - .enable_irq = adis16480_enable_irq, \ - .timeouts = (_timeouts), \ - .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \ - .burst_len = (_burst_len), \ - .burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED \ +#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len, _burst_max_speed) \ +{ \ + .diag_stat_reg = ADIS16480_REG_DIAG_STS, \ + .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \ + .prod_id_reg = ADIS16480_REG_PROD_ID, \ + .prod_id = (_prod_id), \ + .has_paging = true, \ + .read_delay = 5, \ + .write_delay = 5, \ + .self_test_mask = BIT(1), \ + .self_test_reg = ADIS16480_REG_GLOB_CMD, \ + .status_error_msgs = adis16480_status_error_msgs, \ + .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \ + BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \ + .enable_irq = adis16480_enable_irq, \ + .timeouts = (_timeouts), \ + .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \ + .burst_len = (_burst_len), \ + .burst_max_speed_hz = _burst_max_speed \ } static const struct adis_timeout adis16485_timeouts = { @@ -944,7 +942,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 2048, .has_sleep_cnt = true, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0), + .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0, 0), }, [ADIS16480] = { .channels = adis16480_channels, @@ -958,7 +956,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 2048, .has_sleep_cnt = true, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0), + .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0, 0), }, [ADIS16485] = { .channels = adis16485_channels, @@ -972,7 +970,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 2048, .has_sleep_cnt = true, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0), + .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0, 0), }, [ADIS16488] = { .channels = adis16480_channels, @@ -986,7 +984,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 2048, .has_sleep_cnt = true, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0), + .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0, 0), }, [ADIS16490] = { .channels = adis16485_channels, @@ -1000,7 +998,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0), + .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0, 0), }, [ADIS16495_1] = { .channels = adis16485_channels, @@ -1016,7 +1014,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .has_pps_clk_mode = true, /* 20 elements of 16bits */ .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, - ADIS16495_BURST_MAX_DATA * 2), + ADIS16495_BURST_MAX_DATA * 2, + 6000000), }, [ADIS16495_2] = { .channels = adis16485_channels, @@ -1032,7 +1031,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .has_pps_clk_mode = true, /* 20 elements of 16bits */ .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, - ADIS16495_BURST_MAX_DATA * 2), + ADIS16495_BURST_MAX_DATA * 2, + 6000000), }, [ADIS16495_3] = { .channels = adis16485_channels, @@ -1048,7 +1048,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .has_pps_clk_mode = true, /* 20 elements of 16bits */ .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, - ADIS16495_BURST_MAX_DATA * 2), + ADIS16495_BURST_MAX_DATA * 2, + 6000000), }, [ADIS16497_1] = { .channels = adis16485_channels, @@ -1064,7 +1065,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .has_pps_clk_mode = true, /* 20 elements of 16bits */ .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, - ADIS16495_BURST_MAX_DATA * 2), + ADIS16495_BURST_MAX_DATA * 2, + 6000000), }, [ADIS16497_2] = { .channels = adis16485_channels, @@ -1080,7 +1082,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .has_pps_clk_mode = true, /* 20 elements of 16bits */ .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, - ADIS16495_BURST_MAX_DATA * 2), + ADIS16495_BURST_MAX_DATA * 2, + 6000000), }, [ADIS16497_3] = { .channels = adis16485_channels, @@ -1096,7 +1099,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .has_pps_clk_mode = true, /* 20 elements of 16bits */ .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, - ADIS16495_BURST_MAX_DATA * 2), + ADIS16495_BURST_MAX_DATA * 2, + 6000000), }, }; From 196f5406baa55c05746c4b3733c7d80a91ecdeeb Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Tue, 28 May 2024 17:24:05 +0300 Subject: [PATCH 093/330] iio: imu: adis16480.c: Add delta angle and delta velocity channels Add support for delta angle and delta velocity raw readings to adis16480 driver. The following devices do not support delta readings in burst mode: ADIS16375, ADIS16480, ADIS16485, ADIS16488, ADIS16490, ADIS16495-1, ADIS16495-2, ADIS16495-3, ADIS16497-1, ADIS16497-2, ADIS16497-3, thus they cannot be retrieved via the buffer interface. For these devices, the delta measurements are retrieved by performing normal register readings and are made available through the raw attributes of the specific channels. Signed-off-by: Ramona Gradinariu Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240528142409.239187-3-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 72 +++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index bc6cbd00cd4b..0cd55040db93 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -140,6 +140,8 @@ struct adis16480_chip_info { unsigned int accel_max_val; unsigned int accel_max_scale; unsigned int temp_scale; + unsigned int deltang_max_val; + unsigned int deltvel_max_val; unsigned int int_clk; unsigned int max_dec_rate; const unsigned int *filter_freqs; @@ -445,6 +447,12 @@ enum { ADIS16480_SCAN_MAGN_Z, ADIS16480_SCAN_BARO, ADIS16480_SCAN_TEMP, + ADIS16480_SCAN_DELTANG_X, + ADIS16480_SCAN_DELTANG_Y, + ADIS16480_SCAN_DELTANG_Z, + ADIS16480_SCAN_DELTVEL_X, + ADIS16480_SCAN_DELTVEL_Y, + ADIS16480_SCAN_DELTVEL_Z, }; static const unsigned int adis16480_calibbias_regs[] = { @@ -688,6 +696,14 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, *val = 131; /* 1310mbar = 131 kPa */ *val2 = 32767 << 16; return IIO_VAL_FRACTIONAL; + case IIO_DELTA_ANGL: + *val = st->chip_info->deltang_max_val; + *val2 = 31; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_DELTA_VELOCITY: + *val = st->chip_info->deltvel_max_val; + *val2 = 31; + return IIO_VAL_FRACTIONAL_LOG2; default: return -EINVAL; } @@ -761,6 +777,24 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, BIT(IIO_CHAN_INFO_CALIBSCALE), \ 32) +#define ADIS16480_DELTANG_CHANNEL(_mod) \ + ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \ + ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, ADIS16480_SCAN_DELTANG_ ## _mod, \ + 0, 32) + +#define ADIS16480_DELTANG_CHANNEL_NO_SCAN(_mod) \ + ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \ + ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, -1, 0, 32) + +#define ADIS16480_DELTVEL_CHANNEL(_mod) \ + ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \ + ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, ADIS16480_SCAN_DELTVEL_ ## _mod, \ + 0, 32) + +#define ADIS16480_DELTVEL_CHANNEL_NO_SCAN(_mod) \ + ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \ + ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, -1, 0, 32) + #define ADIS16480_MAGN_CHANNEL(_mod) \ ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \ ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \ @@ -816,7 +850,13 @@ static const struct iio_chan_spec adis16480_channels[] = { ADIS16480_MAGN_CHANNEL(Z), ADIS16480_PRESSURE_CHANNEL(), ADIS16480_TEMP_CHANNEL(), - IIO_CHAN_SOFT_TIMESTAMP(11) + IIO_CHAN_SOFT_TIMESTAMP(11), + ADIS16480_DELTANG_CHANNEL_NO_SCAN(X), + ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y), + ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z), + ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X), + ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y), + ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z), }; static const struct iio_chan_spec adis16485_channels[] = { @@ -827,7 +867,13 @@ static const struct iio_chan_spec adis16485_channels[] = { ADIS16480_ACCEL_CHANNEL(Y), ADIS16480_ACCEL_CHANNEL(Z), ADIS16480_TEMP_CHANNEL(), - IIO_CHAN_SOFT_TIMESTAMP(7) + IIO_CHAN_SOFT_TIMESTAMP(7), + ADIS16480_DELTANG_CHANNEL_NO_SCAN(X), + ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y), + ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z), + ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X), + ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y), + ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z), }; enum adis16480_variant { @@ -938,6 +984,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(21973 << 16), .accel_max_scale = 18, .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(180), + .deltvel_max_val = 100, .int_clk = 2460000, .max_dec_rate = 2048, .has_sleep_cnt = true, @@ -952,6 +1000,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(12500 << 16), .accel_max_scale = 10, .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 200, .int_clk = 2460000, .max_dec_rate = 2048, .has_sleep_cnt = true, @@ -966,6 +1016,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), .accel_max_scale = 5, .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 50, .int_clk = 2460000, .max_dec_rate = 2048, .has_sleep_cnt = true, @@ -980,6 +1032,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(22500 << 16), .accel_max_scale = 18, .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 200, .int_clk = 2460000, .max_dec_rate = 2048, .has_sleep_cnt = true, @@ -994,6 +1048,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(16000 << 16), .accel_max_scale = 8, .temp_scale = 14285, /* 14.285 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 200, .int_clk = 4250000, .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, @@ -1008,6 +1064,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 8, .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, .int_clk = 4250000, .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, @@ -1025,6 +1083,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 8, .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, .int_clk = 4250000, .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, @@ -1042,6 +1102,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 8, .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, .int_clk = 4250000, .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, @@ -1059,6 +1121,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 40, .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, .int_clk = 4250000, .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, @@ -1076,6 +1140,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 40, .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, .int_clk = 4250000, .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, @@ -1093,6 +1159,8 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), .accel_max_scale = 40, .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 4250000, .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, From 1c083963fccd84ff9375d6383f9c97557750e94d Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Tue, 28 May 2024 17:24:06 +0300 Subject: [PATCH 094/330] dt-bindings: iio: imu: Add ADIS16545/47 compatibles Add ADIS16545/47 compatibles. Each newly added device has a different angular velocity/linear acceleration scale combination, as follows: Accel dynamic range: - 8g: ADIS16545 - 40g: ADIS16547 Gyro dynamic range: - 125 deg/sec: ADIS1545-1, ADIS16547-1 - 450 deg/sec: ADIS1545-2, ADIS16547-2 - 2000 deg/sec: ADIS1545-3, ADIS16547-3 Signed-off-by: Ramona Gradinariu Reviewed-by: Conor Dooley Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240528142409.239187-4-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/imu/adi,adis16480.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml index 56e0dc20f5e4..e3eec38897bf 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml @@ -23,6 +23,12 @@ properties: - adi,adis16497-1 - adi,adis16497-2 - adi,adis16497-3 + - adi,adis16545-1 + - adi,adis16545-2 + - adi,adis16545-3 + - adi,adis16547-1 + - adi,adis16547-2 + - adi,adis16547-3 reg: maxItems: 1 From 85b2aeaa2f4cb495a688292d175f09b8010990fe Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Tue, 28 May 2024 17:24:07 +0300 Subject: [PATCH 095/330] iio: adis16480: add support for adis16545/7 families MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADIS16545 and ADIS16547 are a complete inertial system that includes a triaxis gyroscope and a triaxis accelerometer. The serial peripheral interface (SPI) and register structure provide a simple interface for data collection and configuration control. These devices are similar to the ones already supported in the driver, with changes in the scales, timings and the max spi speed in burst mode. Also, they support delta angle and delta velocity readings in burst mode, for which support was added in the trigger handler. Co-developed-by: Nuno Sá Signed-off-by: Ramona Gradinariu Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240528142409.239187-5-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 237 ++++++++++++++++++++++++++++++++++-- 1 file changed, 229 insertions(+), 8 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 0cd55040db93..56ca5a09fbbf 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -104,7 +104,8 @@ */ #define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10) #define ADIS16495_REG_BURST_CMD ADIS16480_REG(0x00, 0x7C) -#define ADIS16495_BURST_ID 0xA5A5 +#define ADIS16495_GYRO_ACCEL_BURST_ID 0xA5A5 +#define ADIS16545_DELTA_ANG_VEL_BURST_ID 0xC3C3 /* total number of segments in burst */ #define ADIS16495_BURST_MAX_DATA 20 @@ -132,6 +133,10 @@ #define ADIS16480_SYNC_MODE_MSK BIT(8) #define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x) +#define ADIS16545_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0) +#define ADIS16545_BURST_DATA_SEL_1_CHN_MASK GENMASK(16, 11) +#define ADIS16545_BURST_DATA_SEL_MASK BIT(8) + struct adis16480_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; @@ -147,6 +152,7 @@ struct adis16480_chip_info { const unsigned int *filter_freqs; bool has_pps_clk_mode; bool has_sleep_cnt; + bool has_burst_delta_data; const struct adis_data adis_data; }; @@ -170,6 +176,7 @@ struct adis16480 { struct clk *ext_clk; enum adis16480_clock_mode clk_mode; unsigned int clk_freq; + u16 burst_id; /* Alignment needed for the timestamp */ __be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8); }; @@ -876,6 +883,23 @@ static const struct iio_chan_spec adis16485_channels[] = { ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z), }; +static const struct iio_chan_spec adis16545_channels[] = { + ADIS16480_GYRO_CHANNEL(X), + ADIS16480_GYRO_CHANNEL(Y), + ADIS16480_GYRO_CHANNEL(Z), + ADIS16480_ACCEL_CHANNEL(X), + ADIS16480_ACCEL_CHANNEL(Y), + ADIS16480_ACCEL_CHANNEL(Z), + ADIS16480_TEMP_CHANNEL(), + ADIS16480_DELTANG_CHANNEL(X), + ADIS16480_DELTANG_CHANNEL(Y), + ADIS16480_DELTANG_CHANNEL(Z), + ADIS16480_DELTVEL_CHANNEL(X), + ADIS16480_DELTVEL_CHANNEL(Y), + ADIS16480_DELTVEL_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(17), +}; + enum adis16480_variant { ADIS16375, ADIS16480, @@ -888,6 +912,12 @@ enum adis16480_variant { ADIS16497_1, ADIS16497_2, ADIS16497_3, + ADIS16545_1, + ADIS16545_2, + ADIS16545_3, + ADIS16547_1, + ADIS16547_2, + ADIS16547_3 }; #define ADIS16480_DIAG_STAT_XGYRO_FAIL 0 @@ -969,6 +999,12 @@ static const struct adis_timeout adis16495_1_timeouts = { .self_test_ms = 20, }; +static const struct adis_timeout adis16545_timeouts = { + .reset_ms = 315, + .sw_reset_ms = 270, + .self_test_ms = 35, +}; + static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16375] = { .channels = adis16485_channels, @@ -1170,6 +1206,126 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { ADIS16495_BURST_MAX_DATA * 2, 6000000), }, + [ADIS16545_1] = { + .channels = adis16545_channels, + .num_channels = ARRAY_SIZE(adis16545_channels), + .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 = 7000, /* 7 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + .has_burst_delta_data = true, + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts, + ADIS16495_BURST_MAX_DATA * 2, + 6500000), + }, + [ADIS16545_2] = { + .channels = adis16545_channels, + .num_channels = ARRAY_SIZE(adis16545_channels), + .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 = 7000, /* 7 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + .has_burst_delta_data = true, + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts, + ADIS16495_BURST_MAX_DATA * 2, + 6500000), + }, + [ADIS16545_3] = { + .channels = adis16545_channels, + .num_channels = ARRAY_SIZE(adis16545_channels), + .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 = 7000, /* 7 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + .has_burst_delta_data = true, + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts, + ADIS16495_BURST_MAX_DATA * 2, + 6500000), + }, + [ADIS16547_1] = { + .channels = adis16545_channels, + .num_channels = ARRAY_SIZE(adis16545_channels), + .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 = 7000, /* 7 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + .has_burst_delta_data = true, + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts, + ADIS16495_BURST_MAX_DATA * 2, + 6500000), + }, + [ADIS16547_2] = { + .channels = adis16545_channels, + .num_channels = ARRAY_SIZE(adis16545_channels), + .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 = 7000, /* 7 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + .has_burst_delta_data = true, + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts, + ADIS16495_BURST_MAX_DATA * 2, + 6500000), + }, + [ADIS16547_3] = { + .channels = adis16545_channels, + .num_channels = ARRAY_SIZE(adis16545_channels), + .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 = 7000, /* 7 milli degree Celsius */ + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + .has_burst_delta_data = true, + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts, + ADIS16495_BURST_MAX_DATA * 2, + 6500000), + }, }; static bool adis16480_validate_crc(const u16 *buf, const u8 n_elem, const u32 crc) @@ -1194,7 +1350,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) struct adis16480 *st = iio_priv(indio_dev); struct adis *adis = &st->adis; struct device *dev = &adis->spi->dev; - int ret, bit, offset, i = 0; + int ret, bit, offset, i = 0, buff_offset = 0; __be16 *buffer; u32 crc; bool valid; @@ -1227,8 +1383,8 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) * 16-bit responses containing the BURST_ID depending on the sclk. If * clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ, * we have only one. To manage that variation, we use the transition from the - * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If - * we not find this variation in the first 4 segments, then the data should + * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5/0xC3C3. + * If we not find this variation in the first 4 segments, then the data should * not be valid. */ buffer = adis->buffer; @@ -1236,7 +1392,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) u16 curr = be16_to_cpu(buffer[offset]); u16 next = be16_to_cpu(buffer[offset + 1]); - if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) { + if (curr == st->burst_id && next != st->burst_id) { offset++; break; } @@ -1263,11 +1419,24 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) switch (bit) { case ADIS16480_SCAN_TEMP: st->data[i++] = buffer[offset + 1]; + /* + * The temperature channel has 16-bit storage size. + * We need to perform the padding to have the buffer + * elements naturally aligned in case there are any + * 32-bit storage size channels enabled which are added + * in the buffer after the temprature data. In case + * there is no data being added after the temperature + * data, the padding is harmless. + */ + st->data[i++] = 0; break; + case ADIS16480_SCAN_DELTANG_X ... ADIS16480_SCAN_DELTVEL_Z: + buff_offset = ADIS16480_SCAN_DELTANG_X; + fallthrough; case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z: /* The lower register data is sequenced first */ - st->data[i++] = buffer[2 * bit + offset + 3]; - st->data[i++] = buffer[2 * bit + offset + 2]; + st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 3]; + st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 2]; break; } } @@ -1279,10 +1448,41 @@ irq_done: return IRQ_HANDLED; } +static const unsigned long adis16545_channel_masks[] = { + ADIS16545_BURST_DATA_SEL_0_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17), + ADIS16545_BURST_DATA_SEL_1_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17), + 0, +}; + +static int adis16480_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + u16 en; + int ret; + struct adis16480 *st = iio_priv(indio_dev); + + if (st->chip_info->has_burst_delta_data) { + if (*scan_mask & ADIS16545_BURST_DATA_SEL_0_CHN_MASK) { + en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 0); + st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID; + } else { + en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 1); + st->burst_id = ADIS16545_DELTA_ANG_VEL_BURST_ID; + } + + ret = __adis_update_bits(&st->adis, ADIS16480_REG_CONFIG, + ADIS16545_BURST_DATA_SEL_MASK, en); + if (ret) + return ret; + } + + return adis_update_scan_mode(indio_dev, scan_mask); +} + static const struct iio_info adis16480_info = { .read_raw = &adis16480_read_raw, .write_raw = &adis16480_write_raw, - .update_scan_mode = adis_update_scan_mode, + .update_scan_mode = &adis16480_update_scan_mode, .debugfs_reg_access = adis_debugfs_reg_access, }; @@ -1479,6 +1679,8 @@ static int adis16480_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; + if (st->chip_info->has_burst_delta_data) + indio_dev->available_scan_masks = adis16545_channel_masks; indio_dev->info = &adis16480_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -1492,6 +1694,13 @@ static int adis16480_probe(struct spi_device *spi) if (ret) return ret; + /* + * By default, use burst id for gyroscope and accelerometer data. + * This is the only option for devices which do not offer delta angle + * and delta velocity burst readings. + */ + st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID; + if (st->chip_info->has_sleep_cnt) { ret = devm_add_action_or_reset(dev, adis16480_stop, indio_dev); if (ret) @@ -1565,6 +1774,12 @@ static const struct spi_device_id adis16480_ids[] = { { "adis16497-1", ADIS16497_1 }, { "adis16497-2", ADIS16497_2 }, { "adis16497-3", ADIS16497_3 }, + { "adis16545-1", ADIS16545_1 }, + { "adis16545-2", ADIS16545_2 }, + { "adis16545-3", ADIS16545_3 }, + { "adis16547-1", ADIS16547_1 }, + { "adis16547-2", ADIS16547_2 }, + { "adis16547-3", ADIS16547_3 }, { } }; MODULE_DEVICE_TABLE(spi, adis16480_ids); @@ -1581,6 +1796,12 @@ static const struct of_device_id adis16480_of_match[] = { { .compatible = "adi,adis16497-1" }, { .compatible = "adi,adis16497-2" }, { .compatible = "adi,adis16497-3" }, + { .compatible = "adi,adis16545-1" }, + { .compatible = "adi,adis16545-2" }, + { .compatible = "adi,adis16545-3" }, + { .compatible = "adi,adis16547-1" }, + { .compatible = "adi,adis16547-2" }, + { .compatible = "adi,adis16547-3" }, { }, }; MODULE_DEVICE_TABLE(of, adis16480_of_match); From 9bc8b4d27c410f62742bad6a05639ee3e13f49eb Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Tue, 28 May 2024 17:24:08 +0300 Subject: [PATCH 096/330] docs: iio: add documentation for interfacing tools Add documentation for IIO interfacing tools describing the available tools which can be used to retrieve data from IIO sysfs. Reference this documentation in adis16475.rst Signed-off-by: Ramona Gradinariu Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240528142409.239187-6-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- Documentation/iio/adis16475.rst | 23 ++--------------------- Documentation/iio/iio_tools.rst | 27 +++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 3 files changed, 30 insertions(+), 21 deletions(-) create mode 100644 Documentation/iio/iio_tools.rst diff --git a/Documentation/iio/adis16475.rst b/Documentation/iio/adis16475.rst index 130f9e97cc17..4bf0998be36e 100644 --- a/Documentation/iio/adis16475.rst +++ b/Documentation/iio/adis16475.rst @@ -380,24 +380,5 @@ data is structured. 4. IIO Interfacing Tools ======================== -Linux Kernel Tools ------------------- - -Linux Kernel provides some userspace tools that can be used to retrieve data -from IIO sysfs: - -* lsiio: example application that provides a list of IIO devices and triggers -* iio_event_monitor: example application that reads events from an IIO device - and prints them -* iio_generic_buffer: example application that reads data from buffer -* iio_utils: set of APIs, typically used to access sysfs files. - -LibIIO ------- - -LibIIO is a C/C++ library that provides generic access to IIO devices. The -library abstracts the low-level details of the hardware, and provides a simple -yet complete programming interface that can be used for advanced projects. - -For more information about LibIIO, please see: -https://github.com/analogdevicesinc/libiio +See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO +interfacing tools. diff --git a/Documentation/iio/iio_tools.rst b/Documentation/iio/iio_tools.rst new file mode 100644 index 000000000000..cc691c7f6365 --- /dev/null +++ b/Documentation/iio/iio_tools.rst @@ -0,0 +1,27 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================== +IIO Interfacing Tools +===================== + +1. Linux Kernel Tools +===================== + +Linux Kernel provides some userspace tools that can be used to retrieve data +from IIO sysfs: + +* lsiio: example application that provides a list of IIO devices and triggers +* iio_event_monitor: example application that reads events from an IIO device + and prints them +* iio_generic_buffer: example application that reads data from buffer +* iio_utils: set of APIs, typically used to access sysfs files. + +2. LibIIO +========= + +LibIIO is a C/C++ library that provides generic access to IIO devices. The +library abstracts the low-level details of the hardware, and provides a simple +yet complete programming interface that can be used for advanced projects. + +For more information about LibIIO, please see: +https://github.com/analogdevicesinc/libiio diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index fb6f9d743211..66fa69102e3a 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -9,6 +9,7 @@ Industrial I/O iio_configfs iio_devbuf + iio_tools Industrial I/O Kernel Drivers ============================= From 7fcb9cb2fe47294e16067c3cfd25332c8662a115 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 29 May 2024 14:36:26 +0100 Subject: [PATCH 097/330] coresight: Fix ref leak when of_coresight_parse_endpoint() fails of_graph_get_next_endpoint() releases the reference to the previous endpoint on each iteration, but when parsing fails the loop exits early meaning the last reference is never dropped. Fix it by dropping the refcount in the exit condition. Fixes: d375b356e687 ("coresight: Fix support for sparsely populated ports") Signed-off-by: James Clark Reported-by: Laurent Pinchart Reviewed-by: Laurent Pinchart Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240529133626.90080-1-james.clark@arm.com --- drivers/hwtracing/coresight/coresight-platform.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 9d550f5697fa..57a009552cc5 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -297,8 +297,10 @@ static int of_get_coresight_platform_data(struct device *dev, continue; ret = of_coresight_parse_endpoint(dev, ep, pdata); - if (ret) + if (ret) { + of_node_put(ep); return ret; + } } return 0; From ef60f9ca26d33d0f8e1a709771c61d3e96f64559 Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Tue, 28 May 2024 17:24:09 +0300 Subject: [PATCH 098/330] docs: iio: add documentation for adis16480 driver Add documentation for adis16480 driver which describes the driver device files and shows how the user may use the ABI for various scenarios (configuration, measurement, etc.). Signed-off-by: Ramona Gradinariu Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240528142409.239187-7-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- Documentation/iio/adis16480.rst | 443 ++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 2 files changed, 444 insertions(+) create mode 100644 Documentation/iio/adis16480.rst diff --git a/Documentation/iio/adis16480.rst b/Documentation/iio/adis16480.rst new file mode 100644 index 000000000000..bc78fa04d958 --- /dev/null +++ b/Documentation/iio/adis16480.rst @@ -0,0 +1,443 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================ +ADIS16480 driver +================ + +This driver supports Analog Device's IMUs on SPI bus. + +1. Supported devices +==================== + +* `ADIS16375 `_ +* `ADIS16480 `_ +* `ADIS16485 `_ +* `ADIS16488 `_ +* `ADIS16490 `_ +* `ADIS16495 `_ +* `ADIS16497 `_ +* `ADIS16545 `_ +* `ADIS16547 `_ + +Each supported device is a complete inertial system that includes a triaxial +gyroscope and a triaxial accelerometer. Each inertial sensor in device combines +with signal conditioning that optimizes dynamic performance. The factory +calibration characterizes each sensor for sensitivity, bias, and alignment. As +a result, each sensor has its own dynamic compensation formulas that provide +accurate sensor measurements. + +2. Device attributes +==================== + +Accelerometer, gyroscope measurements are always provided. Furthermore, the +driver offers the capability to retrieve the delta angle and the delta velocity +measurements computed by the device. + +The delta angle measurements represent a calculation of angular displacement +between each sample update, while the delta velocity measurements represent a +calculation of linear velocity change between each sample update. + +Finally, temperature data are provided which show a coarse measurement of +the temperature inside of the IMU device. This data is most useful for +monitoring relative changes in the thermal environment. + +ADIS16480 and ADIS16488 also provide access to barometric pressure data and +triaxial magnetometer measurements. + +Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``, +where X is the IIO index of the device. Under these folders reside a set of +device files, depending on the characteristics and features of the hardware +device in questions. These files are consistently generalized and documented in +the IIO ABI documentation. + +The following tables show the adis16480 related device files, found in the +specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. + +**Available only for ADIS16480 and ADIS16488:** + ++------------------------------------------+---------------------------------------------------------+ +| 3-Axis Magnetometer related device files | Description | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_scale | Scale for the magnetometer channels. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_x_calibbias | Calibration offset for the X-axis magnetometer channel. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis magnetometer channel. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_x_raw | Raw X-axis magnetometer channel value. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_y_calibbias | Calibration offset for the Y-axis magnetometer channel. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis magnetometer channel. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_y_raw | Raw Y-axis magnetometer channel value. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_z_calibbias | Calibration offset for the Z-axis magnetometer channel. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis magnetometer channel. | ++------------------------------------------+---------------------------------------------------------+ +| in_magn_z_raw | Raw Z-axis magnetometer channel value. | ++------------------------------------------+---------------------------------------------------------+ + ++------------------------------------------+-----------------------------------------------------+ +| Barometric pressure sensor related files | Description | ++------------------------------------------+-----------------------------------------------------+ +| in_pressure0_calibbias | Calibration offset for barometric pressure channel. | ++------------------------------------------+-----------------------------------------------------+ +| in_pressure0_raw | Raw barometric pressure channel value. | ++------------------------------------------+-----------------------------------------------------+ +| in_pressure0_scale | Scale for the barometric pressure sensor channel. | ++------------------------------------------+-----------------------------------------------------+ + +**Available for all supported devices:** + ++-------------------------------------------+----------------------------------------------------------+ +| 3-Axis Accelerometer related device files | Description | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_scale | Scale for the accelerometer channels. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_x_calibscale | Calibration scale for the X-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_x_raw | Raw X-axis accelerometer channel value. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_y_calibscale | Calibration scale for the Y-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_y_raw | Raw Y-axis accelerometer channel value. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_z_calibscale | Calibration scale for the Z-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_z_raw | Raw Z-axis accelerometer channel value. | ++-------------------------------------------+----------------------------------------------------------+ +| in_deltavelocity_scale | Scale for delta velocity channels. | ++-------------------------------------------+----------------------------------------------------------+ +| in_deltavelocity_x_raw | Raw X-axis delta velocity channel value. | ++-------------------------------------------+----------------------------------------------------------+ +| in_deltavelocity_y_raw | Raw Y-axis delta velocity channel value. | ++-------------------------------------------+----------------------------------------------------------+ +| in_deltavelocity_z_raw | Raw Z-axis delta velocity channel value. | ++-------------------------------------------+----------------------------------------------------------+ + ++--------------------------------------------+------------------------------------------------------+ +| 3-Axis Gyroscope related device files | Description | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_scale | Scale for the gyroscope channels. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_x_calibbias | Calibration offset for the X-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_x_calibscale | Calibration scale for the X-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_x_raw | Raw X-axis gyroscope channel value. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_y_calibbias | Calibration offset for the Y-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_y_calibscale | Calibration scale for the Y-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_y_raw | Raw Y-axis gyroscope channel value. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_z_calibbias | Calibration offset for the Z-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_z_calibscale | Calibration scale for the Z-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis gyroscope channel. | ++--------------------------------------------+------------------------------------------------------+ +| in_anglvel_z_raw | Raw Z-axis gyroscope channel value. | ++--------------------------------------------+------------------------------------------------------+ +| in_deltaangl_scale | Scale for delta angle channels. | ++--------------------------------------------+------------------------------------------------------+ +| in_deltaangl_x_raw | Raw X-axis delta angle channel value. | ++--------------------------------------------+------------------------------------------------------+ +| in_deltaangl_y_raw | Raw Y-axis delta angle channel value. | ++--------------------------------------------+------------------------------------------------------+ +| in_deltaangl_z_raw | Raw Z-axis delta angle channel value. | ++--------------------------------------------+------------------------------------------------------+ + ++----------------------------------+-------------------------------------------+ +| Temperature sensor related files | Description | ++----------------------------------+-------------------------------------------+ +| in_temp0_raw | Raw temperature channel value. | ++----------------------------------+-------------------------------------------+ +| in_temp0_offset | Offset for the temperature sensor channel.| ++----------------------------------+-------------------------------------------+ +| in_temp0_scale | Scale for the temperature sensor channel. | ++----------------------------------+-------------------------------------------+ + ++-------------------------------+---------------------------------------------------------+ +| Miscellaneous device files | Description | ++-------------------------------+---------------------------------------------------------+ +| name | Name of the IIO device. | ++-------------------------------+---------------------------------------------------------+ +| sampling_frequency | Currently selected sample rate. | ++-------------------------------+---------------------------------------------------------+ + +The following table shows the adis16480 related device debug files, found in the +specific device debug folder path ``/sys/kernel/debug/iio/iio:deviceX``. + ++----------------------+-------------------------------------------------------------------------+ +| Debugfs device files | Description | ++----------------------+-------------------------------------------------------------------------+ +| serial_number | The serial number of the chip in hexadecimal format. | ++----------------------+-------------------------------------------------------------------------+ +| product_id | Chip specific product id (e.g. 16480, 16488, 16545, etc.). | ++----------------------+-------------------------------------------------------------------------+ +| flash_count | The number of flash writes performed on the device. | ++----------------------+-------------------------------------------------------------------------+ +| firmware_revision | String containing the firmware revision in the following format ##.##. | ++----------------------+-------------------------------------------------------------------------+ +| firmware_date | String containing the firmware date in the following format mm-dd-yyyy. | ++----------------------+-------------------------------------------------------------------------+ + +Channels processed values +------------------------- + +A channel value can be read from its _raw attribute. The value returned is the +raw value as reported by the devices. To get the processed value of the channel, +apply the following formula: + +.. code-block:: bash + + processed value = (_raw + _offset) * _scale + +Where _offset and _scale are device attributes. If no _offset attribute is +present, simply assume its value is 0. + +The adis16480 driver offers data for 7 types of channels, the table below shows +the measurement units for the processed value, which are defined by the IIO +framework: + ++--------------------------------------+---------------------------+ +| Channel type | Measurement unit | ++--------------------------------------+---------------------------+ +| Acceleration on X, Y, and Z axis | Meters per Second squared | ++--------------------------------------+---------------------------+ +| Angular velocity on X, Y and Z axis | Radians per second | ++--------------------------------------+---------------------------+ +| Delta velocity on X. Y, and Z axis | Meters per Second | ++--------------------------------------+---------------------------+ +| Delta angle on X, Y, and Z axis | Radians | ++--------------------------------------+---------------------------+ +| Temperature | Millidegrees Celsius | ++--------------------------------------+---------------------------+ +| Magnetic field along X, Y and Z axis | Gauss | ++--------------------------------------+---------------------------+ +| Barometric pressure | kilo Pascal | ++--------------------------------------+---------------------------+ + +Usage examples +-------------- + +Show device name: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat name + adis16545-1 + +Show accelerometer channels value: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw + 1376728 + root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw + 4487621 + root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw + 262773792 + root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale + 0.000000037 + +- X-axis acceleration = in_accel_x_raw * in_accel_scale = 0.050938936 m/s^2 +- Y-axis acceleration = in_accel_y_raw * in_accel_scale = 0.166041977 m/s^2 +- Z-axis acceleration = in_accel_z_raw * in_accel_scale = 9.722630304 m/s^2 + +Show gyroscope channels value: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_x_raw + -1041702 + root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_raw + -273013 + root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_z_raw + 2745116 + root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_scale + 0.000000001 + +- X-axis angular velocity = in_anglvel_x_raw * in_anglvel_scale = −0.001041702 rad/s +- Y-axis angular velocity = in_anglvel_y_raw * in_anglvel_scale = −0.000273013 rad/s +- Z-axis angular velocity = in_anglvel_z_raw * in_anglvel_scale = 0.002745116 rad/s + +Set calibration offset for accelerometer channels: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias + 0 + + root:/sys/bus/iio/devices/iio:device0> echo 5000 > in_accel_x_calibbias + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias + 5000 + +Set calibration offset for gyroscope channels: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias + 0 + + root:/sys/bus/iio/devices/iio:device0> echo -5000 > in_anglvel_y_calibbias + root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias + -5000 + +Set sampling frequency: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency + 4250.000000 + + root:/sys/bus/iio/devices/iio:device0> echo 1000 > sampling_frequency + 1062.500000 + +Set bandwidth for accelerometer channels: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_filter_low_pass_3db_frequency + 0 + + root:/sys/bus/iio/devices/iio:device0> echo 300 > in_accel_x_filter_low_pass_3db_frequency + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_filter_low_pass_3db_frequency + 300 + +Show serial number: + +.. code-block:: bash + + root:/sys/kernel/debug/iio/iio:device0> cat serial_number + 0x000c + +Show product id: + +.. code-block:: bash + + root:/sys/kernel/debug/iio/iio:device0> cat product_id + 16545 + +Show flash count: + +.. code-block:: bash + + root:/sys/kernel/debug/iio/iio:device0> cat flash_count + 88 + +Show firmware revision: + +.. code-block:: bash + + root:/sys/kernel/debug/iio/iio:device0> cat firmware_revision + 1.4 + +Show firmware date: + +.. code-block:: bash + + root:/sys/kernel/debug/iio/iio:device0> cat firmware_date + 09-23-2023 + +3. Device buffers +================= + +This driver supports IIO buffers. + +All devices support retrieving the raw acceleration, gyroscope and temperature +measurements using buffers. + +The following device families also support retrieving the delta velocity, delta +angle and temperature measurements using buffers: + +- ADIS16545 +- ADIS16547 + +However, when retrieving acceleration or gyroscope data using buffers, delta +readings will not be available and vice versa. This is because the device only +allows to read either acceleration and gyroscope data or delta velocity and +delta angle data at a time and switching between these two burst data selection +modes is time consuming. + +Usage examples +-------------- + +Set device trigger in current_trigger, if not already set: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger + + root:/sys/bus/iio/devices/iio:device0> echo adis16545-1-dev0 > trigger/current_trigger + root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger + adis16545-1-dev0 + +Select channels for buffer read: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_x_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_y_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_z_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp0_en + +Set the number of samples to be stored in the buffer: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length + +Enable buffer readings: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable + +Obtain buffered data:: + + root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0 + ... + 00006aa0 09 62 00 00 ff ff fc a4 00 00 01 69 00 03 3c 08 |.b.........i..<.| + 00006ab0 09 61 00 00 00 00 02 96 00 00 02 8f 00 03 37 50 |.a............7P| + 00006ac0 09 61 00 00 00 00 12 3d 00 00 0b 89 00 03 2c 0b |.a.....=......,.| + 00006ad0 09 61 00 00 00 00 1e dc 00 00 16 dd 00 03 25 bf |.a............%.| + 00006ae0 09 61 00 00 00 00 1e e3 00 00 1b bf 00 03 27 0b |.a............'.| + 00006af0 09 61 00 00 00 00 15 50 00 00 19 44 00 03 30 fd |.a.....P...D..0.| + 00006b00 09 61 00 00 00 00 09 0e 00 00 14 41 00 03 3d 7f |.a.........A..=.| + 00006b10 09 61 00 00 ff ff ff f0 00 00 0e bc 00 03 48 d0 |.a............H.| + 00006b20 09 63 00 00 00 00 00 9f 00 00 0f 37 00 03 4c fe |.c.........7..L.| + 00006b30 09 64 00 00 00 00 0b f6 00 00 18 92 00 03 43 22 |.d............C"| + 00006b40 09 64 00 00 00 00 18 df 00 00 22 33 00 03 33 ab |.d........"3..3.| + 00006b50 09 63 00 00 00 00 1e 81 00 00 26 be 00 03 29 60 |.c........&...)`| + 00006b60 09 63 00 00 00 00 1b 13 00 00 22 2f 00 03 23 91 |.c........"/..#.| + ... + +See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered +data is structured. + +4. IIO Interfacing Tools +======================== + +See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO +interfacing tools. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index 66fa69102e3a..4c13bfa2865c 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -19,5 +19,6 @@ Industrial I/O Kernel Drivers ad7944 adis16475 + adis16480 bno055 ep93xx_adc From 9f53b59f4843e7020f1cb0baecd2873f78136d76 Mon Sep 17 00:00:00 2001 From: Bruna Bispo Date: Tue, 28 May 2024 11:38:16 -0300 Subject: [PATCH 099/330] iio: chemical: ams-iaq-core: clean up codestyle warning This fixes a checkpatch warning by changing the struct attribute from __attribute__((__packed__)) to __packed. Signed-off-by: Bruna Bispo Link: https://lore.kernel.org/r/20240528143816.13409-1-blbispo1@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/ams-iaq-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c index 4d605c2b9750..10156d794092 100644 --- a/drivers/iio/chemical/ams-iaq-core.c +++ b/drivers/iio/chemical/ams-iaq-core.c @@ -24,7 +24,7 @@ struct ams_iaqcore_reading { u8 status; __be32 resistance; __be16 voc_ppb; -} __attribute__((__packed__)); +} __packed; struct ams_iaqcore_data { struct i2c_client *client; From b9b25c8496019402ecd64ddc5ae56f9bd97b12b2 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 6 May 2024 09:11:21 +0800 Subject: [PATCH 100/330] coresight: tmc: Remove duplicated include in coresight-tmc-core.c The header files linux/acpi.h is included twice in coresight-tmc-core.c, so one inclusion of each can be removed. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=8937 Signed-off-by: Yang Li Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240506011121.39179-1-yang.lee@linux.alibaba.com --- drivers/hwtracing/coresight/coresight-tmc-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 4f11a739ae4d..b54562f392f3 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "coresight-priv.h" #include "coresight-tmc.h" From c107697c82af8b9a0f1f914fa961cdb87a1a825f Mon Sep 17 00:00:00 2001 From: Marco Pagani Date: Tue, 4 Jun 2024 12:25:35 +0200 Subject: [PATCH 101/330] Revert "fpga: disable KUnit test suites when module support is enabled" This reverts commit a3fad2e92c76587fe262a1a4a122045b29885354. The core components of the subsystem no longer assume that low-level modules register a driver for the parent device and rely on its owner pointer to take the module's refcount. KUnit test suites can now be safely re-enabled with loadable module support. Signed-off-by: Marco Pagani Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240604102536.59010-1-marpagan@redhat.com Signed-off-by: Xu Yilun --- drivers/fpga/tests/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig index d4e55204c092..e4a64815f16d 100644 --- a/drivers/fpga/tests/Kconfig +++ b/drivers/fpga/tests/Kconfig @@ -1,6 +1,6 @@ config FPGA_KUNIT_TESTS - bool "KUnit test for the FPGA subsystem" if !KUNIT_ALL_TESTS - depends on FPGA=y && FPGA_REGION=y && FPGA_BRIDGE=y && KUNIT=y && MODULES=n + tristate "KUnit test for the FPGA subsystem" if !KUNIT_ALL_TESTS + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT=y default KUNIT_ALL_TESTS help This builds unit tests for the FPGA subsystem From 1a8009e108382848d149a24dd3fc67607d054a05 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 10 Jun 2024 10:57:30 +0200 Subject: [PATCH 102/330] dt-bindings: interconnect: Add MediaTek EMI Interconnect bindings Add bindings for the MediaTek External Memory Interface Interconnect, which providers support system bandwidth requirements through Dynamic Voltage Frequency Scaling Resource Collector (DVFSRC) hardware. This adds bindings for MediaTek MT8183 and MT8195 SoCs. Note that this is modeled as a subnode of DVFSRC for multiple reasons: - Some SoCs have more than one interconnect on the DVFSRC (and two different kinds of EMI interconnect, and also a SMI interconnect); - Some boards will want to not enable the interconnect driver because some of those are not battery powered (so they just keep the knobs at full thrust from the bootloader and never care scaling busses); - Some DVFSRC interconnect features may depend on firmware. Reviewed-by: Rob Herring Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240610085735.147134-3-angelogioacchino.delregno@collabora.com Signed-off-by: Georgi Djakov --- .../interconnect/mediatek,mt8183-emi.yaml | 51 +++++++++++++++++++ .../interconnect/mediatek,mt8183.h | 23 +++++++++ .../interconnect/mediatek,mt8195.h | 44 ++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/mediatek,mt8183-emi.yaml create mode 100644 include/dt-bindings/interconnect/mediatek,mt8183.h create mode 100644 include/dt-bindings/interconnect/mediatek,mt8195.h diff --git a/Documentation/devicetree/bindings/interconnect/mediatek,mt8183-emi.yaml b/Documentation/devicetree/bindings/interconnect/mediatek,mt8183-emi.yaml new file mode 100644 index 000000000000..017c8478b2a7 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/mediatek,mt8183-emi.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/mediatek,mt8183-emi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek External Memory Interface (EMI) Interconnect + +maintainers: + - AngeloGioacchino Del Regno + +description: | + EMI interconnect providers support system bandwidth requirements through + Dynamic Voltage Frequency Scaling Resource Collector (DVFSRC) hardware. + The provider is able to communicate with the DVFSRC through Secure Monitor + Call (SMC). + + ICC provider ICC Nodes + ---- ---- + _________ |CPU | |--- |VPU | + _____ | |----- ---- | ---- + | |->| DRAM | ---- | ---- + |DRAM |->|scheduler|----- |GPU | |--- |DISP| + | |->| (EMI) | ---- | ---- + |_____|->|_________|---. ----- | ---- + /|\ `-|MMSYS|--|--- |VDEC| + | ----- | ---- + | | ---- + | change DRAM freq |--- |VENC| + -------- | ---- + SMC --> | DVFSRC | | ---- + -------- |--- |IMG | + | ---- + | ---- + |--- |CAM | + ---- + +properties: + compatible: + enum: + - mediatek,mt8183-emi + - mediatek,mt8195-emi + + '#interconnect-cells': + const: 1 + +required: + - compatible + - '#interconnect-cells' + +unevaluatedProperties: false diff --git a/include/dt-bindings/interconnect/mediatek,mt8183.h b/include/dt-bindings/interconnect/mediatek,mt8183.h new file mode 100644 index 000000000000..1088c350258d --- /dev/null +++ b/include/dt-bindings/interconnect/mediatek,mt8183.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_MEDIATEK_MT8183_H +#define __DT_BINDINGS_INTERCONNECT_MEDIATEK_MT8183_H + +#define SLAVE_DDR_EMI 0 +#define MASTER_MCUSYS 1 +#define MASTER_MFG 2 +#define MASTER_MMSYS 3 +#define MASTER_MM_VPU 4 +#define MASTER_MM_DISP 5 +#define MASTER_MM_VDEC 6 +#define MASTER_MM_VENC 7 +#define MASTER_MM_CAM 8 +#define MASTER_MM_IMG 9 +#define MASTER_MM_MDP 10 + +#endif diff --git a/include/dt-bindings/interconnect/mediatek,mt8195.h b/include/dt-bindings/interconnect/mediatek,mt8195.h new file mode 100644 index 000000000000..33e0e6cde732 --- /dev/null +++ b/include/dt-bindings/interconnect/mediatek,mt8195.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2020 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_MEDIATEK_MT8195_H +#define __DT_BINDINGS_INTERCONNECT_MEDIATEK_MT8195_H + +#define SLAVE_DDR_EMI 0 +#define MASTER_MCUSYS 1 +#define MASTER_GPUSYS 2 +#define MASTER_MMSYS 3 +#define MASTER_MM_VPU 4 +#define MASTER_MM_DISP 5 +#define MASTER_MM_VDEC 6 +#define MASTER_MM_VENC 7 +#define MASTER_MM_CAM 8 +#define MASTER_MM_IMG 9 +#define MASTER_MM_MDP 10 +#define MASTER_VPUSYS 11 +#define MASTER_VPU_0 12 +#define MASTER_VPU_1 13 +#define MASTER_MDLASYS 14 +#define MASTER_MDLA_0 15 +#define MASTER_UFS 16 +#define MASTER_PCIE_0 17 +#define MASTER_PCIE_1 18 +#define MASTER_USB 19 +#define MASTER_DBGIF 20 +#define SLAVE_HRT_DDR_EMI 21 +#define MASTER_HRT_MMSYS 22 +#define MASTER_HRT_MM_DISP 23 +#define MASTER_HRT_MM_VDEC 24 +#define MASTER_HRT_MM_VENC 25 +#define MASTER_HRT_MM_CAM 26 +#define MASTER_HRT_MM_IMG 27 +#define MASTER_HRT_MM_MDP 28 +#define MASTER_HRT_DBGIF 29 +#define MASTER_WIFI 30 +#define MASTER_BT 31 +#define MASTER_NETSYS 32 +#endif From b45293799f75e002d5da9d9e3d2a5c418f492fd0 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 10 Jun 2024 10:57:35 +0200 Subject: [PATCH 103/330] interconnect: mediatek: Add MediaTek MT8183/8195 EMI Interconnect driver Add an interconnect driver for the External Memory Interface (EMI), voting for bus bandwidth over the Dynamic Voltage and Frequency Scaling Resource Collector (DVFSRC). ICC provider ICC Nodes ---- ---- --------- |CPU | |--- |VPU | ----- | |----- ---- | ---- |DRAM |--|DRAM | ---- | ---- | |--|scheduler|----- |GPU | |--- |DISP| | |--|(EMI) | ---- | ---- | |--| | ----- | ---- ----- | |----- |MMSYS|--|--- |VDEC| --------- ----- | ---- /|\ | ---- |change DRAM freq |--- |VENC| ---------- | ---- | DVFSR | | | | | ---- ---------- |--- |IMG | | ---- | ---- |--- |CAM | ---- Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240610085735.147134-8-angelogioacchino.delregno@collabora.com Signed-off-by: Georgi Djakov --- drivers/interconnect/Kconfig | 1 + drivers/interconnect/Makefile | 1 + drivers/interconnect/mediatek/Kconfig | 29 ++ drivers/interconnect/mediatek/Makefile | 5 + drivers/interconnect/mediatek/icc-emi.c | 153 +++++++++++ drivers/interconnect/mediatek/icc-emi.h | 40 +++ drivers/interconnect/mediatek/mt8183.c | 143 ++++++++++ drivers/interconnect/mediatek/mt8195.c | 339 ++++++++++++++++++++++++ 8 files changed, 711 insertions(+) create mode 100644 drivers/interconnect/mediatek/Kconfig create mode 100644 drivers/interconnect/mediatek/Makefile create mode 100644 drivers/interconnect/mediatek/icc-emi.c create mode 100644 drivers/interconnect/mediatek/icc-emi.h create mode 100644 drivers/interconnect/mediatek/mt8183.c create mode 100644 drivers/interconnect/mediatek/mt8195.c diff --git a/drivers/interconnect/Kconfig b/drivers/interconnect/Kconfig index 5faa8d2aecff..f2e49bd97d31 100644 --- a/drivers/interconnect/Kconfig +++ b/drivers/interconnect/Kconfig @@ -12,6 +12,7 @@ menuconfig INTERCONNECT if INTERCONNECT source "drivers/interconnect/imx/Kconfig" +source "drivers/interconnect/mediatek/Kconfig" source "drivers/interconnect/qcom/Kconfig" source "drivers/interconnect/samsung/Kconfig" diff --git a/drivers/interconnect/Makefile b/drivers/interconnect/Makefile index d0888babb9a1..b0a9a6753b9d 100644 --- a/drivers/interconnect/Makefile +++ b/drivers/interconnect/Makefile @@ -5,6 +5,7 @@ icc-core-objs := core.o bulk.o debugfs-client.o obj-$(CONFIG_INTERCONNECT) += icc-core.o obj-$(CONFIG_INTERCONNECT_IMX) += imx/ +obj-$(CONFIG_INTERCONNECT_MTK) += mediatek/ obj-$(CONFIG_INTERCONNECT_QCOM) += qcom/ obj-$(CONFIG_INTERCONNECT_SAMSUNG) += samsung/ diff --git a/drivers/interconnect/mediatek/Kconfig b/drivers/interconnect/mediatek/Kconfig new file mode 100644 index 000000000000..985c849efac3 --- /dev/null +++ b/drivers/interconnect/mediatek/Kconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config INTERCONNECT_MTK + bool "MediaTek interconnect drivers" + depends on ARCH_MEDIATEK || COMPILE_TEST + help + Support for MediaTek's bus interconnect hardware. + +config INTERCONNECT_MTK_DVFSRC_EMI + tristate "MediaTek DVFSRC EMI interconnect driver" + depends on INTERCONNECT_MTK && MTK_DVFSRC + help + This is a driver for the MediaTek External Memory Interface + interconnect on SoCs equipped with the integrated Dynamic + Voltage Frequency Scaling Resource Collector (DVFSRC) MCU + +config INTERCONNECT_MTK_MT8183 + tristate "MediaTek MT8183 interconnect driver" + depends on INTERCONNECT_MTK_DVFSRC_EMI + help + This is a driver for the MediaTek bus interconnect on MT8183-based + platforms. + +config INTERCONNECT_MTK_MT8195 + tristate "MediaTek MT8195 interconnect driver" + depends on INTERCONNECT_MTK_DVFSRC_EMI + help + This is a driver for the MediaTek bus interconnect on MT8195-based + platforms. diff --git a/drivers/interconnect/mediatek/Makefile b/drivers/interconnect/mediatek/Makefile new file mode 100644 index 000000000000..8e2283a9a5b5 --- /dev/null +++ b/drivers/interconnect/mediatek/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_INTERCONNECT_MTK_DVFSRC_EMI) += icc-emi.o +obj-$(CONFIG_INTERCONNECT_MTK_MT8183) += mt8183.o +obj-$(CONFIG_INTERCONNECT_MTK_MT8195) += mt8195.o diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c new file mode 100644 index 000000000000..d420c55682d0 --- /dev/null +++ b/drivers/interconnect/mediatek/icc-emi.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek External Memory Interface (EMI) Interconnect driver + * + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "icc-emi.h" + +static int mtk_emi_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, + u32 peak_bw, u32 *agg_avg, u32 *agg_peak) +{ + struct mtk_icc_node *in = node->data; + + *agg_avg += avg_bw; + *agg_peak = max_t(u32, *agg_peak, peak_bw); + + in->sum_avg = *agg_avg; + in->max_peak = *agg_peak; + + return 0; +} + +static int mtk_emi_icc_set(struct icc_node *src, struct icc_node *dst) +{ + struct mtk_icc_node *node = dst->data; + struct device *dev; + int ret; + + if (unlikely(!src->provider)) + return -EINVAL; + + dev = src->provider->dev; + + switch (node->ep) { + case 0: + break; + case 1: + ret = mtk_dvfsrc_send_request(dev, MTK_DVFSRC_CMD_PEAK_BW, node->max_peak); + if (ret) { + dev_err(dev, "Cannot send peak bw request: %d\n", ret); + return ret; + } + + ret = mtk_dvfsrc_send_request(dev, MTK_DVFSRC_CMD_BW, node->sum_avg); + if (ret) { + dev_err(dev, "Cannot send bw request: %d\n", ret); + return ret; + } + break; + case 2: + ret = mtk_dvfsrc_send_request(dev, MTK_DVFSRC_CMD_HRT_BW, node->sum_avg); + if (ret) { + dev_err(dev, "Cannot send HRT bw request: %d\n", ret); + return ret; + } + break; + default: + dev_err(src->provider->dev, "Unknown endpoint %u\n", node->ep); + return -EINVAL; + }; + + return 0; +} + +int mtk_emi_icc_probe(struct platform_device *pdev) +{ + const struct mtk_icc_desc *desc; + struct device *dev = &pdev->dev; + struct icc_node *node; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct mtk_icc_node **mnodes; + int i, j, ret; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + mnodes = desc->nodes; + + provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL); + if (!provider) + return -ENOMEM; + + data = devm_kzalloc(dev, struct_size(data, nodes, desc->num_nodes), GFP_KERNEL); + if (!data) + return -ENOMEM; + + provider->dev = pdev->dev.parent; + provider->set = mtk_emi_icc_set; + provider->aggregate = mtk_emi_icc_aggregate; + provider->xlate = of_icc_xlate_onecell; + INIT_LIST_HEAD(&provider->nodes); + provider->data = data; + + for (i = 0; i < desc->num_nodes; i++) { + if (!mnodes[i]) + continue; + + node = icc_node_create(mnodes[i]->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = mnodes[i]->name; + node->data = mnodes[i]; + icc_node_add(node, provider); + + for (j = 0; j < mnodes[i]->num_links; j++) + icc_link_create(node, mnodes[i]->links[j]); + + data->nodes[i] = node; + } + data->num_nodes = desc->num_nodes; + + ret = icc_provider_register(provider); + if (ret) + goto err; + + platform_set_drvdata(pdev, provider); + + return 0; +err: + icc_nodes_remove(provider); + return ret; +} +EXPORT_SYMBOL_GPL(mtk_emi_icc_probe); + +void mtk_emi_icc_remove(struct platform_device *pdev) +{ + struct icc_provider *provider = platform_get_drvdata(pdev); + + icc_provider_deregister(provider); + icc_nodes_remove(provider); +} +EXPORT_SYMBOL_GPL(mtk_emi_icc_remove); + +MODULE_AUTHOR("AngeloGioacchino Del Regno "); +MODULE_AUTHOR("Henry Chen "); +MODULE_DESCRIPTION("MediaTek External Memory Interface interconnect driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/mediatek/icc-emi.h b/drivers/interconnect/mediatek/icc-emi.h new file mode 100644 index 000000000000..9512a50db6fa --- /dev/null +++ b/drivers/interconnect/mediatek/icc-emi.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#ifndef __DRIVERS_INTERCONNECT_MEDIATEK_ICC_EMI_H +#define __DRIVERS_INTERCONNECT_MEDIATEK_ICC_EMI_H + +/** + * struct mtk_icc_node - Mediatek EMI Interconnect Node + * @name: The interconnect node name which is shown in debugfs + * @ep: Type of this endpoint + * @id: Unique node identifier + * @sum_avg: Current sum aggregate value of all average bw requests in kBps + * @max_peak: Current max aggregate value of all peak bw requests in kBps + * @num_links: The total number of @links + * @links: Array of @id linked to this node + */ +struct mtk_icc_node { + unsigned char *name; + int ep; + u16 id; + u64 sum_avg; + u64 max_peak; + + u16 num_links; + u16 links[] __counted_by(num_links); +}; + +struct mtk_icc_desc { + struct mtk_icc_node **nodes; + size_t num_nodes; +}; + +int mtk_emi_icc_probe(struct platform_device *pdev); +void mtk_emi_icc_remove(struct platform_device *pdev); + +#endif /* __DRIVERS_INTERCONNECT_MEDIATEK_ICC_EMI_H */ diff --git a/drivers/interconnect/mediatek/mt8183.c b/drivers/interconnect/mediatek/mt8183.c new file mode 100644 index 000000000000..24245085c7a9 --- /dev/null +++ b/drivers/interconnect/mediatek/mt8183.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "icc-emi.h" + +static struct mtk_icc_node ddr_emi = { + .name = "ddr-emi", + .id = SLAVE_DDR_EMI, + .ep = 1, +}; + +static struct mtk_icc_node mcusys = { + .name = "mcusys", + .id = MASTER_MCUSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node gpu = { + .name = "gpu", + .id = MASTER_MFG, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node mmsys = { + .name = "mmsys", + .id = MASTER_MMSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node mm_vpu = { + .name = "mm-vpu", + .id = MASTER_MM_VPU, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_disp = { + .name = "mm-disp", + .id = MASTER_MM_DISP, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_vdec = { + .name = "mm-vdec", + .id = MASTER_MM_VDEC, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_venc = { + .name = "mm-venc", + .id = MASTER_MM_VENC, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_cam = { + .name = "mm-cam", + .id = MASTER_MM_CAM, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_img = { + .name = "mm-img", + .id = MASTER_MM_IMG, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_mdp = { + .name = "mm-mdp", + .id = MASTER_MM_MDP, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node *mt8183_emi_icc_nodes[] = { + [SLAVE_DDR_EMI] = &ddr_emi, + [MASTER_MCUSYS] = &mcusys, + [MASTER_MFG] = &gpu, + [MASTER_MMSYS] = &mmsys, + [MASTER_MM_VPU] = &mm_vpu, + [MASTER_MM_DISP] = &mm_disp, + [MASTER_MM_VDEC] = &mm_vdec, + [MASTER_MM_VENC] = &mm_venc, + [MASTER_MM_CAM] = &mm_cam, + [MASTER_MM_IMG] = &mm_img, + [MASTER_MM_MDP] = &mm_mdp +}; + +static const struct mtk_icc_desc mt8183_emi_icc = { + .nodes = mt8183_emi_icc_nodes, + .num_nodes = ARRAY_SIZE(mt8183_emi_icc_nodes), +}; + +static const struct of_device_id mtk_mt8183_emi_icc_of_match[] = { + { .compatible = "mediatek,mt8183-emi", .data = &mt8183_emi_icc }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mtk_mt8183_emi_icc_of_match); + +static struct platform_driver mtk_emi_icc_mt8183_driver = { + .driver = { + .name = "emi-icc-mt8183", + .of_match_table = mtk_mt8183_emi_icc_of_match, + .sync_state = icc_sync_state, + }, + .probe = mtk_emi_icc_probe, + .remove_new = mtk_emi_icc_remove, + +}; +module_platform_driver(mtk_emi_icc_mt8183_driver); + +MODULE_AUTHOR("AngeloGioacchino Del Regno "); +MODULE_DESCRIPTION("MediaTek MT8183 EMI ICC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/mediatek/mt8195.c b/drivers/interconnect/mediatek/mt8195.c new file mode 100644 index 000000000000..710e14c5447c --- /dev/null +++ b/drivers/interconnect/mediatek/mt8195.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "icc-emi.h" + +static struct mtk_icc_node ddr_emi = { + .name = "ddr-emi", + .id = SLAVE_DDR_EMI, + .ep = 1, +}; + +static struct mtk_icc_node mcusys = { + .name = "mcusys", + .id = MASTER_MCUSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node gpu = { + .name = "gpu", + .id = MASTER_GPUSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node mmsys = { + .name = "mmsys", + .id = MASTER_MMSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node mm_vpu = { + .name = "mm-vpu", + .id = MASTER_MM_VPU, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_disp = { + .name = "mm-disp", + .id = MASTER_MM_DISP, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_vdec = { + .name = "mm-vdec", + .id = MASTER_MM_VDEC, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_venc = { + .name = "mm-venc", + .id = MASTER_MM_VENC, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_cam = { + .name = "mm-cam", + .id = MASTER_MM_CAM, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_img = { + .name = "mm-img", + .id = MASTER_MM_IMG, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node mm_mdp = { + .name = "mm-mdp", + .id = MASTER_MM_MDP, + .ep = 0, + .num_links = 1, + .links = { MASTER_MMSYS } +}; + +static struct mtk_icc_node vpusys = { + .name = "vpusys", + .id = MASTER_VPUSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node vpu_port0 = { + .name = "vpu-port0", + .id = MASTER_VPU_0, + .ep = 0, + .num_links = 1, + .links = { MASTER_VPUSYS } +}; + +static struct mtk_icc_node vpu_port1 = { + .name = "vpu-port1", + .id = MASTER_VPU_1, + .ep = 0, + .num_links = 1, + .links = { MASTER_VPUSYS } +}; + +static struct mtk_icc_node mdlasys = { + .name = "mdlasys", + .id = MASTER_MDLASYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node mdla_port0 = { + .name = "mdla-port0", + .id = MASTER_MDLA_0, + .ep = 0, + .num_links = 1, + .links = { MASTER_MDLASYS } +}; + +static struct mtk_icc_node ufs = { + .name = "ufs", + .id = MASTER_UFS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node pcie0 = { + .name = "pcie0", + .id = MASTER_PCIE_0, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node pcie1 = { + .name = "pcie1", + .id = MASTER_PCIE_1, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node usb = { + .name = "usb", + .id = MASTER_USB, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node wifi = { + .name = "wifi", + .id = MASTER_WIFI, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node bt = { + .name = "bt", + .id = MASTER_BT, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node netsys = { + .name = "netsys", + .id = MASTER_NETSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node dbgif = { + .name = "dbgif", + .id = MASTER_DBGIF, + .ep = 0, + .num_links = 1, + .links = { SLAVE_DDR_EMI } +}; + +static struct mtk_icc_node hrt_ddr_emi = { + .name = "hrt-ddr-emi", + .id = SLAVE_HRT_DDR_EMI, + .ep = 2, +}; + +static struct mtk_icc_node hrt_mmsys = { + .name = "hrt-mmsys", + .id = MASTER_HRT_MMSYS, + .ep = 0, + .num_links = 1, + .links = { SLAVE_HRT_DDR_EMI } +}; + +static struct mtk_icc_node hrt_mm_disp = { + .name = "hrt-mm-disp", + .id = MASTER_HRT_MM_DISP, + .ep = 0, + .num_links = 1, + .links = { MASTER_HRT_MMSYS } +}; + +static struct mtk_icc_node hrt_mm_vdec = { + .name = "hrt-mm-vdec", + .id = MASTER_HRT_MM_VDEC, + .ep = 0, + .num_links = 1, + .links = { MASTER_HRT_MMSYS } +}; + +static struct mtk_icc_node hrt_mm_venc = { + .name = "hrt-mm-venc", + .id = MASTER_HRT_MM_VENC, + .ep = 0, + .num_links = 1, + .links = { MASTER_HRT_MMSYS } +}; + +static struct mtk_icc_node hrt_mm_cam = { + .name = "hrt-mm-cam", + .id = MASTER_HRT_MM_CAM, + .ep = 0, + .num_links = 1, + .links = { MASTER_HRT_MMSYS } +}; + +static struct mtk_icc_node hrt_mm_img = { + .name = "hrt-mm-img", + .id = MASTER_HRT_MM_IMG, + .ep = 0, + .num_links = 1, + .links = { MASTER_HRT_MMSYS } +}; + +static struct mtk_icc_node hrt_mm_mdp = { + .name = "hrt-mm-mdp", + .id = MASTER_HRT_MM_MDP, + .ep = 0, + .num_links = 1, + .links = { MASTER_HRT_MMSYS } +}; + +static struct mtk_icc_node hrt_dbgif = { + .name = "hrt-dbgif", + .id = MASTER_HRT_DBGIF, + .ep = 0, + .num_links = 1, + .links = { SLAVE_HRT_DDR_EMI } +}; + +static struct mtk_icc_node *mt8195_emi_icc_nodes[] = { + [SLAVE_DDR_EMI] = &ddr_emi, + [MASTER_MCUSYS] = &mcusys, + [MASTER_GPUSYS] = &gpu, + [MASTER_MMSYS] = &mmsys, + [MASTER_MM_VPU] = &mm_vpu, + [MASTER_MM_DISP] = &mm_disp, + [MASTER_MM_VDEC] = &mm_vdec, + [MASTER_MM_VENC] = &mm_venc, + [MASTER_MM_CAM] = &mm_cam, + [MASTER_MM_IMG] = &mm_img, + [MASTER_MM_MDP] = &mm_mdp, + [MASTER_VPUSYS] = &vpusys, + [MASTER_VPU_0] = &vpu_port0, + [MASTER_VPU_1] = &vpu_port1, + [MASTER_MDLASYS] = &mdlasys, + [MASTER_MDLA_0] = &mdla_port0, + [MASTER_UFS] = &ufs, + [MASTER_PCIE_0] = &pcie0, + [MASTER_PCIE_1] = &pcie1, + [MASTER_USB] = &usb, + [MASTER_WIFI] = &wifi, + [MASTER_BT] = &bt, + [MASTER_NETSYS] = &netsys, + [MASTER_DBGIF] = &dbgif, + [SLAVE_HRT_DDR_EMI] = &hrt_ddr_emi, + [MASTER_HRT_MMSYS] = &hrt_mmsys, + [MASTER_HRT_MM_DISP] = &hrt_mm_disp, + [MASTER_HRT_MM_VDEC] = &hrt_mm_vdec, + [MASTER_HRT_MM_VENC] = &hrt_mm_venc, + [MASTER_HRT_MM_CAM] = &hrt_mm_cam, + [MASTER_HRT_MM_IMG] = &hrt_mm_img, + [MASTER_HRT_MM_MDP] = &hrt_mm_mdp, + [MASTER_HRT_DBGIF] = &hrt_dbgif +}; + +static struct mtk_icc_desc mt8195_emi_icc = { + .nodes = mt8195_emi_icc_nodes, + .num_nodes = ARRAY_SIZE(mt8195_emi_icc_nodes), +}; + +static const struct of_device_id mtk_mt8195_emi_icc_of_match[] = { + { .compatible = "mediatek,mt8195-emi", .data = &mt8195_emi_icc }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mtk_mt8195_emi_icc_of_match); + +static struct platform_driver mtk_emi_icc_mt8195_driver = { + .driver = { + .name = "emi-icc-mt8195", + .of_match_table = mtk_mt8195_emi_icc_of_match, + .sync_state = icc_sync_state, + }, + .probe = mtk_emi_icc_probe, + .remove_new = mtk_emi_icc_remove, + +}; +module_platform_driver(mtk_emi_icc_mt8195_driver); + +MODULE_AUTHOR("AngeloGioacchino Del Regno "); +MODULE_DESCRIPTION("MediaTek MT8195 EMI ICC driver"); +MODULE_LICENSE("GPL"); From c136ef2315bfa3c43e6241b2d0ca04094e1612ad Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 3 Jun 2024 16:42:48 -0700 Subject: [PATCH 104/330] interconnect: imx: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/interconnect/imx/imx-interconnect.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/interconnect/imx/imx8mm-interconnect.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/interconnect/imx/imx8mq-interconnect.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/interconnect/imx/imx8mn-interconnect.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/interconnect/imx/imx8mp-interconnect.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20240603-md-interconnect-imx-v1-1-348a9205506c@quicinc.com Signed-off-by: Georgi Djakov --- drivers/interconnect/imx/imx.c | 1 + drivers/interconnect/imx/imx8mm.c | 1 + drivers/interconnect/imx/imx8mn.c | 1 + drivers/interconnect/imx/imx8mp.c | 1 + drivers/interconnect/imx/imx8mq.c | 1 + 5 files changed, 5 insertions(+) diff --git a/drivers/interconnect/imx/imx.c b/drivers/interconnect/imx/imx.c index 979ed610f704..9511f80cf041 100644 --- a/drivers/interconnect/imx/imx.c +++ b/drivers/interconnect/imx/imx.c @@ -334,4 +334,5 @@ void imx_icc_unregister(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(imx_icc_unregister); +MODULE_DESCRIPTION("Interconnect framework driver for i.MX SoC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/imx/imx8mm.c b/drivers/interconnect/imx/imx8mm.c index 8c40f4182263..a36aaaf106ae 100644 --- a/drivers/interconnect/imx/imx8mm.c +++ b/drivers/interconnect/imx/imx8mm.c @@ -96,5 +96,6 @@ static struct platform_driver imx8mm_icc_driver = { module_platform_driver(imx8mm_icc_driver); MODULE_AUTHOR("Alexandre Bailon "); +MODULE_DESCRIPTION("Interconnect framework driver for i.MX8MM SoC"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:imx8mm-interconnect"); diff --git a/drivers/interconnect/imx/imx8mn.c b/drivers/interconnect/imx/imx8mn.c index fa3d4f97dfa4..2a97c74e875b 100644 --- a/drivers/interconnect/imx/imx8mn.c +++ b/drivers/interconnect/imx/imx8mn.c @@ -86,4 +86,5 @@ static struct platform_driver imx8mn_icc_driver = { module_platform_driver(imx8mn_icc_driver); MODULE_ALIAS("platform:imx8mn-interconnect"); MODULE_AUTHOR("Leonard Crestez "); +MODULE_DESCRIPTION("Interconnect framework driver for i.MX8MN SoC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/imx/imx8mp.c b/drivers/interconnect/imx/imx8mp.c index d218bb47757a..86d4c1517b26 100644 --- a/drivers/interconnect/imx/imx8mp.c +++ b/drivers/interconnect/imx/imx8mp.c @@ -249,5 +249,6 @@ static struct platform_driver imx8mp_icc_driver = { module_platform_driver(imx8mp_icc_driver); MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("Interconnect framework driver for i.MX8MP SoC"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:imx8mp-interconnect"); diff --git a/drivers/interconnect/imx/imx8mq.c b/drivers/interconnect/imx/imx8mq.c index 8bbd672b346e..f817d24aeefb 100644 --- a/drivers/interconnect/imx/imx8mq.c +++ b/drivers/interconnect/imx/imx8mq.c @@ -97,4 +97,5 @@ static struct platform_driver imx8mq_icc_driver = { module_platform_driver(imx8mq_icc_driver); MODULE_ALIAS("platform:imx8mq-interconnect"); MODULE_AUTHOR("Leonard Crestez "); +MODULE_DESCRIPTION("Interconnect framework driver for i.MX8MQ SoC"); MODULE_LICENSE("GPL v2"); From b14aa62c83ce6f65b2661c3138c586c93f1c9a77 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Wed, 12 Jun 2024 14:30:13 -0700 Subject: [PATCH 105/330] interconnect: qcom: add missing MODULE_DESCRIPTION() macros With ARCH=arm64, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/interconnect/qcom/interconnect_qcom.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/interconnect/qcom/icc-rpmh.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240612-md-drivers-interconnect-qcom-v1-1-da0462d6301b@quicinc.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-common.c | 1 + drivers/interconnect/qcom/icc-rpmh.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/interconnect/qcom/icc-common.c b/drivers/interconnect/qcom/icc-common.c index 9b9ee113f172..9b8a9c69e0cb 100644 --- a/drivers/interconnect/qcom/icc-common.c +++ b/drivers/interconnect/qcom/icc-common.c @@ -35,4 +35,5 @@ struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec } EXPORT_SYMBOL_GPL(qcom_icc_xlate_extended); +MODULE_DESCRIPTION("Qualcomm interconnect common functions"); MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index c1aa265c1f4e..4c5aa342e013 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -262,4 +262,5 @@ void qcom_icc_rpmh_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove); +MODULE_DESCRIPTION("Qualcomm RPMh interconnect driver"); MODULE_LICENSE("GPL v2"); From c4ec8dedca961db056ec85cb7ca8c9f7e2e92252 Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Thu, 30 May 2024 11:22:46 +0200 Subject: [PATCH 106/330] driver: iio: add missing checks on iio_info's callback access Some callbacks from iio_info structure are accessed without any check, so if a driver doesn't implement them trying to access the corresponding sysfs entries produce a kernel oops such as: [ 2203.527791] Unable to handle kernel NULL pointer dereference at virtual address 00000000 when execute [...] [ 2203.783416] Call trace: [ 2203.783429] iio_read_channel_info_avail from dev_attr_show+0x18/0x48 [ 2203.789807] dev_attr_show from sysfs_kf_seq_show+0x90/0x120 [ 2203.794181] sysfs_kf_seq_show from seq_read_iter+0xd0/0x4e4 [ 2203.798555] seq_read_iter from vfs_read+0x238/0x2a0 [ 2203.802236] vfs_read from ksys_read+0xa4/0xd4 [ 2203.805385] ksys_read from ret_fast_syscall+0x0/0x54 [ 2203.809135] Exception stack(0xe0badfa8 to 0xe0badff0) [ 2203.812880] dfa0: 00000003 b6f10f80 00000003 b6eab000 00020000 00000000 [ 2203.819746] dfc0: 00000003 b6f10f80 7ff00000 00000003 00000003 00000000 00020000 00000000 [ 2203.826619] dfe0: b6e1bc88 bed80958 b6e1bc94 b6e1bcb0 [ 2203.830363] Code: bad PC value [ 2203.832695] ---[ end trace 0000000000000000 ]--- Reviewed-by: Nuno Sa Signed-off-by: Julien Stephan Link: https://lore.kernel.org/r/20240530-iio-core-fix-segfault-v3-1-8b7cd2a03773@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 7 ++++++- drivers/iio/industrialio-event.c | 9 +++++++++ drivers/iio/inkern.c | 32 ++++++++++++++++++++++---------- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index fa7cc051b4c4..2f185b386949 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -758,9 +758,11 @@ static ssize_t iio_read_channel_info(struct device *dev, INDIO_MAX_RAW_ELEMENTS, vals, &val_len, this_attr->address); - else + else if (indio_dev->info->read_raw) ret = indio_dev->info->read_raw(indio_dev, this_attr->c, &vals[0], &vals[1], this_attr->address); + else + return -EINVAL; if (ret < 0) return ret; @@ -842,6 +844,9 @@ static ssize_t iio_read_channel_info_avail(struct device *dev, int length; int type; + if (!indio_dev->info->read_avail) + return -EINVAL; + ret = indio_dev->info->read_avail(indio_dev, this_attr->c, &vals, &type, &length, this_attr->address); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 910c1f14abd5..a64f8fbac597 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -285,6 +285,9 @@ static ssize_t iio_ev_state_store(struct device *dev, if (ret < 0) return ret; + if (!indio_dev->info->write_event_config) + return -EINVAL; + ret = indio_dev->info->write_event_config(indio_dev, this_attr->c, iio_ev_attr_type(this_attr), iio_ev_attr_dir(this_attr), val); @@ -300,6 +303,9 @@ static ssize_t iio_ev_state_show(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int val; + if (!indio_dev->info->read_event_config) + return -EINVAL; + val = indio_dev->info->read_event_config(indio_dev, this_attr->c, iio_ev_attr_type(this_attr), iio_ev_attr_dir(this_attr)); @@ -318,6 +324,9 @@ static ssize_t iio_ev_value_show(struct device *dev, int val, val2, val_arr[2]; int ret; + if (!indio_dev->info->read_event_value) + return -EINVAL; + ret = indio_dev->info->read_event_value(indio_dev, this_attr->c, iio_ev_attr_type(this_attr), iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 52d773261828..77cf1f22df31 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -543,6 +543,7 @@ EXPORT_SYMBOL_GPL(devm_iio_channel_get_all); static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum info) { + const struct iio_info *iio_info = chan->indio_dev->info; int unused; int vals[INDIO_MAX_RAW_ELEMENTS]; int ret; @@ -554,15 +555,18 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, if (!iio_channel_has_info(chan->channel, info)) return -EINVAL; - if (chan->indio_dev->info->read_raw_multi) { - ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev, - chan->channel, INDIO_MAX_RAW_ELEMENTS, - vals, &val_len, info); + if (iio_info->read_raw_multi) { + ret = iio_info->read_raw_multi(chan->indio_dev, + chan->channel, + INDIO_MAX_RAW_ELEMENTS, + vals, &val_len, info); *val = vals[0]; *val2 = vals[1]; + } else if (iio_info->read_raw) { + ret = iio_info->read_raw(chan->indio_dev, + chan->channel, val, val2, info); } else { - ret = chan->indio_dev->info->read_raw(chan->indio_dev, - chan->channel, val, val2, info); + return -EINVAL; } return ret; @@ -750,11 +754,15 @@ static int iio_channel_read_avail(struct iio_channel *chan, const int **vals, int *type, int *length, enum iio_chan_info_enum info) { + const struct iio_info *iio_info = chan->indio_dev->info; + if (!iio_channel_has_available(chan->channel, info)) return -EINVAL; - return chan->indio_dev->info->read_avail(chan->indio_dev, chan->channel, - vals, type, length, info); + if (iio_info->read_avail) + return iio_info->read_avail(chan->indio_dev, chan->channel, + vals, type, length, info); + return -EINVAL; } int iio_read_avail_channel_attribute(struct iio_channel *chan, @@ -917,8 +925,12 @@ EXPORT_SYMBOL_GPL(iio_get_channel_type); static int iio_channel_write(struct iio_channel *chan, int val, int val2, enum iio_chan_info_enum info) { - return chan->indio_dev->info->write_raw(chan->indio_dev, - chan->channel, val, val2, info); + const struct iio_info *iio_info = chan->indio_dev->info; + + if (iio_info->write_raw) + return iio_info->write_raw(chan->indio_dev, + chan->channel, val, val2, info); + return -EINVAL; } int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, From f4bed1ceb82e465d85d2f73c26b4652b81adb257 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Mon, 27 May 2024 05:00:18 -0300 Subject: [PATCH 107/330] iio: accel: mma7660: add mount-matrix support Allow using the mount-matrix device tree property to align the accelerometer relative to the whole device. Signed-off-by: Val Packett Link: https://lore.kernel.org/r/20240527080043.2709-1-val@packett.cool Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma7660.c | 50 ++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index d3febc760c4c..2894aff80161 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -38,21 +38,6 @@ static const int mma7660_nscale = 467142857; -#define MMA7660_CHANNEL(reg, axis) { \ - .type = IIO_ACCEL, \ - .address = reg, \ - .modified = 1, \ - .channel2 = IIO_MOD_##axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ -} - -static const struct iio_chan_spec mma7660_channels[] = { - MMA7660_CHANNEL(MMA7660_REG_XOUT, X), - MMA7660_CHANNEL(MMA7660_REG_YOUT, Y), - MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z), -}; - enum mma7660_mode { MMA7660_MODE_STANDBY, MMA7660_MODE_ACTIVE @@ -62,6 +47,21 @@ struct mma7660_data { struct i2c_client *client; struct mutex lock; enum mma7660_mode mode; + struct iio_mount_matrix orientation; +}; + +static const struct iio_mount_matrix * +mma7660_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mma7660_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info mma7660_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, mma7660_get_mount_matrix), + { } }; static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL); @@ -75,6 +75,22 @@ static const struct attribute_group mma7660_attribute_group = { .attrs = mma7660_attributes }; +#define MMA7660_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = mma7660_ext_info, \ +} + +static const struct iio_chan_spec mma7660_channels[] = { + MMA7660_CHANNEL(MMA7660_REG_XOUT, X), + MMA7660_CHANNEL(MMA7660_REG_YOUT, Y), + MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z), +}; + static int mma7660_set_mode(struct mma7660_data *data, enum mma7660_mode mode) { @@ -187,6 +203,10 @@ static int mma7660_probe(struct i2c_client *client) mutex_init(&data->lock); data->mode = MMA7660_MODE_STANDBY; + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; + indio_dev->info = &mma7660_info; indio_dev->name = MMA7660_DRIVER_NAME; indio_dev->modes = INDIO_DIRECT_MODE; From 1b88a895b931eaa64b500598abc8fac464aa0b5b Mon Sep 17 00:00:00 2001 From: Gustavo Ueti Fukunaga Date: Mon, 27 May 2024 06:19:40 -0300 Subject: [PATCH 108/330] iio: adc: ti-adc161s626: make use of iio_device_claim_direct_scoped() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make use of iio_device_claim_direct_scoped() to make error handling more natural and simplify code. Co-developed-by: Caio Dantas Simão Ugêda Signed-off-by: Caio Dantas Simão Ugêda Signed-off-by: Gustavo Ueti Fukunaga Link: https://lore.kernel.org/r/20240527091942.53616-1-gustavofukunaga@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc161s626.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index b789891dcf49..f7c78d0dd449 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -137,17 +137,13 @@ static int ti_adc_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - ret = ti_adc_read_measurement(data, chan, val); - iio_device_release_direct_mode(indio_dev); - - if (ret) - return ret; - - return IIO_VAL_INT; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + ret = ti_adc_read_measurement(data, chan, val); + if (ret) + return ret; + return IIO_VAL_INT; + } + unreachable(); case IIO_CHAN_INFO_SCALE: ret = regulator_get_voltage(data->ref); if (ret < 0) From 038c57c179eadd1ae6dff3a1c70d76dafa24d854 Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Sun, 2 Jun 2024 17:49:38 +0200 Subject: [PATCH 109/330] dt-bindings: iio: adc: ti,ads1015: add compatible for tla2021 TI tla2021 is a limited single-channel variant of tla2024 which is similar enough to be easily supportable through the same driver. Add compatible string for tla2021 so boards may describe it in device-tree. Signed-off-by: Josua Mayer Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240602-cn9130-som-v6-3-89393e86d4c7@solid-run.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml index d605999ffe28..718f633c6e04 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml @@ -18,6 +18,7 @@ properties: enum: - ti,ads1015 - ti,ads1115 + - ti,tla2021 - ti,tla2024 reg: From f451fbd73b0d54ef53bc2c80e4d969df1c7c7d96 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Mon, 17 Oct 2022 00:43:31 +0100 Subject: [PATCH 110/330] iio: adc: axp20x_adc: Add support for AXP192 The AXP192 is identical to the AXP20x, except for the addition of two more GPIO ADC channels. Reviewed-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Signed-off-by: Aidan MacDonald Signed-off-by: Jonathan Cameron --- drivers/iio/adc/axp20x_adc.c | 279 +++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index d6c51b0f48e3..913ea9e5d9c5 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -22,11 +22,19 @@ #include #include +#define AXP192_ADC_EN1_MASK GENMASK(7, 0) +#define AXP192_ADC_EN2_MASK (GENMASK(3, 0) | BIT(7)) + #define AXP20X_ADC_EN1_MASK GENMASK(7, 0) #define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7)) #define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0)) +#define AXP192_GPIO30_IN_RANGE_GPIO0 BIT(0) +#define AXP192_GPIO30_IN_RANGE_GPIO1 BIT(1) +#define AXP192_GPIO30_IN_RANGE_GPIO2 BIT(2) +#define AXP192_GPIO30_IN_RANGE_GPIO3 BIT(3) + #define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0) #define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1) @@ -71,6 +79,25 @@ struct axp20x_adc_iio { const struct axp_data *data; }; +enum axp192_adc_channel_v { + AXP192_ACIN_V = 0, + AXP192_VBUS_V, + AXP192_TS_IN, + AXP192_GPIO0_V, + AXP192_GPIO1_V, + AXP192_GPIO2_V, + AXP192_GPIO3_V, + AXP192_IPSOUT_V, + AXP192_BATT_V, +}; + +enum axp192_adc_channel_i { + AXP192_ACIN_I = 0, + AXP192_VBUS_I, + AXP192_BATT_CHRG_I, + AXP192_BATT_DISCHRG_I, +}; + enum axp20x_adc_channel_v { AXP20X_ACIN_V = 0, AXP20X_VBUS_V, @@ -158,6 +185,43 @@ static struct iio_map axp22x_maps[] = { * The only exception is for the battery. batt_v will be in_voltage6_raw and * charge current in_current6_raw and discharge current will be in_current7_raw. */ +static const struct iio_chan_spec axp192_adc_channels[] = { + AXP20X_ADC_CHANNEL(AXP192_ACIN_V, "acin_v", IIO_VOLTAGE, + AXP20X_ACIN_V_ADC_H), + AXP20X_ADC_CHANNEL(AXP192_ACIN_I, "acin_i", IIO_CURRENT, + AXP20X_ACIN_I_ADC_H), + AXP20X_ADC_CHANNEL(AXP192_VBUS_V, "vbus_v", IIO_VOLTAGE, + AXP20X_VBUS_V_ADC_H), + AXP20X_ADC_CHANNEL(AXP192_VBUS_I, "vbus_i", IIO_CURRENT, + AXP20X_VBUS_I_ADC_H), + { + .type = IIO_TEMP, + .address = AXP20X_TEMP_ADC_H, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .datasheet_name = "pmic_temp", + }, + AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO0_V, "gpio0_v", IIO_VOLTAGE, + AXP20X_GPIO0_V_ADC_H), + AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO1_V, "gpio1_v", IIO_VOLTAGE, + AXP20X_GPIO1_V_ADC_H), + AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO2_V, "gpio2_v", IIO_VOLTAGE, + AXP192_GPIO2_V_ADC_H), + AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO3_V, "gpio3_v", IIO_VOLTAGE, + AXP192_GPIO3_V_ADC_H), + AXP20X_ADC_CHANNEL(AXP192_IPSOUT_V, "ipsout_v", IIO_VOLTAGE, + AXP20X_IPSOUT_V_HIGH_H), + AXP20X_ADC_CHANNEL(AXP192_BATT_V, "batt_v", IIO_VOLTAGE, + AXP20X_BATT_V_H), + AXP20X_ADC_CHANNEL(AXP192_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT, + AXP20X_BATT_CHRG_I_H), + AXP20X_ADC_CHANNEL(AXP192_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT, + AXP20X_BATT_DISCHRG_I_H), + AXP20X_ADC_CHANNEL(AXP192_TS_IN, "ts_v", IIO_VOLTAGE, + AXP20X_TS_IN_H), +}; + static const struct iio_chan_spec axp20x_adc_channels[] = { AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE, AXP20X_ACIN_V_ADC_H), @@ -231,6 +295,27 @@ static const struct iio_chan_spec axp813_adc_channels[] = { AXP288_TS_ADC_H), }; +static int axp192_adc_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val) +{ + struct axp20x_adc_iio *info = iio_priv(indio_dev); + int ret, size; + + if (chan->type == IIO_CURRENT && + (chan->channel == AXP192_BATT_CHRG_I || + chan->channel == AXP192_BATT_DISCHRG_I)) + size = 13; + else + size = 12; + + ret = axp20x_read_variable_width(info->regmap, chan->address, size); + if (ret < 0) + return ret; + + *val = ret; + return IIO_VAL_INT; +} + static int axp20x_adc_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { @@ -283,6 +368,44 @@ static int axp813_adc_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; } +static int axp192_adc_scale_voltage(int channel, int *val, int *val2) +{ + switch (channel) { + case AXP192_ACIN_V: + case AXP192_VBUS_V: + *val = 1; + *val2 = 700000; + return IIO_VAL_INT_PLUS_MICRO; + + case AXP192_GPIO0_V: + case AXP192_GPIO1_V: + case AXP192_GPIO2_V: + case AXP192_GPIO3_V: + *val = 0; + *val2 = 500000; + return IIO_VAL_INT_PLUS_MICRO; + + case AXP192_BATT_V: + *val = 1; + *val2 = 100000; + return IIO_VAL_INT_PLUS_MICRO; + + case AXP192_IPSOUT_V: + *val = 1; + *val2 = 400000; + return IIO_VAL_INT_PLUS_MICRO; + + case AXP192_TS_IN: + /* 0.8 mV per LSB */ + *val = 0; + *val2 = 800000; + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + static int axp20x_adc_scale_voltage(int channel, int *val, int *val2) { switch (channel) { @@ -386,6 +509,29 @@ static int axp20x_adc_scale_current(int channel, int *val, int *val2) } } +static int axp192_adc_scale(struct iio_chan_spec const *chan, int *val, + int *val2) +{ + switch (chan->type) { + case IIO_VOLTAGE: + return axp192_adc_scale_voltage(chan->channel, val, val2); + + case IIO_CURRENT: + /* + * AXP192 current channels are identical to the AXP20x, + * therefore we can re-use the scaling function. + */ + return axp20x_adc_scale_current(chan->channel, val, val2); + + case IIO_TEMP: + *val = 100; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val, int *val2) { @@ -445,6 +591,42 @@ static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val, } } +static int axp192_adc_offset_voltage(struct iio_dev *indio_dev, int channel, + int *val) +{ + struct axp20x_adc_iio *info = iio_priv(indio_dev); + unsigned int regval; + int ret; + + ret = regmap_read(info->regmap, AXP192_GPIO30_IN_RANGE, ®val); + if (ret < 0) + return ret; + + switch (channel) { + case AXP192_GPIO0_V: + regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO0, regval); + break; + + case AXP192_GPIO1_V: + regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO1, regval); + break; + + case AXP192_GPIO2_V: + regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO2, regval); + break; + + case AXP192_GPIO3_V: + regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO3, regval); + break; + + default: + return -EINVAL; + } + + *val = regval ? 700000 : 0; + return IIO_VAL_INT; +} + static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel, int *val) { @@ -473,6 +655,22 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel, return IIO_VAL_INT; } +static int axp192_adc_offset(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val) +{ + switch (chan->type) { + case IIO_VOLTAGE: + return axp192_adc_offset_voltage(indio_dev, chan->channel, val); + + case IIO_TEMP: + *val = -1447; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + static int axp20x_adc_offset(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { @@ -489,6 +687,25 @@ static int axp20x_adc_offset(struct iio_dev *indio_dev, } } +static int axp192_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_OFFSET: + return axp192_adc_offset(indio_dev, chan, val); + + case IIO_CHAN_INFO_SCALE: + return axp192_adc_scale(chan, val, val2); + + case IIO_CHAN_INFO_RAW: + return axp192_adc_raw(indio_dev, chan, val); + + default: + return -EINVAL; + } +} + static int axp20x_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -549,6 +766,51 @@ static int axp813_read_raw(struct iio_dev *indio_dev, } } +static int axp192_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct axp20x_adc_iio *info = iio_priv(indio_dev); + unsigned int regmask, regval; + + /* + * The AXP192 PMIC allows the user to choose between 0V and 0.7V offsets + * for (independently) GPIO0-3 when in ADC mode. + */ + if (mask != IIO_CHAN_INFO_OFFSET) + return -EINVAL; + + if (val != 0 && val != 700000) + return -EINVAL; + + switch (chan->channel) { + case AXP192_GPIO0_V: + regmask = AXP192_GPIO30_IN_RANGE_GPIO0; + regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO0, !!val); + break; + + case AXP192_GPIO1_V: + regmask = AXP192_GPIO30_IN_RANGE_GPIO1; + regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO1, !!val); + break; + + case AXP192_GPIO2_V: + regmask = AXP192_GPIO30_IN_RANGE_GPIO2; + regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO2, !!val); + break; + + case AXP192_GPIO3_V: + regmask = AXP192_GPIO30_IN_RANGE_GPIO3; + regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO3, !!val); + break; + + default: + return -EINVAL; + } + + return regmap_update_bits(info->regmap, AXP192_GPIO30_IN_RANGE, regmask, regval); +} + static int axp20x_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -584,6 +846,11 @@ static int axp20x_write_raw(struct iio_dev *indio_dev, return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, regmask, regval); } +static const struct iio_info axp192_adc_iio_info = { + .read_raw = axp192_read_raw, + .write_raw = axp192_write_raw, +}; + static const struct iio_info axp20x_adc_iio_info = { .read_raw = axp20x_read_raw, .write_raw = axp20x_write_raw, @@ -629,6 +896,16 @@ struct axp_data { struct iio_map *maps; }; +static const struct axp_data axp192_data = { + .iio_info = &axp192_adc_iio_info, + .num_channels = ARRAY_SIZE(axp192_adc_channels), + .channels = axp192_adc_channels, + .adc_en1_mask = AXP192_ADC_EN1_MASK, + .adc_en2_mask = AXP192_ADC_EN2_MASK, + .adc_rate = axp20x_adc_rate, + .maps = axp20x_maps, +}; + static const struct axp_data axp20x_data = { .iio_info = &axp20x_adc_iio_info, .num_channels = ARRAY_SIZE(axp20x_adc_channels), @@ -658,6 +935,7 @@ static const struct axp_data axp813_data = { }; static const struct of_device_id axp20x_adc_of_match[] = { + { .compatible = "x-powers,axp192-adc", .data = (void *)&axp192_data, }, { .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, }, { .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, }, { .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, }, @@ -666,6 +944,7 @@ static const struct of_device_id axp20x_adc_of_match[] = { MODULE_DEVICE_TABLE(of, axp20x_adc_of_match); static const struct platform_device_id axp20x_adc_id_match[] = { + { .name = "axp192-adc", .driver_data = (kernel_ulong_t)&axp192_data, }, { .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, }, { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, }, { .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, }, From f91f9ece67972885fd41d06dfd034dcce057ef20 Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Sun, 2 Jun 2024 19:23:54 +0200 Subject: [PATCH 111/330] iio: event: use sizeof(*pointer) instead of sizeof(type) It is preferred to use sizeof(*pointer) instead of sizeof(type) due to the type of the variable can change and one needs not change the former (unlike the latter). At the same time refactor the NULL comparison. This patch has no effect on runtime behavior. Signed-off-by: Erick Archer Link: https://lore.kernel.org/r/AS8PR02MB7237D024459C314CECE72EAF8BFE2@AS8PR02MB7237.eurprd02.prod.outlook.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index a64f8fbac597..db06501b0e61 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -581,8 +581,8 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) iio_check_for_dynamic_events(indio_dev))) return 0; - ev_int = kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL); - if (ev_int == NULL) + ev_int = kzalloc(sizeof(*ev_int), GFP_KERNEL); + if (!ev_int) return -ENOMEM; iio_dev_opaque->event_interface = ev_int; From b2fb2d03e2dc3963bcf41f1d0cbd467ad9e6e89b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 7 Jun 2024 09:17:52 -0700 Subject: [PATCH 112/330] iio: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/iio/adc/ingenic-adc.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/iio/adc/xilinx-ams.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/iio/buffer/kfifo_buf.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240607-md-drivers-iic-v1-1-9f9db6246083@quicinc.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ingenic-adc.c | 1 + drivers/iio/adc/xilinx-ams.c | 1 + drivers/iio/buffer/kfifo_buf.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index a7325dbbb99a..af70ca760797 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -920,4 +920,5 @@ static struct platform_driver ingenic_adc_driver = { .probe = ingenic_adc_probe, }; module_platform_driver(ingenic_adc_driver); +MODULE_DESCRIPTION("ADC driver for the Ingenic JZ47xx SoCs"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index f0b71a1220e0..ee45475c495b 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -1430,5 +1430,6 @@ static struct platform_driver ams_driver = { }; module_platform_driver(ams_driver); +MODULE_DESCRIPTION("Xilinx AMS driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Xilinx, Inc."); diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 05b285f0eb22..38034c8bcc04 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -287,4 +287,5 @@ int devm_iio_kfifo_buffer_setup_ext(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup_ext); +MODULE_DESCRIPTION("Industrial I/O buffering based on kfifo"); MODULE_LICENSE("GPL"); From 2aac3f9aec74b28ea73ad96efbcc0c56e5ff814f Mon Sep 17 00:00:00 2001 From: Antoni Pokusinski Date: Fri, 7 Jun 2024 16:10:30 +0200 Subject: [PATCH 113/330] iio: humidity: si7020: add heater support This patch adds support for the integrated on-chip heater that is present on all the devices supported by this driver (si7020, si7021, si7013, th6). In order to configure the heater, the driver interacts with the following device registers: * User Register - the 2nd bit of this register is a "Heater Enable bit" (0 means that the heater is off, 1 means that it's on). * Heater Register - this register is present only on the si70xx devices and controls the current flowing through the heater. The 4 lower bits of this register can be assigned values from 0x0 to 0xF. Signed-off-by: Antoni Pokusinski Link: https://lore.kernel.org/r/20240607141029.51744-1-apokusinski@o2.pl Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/si7020.c | 137 +++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 4 deletions(-) diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index d34a915e3d4a..ff2dba50c0a5 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -33,17 +34,38 @@ #define SI7020CMD_TEMP_HOLD 0xE3 /* Software Reset */ #define SI7020CMD_RESET 0xFE +#define SI7020CMD_USR_WRITE 0xE6 +/* "Heater Enabled" bit in the User Register */ +#define SI7020_USR_HEATER_EN BIT(2) +#define SI7020CMD_HEATER_WRITE 0x51 +/* Heater current configuration bits */ +#define SI7020_HEATER_VAL GENMASK(3, 0) + +struct si7020_data { + struct i2c_client *client; + /* Lock for cached register values */ + struct mutex lock; + u8 user_reg; + u8 heater_reg; +}; + +static const int si7020_heater_vals[] = { 0, 1, 0xF }; static int si7020_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - struct i2c_client **client = iio_priv(indio_dev); + struct si7020_data *data = iio_priv(indio_dev); int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = i2c_smbus_read_word_swapped(*client, + if (chan->type == IIO_CURRENT) { + *val = data->heater_reg; + return IIO_VAL_INT; + } + + ret = i2c_smbus_read_word_swapped(data->client, chan->type == IIO_TEMP ? SI7020CMD_TEMP_HOLD : SI7020CMD_RH_HOLD); @@ -96,17 +118,118 @@ static const struct iio_chan_spec si7020_channels[] = { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + }, + { + .type = IIO_CURRENT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), + .extend_name = "heater", } }; +static int si7020_update_reg(struct si7020_data *data, + u8 *reg, u8 cmd, u8 mask, u8 val) +{ + u8 new = (*reg & ~mask) | val; + int ret; + + ret = i2c_smbus_write_byte_data(data->client, cmd, new); + if (ret) + return ret; + + *reg = new; + + return 0; +} + +static int si7020_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct si7020_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_CURRENT || val2 != 0 || + val < si7020_heater_vals[0] || val > si7020_heater_vals[2]) + return -EINVAL; + + scoped_guard(mutex, &data->lock) + ret = si7020_update_reg(data, &data->heater_reg, + SI7020CMD_HEATER_WRITE, SI7020_HEATER_VAL, val); + return ret; + default: + return -EINVAL; + } +} + +static int si7020_read_available(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, + int *type, int *length, long mask) +{ + if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_CURRENT) + return -EINVAL; + + *vals = si7020_heater_vals; + *type = IIO_VAL_INT; + + return IIO_AVAIL_RANGE; +} + +static ssize_t si7020_show_heater_en(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct si7020_data *data = iio_priv(indio_dev); + + return sysfs_emit(buf, "%d\n", !!(data->user_reg & SI7020_USR_HEATER_EN)); +} + +static ssize_t si7020_store_heater_en(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct si7020_data *data = iio_priv(indio_dev); + int ret; + bool val; + + ret = kstrtobool(buf, &val); + if (ret) + return ret; + + scoped_guard(mutex, &data->lock) + ret = si7020_update_reg(data, &data->user_reg, SI7020CMD_USR_WRITE, + SI7020_USR_HEATER_EN, val ? SI7020_USR_HEATER_EN : 0); + + return ret < 0 ? ret : len; +} + +static IIO_DEVICE_ATTR(heater_enable, 0644, + si7020_show_heater_en, si7020_store_heater_en, 0); + +static struct attribute *si7020_attributes[] = { + &iio_dev_attr_heater_enable.dev_attr.attr, + NULL +}; + +static const struct attribute_group si7020_attribute_group = { + .attrs = si7020_attributes, +}; + static const struct iio_info si7020_info = { .read_raw = si7020_read_raw, + .write_raw = si7020_write_raw, + .read_avail = si7020_read_available, + .attrs = &si7020_attribute_group, }; static int si7020_probe(struct i2c_client *client) { struct iio_dev *indio_dev; - struct i2c_client **data; + struct si7020_data *data; int ret; if (!i2c_check_functionality(client->adapter, @@ -126,7 +249,9 @@ static int si7020_probe(struct i2c_client *client) return -ENOMEM; data = iio_priv(indio_dev); - *data = client; + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); indio_dev->name = dev_name(&client->dev); indio_dev->modes = INDIO_DIRECT_MODE; @@ -134,6 +259,10 @@ static int si7020_probe(struct i2c_client *client) indio_dev->channels = si7020_channels; indio_dev->num_channels = ARRAY_SIZE(si7020_channels); + /* All the "reserved" bits in the User Register are 1s by default */ + data->user_reg = 0x3A; + data->heater_reg = 0x0; + return devm_iio_device_register(&client->dev, indio_dev); } From 4f9b4594bb09734b53212d23f8a4b78b7a3bdc2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 6 Jun 2024 17:54:04 +0200 Subject: [PATCH 114/330] staging: iio: Drop explicit initialization of struct i2c_device_id::driver_data to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These drivers don't use the driver_data member of struct i2c_device_id, so don't explicitly initialize this member. This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own. Signed-off-by: Uwe Kleine-König Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606155407.499344-1-u.kleine-koenig@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316-i2c.c | 12 ++++++------ drivers/staging/iio/impedance-analyzer/ad5933.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c index 6c1f91c859ca..e6ad088636f6 100644 --- a/drivers/staging/iio/addac/adt7316-i2c.c +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -109,12 +109,12 @@ static int adt7316_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adt7316_i2c_id[] = { - { "adt7316", 0 }, - { "adt7317", 0 }, - { "adt7318", 0 }, - { "adt7516", 0 }, - { "adt7517", 0 }, - { "adt7519", 0 }, + { "adt7316" }, + { "adt7317" }, + { "adt7318" }, + { "adt7516" }, + { "adt7517" }, + { "adt7519" }, { } }; diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index b7af5fe63e09..cd00d9607565 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -721,8 +721,8 @@ static int ad5933_probe(struct i2c_client *client) } static const struct i2c_device_id ad5933_id[] = { - { "ad5933", 0 }, - { "ad5934", 0 }, + { "ad5933" }, + { "ad5934" }, {} }; From d6e3ee74d16f2faef0cbe0251071076e0654e68a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:43 +0200 Subject: [PATCH 115/330] iio: accel: adxl313: simplify with spi_get_device_match_data() Use spi_get_device_match_data() helper to simplify a bit the driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-1-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl313_spi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index b7cc15678a2b..6f8d73f6e5a9 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -72,13 +72,7 @@ static int adxl313_spi_probe(struct spi_device *spi) if (ret) return ret; - /* - * Retrieves device specific data as a pointer to a - * adxl313_chip_info structure - */ - chip_data = device_get_match_data(&spi->dev); - if (!chip_data) - chip_data = (const struct adxl313_chip_info *)spi_get_device_id(spi)->driver_data; + chip_data = spi_get_device_match_data(spi); regmap = devm_regmap_init_spi(spi, &adxl31x_spi_regmap_config[chip_data->type]); From eafc2664be3adecf6a1902e4a58ac0719b62341c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:44 +0200 Subject: [PATCH 116/330] iio: accel: adxl355: simplify with spi_get_device_match_data() Use spi_get_device_match_data() helper to simplify a bit the driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-2-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl355_spi.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index fc99534d91ff..5153ac815e4b 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -28,13 +28,9 @@ static int adxl355_spi_probe(struct spi_device *spi) const struct adxl355_chip_info *chip_data; struct regmap *regmap; - chip_data = device_get_match_data(&spi->dev); - if (!chip_data) { - chip_data = (void *)spi_get_device_id(spi)->driver_data; - - if (!chip_data) - return -EINVAL; - } + chip_data = spi_get_device_match_data(spi); + if (!chip_data) + return -EINVAL; regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config); if (IS_ERR(regmap)) { From bf3c855be8017fb339755fcb2fee80dac4071f41 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:45 +0200 Subject: [PATCH 117/330] iio: adc: max11205: simplify with spi_get_device_match_data() Use spi_get_device_match_data() helper to simplify a bit the driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-3-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max11205.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c index 65fc32971ba5..9d8bc0b154dd 100644 --- a/drivers/iio/adc/max11205.c +++ b/drivers/iio/adc/max11205.c @@ -116,10 +116,7 @@ static int max11205_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &max11205_sigma_delta_info); - st->chip_info = device_get_match_data(&spi->dev); - if (!st->chip_info) - st->chip_info = - (const struct max11205_chip_info *)spi_get_device_id(spi)->driver_data; + st->chip_info = spi_get_device_match_data(spi); indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; From d7bffff19b6d5864b6322ab191ca3dfe6180673e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:46 +0200 Subject: [PATCH 118/330] iio: adc: ti-ads131e08: simplify with spi_get_device_match_data() Use spi_get_device_match_data() helper to simplify a bit the driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-4-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads131e08.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index cb04a29b3dba..96dd9366f8ff 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -802,9 +802,7 @@ static int ads131e08_probe(struct spi_device *spi) unsigned long adc_clk_ns; int ret; - info = device_get_match_data(&spi->dev); - if (!info) - info = (void *)spi_get_device_id(spi)->driver_data; + info = spi_get_device_match_data(spi); if (!info) { dev_err(&spi->dev, "failed to get match data\n"); return -ENODEV; From d8f2d8ae94d1ad6c7c0f2db6e86a37a2e54bd23e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:47 +0200 Subject: [PATCH 119/330] iio: adc: ti-tsc2046: simplify with spi_get_device_match_data() Use spi_get_device_match_data() helper to simplify a bit the driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-5-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-tsc2046.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index 1bbb51a6683c..edcef8f11522 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -804,12 +804,7 @@ static int tsc2046_adc_probe(struct spi_device *spi) return -EINVAL; } - dcfg = device_get_match_data(dev); - if (!dcfg) { - const struct spi_device_id *id = spi_get_device_id(spi); - - dcfg = (const struct tsc2046_adc_dcfg *)id->driver_data; - } + dcfg = spi_get_device_match_data(spi); if (!dcfg) return -EINVAL; From ce17861c8635b4bac5137c2faec3c3a59990f0b1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:48 +0200 Subject: [PATCH 120/330] iio: addac: ad74413r: simplify with spi_get_device_match_data() Use spi_get_device_match_data() helper to simplify a bit the driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-6-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/addac/ad74413r.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index cd26a16dc0ff..2410d72da49b 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -1365,16 +1365,9 @@ static int ad74413r_probe(struct spi_device *spi) st->spi = spi; st->dev = &spi->dev; - st->chip_info = device_get_match_data(&spi->dev); - if (!st->chip_info) { - const struct spi_device_id *id = spi_get_device_id(spi); - - if (id) - st->chip_info = - (struct ad74413r_chip_info *)id->driver_data; - if (!st->chip_info) - return -EINVAL; - } + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -EINVAL; mutex_init(&st->lock); init_completion(&st->adc_data_completion); From 2ac3ce8afd5f2d3bc0271e76e4d005d62594090e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:49 +0200 Subject: [PATCH 121/330] iio: dac: max5522: simplify with spi_get_device_match_data() Use spi_get_device_match_data() helper to simplify a bit the driver. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-7-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/max5522.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c index 05034a306597..9f72155dcbc7 100644 --- a/drivers/iio/dac/max5522.c +++ b/drivers/iio/dac/max5522.c @@ -132,7 +132,6 @@ static const struct regmap_config max5522_regmap_config = { static int max5522_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); struct iio_dev *indio_dev; struct max5522_state *state; int ret; @@ -144,13 +143,9 @@ static int max5522_spi_probe(struct spi_device *spi) } state = iio_priv(indio_dev); - state->chip_info = device_get_match_data(&spi->dev); - if (!state->chip_info) { - state->chip_info = - (struct max5522_chip_info *)(id->driver_data); - if (!state->chip_info) - return -EINVAL; - } + state->chip_info = spi_get_device_match_data(spi); + if (!state->chip_info) + return -EINVAL; state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin"); if (IS_ERR(state->vrefin_reg)) From bf977499c10667deb38f85dd4d0f287b0133ab54 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Jun 2024 16:26:50 +0200 Subject: [PATCH 122/330] iio: adc: mcp3564: drop redundant open-coded spi_get_device_match_data() The driver calls spi_get_device_match_data() and on its failure calls again parts of it: spi_get_device_id() and getting driver data. This is entirely redundant, because it is part of spi_get_device_match_data(). Signed-off-by: Krzysztof Kozlowski Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240606-spi-match-data-v1-8-320b291ee1fe@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3564.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index e2ae13f1e842..d83bed0e63d2 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -1114,7 +1114,6 @@ static int mcp3564_config(struct iio_dev *indio_dev) { struct mcp3564_state *adc = iio_priv(indio_dev); struct device *dev = &adc->spi->dev; - const struct spi_device_id *dev_id; u8 tmp_reg; u16 tmp_u16; enum mcp3564_ids ids; @@ -1212,11 +1211,6 @@ static int mcp3564_config(struct iio_dev *indio_dev) * try using fallback compatible in device tree to deal with some newer part number. */ adc->chip_info = spi_get_device_match_data(adc->spi); - if (!adc->chip_info) { - dev_id = spi_get_device_id(adc->spi); - adc->chip_info = (const struct mcp3564_chip_info *)dev_id->driver_data; - } - adc->have_vref = adc->chip_info->have_vref; } else { adc->chip_info = &mcp3564_chip_infos_tbl[ids]; From 50cfe81b71e50d7a7f6afb84d5dbe084ed4ea174 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Fri, 7 Jun 2024 08:10:39 +0000 Subject: [PATCH 123/330] iio: imu: inv_icm42600: add register caching in the regmap Register caching is improving bus access a lot because of the register window bank setting. Previously, bank register was set for every register access. Now with caching, it happens only when changing bank which is very infrequent. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240607081039.789079-1-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- .../iio/imu/inv_icm42600/inv_icm42600_core.c | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 96116a68ab29..ada5a8cca629 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -34,12 +34,56 @@ static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = { }, }; +static const struct regmap_range inv_icm42600_regmap_volatile_yes_ranges[] = { + /* Sensor data registers */ + regmap_reg_range(0x001D, 0x002A), + /* INT status, FIFO, APEX data */ + regmap_reg_range(0x002D, 0x0038), + /* Signal path reset */ + regmap_reg_range(0x004B, 0x004B), + /* FIFO lost packets */ + regmap_reg_range(0x006C, 0x006D), + /* Timestamp value */ + regmap_reg_range(0x1062, 0x1064), +}; + +static const struct regmap_range inv_icm42600_regmap_volatile_no_ranges[] = { + regmap_reg_range(0x0000, 0x001C), + regmap_reg_range(0x006E, 0x1061), + regmap_reg_range(0x1065, 0x4FFF), +}; + +static const struct regmap_access_table inv_icm42600_regmap_volatile_accesses[] = { + { + .yes_ranges = inv_icm42600_regmap_volatile_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(inv_icm42600_regmap_volatile_yes_ranges), + .no_ranges = inv_icm42600_regmap_volatile_no_ranges, + .n_no_ranges = ARRAY_SIZE(inv_icm42600_regmap_volatile_no_ranges), + }, +}; + +static const struct regmap_range inv_icm42600_regmap_rd_noinc_no_ranges[] = { + regmap_reg_range(0x0000, INV_ICM42600_REG_FIFO_DATA - 1), + regmap_reg_range(INV_ICM42600_REG_FIFO_DATA + 1, 0x4FFF), +}; + +static const struct regmap_access_table inv_icm42600_regmap_rd_noinc_accesses[] = { + { + .no_ranges = inv_icm42600_regmap_rd_noinc_no_ranges, + .n_no_ranges = ARRAY_SIZE(inv_icm42600_regmap_rd_noinc_no_ranges), + }, +}; + const struct regmap_config inv_icm42600_regmap_config = { + .name = "inv_icm42600", .reg_bits = 8, .val_bits = 8, .max_register = 0x4FFF, .ranges = inv_icm42600_regmap_ranges, .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges), + .volatile_table = inv_icm42600_regmap_volatile_accesses, + .rd_noinc_table = inv_icm42600_regmap_rd_noinc_accesses, + .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600); From 9fae1f2aa41963faae96e03175c7684522246ab5 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 4 Jun 2024 11:16:58 +0200 Subject: [PATCH 124/330] iio: adc: adi-axi-adc: add platform dependencies Being this device a soft core, it's only supported on some/specific platforms. Hence add proper dependencies for the supported platforms. Also add COMPILE_TEST to increase the build coverage. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240604-dev-axi-adc-kconfig-v1-1-cfb725606b8e@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 5030319249c5..3d91015af6ea 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -353,6 +353,7 @@ config AD9467 config ADI_AXI_ADC tristate "Analog Devices Generic AXI ADC IP core driver" + depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST select IIO_BUFFER select IIO_BUFFER_HW_CONSUMER select IIO_BUFFER_DMAENGINE From d157d0ba0213768119bacd819ec09a8a484dbc4f Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 4 Jun 2024 11:19:56 +0200 Subject: [PATCH 125/330] iio: dac: adi-axi-dac: add platform dependencies Being this device a soft core, it's only supported on some/specific platforms. Hence add proper dependencies for the supported platforms. Also add COMPILE_TEST to increase the build coverage. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240604-dev-axi-dac-kconfig-v1-1-99ccd03938d1@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 3c2bf620f00f..fb48dddbcc20 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -149,6 +149,7 @@ config AD9739A config ADI_AXI_DAC tristate "Analog Devices Generic AXI DAC IP core driver" + depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST select IIO_BUFFER select IIO_BUFFER_DMAENGINE select REGMAP_MMIO From 5cf99438d5d8db6007762eb6734125f58bcae48b Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Jun 2024 11:37:08 +0200 Subject: [PATCH 126/330] dt-bindings: iio: adc: amlogic,meson-saradc: add optional power-domains On newer SoCs, the SAR ADC hardware can require a power-domain to operate, add it as optional. Signed-off-by: Neil Armstrong Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240605-topic-amlogic-upstream-bindings-fixes-power-domains-sardac-v1-1-40a8de6baa59@linaro.org Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml index 7e8328e9ce13..f748f3a60b35 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml @@ -66,6 +66,9 @@ properties: nvmem-cell-names: const: temperature_calib + power-domains: + maxItems: 1 + allOf: - if: properties: From 3c34171c1b12c100a42c0a8ed88355a13fcb5be8 Mon Sep 17 00:00:00 2001 From: Arthur Becker Date: Tue, 4 Jun 2024 10:01:48 +0200 Subject: [PATCH 127/330] iio: light: driver for Vishay VEML6040 Implements driver for the Vishay VEML6040 rgbw light sensor. Included functionality: setting the integration time and reading the raw values for the four channels Not yet implemented: setting the measurements to 'Manual Force Mode' (Auto measurements off, and adding a measurement trigger) Datasheet: https://www.vishay.com/docs/84276/veml6040.pdf Signed-off-by: Arthur Becker Link: https://lore.kernel.org/r/20240604-veml6040-v4-1-5a4d59597874@sentec.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 11 ++ drivers/iio/light/Makefile | 1 + drivers/iio/light/veml6040.c | 281 +++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 drivers/iio/light/veml6040.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 9a587d403118..b68dcc1fbaca 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -666,6 +666,17 @@ config VEML6030 To compile this driver as a module, choose M here: the module will be called veml6030. +config VEML6040 + tristate "VEML6040 RGBW light sensor" + select REGMAP_I2C + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML6040 + RGBW light sensor. + + To compile this driver as a module, choose M here: the + module will be called veml6040. + config VEML6070 tristate "VEML6070 UV A light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index a30f906e91ba..1a071a8e9f8e 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_VCNL4035) += vcnl4035.o obj-$(CONFIG_VEML6030) += veml6030.o +obj-$(CONFIG_VEML6040) += veml6040.o obj-$(CONFIG_VEML6070) += veml6070.o obj-$(CONFIG_VEML6075) += veml6075.o obj-$(CONFIG_VL6180) += vl6180.o diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c new file mode 100644 index 000000000000..216e271001a8 --- /dev/null +++ b/drivers/iio/light/veml6040.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Vishay VEML6040 RGBW light sensor driver + * + * Copyright (C) 2024 Sentec AG + * Author: Arthur Becker + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* VEML6040 Configuration Registers + * + * SD: Shutdown + * AF: Auto / Force Mode (Auto Measurements On:0, Off:1) + * TR: Trigger Measurement (when AF Bit is set) + * IT: Integration Time + */ +#define VEML6040_CONF_REG 0x000 +#define VEML6040_CONF_SD_MSK BIT(0) +#define VEML6040_CONF_AF_MSK BIT(1) +#define VEML6040_CONF_TR_MSK BIT(2) +#define VEML6040_CONF_IT_MSK GENMASK(6, 4) +#define VEML6040_CONF_IT_40_MS 0 +#define VEML6040_CONF_IT_80_MS 1 +#define VEML6040_CONF_IT_160_MS 2 +#define VEML6040_CONF_IT_320_MS 3 +#define VEML6040_CONF_IT_640_MS 4 +#define VEML6040_CONF_IT_1280_MS 5 + +/* VEML6040 Read Only Registers */ +#define VEML6040_REG_R 0x08 +#define VEML6040_REG_G 0x09 +#define VEML6040_REG_B 0x0A +#define VEML6040_REG_W 0x0B + +static const int veml6040_it_ms[] = { 40, 80, 160, 320, 640, 1280 }; + +enum veml6040_chan { + CH_RED, + CH_GREEN, + CH_BLUE, + CH_WHITE, +}; + +struct veml6040_data { + struct i2c_client *client; + struct regmap *regmap; +}; + +static const struct regmap_config veml6040_regmap_config = { + .name = "veml6040_regmap", + .reg_bits = 8, + .val_bits = 16, + .max_register = VEML6040_REG_W, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int veml6040_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + int ret, reg, it_index; + struct veml6040_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = &data->client->dev; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(regmap, chan->address, ®); + if (ret) { + dev_err(dev, "Data read failed: %d\n", ret); + return ret; + } + *val = reg; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_INT_TIME: + ret = regmap_read(regmap, VEML6040_CONF_REG, ®); + if (ret) { + dev_err(dev, "Data read failed: %d\n", ret); + return ret; + } + it_index = FIELD_GET(VEML6040_CONF_IT_MSK, reg); + if (it_index >= ARRAY_SIZE(veml6040_it_ms)) { + dev_err(dev, "Invalid Integration Time Set"); + return -EINVAL; + } + *val = veml6040_it_ms[it_index]; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int veml6040_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct veml6040_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + for (int i = 0; i < ARRAY_SIZE(veml6040_it_ms); i++) { + if (veml6040_it_ms[i] != val) + continue; + + return regmap_update_bits(data->regmap, + VEML6040_CONF_REG, + VEML6040_CONF_IT_MSK, + FIELD_PREP(VEML6040_CONF_IT_MSK, i)); + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static int veml6040_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *length = ARRAY_SIZE(veml6040_it_ms); + *vals = veml6040_it_ms; + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + + default: + return -EINVAL; + } +} + +static const struct iio_info veml6040_info = { + .read_raw = veml6040_read_raw, + .write_raw = veml6040_write_raw, + .read_avail = veml6040_read_avail, +}; + +static const struct iio_chan_spec veml6040_channels[] = { + { + .type = IIO_INTENSITY, + .address = VEML6040_REG_R, + .channel = CH_RED, + .channel2 = IIO_MOD_LIGHT_RED, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_INT_TIME), + }, + { + .type = IIO_INTENSITY, + .address = VEML6040_REG_G, + .channel = CH_GREEN, + .channel2 = IIO_MOD_LIGHT_GREEN, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_INT_TIME), + }, + { + .type = IIO_INTENSITY, + .address = VEML6040_REG_B, + .channel = CH_BLUE, + .channel2 = IIO_MOD_LIGHT_BLUE, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_INT_TIME), + }, + { + .type = IIO_INTENSITY, + .address = VEML6040_REG_W, + .channel = CH_WHITE, + .channel2 = IIO_MOD_LIGHT_CLEAR, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_INT_TIME), + } +}; + +static void veml6040_shutdown_action(void *data) +{ + struct veml6040_data *veml6040_data = data; + + regmap_update_bits(veml6040_data->regmap, VEML6040_CONF_REG, + VEML6040_CONF_SD_MSK, VEML6040_CONF_SD_MSK); +} + +static int veml6040_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct veml6040_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + const int init_config = + FIELD_PREP(VEML6040_CONF_IT_MSK, VEML6040_CONF_IT_40_MS) | + FIELD_PREP(VEML6040_CONF_AF_MSK, 0) | + FIELD_PREP(VEML6040_CONF_SD_MSK, 0); + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return dev_err_probe(dev, -EOPNOTSUPP, + "I2C adapter doesn't support plain I2C\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, + "IIO device allocation failed\n"); + + regmap = devm_regmap_init_i2c(client, &veml6040_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Regmap setup failed\n"); + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + data->regmap = regmap; + + indio_dev->name = "veml6040"; + indio_dev->info = &veml6040_info; + indio_dev->channels = veml6040_channels; + indio_dev->num_channels = ARRAY_SIZE(veml6040_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return ret; + + ret = regmap_write(regmap, VEML6040_CONF_REG, init_config); + if (ret) + return dev_err_probe(dev, ret, + "Could not set initial config\n"); + + ret = devm_add_action_or_reset(dev, veml6040_shutdown_action, data); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct i2c_device_id veml6040_id_table[] = { + {"veml6040"}, + {} +}; +MODULE_DEVICE_TABLE(i2c, veml6040_id_table); + +static const struct of_device_id veml6040_of_match[] = { + {.compatible = "vishay,veml6040"}, + {} +}; +MODULE_DEVICE_TABLE(of, veml6040_of_match); + +static struct i2c_driver veml6040_driver = { + .probe = veml6040_probe, + .id_table = veml6040_id_table, + .driver = { + .name = "veml6040", + .of_match_table = veml6040_of_match, + }, +}; +module_i2c_driver(veml6040_driver); + +MODULE_DESCRIPTION("veml6040 RGBW light sensor driver"); +MODULE_AUTHOR("Arthur Becker "); +MODULE_LICENSE("GPL"); From 8af8d75e9f829fdd247c15145966e0a5c64668b6 Mon Sep 17 00:00:00 2001 From: Arthur Becker Date: Tue, 4 Jun 2024 10:01:49 +0200 Subject: [PATCH 128/330] dt-bindings: iio: light: add VEML6040 RGBW-LS Device tree bindings for the vishay VEML6040 RGBW light sensor iio driver Signed-off-by: Arthur Becker Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240604-veml6040-v4-2-5a4d59597874@sentec.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/light/vishay,veml6075.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml index 91c318746bf3..ecf2339e02f6 100644 --- a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml +++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml @@ -4,14 +4,19 @@ $id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Vishay VEML6075 UVA and UVB sensor +title: Vishay VEML6075 UVA/B and VEML6040 RGBW sensors maintainers: - Javier Carrasco +description: + VEML6040 datasheet at https://www.vishay.com/docs/84276/veml6040.pdf + properties: compatible: - const: vishay,veml6075 + enum: + - vishay,veml6040 + - vishay,veml6075 reg: maxItems: 1 From dea750f8015b514923e57c0a992e8d5db41efbb4 Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Tue, 4 Jun 2024 15:36:39 +0200 Subject: [PATCH 129/330] iio: temperature: mcp9600: add threshold events support The device has four programmable temperature alert outputs which can be used to monitor hot or cold-junction temperatures and detect falling and rising temperatures. It supports up to 255 degree celsius programmable hysteresis. Each alert can be individually configured by setting following options in the associated alert configuration register: - monitor hot or cold junction temperature - monitor rising or falling temperature - set comparator or interrupt mode - set output polarity - enable alert This patch binds alert outputs to iio events: - alert1: hot junction, rising temperature - alert2: hot junction, falling temperature - alert3: cold junction, rising temperature - alert4: cold junction, falling temperature All outputs are set in comparator mode and polarity depends on interrupt configuration. Signed-off-by: Dimitri Fedrau Link: https://lore.kernel.org/r/20240604133639.959682-1-dima.fedrau@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mcp9600.c | 363 ++++++++++++++++++++++++++++-- 1 file changed, 349 insertions(+), 14 deletions(-) diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index 7a3eef5d5e75..f1bb0976273d 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -6,39 +6,123 @@ * Author: */ +#include +#include +#include #include #include #include +#include +#include +#include +#include #include #include +#include #include /* MCP9600 registers */ #define MCP9600_HOT_JUNCTION 0x0 #define MCP9600_COLD_JUNCTION 0x2 +#define MCP9600_STATUS 0x4 +#define MCP9600_STATUS_ALERT(x) BIT(x) +#define MCP9600_ALERT_CFG1 0x8 +#define MCP9600_ALERT_CFG(x) (MCP9600_ALERT_CFG1 + (x - 1)) +#define MCP9600_ALERT_CFG_ENABLE BIT(0) +#define MCP9600_ALERT_CFG_ACTIVE_HIGH BIT(2) +#define MCP9600_ALERT_CFG_FALLING BIT(3) +#define MCP9600_ALERT_CFG_COLD_JUNCTION BIT(4) +#define MCP9600_ALERT_HYSTERESIS1 0xc +#define MCP9600_ALERT_HYSTERESIS(x) (MCP9600_ALERT_HYSTERESIS1 + (x - 1)) +#define MCP9600_ALERT_LIMIT1 0x10 +#define MCP9600_ALERT_LIMIT(x) (MCP9600_ALERT_LIMIT1 + (x - 1)) +#define MCP9600_ALERT_LIMIT_MASK GENMASK(15, 2) #define MCP9600_DEVICE_ID 0x20 /* MCP9600 device id value */ #define MCP9600_DEVICE_ID_MCP9600 0x40 -static const struct iio_chan_spec mcp9600_channels[] = { +#define MCP9600_ALERT_COUNT 4 + +#define MCP9600_MIN_TEMP_HOT_JUNCTION_MICRO -200000000 +#define MCP9600_MAX_TEMP_HOT_JUNCTION_MICRO 1800000000 + +#define MCP9600_MIN_TEMP_COLD_JUNCTION_MICRO -40000000 +#define MCP9600_MAX_TEMP_COLD_JUNCTION_MICRO 125000000 + +enum mcp9600_alert { + MCP9600_ALERT1, + MCP9600_ALERT2, + MCP9600_ALERT3, + MCP9600_ALERT4 +}; + +static const char * const mcp9600_alert_name[MCP9600_ALERT_COUNT] = { + [MCP9600_ALERT1] = "alert1", + [MCP9600_ALERT2] = "alert2", + [MCP9600_ALERT3] = "alert3", + [MCP9600_ALERT4] = "alert4", +}; + +static const struct iio_event_spec mcp9600_events[] = { { - .type = IIO_TEMP, - .address = MCP9600_HOT_JUNCTION, - .info_mask_separate = - BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_HYSTERESIS), }, { - .type = IIO_TEMP, - .address = MCP9600_COLD_JUNCTION, - .channel2 = IIO_MOD_TEMP_AMBIENT, - .modified = 1, - .info_mask_separate = - BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_HYSTERESIS), }, }; +#define MCP9600_CHANNELS(hj_num_ev, hj_ev_spec_off, cj_num_ev, cj_ev_spec_off) \ + { \ + { \ + .type = IIO_TEMP, \ + .address = MCP9600_HOT_JUNCTION, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .event_spec = &mcp9600_events[hj_ev_spec_off], \ + .num_event_specs = hj_num_ev, \ + }, \ + { \ + .type = IIO_TEMP, \ + .address = MCP9600_COLD_JUNCTION, \ + .channel2 = IIO_MOD_TEMP_AMBIENT, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .event_spec = &mcp9600_events[cj_ev_spec_off], \ + .num_event_specs = cj_num_ev, \ + }, \ + } + +static const struct iio_chan_spec mcp9600_channels[][2] = { + MCP9600_CHANNELS(0, 0, 0, 0), /* Alerts: - - - - */ + MCP9600_CHANNELS(1, 0, 0, 0), /* Alerts: 1 - - - */ + MCP9600_CHANNELS(1, 1, 0, 0), /* Alerts: - 2 - - */ + MCP9600_CHANNELS(2, 0, 0, 0), /* Alerts: 1 2 - - */ + MCP9600_CHANNELS(0, 0, 1, 0), /* Alerts: - - 3 - */ + MCP9600_CHANNELS(1, 0, 1, 0), /* Alerts: 1 - 3 - */ + MCP9600_CHANNELS(1, 1, 1, 0), /* Alerts: - 2 3 - */ + MCP9600_CHANNELS(2, 0, 1, 0), /* Alerts: 1 2 3 - */ + MCP9600_CHANNELS(0, 0, 1, 1), /* Alerts: - - - 4 */ + MCP9600_CHANNELS(1, 0, 1, 1), /* Alerts: 1 - - 4 */ + MCP9600_CHANNELS(1, 1, 1, 1), /* Alerts: - 2 - 4 */ + MCP9600_CHANNELS(2, 0, 1, 1), /* Alerts: 1 2 - 4 */ + MCP9600_CHANNELS(0, 0, 2, 0), /* Alerts: - - 3 4 */ + MCP9600_CHANNELS(1, 0, 2, 0), /* Alerts: 1 - 3 4 */ + MCP9600_CHANNELS(1, 1, 2, 0), /* Alerts: - 2 3 4 */ + MCP9600_CHANNELS(2, 0, 2, 0), /* Alerts: 1 2 3 4 */ +}; + struct mcp9600_data { struct i2c_client *client; }; @@ -80,15 +164,261 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev, } } +static int mcp9600_get_alert_index(int channel2, enum iio_event_direction dir) +{ + if (channel2 == IIO_MOD_TEMP_AMBIENT) { + if (dir == IIO_EV_DIR_RISING) + return MCP9600_ALERT3; + else + return MCP9600_ALERT4; + } else { + if (dir == IIO_EV_DIR_RISING) + return MCP9600_ALERT1; + else + return MCP9600_ALERT2; + } +} + +static int mcp9600_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct mcp9600_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int i, ret; + + i = mcp9600_get_alert_index(chan->channel2, dir); + ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_CFG(i + 1)); + if (ret < 0) + return ret; + + return FIELD_GET(MCP9600_ALERT_CFG_ENABLE, ret); +} + +static int mcp9600_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct mcp9600_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int i, ret; + + i = mcp9600_get_alert_index(chan->channel2, dir); + ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_CFG(i + 1)); + if (ret < 0) + return ret; + + if (state) + ret |= MCP9600_ALERT_CFG_ENABLE; + else + ret &= ~MCP9600_ALERT_CFG_ENABLE; + + return i2c_smbus_write_byte_data(client, MCP9600_ALERT_CFG(i + 1), ret); +} + +static int mcp9600_read_thresh(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) +{ + struct mcp9600_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + s32 ret; + int i; + + i = mcp9600_get_alert_index(chan->channel2, dir); + switch (info) { + case IIO_EV_INFO_VALUE: + ret = i2c_smbus_read_word_swapped(client, MCP9600_ALERT_LIMIT(i + 1)); + if (ret < 0) + return ret; + /* + * Temperature is stored in two’s complement format in + * bits(15:2), LSB is 0.25 degree celsius. + */ + *val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13); + *val2 = 4; + return IIO_VAL_FRACTIONAL; + case IIO_EV_INFO_HYSTERESIS: + ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_HYSTERESIS(i + 1)); + if (ret < 0) + return ret; + + *val = ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int mcp9600_write_thresh(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) +{ + struct mcp9600_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int s_val, i; + s16 thresh; + u8 hyst; + + i = mcp9600_get_alert_index(chan->channel2, dir); + switch (info) { + case IIO_EV_INFO_VALUE: + /* Scale value to include decimal part into calculations */ + s_val = (val < 0) ? ((val * 1000000) - val2) : + ((val * 1000000) + val2); + if (chan->channel2 == IIO_MOD_TEMP_AMBIENT) { + s_val = max(s_val, MCP9600_MIN_TEMP_COLD_JUNCTION_MICRO); + s_val = min(s_val, MCP9600_MAX_TEMP_COLD_JUNCTION_MICRO); + } else { + s_val = max(s_val, MCP9600_MIN_TEMP_HOT_JUNCTION_MICRO); + s_val = min(s_val, MCP9600_MAX_TEMP_HOT_JUNCTION_MICRO); + } + + /* + * Shift length 4 bits = 2(15:2) + 2(0.25 LSB), temperature is + * stored in two’s complement format. + */ + thresh = (s16)(s_val / (1000000 >> 4)); + return i2c_smbus_write_word_swapped(client, + MCP9600_ALERT_LIMIT(i + 1), + thresh); + case IIO_EV_INFO_HYSTERESIS: + hyst = min(abs(val), 255); + return i2c_smbus_write_byte_data(client, + MCP9600_ALERT_HYSTERESIS(i + 1), + hyst); + default: + return -EINVAL; + } +} + static const struct iio_info mcp9600_info = { .read_raw = mcp9600_read_raw, + .read_event_config = mcp9600_read_event_config, + .write_event_config = mcp9600_write_event_config, + .read_event_value = mcp9600_read_thresh, + .write_event_value = mcp9600_write_thresh, }; +static irqreturn_t mcp9600_alert_handler(void *private, + enum mcp9600_alert alert, + enum iio_modifier mod, + enum iio_event_direction dir) +{ + struct iio_dev *indio_dev = private; + struct mcp9600_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_read_byte_data(data->client, MCP9600_STATUS); + if (ret < 0) + return IRQ_HANDLED; + + if (!(ret & MCP9600_STATUS_ALERT(alert))) + return IRQ_NONE; + + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_TEMP, 0, mod, IIO_EV_TYPE_THRESH, + dir), + iio_get_time_ns(indio_dev)); + + return IRQ_HANDLED; +} + +static irqreturn_t mcp9600_alert1_handler(int irq, void *private) +{ + return mcp9600_alert_handler(private, MCP9600_ALERT1, IIO_NO_MOD, + IIO_EV_DIR_RISING); +} + +static irqreturn_t mcp9600_alert2_handler(int irq, void *private) +{ + return mcp9600_alert_handler(private, MCP9600_ALERT2, IIO_NO_MOD, + IIO_EV_DIR_FALLING); +} + +static irqreturn_t mcp9600_alert3_handler(int irq, void *private) +{ + return mcp9600_alert_handler(private, MCP9600_ALERT3, + IIO_MOD_TEMP_AMBIENT, IIO_EV_DIR_RISING); +} + +static irqreturn_t mcp9600_alert4_handler(int irq, void *private) +{ + return mcp9600_alert_handler(private, MCP9600_ALERT4, + IIO_MOD_TEMP_AMBIENT, IIO_EV_DIR_FALLING); +} + +static irqreturn_t (*mcp9600_alert_handler_func[MCP9600_ALERT_COUNT]) (int, void *) = { + mcp9600_alert1_handler, + mcp9600_alert2_handler, + mcp9600_alert3_handler, + mcp9600_alert4_handler, +}; + +static int mcp9600_probe_alerts(struct iio_dev *indio_dev) +{ + struct mcp9600_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + struct device *dev = &client->dev; + struct fwnode_handle *fwnode = dev_fwnode(dev); + unsigned int irq_type; + int ret, irq, i; + u8 val, ch_sel; + + /* + * alert1: hot junction, rising temperature + * alert2: hot junction, falling temperature + * alert3: cold junction, rising temperature + * alert4: cold junction, falling temperature + */ + ch_sel = 0; + for (i = 0; i < MCP9600_ALERT_COUNT; i++) { + irq = fwnode_irq_get_byname(fwnode, mcp9600_alert_name[i]); + if (irq <= 0) + continue; + + val = 0; + irq_type = irq_get_trigger_type(irq); + if (irq_type == IRQ_TYPE_EDGE_RISING) + val |= MCP9600_ALERT_CFG_ACTIVE_HIGH; + + if (i == MCP9600_ALERT2 || i == MCP9600_ALERT4) + val |= MCP9600_ALERT_CFG_FALLING; + + if (i == MCP9600_ALERT3 || i == MCP9600_ALERT4) + val |= MCP9600_ALERT_CFG_COLD_JUNCTION; + + ret = i2c_smbus_write_byte_data(client, + MCP9600_ALERT_CFG(i + 1), + val); + if (ret < 0) + return ret; + + ret = devm_request_threaded_irq(dev, irq, NULL, + mcp9600_alert_handler_func[i], + IRQF_ONESHOT, "mcp9600", + indio_dev); + if (ret) + return ret; + + ch_sel |= BIT(i); + } + + return ch_sel; +} + static int mcp9600_probe(struct i2c_client *client) { struct iio_dev *indio_dev; struct mcp9600_data *data; - int ret; + int ret, ch_sel; ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID); if (ret < 0) @@ -104,11 +434,15 @@ static int mcp9600_probe(struct i2c_client *client) data = iio_priv(indio_dev); data->client = client; + ch_sel = mcp9600_probe_alerts(indio_dev); + if (ch_sel < 0) + return ch_sel; + indio_dev->info = &mcp9600_info; indio_dev->name = "mcp9600"; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = mcp9600_channels; - indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels); + indio_dev->channels = mcp9600_channels[ch_sel]; + indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels[ch_sel]); return devm_iio_device_register(&client->dev, indio_dev); } @@ -135,6 +469,7 @@ static struct i2c_driver mcp9600_driver = { }; module_i2c_driver(mcp9600_driver); +MODULE_AUTHOR("Dimitri Fedrau "); MODULE_AUTHOR("Andrew Hepp "); MODULE_DESCRIPTION("Microchip MCP9600 thermocouple EMF converter driver"); MODULE_LICENSE("GPL"); From 202ce3eaa691225f11dab93a76e7afab67edc4ec Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Tue, 4 Jun 2024 19:57:25 -0300 Subject: [PATCH 130/330] dt-bindings: vendor-prefixes: add ScioSense Add vendor prefix for ScioSense B.V. https://www.sciosense.com/ Acked-by: Conor Dooley Signed-off-by: Gustavo Silva Link: https://lore.kernel.org/r/20240604225747.7212-2-gustavograzs@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index fbf47f0bacf1..044e2001f4e3 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1254,6 +1254,8 @@ patternProperties: description: Smart Battery System "^schindler,.*": description: Schindler + "^sciosense,.*": + description: ScioSense B.V. "^seagate,.*": description: Seagate Technology PLC "^seeed,.*": From ec6c56577b3908744e35a709ffd58e6cf4f8dd6b Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Tue, 4 Jun 2024 19:57:26 -0300 Subject: [PATCH 131/330] dt-bindings: iio: chemical: add ENS160 sensor Add bindings for ScioSense ENS160 multi-gas sensor. Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf Reviewed-by: Conor Dooley Signed-off-by: Gustavo Silva Link: https://lore.kernel.org/r/20240604225747.7212-3-gustavograzs@gmail.com Signed-off-by: Jonathan Cameron --- .../iio/chemical/sciosense,ens160.yaml | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml diff --git a/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml new file mode 100644 index 000000000000..267033a68abb --- /dev/null +++ b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/chemical/sciosense,ens160.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ScioSense ENS160 multi-gas sensor + +maintainers: + - Gustavo Silva + +description: | + Digital Multi-Gas Sensor for Monitoring Indoor Air Quality. + + Datasheet: + https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf + +properties: + compatible: + enum: + - sciosense,ens160 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: true + vddio-supply: true + +required: + - compatible + - reg + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + gas-sensor@52 { + compatible = "sciosense,ens160"; + reg = <0x52>; + interrupt-parent = <&gpio0>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; + }; + }; + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + gas-sensor@0 { + compatible = "sciosense,ens160"; + reg = <0>; + spi-max-frequency = <10000000>; + interrupt-parent = <&gpio>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; + }; + }; + +... From e3166508a12e2ff7bfa711f895177dab971fd716 Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Tue, 4 Jun 2024 19:57:27 -0300 Subject: [PATCH 132/330] iio: chemical: add driver for ENS160 sensor ScioSense ENS160 is a digital metal oxide multi-gas sensor, designed for indoor air quality monitoring. The driver supports readings of CO2 and VOC, and can be accessed via both SPI and I2C. Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf Signed-off-by: Gustavo Silva Link: https://lore.kernel.org/r/20240604225747.7212-4-gustavograzs@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/Kconfig | 20 +++ drivers/iio/chemical/Makefile | 3 + drivers/iio/chemical/ens160.h | 7 + drivers/iio/chemical/ens160_core.c | 221 +++++++++++++++++++++++++++++ drivers/iio/chemical/ens160_i2c.c | 60 ++++++++ drivers/iio/chemical/ens160_spi.c | 60 ++++++++ 6 files changed, 371 insertions(+) create mode 100644 drivers/iio/chemical/ens160.h create mode 100644 drivers/iio/chemical/ens160_core.c create mode 100644 drivers/iio/chemical/ens160_i2c.c create mode 100644 drivers/iio/chemical/ens160_spi.c diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index 02649ab81b3c..678a6adb9a75 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -76,6 +76,26 @@ config CCS811 Say Y here to build I2C interface support for the AMS CCS811 VOC (Volatile Organic Compounds) sensor +config ENS160 + tristate "ScioSense ENS160 sensor driver" + depends on (I2C || SPI) + select REGMAP + select ENS160_I2C if I2C + select ENS160_SPI if SPI + help + Say yes here to build support for ScioSense ENS160 multi-gas sensor. + + This driver can also be built as a module. If so, the module for I2C + would be called ens160_i2c and ens160_spi for SPI support. + +config ENS160_I2C + tristate + select REGMAP_I2C + +config ENS160_SPI + tristate + select REGMAP_SPI + config IAQCORE tristate "AMS iAQ-Core VOC sensors" depends on I2C diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index 2f3dee8bb779..4866db06bdc9 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -11,6 +11,9 @@ obj-$(CONFIG_BME680) += bme680_core.o obj-$(CONFIG_BME680_I2C) += bme680_i2c.o obj-$(CONFIG_BME680_SPI) += bme680_spi.o obj-$(CONFIG_CCS811) += ccs811.o +obj-$(CONFIG_ENS160) += ens160_core.o +obj-$(CONFIG_ENS160_I2C) += ens160_i2c.o +obj-$(CONFIG_ENS160_SPI) += ens160_spi.o obj-$(CONFIG_IAQCORE) += ams-iaq-core.o obj-$(CONFIG_PMS7003) += pms7003.o obj-$(CONFIG_SCD30_CORE) += scd30_core.o diff --git a/drivers/iio/chemical/ens160.h b/drivers/iio/chemical/ens160.h new file mode 100644 index 000000000000..d0df15f08db5 --- /dev/null +++ b/drivers/iio/chemical/ens160.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ENS160_H_ +#define ENS160_H_ + +int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, + const char *name); +#endif diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c new file mode 100644 index 000000000000..ae99a95c6ae1 --- /dev/null +++ b/drivers/iio/chemical/ens160_core.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ScioSense ENS160 multi-gas sensor driver + * + * Copyright (c) 2024 Gustavo Silva + * + * Datasheet: + * https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf + */ + +#include +#include +#include +#include + +#include "ens160.h" + +#define ENS160_PART_ID 0x160 + +#define ENS160_BOOTING_TIME_MS 10U + +#define ENS160_REG_PART_ID 0x00 + +#define ENS160_REG_OPMODE 0x10 + +#define ENS160_REG_MODE_DEEP_SLEEP 0x00 +#define ENS160_REG_MODE_IDLE 0x01 +#define ENS160_REG_MODE_STANDARD 0x02 +#define ENS160_REG_MODE_RESET 0xF0 + +#define ENS160_REG_COMMAND 0x12 +#define ENS160_REG_COMMAND_GET_APPVER 0x0E +#define ENS160_REG_COMMAND_CLRGPR 0xCC + +#define ENS160_REG_TEMP_IN 0x13 +#define ENS160_REG_RH_IN 0x15 +#define ENS160_REG_DEVICE_STATUS 0x20 +#define ENS160_REG_DATA_AQI 0x21 +#define ENS160_REG_DATA_TVOC 0x22 +#define ENS160_REG_DATA_ECO2 0x24 +#define ENS160_REG_DATA_T 0x30 +#define ENS160_REG_DATA_RH 0x32 +#define ENS160_REG_GPR_READ4 0x4C + +#define ENS160_STATUS_VALIDITY_FLAG GENMASK(3, 2) + +#define ENS160_STATUS_NORMAL 0x00 + +struct ens160_data { + struct regmap *regmap; + u8 fw_version[3] __aligned(IIO_DMA_MINALIGN); + __le16 buf; +}; + +static const struct iio_chan_spec ens160_channels[] = { + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_VOC, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .address = ENS160_REG_DATA_TVOC, + }, + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_CO2, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .address = ENS160_REG_DATA_ECO2, + }, +}; + +static int ens160_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ens160_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_bulk_read(data->regmap, chan->address, + &data->buf, sizeof(data->buf)); + if (ret) + return ret; + *val = le16_to_cpu(data->buf); + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + switch (chan->channel2) { + case IIO_MOD_CO2: + /* The sensor reads CO2 data as ppm */ + *val = 0; + *val2 = 100; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_MOD_VOC: + /* The sensor reads VOC data as ppb */ + *val = 0; + *val2 = 100; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ens160_set_mode(struct ens160_data *data, u8 mode) +{ + int ret; + + ret = regmap_write(data->regmap, ENS160_REG_OPMODE, mode); + if (ret) + return ret; + + msleep(ENS160_BOOTING_TIME_MS); + + return 0; +} + +static void ens160_set_idle(void *data) +{ + ens160_set_mode(data, ENS160_REG_MODE_IDLE); +} + +static int ens160_chip_init(struct ens160_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + unsigned int status; + int ret; + + ret = ens160_set_mode(data, ENS160_REG_MODE_RESET); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, ENS160_REG_PART_ID, &data->buf, + sizeof(data->buf)); + if (ret) + return ret; + + if (le16_to_cpu(data->buf) != ENS160_PART_ID) + return -ENODEV; + + ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE); + if (ret) + return ret; + + ret = regmap_write(data->regmap, ENS160_REG_COMMAND, + ENS160_REG_COMMAND_CLRGPR); + if (ret) + return ret; + + ret = regmap_write(data->regmap, ENS160_REG_COMMAND, + ENS160_REG_COMMAND_GET_APPVER); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, ENS160_REG_GPR_READ4, + data->fw_version, sizeof(data->fw_version)); + if (ret) + return ret; + + dev_info(dev, "firmware version: %u.%u.%u\n", data->fw_version[2], + data->fw_version[1], data->fw_version[0]); + + ret = ens160_set_mode(data, ENS160_REG_MODE_STANDARD); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, ens160_set_idle, data); + if (ret) + return ret; + + ret = regmap_read(data->regmap, ENS160_REG_DEVICE_STATUS, &status); + if (ret) + return ret; + + if (FIELD_GET(ENS160_STATUS_VALIDITY_FLAG, status) + != ENS160_STATUS_NORMAL) + return -EINVAL; + + return 0; +} + +static const struct iio_info ens160_info = { + .read_raw = ens160_read_raw, +}; + +int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, + const char *name) +{ + struct ens160_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->regmap = regmap; + + indio_dev->name = name; + indio_dev->info = &ens160_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ens160_channels; + indio_dev->num_channels = ARRAY_SIZE(ens160_channels); + + ret = ens160_chip_init(data); + if (ret) + return dev_err_probe(dev, ret, "chip initialization failed\n"); + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160); + +MODULE_AUTHOR("Gustavo Silva "); +MODULE_DESCRIPTION("ScioSense ENS160 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c new file mode 100644 index 000000000000..f885903feb7a --- /dev/null +++ b/drivers/iio/chemical/ens160_i2c.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ScioSense ENS160 multi-gas sensor I2C driver + * + * Copyright (c) 2024 Gustavo Silva + * + * 7-Bit I2C slave address is: + * - 0x52 if ADDR pin LOW + * - 0x53 if ADDR pin HIGH + */ + +#include +#include +#include + +#include "ens160.h" + +static const struct regmap_config ens160_regmap_i2c_conf = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int ens160_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &ens160_regmap_i2c_conf); + if (IS_ERR(regmap)) + return dev_err_probe(&client->dev, PTR_ERR(regmap), + "Failed to register i2c regmap\n"); + + return devm_ens160_core_probe(&client->dev, regmap, "ens160"); +} + +static const struct i2c_device_id ens160_i2c_id[] = { + { "ens160" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ens160_i2c_id); + +static const struct of_device_id ens160_of_i2c_match[] = { + { .compatible = "sciosense,ens160" }, + { } +}; +MODULE_DEVICE_TABLE(of, ens160_of_i2c_match); + +static struct i2c_driver ens160_i2c_driver = { + .driver = { + .name = "ens160", + .of_match_table = ens160_of_i2c_match, + }, + .probe = ens160_i2c_probe, + .id_table = ens160_i2c_id, +}; +module_i2c_driver(ens160_i2c_driver); + +MODULE_AUTHOR("Gustavo Silva "); +MODULE_DESCRIPTION("ScioSense ENS160 I2C driver"); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ENS160); diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c new file mode 100644 index 000000000000..40c68c5c4223 --- /dev/null +++ b/drivers/iio/chemical/ens160_spi.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ScioSense ENS160 multi-gas sensor SPI driver + * + * Copyright (c) 2024 Gustavo Silva + */ + +#include +#include +#include + +#include "ens160.h" + +#define ENS160_SPI_READ BIT(0) + +static const struct regmap_config ens160_regmap_spi_conf = { + .reg_bits = 8, + .val_bits = 8, + .reg_shift = -1, + .read_flag_mask = ENS160_SPI_READ, +}; + +static int ens160_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &ens160_regmap_spi_conf); + if (IS_ERR(regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(regmap), + "Failed to register spi regmap\n"); + + return devm_ens160_core_probe(&spi->dev, regmap, "ens160"); +} + +static const struct of_device_id ens160_spi_of_match[] = { + { .compatible = "sciosense,ens160" }, + { } +}; +MODULE_DEVICE_TABLE(of, ens160_spi_of_match); + +static const struct spi_device_id ens160_spi_id[] = { + { "ens160" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ens160_spi_id); + +static struct spi_driver ens160_spi_driver = { + .driver = { + .name = "ens160", + .of_match_table = ens160_spi_of_match, + }, + .probe = ens160_spi_probe, + .id_table = ens160_spi_id, +}; +module_spi_driver(ens160_spi_driver); + +MODULE_AUTHOR("Gustavo Silva "); +MODULE_DESCRIPTION("ScioSense ENS160 SPI driver"); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ENS160); From 0fc26596b4b3619a47ae05e3ed89e017fa9149b4 Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Tue, 4 Jun 2024 19:57:28 -0300 Subject: [PATCH 133/330] iio: chemical: ens160: add triggered buffer support ENS160 supports a data ready interrupt. Use it in combination with triggered buffer for continuous data readings. Signed-off-by: Gustavo Silva Link: https://lore.kernel.org/r/20240604225747.7212-5-gustavograzs@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/ens160.h | 2 +- drivers/iio/chemical/ens160_core.c | 141 +++++++++++++++++++++++++++-- drivers/iio/chemical/ens160_i2c.c | 3 +- drivers/iio/chemical/ens160_spi.c | 2 +- 4 files changed, 136 insertions(+), 12 deletions(-) diff --git a/drivers/iio/chemical/ens160.h b/drivers/iio/chemical/ens160.h index d0df15f08db5..e6cc0987aed0 100644 --- a/drivers/iio/chemical/ens160.h +++ b/drivers/iio/chemical/ens160.h @@ -2,6 +2,6 @@ #ifndef ENS160_H_ #define ENS160_H_ -int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, +int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq, const char *name); #endif diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c index ae99a95c6ae1..3da3b10950dd 100644 --- a/drivers/iio/chemical/ens160_core.c +++ b/drivers/iio/chemical/ens160_core.c @@ -10,6 +10,9 @@ #include #include +#include +#include +#include #include #include @@ -23,6 +26,11 @@ #define ENS160_REG_OPMODE 0x10 +#define ENS160_REG_CONFIG 0x11 +#define ENS160_REG_CONFIG_INTEN BIT(0) +#define ENS160_REG_CONFIG_INTDAT BIT(1) +#define ENS160_REG_CONFIG_INT_CFG BIT(5) + #define ENS160_REG_MODE_DEEP_SLEEP 0x00 #define ENS160_REG_MODE_IDLE 0x01 #define ENS160_REG_MODE_STANDARD 0x02 @@ -48,7 +56,13 @@ struct ens160_data { struct regmap *regmap; - u8 fw_version[3] __aligned(IIO_DMA_MINALIGN); + /* Protect reads from the sensor */ + struct mutex mutex; + struct { + __le16 chans[2]; + s64 timestamp __aligned(8); + } scan __aligned(IIO_DMA_MINALIGN); + u8 fw_version[3]; __le16 buf; }; @@ -60,6 +74,13 @@ static const struct iio_chan_spec ens160_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .address = ENS160_REG_DATA_TVOC, + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, }, { .type = IIO_CONCENTRATION, @@ -68,7 +89,15 @@ static const struct iio_chan_spec ens160_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .address = ENS160_REG_DATA_ECO2, + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, }, + IIO_CHAN_SOFT_TIMESTAMP(2), }; static int ens160_read_raw(struct iio_dev *indio_dev, @@ -80,13 +109,16 @@ static int ens160_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = regmap_bulk_read(data->regmap, chan->address, - &data->buf, sizeof(data->buf)); - if (ret) - return ret; - *val = le16_to_cpu(data->buf); - return IIO_VAL_INT; - + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + guard(mutex)(&data->mutex); + ret = regmap_bulk_read(data->regmap, chan->address, + &data->buf, sizeof(data->buf)); + if (ret) + return ret; + *val = le16_to_cpu(data->buf); + return IIO_VAL_INT; + } + unreachable(); case IIO_CHAN_INFO_SCALE: switch (chan->channel2) { case IIO_MOD_CO2: @@ -188,7 +220,83 @@ static const struct iio_info ens160_info = { .read_raw = ens160_read_raw, }; -int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, +static irqreturn_t ens160_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ens160_data *data = iio_priv(indio_dev); + int ret; + + guard(mutex)(&data->mutex); + + ret = regmap_bulk_read(data->regmap, ENS160_REG_DATA_TVOC, + data->scan.chans, sizeof(data->scan.chans)); + if (ret) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + pf->timestamp); +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ens160_set_trigger_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct ens160_data *data = iio_priv(indio_dev); + unsigned int int_bits = ENS160_REG_CONFIG_INTEN | + ENS160_REG_CONFIG_INTDAT | + ENS160_REG_CONFIG_INT_CFG; + + if (state) + return regmap_set_bits(data->regmap, ENS160_REG_CONFIG, + int_bits); + else + return regmap_clear_bits(data->regmap, ENS160_REG_CONFIG, + int_bits); +} + +static const struct iio_trigger_ops ens160_trigger_ops = { + .set_trigger_state = ens160_set_trigger_state, + .validate_device = iio_trigger_validate_own_device, +}; + +static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq) +{ + struct device *dev = indio_dev->dev.parent; + struct iio_trigger *trig; + int ret; + + trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); + if (!trig) + return dev_err_probe(dev, -ENOMEM, + "failed to allocate trigger\n"); + + trig->ops = &ens160_trigger_ops; + iio_trigger_set_drvdata(trig, indio_dev); + + ret = devm_iio_trigger_register(dev, trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(trig); + + ret = devm_request_threaded_irq(dev, irq, + iio_trigger_generic_data_rdy_poll, + NULL, + IRQF_ONESHOT, + indio_dev->name, + indio_dev->trig); + if (ret) + return dev_err_probe(dev, ret, "failed to request irq\n"); + + return 0; +} + +int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { struct ens160_data *data; @@ -208,10 +316,25 @@ int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, indio_dev->channels = ens160_channels; indio_dev->num_channels = ARRAY_SIZE(ens160_channels); + if (irq > 0) { + ret = ens160_setup_trigger(indio_dev, irq); + if (ret) + return dev_err_probe(dev, ret, + "failed to setup trigger\n"); + } + ret = ens160_chip_init(data); if (ret) return dev_err_probe(dev, ret, "chip initialization failed\n"); + mutex_init(&data->mutex); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ens160_trigger_handler, NULL); + if (ret) + return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160); diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c index f885903feb7a..f3fb45b75f29 100644 --- a/drivers/iio/chemical/ens160_i2c.c +++ b/drivers/iio/chemical/ens160_i2c.c @@ -29,7 +29,8 @@ static int ens160_i2c_probe(struct i2c_client *client) return dev_err_probe(&client->dev, PTR_ERR(regmap), "Failed to register i2c regmap\n"); - return devm_ens160_core_probe(&client->dev, regmap, "ens160"); + return devm_ens160_core_probe(&client->dev, regmap, client->irq, + "ens160"); } static const struct i2c_device_id ens160_i2c_id[] = { diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c index 40c68c5c4223..90e1e8386bdb 100644 --- a/drivers/iio/chemical/ens160_spi.c +++ b/drivers/iio/chemical/ens160_spi.c @@ -29,7 +29,7 @@ static int ens160_spi_probe(struct spi_device *spi) return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Failed to register spi regmap\n"); - return devm_ens160_core_probe(&spi->dev, regmap, "ens160"); + return devm_ens160_core_probe(&spi->dev, regmap, spi->irq, "ens160"); } static const struct of_device_id ens160_spi_of_match[] = { From d12b7d6ede9be336fb7a308c2ad9f4e1d8d817ad Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Tue, 4 Jun 2024 19:57:29 -0300 Subject: [PATCH 134/330] iio: chemical: ens160: add power management support ENS160 supports a deep sleep mode for minimal power consumption. Use it to add PM sleep capability to the driver. Signed-off-by: Gustavo Silva Link: https://lore.kernel.org/r/20240604225747.7212-6-gustavograzs@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/ens160.h | 3 +++ drivers/iio/chemical/ens160_core.c | 23 +++++++++++++++++++++++ drivers/iio/chemical/ens160_i2c.c | 1 + drivers/iio/chemical/ens160_spi.c | 1 + 4 files changed, 28 insertions(+) diff --git a/drivers/iio/chemical/ens160.h b/drivers/iio/chemical/ens160.h index e6cc0987aed0..f9f0575ce55d 100644 --- a/drivers/iio/chemical/ens160.h +++ b/drivers/iio/chemical/ens160.h @@ -4,4 +4,7 @@ int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq, const char *name); + +extern const struct dev_pm_ops ens160_pm_ops; + #endif diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c index 3da3b10950dd..c1aa3b498d3b 100644 --- a/drivers/iio/chemical/ens160_core.c +++ b/drivers/iio/chemical/ens160_core.c @@ -220,6 +220,29 @@ static const struct iio_info ens160_info = { .read_raw = ens160_read_raw, }; +static int ens160_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ens160_data *data = iio_priv(indio_dev); + + return ens160_set_mode(data, ENS160_REG_MODE_DEEP_SLEEP); +} + +static int ens160_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ens160_data *data = iio_priv(indio_dev); + int ret; + + ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE); + if (ret) + return ret; + + return ens160_set_mode(data, ENS160_REG_MODE_STANDARD); +} +EXPORT_NS_SIMPLE_DEV_PM_OPS(ens160_pm_ops, ens160_suspend, ens160_resume, + IIO_ENS160); + static irqreturn_t ens160_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c index f3fb45b75f29..57a189a4c257 100644 --- a/drivers/iio/chemical/ens160_i2c.c +++ b/drivers/iio/chemical/ens160_i2c.c @@ -49,6 +49,7 @@ static struct i2c_driver ens160_i2c_driver = { .driver = { .name = "ens160", .of_match_table = ens160_of_i2c_match, + .pm = pm_sleep_ptr(&ens160_pm_ops), }, .probe = ens160_i2c_probe, .id_table = ens160_i2c_id, diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c index 90e1e8386bdb..10e4f5fd0f45 100644 --- a/drivers/iio/chemical/ens160_spi.c +++ b/drivers/iio/chemical/ens160_spi.c @@ -48,6 +48,7 @@ static struct spi_driver ens160_spi_driver = { .driver = { .name = "ens160", .of_match_table = ens160_spi_of_match, + .pm = pm_sleep_ptr(&ens160_pm_ops), }, .probe = ens160_spi_probe, .id_table = ens160_spi_id, From 4c4daafc996a858c9227e9f47f6133b69d4be893 Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Tue, 4 Jun 2024 19:57:30 -0300 Subject: [PATCH 135/330] MAINTAINERS: Add ScioSense ENS160 Add myself as maintainer for ScioSense ENS160 multi-gas sensor driver. Signed-off-by: Gustavo Silva Link: https://lore.kernel.org/r/20240604225747.7212-7-gustavograzs@gmail.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index bff979a507ba..c870bc6b8d63 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19948,6 +19948,14 @@ F: include/linux/wait.h F: include/uapi/linux/sched.h F: kernel/sched/ +SCIOSENSE ENS160 MULTI-GAS SENSOR DRIVER +M: Gustavo Silva +S: Maintained +F: drivers/iio/chemical/ens160_core.c +F: drivers/iio/chemical/ens160_i2c.c +F: drivers/iio/chemical/ens160_spi.c +F: drivers/iio/chemical/ens160.h + SCSI LIBSAS SUBSYSTEM R: John Garry R: Jason Yan From 3d4d033a8d554e533d87ddf315b1e0d137e6ade8 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Wed, 5 Jun 2024 19:59:48 +0000 Subject: [PATCH 136/330] iio: document inv_icm42600 driver private sysfs attributes Add ABI documentation for inv_icm42600 private sysfs attributes. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240605195949.766677-2-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- .../ABI/testing/sysfs-bus-iio-inv_icm42600 | 18 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 19 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600 b/Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600 new file mode 100644 index 000000000000..7eeacfb7650d --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600 @@ -0,0 +1,18 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_accel_power_mode +KernelVersion: 6.11 +Contact: linux-iio@vger.kernel.org +Description: + Accelerometer power mode. Setting this attribute will set the + requested power mode to use if the ODR support it. If ODR + support only 1 mode, power mode will be enforced. + Reading this attribute will return the current accelerometer + power mode if the sensor is on, or the requested value if the + sensor is off. The value between real and requested value can + be different for ODR supporting only 1 mode. + +What: /sys/bus/iio/devices/iio:deviceX/in_accel_power_mode_available +KernelVersion: 6.11 +Contact: linux-iio@vger.kernel.org +Description: + List of available accelerometer power modes that can be set in + in_accel_power_mode attribute. diff --git a/MAINTAINERS b/MAINTAINERS index c870bc6b8d63..be590c462d91 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11520,6 +11520,7 @@ M: Jean-Baptiste Maneyrol L: linux-iio@vger.kernel.org S: Maintained W: https://invensense.tdk.com/ +F: Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600 F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml F: drivers/iio/imu/inv_icm42600/ From 07d4d0bb4a8ddcc463ed599b22f510d5926c2495 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Wed, 5 Jun 2024 19:59:49 +0000 Subject: [PATCH 137/330] iio: imu: inv_icm42600: add support of accel low-power mode Add ODRs accessible only in low-power mode. Switch automatically to low-power or low-noise depending on the ODR set. Add channel attributes "power_mode" and "power_mode_available" for setting the power mode to use (low-noise or low-power) for ODRs supporting both mode. Reading "power_mode" when the sensor is on will return the actual mode and not the requested one. It will be different when using ODRs not supported by the requested mode. Use low-power mode by default. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240605195949.766677-3-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 4 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 124 +++++++++++++++++- .../iio/imu/inv_icm42600/inv_icm42600_core.c | 27 ++++ 3 files changed, 151 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index c4ac91f6bafe..3a07e43e4cf1 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -177,11 +177,15 @@ struct inv_icm42600_state { * struct inv_icm42600_sensor_state - sensor state variables * @scales: table of scales. * @scales_len: length (nb of items) of the scales table. + * @power_mode: sensor requested power mode (for common frequencies) + * @filter: sensor filter. * @ts: timestamp module states. */ struct inv_icm42600_sensor_state { const int *scales; size_t scales_len; + enum inv_icm42600_sensor_mode power_mode; + enum inv_icm42600_filter filter; struct inv_sensors_timestamp ts; }; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 83d8504ebfff..3927829dd344 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -55,8 +55,108 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_TIMESTAMP, }; +static const char * const inv_icm42600_accel_power_mode_items[] = { + "low-noise", + "low-power", +}; +static const int inv_icm42600_accel_power_mode_values[] = { + INV_ICM42600_SENSOR_MODE_LOW_NOISE, + INV_ICM42600_SENSOR_MODE_LOW_POWER, +}; +static const int inv_icm42600_accel_filter_values[] = { + INV_ICM42600_FILTER_BW_ODR_DIV_2, + INV_ICM42600_FILTER_AVG_16X, +}; + +static int inv_icm42600_accel_power_mode_set(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int idx) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); + int power_mode, filter; + + if (chan->type != IIO_ACCEL) + return -EINVAL; + + if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values)) + return -EINVAL; + + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + power_mode = inv_icm42600_accel_power_mode_values[idx]; + filter = inv_icm42600_accel_filter_values[idx]; + + guard(mutex)(&st->lock); + + /* prevent change if power mode is not supported by the ODR */ + switch (power_mode) { + case INV_ICM42600_SENSOR_MODE_LOW_NOISE: + if (st->conf.accel.odr >= INV_ICM42600_ODR_6_25HZ_LP && + st->conf.accel.odr <= INV_ICM42600_ODR_1_5625HZ_LP) + return -EPERM; + break; + case INV_ICM42600_SENSOR_MODE_LOW_POWER: + default: + if (st->conf.accel.odr <= INV_ICM42600_ODR_1KHZ_LN) + return -EPERM; + break; + } + + accel_st->power_mode = power_mode; + accel_st->filter = filter; + + return 0; +} + +static int inv_icm42600_accel_power_mode_get(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); + unsigned int idx; + int power_mode; + + if (chan->type != IIO_ACCEL) + return -EINVAL; + + guard(mutex)(&st->lock); + + /* if sensor is on, returns actual power mode and not configured one */ + switch (st->conf.accel.mode) { + case INV_ICM42600_SENSOR_MODE_LOW_POWER: + case INV_ICM42600_SENSOR_MODE_LOW_NOISE: + power_mode = st->conf.accel.mode; + break; + default: + power_mode = accel_st->power_mode; + break; + } + + for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_power_mode_values); ++idx) { + if (power_mode == inv_icm42600_accel_power_mode_values[idx]) + break; + } + if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values)) + return -EINVAL; + + return idx; +} + +static const struct iio_enum inv_icm42600_accel_power_mode_enum = { + .items = inv_icm42600_accel_power_mode_items, + .num_items = ARRAY_SIZE(inv_icm42600_accel_power_mode_items), + .set = inv_icm42600_accel_power_mode_set, + .get = inv_icm42600_accel_power_mode_get, +}; + static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix), + IIO_ENUM_AVAILABLE("power_mode", IIO_SHARED_BY_TYPE, + &inv_icm42600_accel_power_mode_enum), + IIO_ENUM("power_mode", IIO_SHARED_BY_TYPE, + &inv_icm42600_accel_power_mode_enum), {}, }; @@ -120,7 +220,8 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, if (*scan_mask & INV_ICM42600_SCAN_MASK_ACCEL_3AXIS) { /* enable accel sensor */ - conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE; + conf.mode = accel_st->power_mode; + conf.filter = accel_st->filter; ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_accel); if (ret) goto out_unlock; @@ -144,10 +245,12 @@ out_unlock: return ret; } -static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, +static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int16_t *val) { + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); struct device *dev = regmap_get_device(st->map); struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int reg; @@ -175,7 +278,8 @@ static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, mutex_lock(&st->lock); /* enable accel sensor */ - conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE; + conf.mode = accel_st->power_mode; + conf.filter = accel_st->filter; ret = inv_icm42600_set_accel_conf(st, &conf, NULL); if (ret) goto exit; @@ -277,6 +381,12 @@ static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev, /* IIO format int + micro */ static const int inv_icm42600_accel_odr[] = { + /* 1.5625Hz */ + 1, 562500, + /* 3.125Hz */ + 3, 125000, + /* 6.25Hz */ + 6, 250000, /* 12.5Hz */ 12, 500000, /* 25Hz */ @@ -296,6 +406,9 @@ static const int inv_icm42600_accel_odr[] = { }; static const int inv_icm42600_accel_odr_conv[] = { + INV_ICM42600_ODR_1_5625HZ_LP, + INV_ICM42600_ODR_3_125HZ_LP, + INV_ICM42600_ODR_6_25HZ_LP, INV_ICM42600_ODR_12_5HZ, INV_ICM42600_ODR_25HZ, INV_ICM42600_ODR_50HZ, @@ -581,7 +694,7 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; - ret = inv_icm42600_accel_read_sensor(st, chan, &data); + ret = inv_icm42600_accel_read_sensor(indio_dev, chan, &data); iio_device_release_direct_mode(indio_dev); if (ret) return ret; @@ -754,6 +867,9 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale); break; } + /* low-power by default at init */ + accel_st->power_mode = INV_ICM42600_SENSOR_MODE_LOW_POWER; + accel_st->filter = INV_ICM42600_FILTER_AVG_16X; /* * clock period is 32kHz (31250ns) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index ada5a8cca629..184ce942e5fb 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -292,6 +292,23 @@ int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st, if (conf->filter < 0) conf->filter = oldconf->filter; + /* force power mode against ODR when sensor is on */ + switch (conf->mode) { + case INV_ICM42600_SENSOR_MODE_LOW_POWER: + case INV_ICM42600_SENSOR_MODE_LOW_NOISE: + if (conf->odr <= INV_ICM42600_ODR_1KHZ_LN) { + conf->mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE; + conf->filter = INV_ICM42600_FILTER_BW_ODR_DIV_2; + } else if (conf->odr >= INV_ICM42600_ODR_6_25HZ_LP && + conf->odr <= INV_ICM42600_ODR_1_5625HZ_LP) { + conf->mode = INV_ICM42600_SENSOR_MODE_LOW_POWER; + conf->filter = INV_ICM42600_FILTER_AVG_16X; + } + break; + default: + break; + } + /* set ACCEL_CONFIG0 register (accel fullscale & odr) */ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) { val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) | @@ -485,6 +502,16 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st, if (ret) return ret; + /* + * Use RC clock for accel low-power to fix glitches when switching + * gyro on/off while accel low-power is on. + */ + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG1, + INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RC, + INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RC); + if (ret) + return ret; + return inv_icm42600_set_conf(st, hw->conf); } From 3a0fa8e97d3024de199634667900b6a90bbe43d0 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 30 May 2024 21:52:45 +0100 Subject: [PATCH 138/330] fpga: altera-fpga2sdram: remove unused struct 'prop_map' 'prop_map' has been unused since the original commit e5f8efa5c8bf ("ARM: socfpga: fpga bridge driver support"). Remove it. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Russ Weight Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240530205245.125513-1-linux@treblig.org Signed-off-by: Xu Yilun --- drivers/fpga/altera-fpga2sdram.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c index 6b60ca004345..f4de3fea0b2d 100644 --- a/drivers/fpga/altera-fpga2sdram.c +++ b/drivers/fpga/altera-fpga2sdram.c @@ -75,12 +75,6 @@ static int alt_fpga2sdram_enable_set(struct fpga_bridge *bridge, bool enable) return _alt_fpga2sdram_enable_set(bridge->priv, enable); } -struct prop_map { - char *prop_name; - u32 *prop_value; - u32 prop_max; -}; - static const struct fpga_bridge_ops altera_fpga2sdram_br_ops = { .enable_set = alt_fpga2sdram_enable_set, .enable_show = alt_fpga2sdram_enable_show, From a43b9ec091b1b1924ea18883a715e5aadba2543e Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 29 May 2024 10:19:20 -0700 Subject: [PATCH 139/330] peci, hwmon: Switch to new Intel CPU model defines Update peci subsystem to use the same vendor-family-model combined definition that core x86 code uses. Signed-off-by: Tony Luck Acked-by: Guenter Roeck Reviewed-by: Iwona Winiarska Link: https://lore.kernel.org/r/20240529171920.62571-1-tony.luck@intel.com Signed-off-by: Iwona Winiarska --- drivers/hwmon/peci/cputemp.c | 8 ++++---- drivers/peci/core.c | 5 ++--- drivers/peci/cpu.c | 21 +++++++-------------- drivers/peci/device.c | 3 +-- drivers/peci/internal.h | 6 ++---- include/linux/peci-cpu.h | 24 ++++++++++++++++++++++++ include/linux/peci.h | 6 ++---- 7 files changed, 42 insertions(+), 31 deletions(-) diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c index a812c15948d9..5a682195b98f 100644 --- a/drivers/hwmon/peci/cputemp.c +++ b/drivers/hwmon/peci/cputemp.c @@ -360,10 +360,10 @@ static int init_core_mask(struct peci_cputemp *priv) int ret; /* Get the RESOLVED_CORES register value */ - switch (peci_dev->info.model) { - case INTEL_FAM6_ICELAKE_X: - case INTEL_FAM6_ICELAKE_D: - case INTEL_FAM6_SAPPHIRERAPIDS_X: + switch (peci_dev->info.x86_vfm) { + case INTEL_ICELAKE_X: + case INTEL_ICELAKE_D: + case INTEL_SAPPHIRERAPIDS_X: ret = peci_ep_pci_local_read(peci_dev, 0, reg->bus, reg->dev, reg->func, reg->offset + 4, &data); if (ret) diff --git a/drivers/peci/core.c b/drivers/peci/core.c index 8f8bda2f2a62..8ff3e5d225ae 100644 --- a/drivers/peci/core.c +++ b/drivers/peci/core.c @@ -163,9 +163,8 @@ EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI); static const struct peci_device_id * peci_bus_match_device_id(const struct peci_device_id *id, struct peci_device *device) { - while (id->family != 0) { - if (id->family == device->info.family && - id->model == device->info.model) + while (id->x86_vfm != 0) { + if (id->x86_vfm == device->info.x86_vfm) return id; id++; } diff --git a/drivers/peci/cpu.c b/drivers/peci/cpu.c index bd990acd92b8..152bbd8e717a 100644 --- a/drivers/peci/cpu.c +++ b/drivers/peci/cpu.c @@ -294,38 +294,31 @@ peci_cpu_probe(struct peci_device *device, const struct peci_device_id *id) static const struct peci_device_id peci_cpu_device_ids[] = { { /* Haswell Xeon */ - .family = 6, - .model = INTEL_FAM6_HASWELL_X, + .x86_vfm = INTEL_HASWELL_X, .data = "hsx", }, { /* Broadwell Xeon */ - .family = 6, - .model = INTEL_FAM6_BROADWELL_X, + .x86_vfm = INTEL_BROADWELL_X, .data = "bdx", }, { /* Broadwell Xeon D */ - .family = 6, - .model = INTEL_FAM6_BROADWELL_D, + .x86_vfm = INTEL_BROADWELL_D, .data = "bdxd", }, { /* Skylake Xeon */ - .family = 6, - .model = INTEL_FAM6_SKYLAKE_X, + .x86_vfm = INTEL_SKYLAKE_X, .data = "skx", }, { /* Icelake Xeon */ - .family = 6, - .model = INTEL_FAM6_ICELAKE_X, + .x86_vfm = INTEL_ICELAKE_X, .data = "icx", }, { /* Icelake Xeon D */ - .family = 6, - .model = INTEL_FAM6_ICELAKE_D, + .x86_vfm = INTEL_ICELAKE_D, .data = "icxd", }, { /* Sapphire Rapids Xeon */ - .family = 6, - .model = INTEL_FAM6_SAPPHIRERAPIDS_X, + .x86_vfm = INTEL_SAPPHIRERAPIDS_X, .data = "spr", }, { } diff --git a/drivers/peci/device.c b/drivers/peci/device.c index ee01f03c29b7..37ca7dd61807 100644 --- a/drivers/peci/device.c +++ b/drivers/peci/device.c @@ -100,8 +100,7 @@ static int peci_device_info_init(struct peci_device *device) if (ret) return ret; - device->info.family = peci_x86_cpu_family(cpu_id); - device->info.model = peci_x86_cpu_model(cpu_id); + device->info.x86_vfm = IFM(peci_x86_cpu_family(cpu_id), peci_x86_cpu_model(cpu_id)); ret = peci_get_revision(device, &revision); if (ret) diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h index 506bafcccbbf..7a4f6eae2f90 100644 --- a/drivers/peci/internal.h +++ b/drivers/peci/internal.h @@ -66,13 +66,11 @@ struct peci_request *peci_xfer_ep_mmio64_readl(struct peci_device *device, u8 ba /** * struct peci_device_id - PECI device data to match * @data: pointer to driver private data specific to device - * @family: device family - * @model: device model + * @x86_vfm: device vendor-family-model */ struct peci_device_id { const void *data; - u16 family; - u8 model; + u32 x86_vfm; }; extern const struct device_type peci_device_type; diff --git a/include/linux/peci-cpu.h b/include/linux/peci-cpu.h index ff8ae9c26c80..601cdd086bf6 100644 --- a/include/linux/peci-cpu.h +++ b/include/linux/peci-cpu.h @@ -6,6 +6,30 @@ #include +/* Copied from x86 */ +#define X86_VENDOR_INTEL 0 + +/* Copied from x86 */ +#define VFM_MODEL_BIT 0 +#define VFM_FAMILY_BIT 8 +#define VFM_VENDOR_BIT 16 +#define VFM_RSVD_BIT 24 + +#define VFM_MODEL_MASK GENMASK(VFM_FAMILY_BIT - 1, VFM_MODEL_BIT) +#define VFM_FAMILY_MASK GENMASK(VFM_VENDOR_BIT - 1, VFM_FAMILY_BIT) +#define VFM_VENDOR_MASK GENMASK(VFM_RSVD_BIT - 1, VFM_VENDOR_BIT) + +#define VFM_MODEL(vfm) (((vfm) & VFM_MODEL_MASK) >> VFM_MODEL_BIT) +#define VFM_FAMILY(vfm) (((vfm) & VFM_FAMILY_MASK) >> VFM_FAMILY_BIT) +#define VFM_VENDOR(vfm) (((vfm) & VFM_VENDOR_MASK) >> VFM_VENDOR_BIT) + +#define VFM_MAKE(_vendor, _family, _model) ( \ + ((_model) << VFM_MODEL_BIT) | \ + ((_family) << VFM_FAMILY_BIT) | \ + ((_vendor) << VFM_VENDOR_BIT) \ +) +/* End of copied code */ + #include "../../arch/x86/include/asm/intel-family.h" #define PECI_PCS_PKG_ID 0 /* Package Identifier Read */ diff --git a/include/linux/peci.h b/include/linux/peci.h index 90e241458ef6..3e0bc37591d6 100644 --- a/include/linux/peci.h +++ b/include/linux/peci.h @@ -59,8 +59,7 @@ static inline struct peci_controller *to_peci_controller(void *d) * struct peci_device - PECI device * @dev: device object to register PECI device to the device model * @info: PECI device characteristics - * @info.family: device family - * @info.model: device model + * @info.x86_vfm: device vendor-family-model * @info.peci_revision: PECI revision supported by the PECI device * @info.socket_id: the socket ID represented by the PECI device * @addr: address used on the PECI bus connected to the parent controller @@ -73,8 +72,7 @@ static inline struct peci_controller *to_peci_controller(void *d) struct peci_device { struct device dev; struct { - u16 family; - u8 model; + u32 x86_vfm; u8 peci_revision; u8 socket_id; } info; From aba59ce109deca2b9abeb9072ddca0ea8682bf5a Mon Sep 17 00:00:00 2001 From: Iwona Winiarska Date: Wed, 17 Apr 2024 15:48:49 +0200 Subject: [PATCH 140/330] peci: aspeed: Clear clock_divider value before setting it PECI clock divider is programmed on 10:8 bits of PECI Control register. Before setting a new value, clear bits read from hardware. Reviewed-by: Billy Tsai Link: https://lore.kernel.org/r/20240417134849.5793-1-iwona.winiarska@intel.com Signed-off-by: Iwona Winiarska --- drivers/peci/controller/peci-aspeed.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/peci/controller/peci-aspeed.c b/drivers/peci/controller/peci-aspeed.c index 7fdc25afcf2f..de7046e6b9c4 100644 --- a/drivers/peci/controller/peci-aspeed.c +++ b/drivers/peci/controller/peci-aspeed.c @@ -351,6 +351,7 @@ static int clk_aspeed_peci_set_rate(struct clk_hw *hw, unsigned long rate, clk_aspeed_peci_find_div_values(this_rate, &msg_timing, &clk_div_exp); val = readl(aspeed_peci->base + ASPEED_PECI_CTRL); + val &= ~ASPEED_PECI_CTRL_CLK_DIV_MASK; val |= FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_exp); writel(val, aspeed_peci->base + ASPEED_PECI_CTRL); From c7d0b2db5bc5e8c0fdc67b3c8f463c3dfec92f77 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 3 Jun 2024 22:13:54 +0530 Subject: [PATCH 141/330] bus: mhi: ep: Do not allocate memory for MHI objects from DMA zone MHI endpoint stack accidentally started allocating memory for objects from DMA zone since commit 62210a26cd4f ("bus: mhi: ep: Use slab allocator where applicable"). But there is no real need to allocate memory from this naturally limited DMA zone. This also causes the MHI endpoint stack to run out of memory while doing high bandwidth transfers. So let's switch over to normal memory. Cc: # 6.8 Fixes: 62210a26cd4f ("bus: mhi: ep: Use slab allocator where applicable") Reviewed-by: Mayank Rana Link: https://lore.kernel.org/r/20240603164354.79035-1-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/ep/main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c index f8f674adf1d4..4acfac73ca9a 100644 --- a/drivers/bus/mhi/ep/main.c +++ b/drivers/bus/mhi/ep/main.c @@ -90,7 +90,7 @@ static int mhi_ep_send_completion_event(struct mhi_ep_cntrl *mhi_cntrl, struct m struct mhi_ring_element *event; int ret; - event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); if (!event) return -ENOMEM; @@ -109,7 +109,7 @@ int mhi_ep_send_state_change_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_stat struct mhi_ring_element *event; int ret; - event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); if (!event) return -ENOMEM; @@ -127,7 +127,7 @@ int mhi_ep_send_ee_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ee_type exec_e struct mhi_ring_element *event; int ret; - event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); if (!event) return -ENOMEM; @@ -146,7 +146,7 @@ static int mhi_ep_send_cmd_comp_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_e struct mhi_ring_element *event; int ret; - event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); if (!event) return -ENOMEM; @@ -438,7 +438,7 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left; write_offset = len - buf_left; - buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL | GFP_DMA); + buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL); if (!buf_addr) return -ENOMEM; @@ -1481,14 +1481,14 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, mhi_cntrl->ev_ring_el_cache = kmem_cache_create("mhi_ep_event_ring_el", sizeof(struct mhi_ring_element), 0, - SLAB_CACHE_DMA, NULL); + 0, NULL); if (!mhi_cntrl->ev_ring_el_cache) { ret = -ENOMEM; goto err_free_cmd; } mhi_cntrl->tre_buf_cache = kmem_cache_create("mhi_ep_tre_buf", MHI_EP_DEFAULT_MTU, 0, - SLAB_CACHE_DMA, NULL); + 0, NULL); if (!mhi_cntrl->tre_buf_cache) { ret = -ENOMEM; goto err_destroy_ev_ring_el_cache; From 4dcc0f95ca2a9738e5e4e3bd7571fd95a9cbf272 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 19 Feb 2024 10:43:05 -0300 Subject: [PATCH 142/330] coresight: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the coresight_dev_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Anshuman Khandual Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240219-device_cleanup-coresight-v1-1-4a8a0b816183@marliere.net Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-priv.h | 2 +- drivers/hwtracing/coresight/coresight-sysfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index fc3617642b01..61a46d3bdcc8 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -13,7 +13,7 @@ #include extern struct mutex coresight_mutex; -extern struct device_type coresight_dev_type[]; +extern const struct device_type coresight_dev_type[]; /* * Coresight management registers (0xf00-0xfcc) diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c index f9444e2cb1d9..1e67cc7758d7 100644 --- a/drivers/hwtracing/coresight/coresight-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-sysfs.c @@ -377,7 +377,7 @@ static struct attribute *coresight_source_attrs[] = { }; ATTRIBUTE_GROUPS(coresight_source); -struct device_type coresight_dev_type[] = { +const struct device_type coresight_dev_type[] = { [CORESIGHT_DEV_TYPE_SINK] = { .name = "sink", .groups = coresight_sink_groups, From 5878853fc9389e7d0988d4b465a415cf96fd14fa Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:20 +0200 Subject: [PATCH 143/330] dmaengine: Add API function dmaengine_prep_peripheral_dma_vec() This function can be used to initiate a scatter-gather DMA transfer, where the address and size of each segment is located in one entry of the dma_vec array. The major difference with dmaengine_prep_slave_sg() is that it supports specifying the lengths of each DMA transfer; as trying to override the length of the transfer with dmaengine_prep_slave_sg() is a very tedious process. The introduction of a new API function is also justified by the fact that scatterlists are on their way out. Note that dmaengine_prep_interleaved_dma() is not helpful either in that case, as it assumes that the address of each segment will be higher than the one of the previous segment, which we just cannot guarantee in case of a scatter-gather transfer. Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240620122726.41232-2-paul@crapouillou.net Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 752dbde4cec1..9fc03068cabc 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -160,6 +160,16 @@ struct dma_interleaved_template { struct data_chunk sgl[]; }; +/** + * struct dma_vec - DMA vector + * @addr: Bus address of the start of the vector + * @len: Length in bytes of the DMA vector + */ +struct dma_vec { + dma_addr_t addr; + size_t len; +}; + /** * enum dma_ctrl_flags - DMA flags to augment operation preparation, * control completion, and communicate status. @@ -910,6 +920,10 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_peripheral_dma_vec)( + struct dma_chan *chan, const struct dma_vec *vecs, + size_t nents, enum dma_transfer_direction direction, + unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_slave_sg)( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, @@ -973,6 +987,25 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single( dir, flags, NULL); } +/** + * dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor + * @chan: The channel to be used for this descriptor + * @vecs: The array of DMA vectors that should be transferred + * @nents: The number of DMA vectors in the array + * @dir: Specifies the direction of the data transfer + * @flags: DMA engine flags + */ +static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec( + struct dma_chan *chan, const struct dma_vec *vecs, size_t nents, + enum dma_transfer_direction dir, unsigned long flags) +{ + if (!chan || !chan->device || !chan->device->device_prep_peripheral_dma_vec) + return NULL; + + return chan->device->device_prep_peripheral_dma_vec(chan, vecs, nents, + dir, flags); +} + static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction dir, unsigned long flags) From 74609e5686701ed8e8adc3082d15f009e327286d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:21 +0200 Subject: [PATCH 144/330] dmaengine: dma-axi-dmac: Implement device_prep_peripheral_dma_vec Add implementation of the .device_prep_peripheral_dma_vec() callback. Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240620122726.41232-3-paul@crapouillou.net Signed-off-by: Vinod Koul --- drivers/dma/dma-axi-dmac.c | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index bdb752f11869..36943b0c6d60 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -620,6 +620,45 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan, return sg; } +static struct dma_async_tx_descriptor * +axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs, + size_t nb, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac_desc *desc; + unsigned int num_sgs = 0; + struct axi_dmac_sg *dsg; + size_t i; + + if (direction != chan->direction) + return NULL; + + for (i = 0; i < nb; i++) + num_sgs += DIV_ROUND_UP(vecs[i].len, chan->max_length); + + desc = axi_dmac_alloc_desc(chan, num_sgs); + if (!desc) + return NULL; + + dsg = desc->sg; + + for (i = 0; i < nb; i++) { + if (!axi_dmac_check_addr(chan, vecs[i].addr) || + !axi_dmac_check_len(chan, vecs[i].len)) { + kfree(desc); + return NULL; + } + + dsg = axi_dmac_fill_linear_sg(chan, direction, vecs[i].addr, 1, + vecs[i].len, dsg); + } + + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg( struct dma_chan *c, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, @@ -1061,6 +1100,7 @@ static int axi_dmac_probe(struct platform_device *pdev) dma_dev->device_tx_status = dma_cookie_status; dma_dev->device_issue_pending = axi_dmac_issue_pending; dma_dev->device_prep_slave_sg = axi_dmac_prep_slave_sg; + dma_dev->device_prep_peripheral_dma_vec = axi_dmac_prep_peripheral_dma_vec; dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic; dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved; dma_dev->device_terminate_all = axi_dmac_terminate_all; From 380afccc2a55e8015adae4266e8beff96ab620be Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:26 +0200 Subject: [PATCH 145/330] Documentation: dmaengine: Document new dma_vec API Document the dmaengine_prep_peripheral_dma_vec() API function, the device_prep_peripheral_dma_vec() backend function, and the dma_vec struct. Signed-off-by: Paul Cercueil Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20240620122726.41232-8-paul@crapouillou.net Signed-off-by: Vinod Koul --- Documentation/driver-api/dmaengine/client.rst | 9 +++++++++ Documentation/driver-api/dmaengine/provider.rst | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst index ecf139f73da4..d491e385d61a 100644 --- a/Documentation/driver-api/dmaengine/client.rst +++ b/Documentation/driver-api/dmaengine/client.rst @@ -80,6 +80,10 @@ The details of these operations are: - slave_sg: DMA a list of scatter gather buffers from/to a peripheral + - peripheral_dma_vec: DMA an array of scatter gather buffers from/to a + peripheral. Similar to slave_sg, but uses an array of dma_vec + structures instead of a scatterlist. + - dma_cyclic: Perform a cyclic DMA operation from/to a peripheral till the operation is explicitly stopped. @@ -102,6 +106,11 @@ The details of these operations are: unsigned int sg_len, enum dma_data_direction direction, unsigned long flags); + struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec( + struct dma_chan *chan, const struct dma_vec *vecs, + size_t nents, enum dma_data_direction direction, + unsigned long flags); + struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_data_direction direction); diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst index ceac2a300e32..3085f8b460fa 100644 --- a/Documentation/driver-api/dmaengine/provider.rst +++ b/Documentation/driver-api/dmaengine/provider.rst @@ -433,6 +433,12 @@ supported. - residue: Provides the residue bytes of the transfer for those that support residue. +- ``device_prep_peripheral_dma_vec`` + + - Similar to ``device_prep_slave_sg``, but it takes a pointer to a + array of ``dma_vec`` structures, which (in the long run) will replace + scatterlists. + - ``device_issue_pending`` - Takes the first transaction descriptor in the pending queue, @@ -544,6 +550,10 @@ dma_cookie_t - Not really relevant any more since the introduction of ``virt-dma`` that abstracts it away. +dma_vec + +- A small structure that contains a DMA address and length. + DMA_CTRL_ACK - If clear, the descriptor cannot be reused by provider until the From 40c0f07528c795b83abb4550a16b7866c6db5778 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Thu, 13 Jun 2024 12:34:06 -0400 Subject: [PATCH 146/330] iio: adc: adi-axi-adc: improve probe() error messaging The current error handling for calls such as devm_clk_get_enabled() in the adi-axi-adc probe() function means that, if a property such as 'clocks' (for example) is not present in the devicetree when booting a kernel with the driver enabled, the resulting error message will be vague, e.g.: |adi_axi_adc 44a00000.backend: probe with driver adi_axi_adc failed with error -2 Change the devm_clk_get_enabled(), devm_regmap_init_mmio(), and devm_iio_backend_register() checks to use dev_err_probe() with some context for easier debugging. After the change: |adi_axi_adc 44a00000.backend: error -ENOENT: failed to get clock |adi_axi_adc 44a00000.backend: probe with driver adi_axi_adc failed with error -2 Signed-off-by: Trevor Gamblin Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240613163407.2147884-1-tgamblin@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 0f8bd1d75131..21ce7564e83d 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -308,7 +308,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) st->regmap = devm_regmap_init_mmio(&pdev->dev, base, &axi_adc_regmap_config); if (IS_ERR(st->regmap)) - return PTR_ERR(st->regmap); + return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap), + "failed to init register map\n"); expected_ver = device_get_match_data(&pdev->dev); if (!expected_ver) @@ -316,7 +317,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) - return PTR_ERR(clk); + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); /* * Force disable the core. Up to the frontend to enable us. And we can @@ -344,7 +346,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st); if (ret) - return ret; + return dev_err_probe(&pdev->dev, ret, + "failed to register iio backend\n"); dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), From 7347d295f54141515af76535134b3ee37d0c781c Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Thu, 13 Jun 2024 14:39:57 +0300 Subject: [PATCH 147/330] iio: adc: ad7192: Clean up dev Clean up by using a local variable struct device *dev. Also use dev_err_probe where possible. Signed-off-by: Alisa-Dariana Roman Link: https://patch.msgid.link/20240613114001.270233-2-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 65 +++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 0789121236d6..c7fb51a90e87 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -1196,17 +1196,16 @@ static void ad7192_reg_disable(void *reg) static int ad7192_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ad7192_state *st; struct iio_dev *indio_dev; struct regulator *aincom; int ret; - if (!spi->irq) { - dev_err(&spi->dev, "no IRQ?\n"); - return -ENODEV; - } + if (!spi->irq) + return dev_err_probe(dev, -ENODEV, "Failed to get IRQ\n"); - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1219,71 +1218,69 @@ static int ad7192_probe(struct spi_device *spi) * Newer firmware should provide a zero volt fixed supply if wired to * ground. */ - aincom = devm_regulator_get_optional(&spi->dev, "aincom"); + aincom = devm_regulator_get_optional(dev, "aincom"); if (IS_ERR(aincom)) { if (PTR_ERR(aincom) != -ENODEV) - return dev_err_probe(&spi->dev, PTR_ERR(aincom), + return dev_err_probe(dev, PTR_ERR(aincom), "Failed to get AINCOM supply\n"); st->aincom_mv = 0; } else { ret = regulator_enable(aincom); if (ret) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to enable specified AINCOM supply\n"); - ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom); + ret = devm_add_action_or_reset(dev, ad7192_reg_disable, aincom); if (ret) return ret; ret = regulator_get_voltage(aincom); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Device tree error, AINCOM voltage undefined\n"); st->aincom_mv = ret / MILLI; } - st->avdd = devm_regulator_get(&spi->dev, "avdd"); + st->avdd = devm_regulator_get(dev, "avdd"); if (IS_ERR(st->avdd)) return PTR_ERR(st->avdd); ret = regulator_enable(st->avdd); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable specified AVdd supply\n"); - ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->avdd); + ret = devm_add_action_or_reset(dev, ad7192_reg_disable, st->avdd); if (ret) return ret; - ret = devm_regulator_get_enable(&spi->dev, "dvdd"); + ret = devm_regulator_get_enable(dev, "dvdd"); if (ret) - return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n"); + return dev_err_probe(dev, ret, "Failed to enable specified DVdd supply\n"); - st->vref = devm_regulator_get_optional(&spi->dev, "vref"); + st->vref = devm_regulator_get_optional(dev, "vref"); if (IS_ERR(st->vref)) { if (PTR_ERR(st->vref) != -ENODEV) return PTR_ERR(st->vref); ret = regulator_get_voltage(st->avdd); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Device tree error, AVdd voltage undefined\n"); } else { ret = regulator_enable(st->vref); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified Vref supply\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable specified Vref supply\n"); - ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->vref); + ret = devm_add_action_or_reset(dev, ad7192_reg_disable, st->vref); if (ret) return ret; ret = regulator_get_voltage(st->vref); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Device tree error, Vref voltage undefined\n"); } st->int_vref_mv = ret / 1000; @@ -1305,13 +1302,13 @@ static int ad7192_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; st->fclk = AD7192_INT_FREQ_MHZ; - st->mclk = devm_clk_get_optional_enabled(&spi->dev, "mclk"); + st->mclk = devm_clk_get_optional_enabled(dev, "mclk"); if (IS_ERR(st->mclk)) return PTR_ERR(st->mclk); @@ -1320,18 +1317,16 @@ static int ad7192_probe(struct spi_device *spi) if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 || st->clock_sel == AD7192_CLK_EXT_MCLK2) { st->fclk = clk_get_rate(st->mclk); - if (!ad7192_valid_external_frequency(st->fclk)) { - dev_err(&spi->dev, - "External clock frequency out of bounds\n"); - return -EINVAL; - } + if (!ad7192_valid_external_frequency(st->fclk)) + return dev_err_probe(dev, -EINVAL, + "External clock frequency out of bounds\n"); } - ret = ad7192_setup(indio_dev, &spi->dev); + ret = ad7192_setup(indio_dev, dev); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad7192_of_match[] = { From 634c6b5ab6289be8f0c2934b9174c26d170da6d2 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 12 Jun 2024 16:03:06 -0500 Subject: [PATCH 148/330] iio: adc: ad7266: use devm_regulator_get_enable_read_voltage This makes use of the new devm_regulator_get_enable_read_voltage() function to reduce boilerplate code. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240612-iio-adc-ref-supply-refactor-v2-2-fa622e7354e9@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7266.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 353a97f9c086..874d2dc34f92 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -23,9 +23,10 @@ #include +#define AD7266_INTERNAL_REF_MV 2500 + struct ad7266_state { struct spi_device *spi; - struct regulator *reg; unsigned long vref_mv; struct spi_transfer single_xfer[3]; @@ -377,11 +378,6 @@ static const char * const ad7266_gpio_labels[] = { "ad0", "ad1", "ad2", }; -static void ad7266_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad7266_probe(struct spi_device *spi) { struct ad7266_platform_data *pdata = spi->dev.platform_data; @@ -396,28 +392,11 @@ static int ad7266_probe(struct spi_device *spi) st = iio_priv(indio_dev); - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - ret = devm_add_action_or_reset(&spi->dev, ad7266_reg_disable, st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - return ret; - - st->vref_mv = ret / 1000; - } else { - /* Any other error indicates that the regulator does exist */ - if (PTR_ERR(st->reg) != -ENODEV) - return PTR_ERR(st->reg); - /* Use internal reference */ - st->vref_mv = 2500; - } + st->vref_mv = ret == -ENODEV ? AD7266_INTERNAL_REF_MV : ret / 1000; if (pdata) { st->fixed_addr = pdata->fixed_addr; From c53ccb4ee1e439bab2414fb32852fae029f901fd Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 12 Jun 2024 16:03:07 -0500 Subject: [PATCH 149/330] iio: adc: ad7292: use devm_regulator_get_enable_read_voltage This makes use of the new devm_regulator_get_enable_read_voltage() function to reduce boilerplate code. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240612-iio-adc-ref-supply-refactor-v2-3-fa622e7354e9@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7292.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index 6aadd14f459d..ede80f380911 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -17,6 +17,8 @@ #define ADI_VENDOR_ID 0x0018 +#define AD7292_INTERNAL_REF_MV 1250 + /* AD7292 registers definition */ #define AD7292_REG_VENDOR_ID 0x00 #define AD7292_REG_CONF_BANK 0x05 @@ -79,7 +81,6 @@ static const struct iio_chan_spec ad7292_channels_diff[] = { struct ad7292_state { struct spi_device *spi; - struct regulator *reg; unsigned short vref_mv; __be16 d16 __aligned(IIO_DMA_MINALIGN); @@ -250,13 +251,6 @@ 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; @@ -277,29 +271,11 @@ static int ad7292_probe(struct spi_device *spi) return -EINVAL; } - 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_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - ret = devm_add_action_or_reset(&spi->dev, - ad7292_regulator_disable, st); - if (ret) - 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; - } + st->vref_mv = ret == -ENODEV ? AD7292_INTERNAL_REF_MV : ret / 1000; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; From 8f485a164de33e3b57d213d49a7e745d273f895c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 12 Jun 2024 16:03:08 -0500 Subject: [PATCH 150/330] iio: adc: ad7793: use devm_regulator_get_enable_read_voltage This makes use of the new devm_regulator_get_enable_read_voltage() function to reduce boilerplate code. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240612-iio-adc-ref-supply-refactor-v2-4-fa622e7354e9@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7793.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 5f8cb9aaac70..d4ad7e0b515a 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -152,7 +152,6 @@ struct ad7793_chip_info { struct ad7793_state { const struct ad7793_chip_info *chip_info; - struct regulator *reg; u16 int_vref_mv; u16 mode; u16 conf; @@ -769,11 +768,6 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { }, }; -static void ad7793_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad7793_probe(struct spi_device *spi) { const struct ad7793_platform_data *pdata = spi->dev.platform_data; @@ -800,23 +794,11 @@ static int ad7793_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); if (pdata->refsel != AD7793_REFSEL_INTERNAL) { - st->reg = devm_regulator_get(&spi->dev, "refin"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); - - ret = regulator_enable(st->reg); - if (ret) + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "refin"); + if (ret < 0) return ret; - ret = devm_add_action_or_reset(&spi->dev, ad7793_reg_disable, st->reg); - if (ret) - return ret; - - vref_mv = regulator_get_voltage(st->reg); - if (vref_mv < 0) - return vref_mv; - - vref_mv /= 1000; + vref_mv = ret / 1000; } else { vref_mv = 1170; /* Build-in ref */ } From 182b6164115a8c6bbe8c3e4e5b80e0adee18355b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 12 Jun 2024 16:03:09 -0500 Subject: [PATCH 151/330] iio: adc: ad7944: use devm_regulator_get_enable_read_voltage This makes use of the new devm_regulator_get_enable_read_voltage() function to reduce boilerplate code. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240612-iio-adc-ref-supply-refactor-v2-5-fa622e7354e9@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 54 +++++++++------------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index e2cb64cef476..4172723bb2ac 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -464,23 +464,17 @@ static const char * const ad7944_power_supplies[] = { "avdd", "dvdd", "bvdd", "vio" }; -static void ad7944_ref_disable(void *ref) -{ - regulator_disable(ref); -} - static int ad7944_probe(struct spi_device *spi) { const struct ad7944_chip_info *chip_info; struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct ad7944_adc *adc; - bool have_refin = false; - struct regulator *ref; + bool have_refin; struct iio_chan_spec *chain_chan; unsigned long *chain_scan_masks; u32 n_chain_dev; - int ret; + int ret, ref_mv; indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); if (!indio_dev) @@ -531,47 +525,23 @@ static int ad7944_probe(struct spi_device *spi) * - external reference: REF is connected, REFIN is not connected */ - ref = devm_regulator_get_optional(dev, "ref"); - if (IS_ERR(ref)) { - if (PTR_ERR(ref) != -ENODEV) - return dev_err_probe(dev, PTR_ERR(ref), - "failed to get REF supply\n"); + ret = devm_regulator_get_enable_read_voltage(dev, "ref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get REF voltage\n"); - ref = NULL; - } + ref_mv = ret == -ENODEV ? 0 : ret / 1000; ret = devm_regulator_get_enable_optional(dev, "refin"); - if (ret == 0) - have_refin = true; - else if (ret != -ENODEV) - return dev_err_probe(dev, ret, - "failed to get and enable REFIN supply\n"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get REFIN voltage\n"); - if (have_refin && ref) + have_refin = ret != -ENODEV; + + if (have_refin && ref_mv) return dev_err_probe(dev, -EINVAL, "cannot have both refin and ref supplies\n"); - if (ref) { - ret = regulator_enable(ref); - if (ret) - return dev_err_probe(dev, ret, - "failed to enable REF supply\n"); - - ret = devm_add_action_or_reset(dev, ad7944_ref_disable, ref); - if (ret) - return ret; - - ret = regulator_get_voltage(ref); - if (ret < 0) - return dev_err_probe(dev, ret, - "failed to get REF voltage\n"); - - /* external reference */ - adc->ref_mv = ret / 1000; - } else { - /* internal reference */ - adc->ref_mv = AD7944_INTERNAL_REF_MV; - } + adc->ref_mv = ref_mv ?: AD7944_INTERNAL_REF_MV; adc->cnv = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_LOW); if (IS_ERR(adc->cnv)) From d86deaec1c5b0fb60c3619e8d2ae7a1d722fd2ad Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:07 +0300 Subject: [PATCH 152/330] dt-bindings: iio: adc: Add common-mode-channel property There are ADCs that are differential but support to measure single-ended signals on the same channels by connecting a constant voltage to the negative input pin. This property allows to properly define a single-ended channel that requires two inputs to be specified. Software can use the presence of this property to mark the channel as not differential. Reviewed-by: Conor Dooley Signed-off-by: Dumitru Ceclan Reviewed-by: Nuno Sa Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-1-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adc.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml index 0a77592f7388..8e7835cf36fd 100644 --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml @@ -46,6 +46,17 @@ properties: differential channels). If this and diff-channels are not present reg shall be used instead. + common-mode-channel: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Some ADCs have differential input pins that can be used to measure + single-ended or pseudo-differential inputs. This property can be used + in addition to single-channel to signal software that this channel is + not differential but still specify two inputs. + + The input pair is specified by setting single-channel to the positive + input pin and common-mode-channel to the negative pin. + settling-time-us: description: Time between enabling the channel and first stable readings. From 561b5d5b7fbc1475e62ae68309f667ad2e18a669 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:08 +0300 Subject: [PATCH 153/330] dt-bindings: adc: ad7173: add support for ad411x Add support for: AD4111, AD4112, AD4114, AD4115, AD4116. AD411x family ADCs support a VCOM pin. The purpose of this pin is to offer a dedicated common-mode voltage input for single-ended channels. This pin is specified as supporting a differential channel with VIN10 on model AD4116. AD4111/AD4112 support current channels. Support is implemented using single-channel and "adi,current-channel". Reviewed-by: Conor Dooley Signed-off-by: Dumitru Ceclan Reviewed-by: Nuno Sa Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-2-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7173.yaml | 194 +++++++++++++++++- 1 file changed, 192 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml index ea6cfcd0aff4..17c5d39cc2c1 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml @@ -19,7 +19,18 @@ description: | primarily for measurement of signals close to DC but also delivers outstanding performance with input bandwidths out to ~10kHz. + Analog Devices AD411x ADC's: + The AD411X family encompasses a series of low power, low noise, 24-bit, + sigma-delta analog-to-digital converters that offer a versatile range of + specifications. They integrate an analog front end suitable for processing + fully differential/single-ended and bipolar voltage inputs. + Datasheets for supported chips: + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4111.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4112.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4114.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4115.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4116.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-2.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7173-8.pdf @@ -31,6 +42,11 @@ description: | properties: compatible: enum: + - adi,ad4111 + - adi,ad4112 + - adi,ad4114 + - adi,ad4115 + - adi,ad4116 - adi,ad7172-2 - adi,ad7172-4 - adi,ad7173-8 @@ -129,10 +145,56 @@ patternProperties: maximum: 15 diff-channels: + description: | + This property is used for defining the inputs of a differential + voltage channel. The first value is the positive input and the second + value is the negative input of the channel. + + Family AD411x supports a dedicated VINCOM voltage input. + To select it set the second channel to 16. + (VIN2, VINCOM) -> diff-channels = <2 16> + + There are special values that can be selected besides the voltage + analog inputs: + 21: REF+ + 22: REF− + + Supported only by AD7172-2, AD7172-4, AD7175-2, AD7175-8, AD7177-2, + must be paired together and can be used to monitor the power supply + of the ADC: + 19: ((AVDD1 − AVSS)/5)+ + 20: ((AVDD1 − AVSS)/5)− + items: minimum: 0 maximum: 31 + single-channel: + description: | + This property is used for defining a current channel or the positive + input of a voltage channel (single-ended or pseudo-differential). + + Models AD4111 and AD4112 support current channels. + Example: (IIN2+, IIN2−) -> single-channel = <2> + To correctly configure a current channel set the "adi,current-channel" + property to true. + + To configure a single-ended/pseudo-differential channel set the + "common-mode-channel" property to the desired negative voltage input. + + When used as a voltage channel, special inputs are valid as well. + minimum: 0 + maximum: 31 + + common-mode-channel: + description: + This property is used for defining the negative input of a + single-ended or pseudo-differential voltage channel. + + Special inputs are valid as well. + minimum: 0 + maximum: 31 + adi,reference-select: description: | Select the reference source to use when converting on @@ -154,9 +216,31 @@ patternProperties: - avdd default: refout-avss + adi,current-channel: + $ref: /schemas/types.yaml#/definitions/flag + description: | + Signal that the selected inputs are current channels. + Only available on AD4111 and AD4112. + required: - reg - - diff-channels + + allOf: + - oneOf: + - required: [single-channel] + properties: + diff-channels: false + - required: [diff-channels] + properties: + single-channel: false + adi,current-channel: false + common-mode-channel: false + + - if: + required: [common-mode-channel] + then: + properties: + adi,current-channel: false required: - compatible @@ -166,7 +250,6 @@ allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# # Only ad7172-4, ad7173-8 and ad7175-8 support vref2 - # Other models have [0-3] channel registers - if: properties: compatible: @@ -187,6 +270,37 @@ allOf: - vref - refout-avss - avdd + + - if: + properties: + compatible: + contains: + enum: + - adi,ad4114 + - adi,ad4115 + - adi,ad4116 + - adi,ad7173-8 + - adi,ad7175-8 + then: + patternProperties: + "^channel@[0-9a-f]$": + properties: + reg: + maximum: 15 + + - if: + properties: + compatible: + contains: + enum: + - adi,ad7172-2 + - adi,ad7175-2 + - adi,ad7176-2 + - adi,ad7177-2 + then: + patternProperties: + "^channel@[0-9a-f]$": + properties: reg: maximum: 3 @@ -210,6 +324,34 @@ allOf: required: - adi,reference-select + - if: + properties: + compatible: + contains: + enum: + - adi,ad4111 + - adi,ad4112 + - adi,ad4114 + - adi,ad4115 + - adi,ad4116 + then: + properties: + avdd2-supply: false + + - if: + properties: + compatible: + not: + contains: + enum: + - adi,ad4111 + - adi,ad4112 + then: + patternProperties: + "^channel@[0-9a-f]$": + properties: + adi,current-channel: false + - if: anyOf: - required: [clock-names] @@ -221,6 +363,7 @@ allOf: unevaluatedProperties: false examples: + # Example AD7173-8 with external reference connected to REF+/REF-: - | #include #include @@ -277,3 +420,50 @@ examples: }; }; }; + + # Example AD4111 with current channel and single-ended channel: + - | + #include + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad4111"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "rdy"; + interrupt-parent = <&gpio>; + spi-max-frequency = <5000000>; + gpio-controller; + #gpio-cells = <2>; + #clock-cells = <0>; + + channel@0 { + reg = <0>; + bipolar; + diff-channels = <4 5>; + }; + + // Single ended channel VIN2/VINCOM + channel@1 { + reg = <1>; + bipolar; + single-channel = <2>; + common-mode-channel = <16>; + }; + + // Current channel IN2+/IN2- + channel@2 { + reg = <2>; + single-channel = <2>; + adi,current-channel; + }; + }; + }; From 9265ea04a7b501e45134de13c0cbb81e897adf33 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 24 Jun 2024 10:53:26 +0800 Subject: [PATCH 154/330] interconnect: mediatek: remove unneeded semicolon No functional modification involved. ./drivers/interconnect/mediatek/icc-emi.c:71:2-3: Unneeded semicolon. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=9401 Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20240624025326.69551-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Georgi Djakov --- drivers/interconnect/mediatek/icc-emi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interconnect/mediatek/icc-emi.c b/drivers/interconnect/mediatek/icc-emi.c index d420c55682d0..7da740b5fa8d 100644 --- a/drivers/interconnect/mediatek/icc-emi.c +++ b/drivers/interconnect/mediatek/icc-emi.c @@ -68,7 +68,7 @@ static int mtk_emi_icc_set(struct icc_node *src, struct icc_node *dst) default: dev_err(src->provider->dev, "Unknown endpoint %u\n", node->ep); return -EINVAL; - }; + } return 0; } From 6822b0c92b435dec18d4317ddb424a63632b6a31 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Fri, 7 Jun 2024 23:09:26 +0530 Subject: [PATCH 155/330] dt-bindings: interconnect: add clock property to enable QOS on SC7280 Add clock property to enable the clocks required for accessing QoS configuration registers. Signed-off-by: Odelu Kukatla Acked-by: "Rob Herring (Arm)" Link: https://lore.kernel.org/r/20240607173927.26321-4-quic_okukatla@quicinc.com Signed-off-by: Georgi Djakov --- .../interconnect/qcom,sc7280-rpmh.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sc7280-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sc7280-rpmh.yaml index b135597d9489..9fce7203bd42 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,sc7280-rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,sc7280-rpmh.yaml @@ -35,6 +35,10 @@ properties: reg: maxItems: 1 + clocks: + minItems: 1 + maxItems: 2 + required: - compatible @@ -53,10 +57,50 @@ allOf: required: - reg + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7280-aggre1-noc + then: + properties: + clocks: + items: + - description: aggre UFS PHY AXI clock + - description: aggre USB3 PRIM AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7280-aggre2-noc + then: + properties: + clocks: + items: + - description: RPMH CC IPA clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7280-aggre1-noc + - qcom,sc7280-aggre2-noc + then: + required: + - clocks + else: + properties: + clocks: false + unevaluatedProperties: false examples: - | + #include interconnect { compatible = "qcom,sc7280-clk-virt"; #interconnect-cells = <2>; @@ -69,3 +113,12 @@ examples: #interconnect-cells = <2>; qcom,bcm-voters = <&apps_bcm_voter>; }; + + interconnect@16e0000 { + reg = <0x016e0000 0x1c080>; + compatible = "qcom,sc7280-aggre1-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + clocks = <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + }; From 0a7be6b35da848323725b5a7ecbfcbae0eed62dd Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Fri, 7 Jun 2024 23:09:24 +0530 Subject: [PATCH 156/330] interconnect: qcom: icc-rpmh: Add QoS configuration support Add QoS support for QNOC device for configuring priority, priority forward disable and urgency forwarding. QoS is required to prioritize the traffic originating from different interconnect masters at NoC (Network On Chip). Signed-off-by: Odelu Kukatla Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240607173927.26321-2-quic_okukatla@quicinc.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpmh.c | 93 ++++++++++++++++++++++++++++ drivers/interconnect/qcom/icc-rpmh.h | 35 +++++++++++ 2 files changed, 128 insertions(+) diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index c1aa265c1f4e..ceea9522df83 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include +#include #include #include #include @@ -14,6 +17,38 @@ #include "icc-common.h" #include "icc-rpmh.h" +/* QNOC QoS */ +#define QOSGEN_MAINCTL_LO(p, qp) (0x8 + (p->port_offsets[qp])) +#define QOS_SLV_URG_MSG_EN_MASK GENMASK(3, 3) +#define QOS_DFLT_PRIO_MASK GENMASK(6, 4) +#define QOS_DISABLE_MASK GENMASK(24, 24) + +/** + * qcom_icc_set_qos - initialize static QoS configurations + * @qp: qcom icc provider to which @node belongs + * @node: qcom icc node to operate on + */ +static void qcom_icc_set_qos(struct qcom_icc_provider *qp, + struct qcom_icc_node *node) +{ + const struct qcom_icc_qosbox *qos = node->qosbox; + int port; + + for (port = 0; port < qos->num_ports; port++) { + regmap_update_bits(qp->regmap, QOSGEN_MAINCTL_LO(qos, port), + QOS_DISABLE_MASK, + FIELD_PREP(QOS_DISABLE_MASK, qos->prio_fwd_disable)); + + regmap_update_bits(qp->regmap, QOSGEN_MAINCTL_LO(qos, port), + QOS_DFLT_PRIO_MASK, + FIELD_PREP(QOS_DFLT_PRIO_MASK, qos->prio)); + + regmap_update_bits(qp->regmap, QOSGEN_MAINCTL_LO(qos, port), + QOS_SLV_URG_MSG_EN_MASK, + FIELD_PREP(QOS_SLV_URG_MSG_EN_MASK, qos->urg_fwd)); + } +} + /** * qcom_icc_pre_aggregate - cleans up stale values from prior icc_set * @node: icc node to operate on @@ -159,6 +194,36 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev) } EXPORT_SYMBOL_GPL(qcom_icc_bcm_init); +/** + * qcom_icc_rpmh_configure_qos - configure QoS parameters + * @qp: qcom icc provider associated with QoS endpoint nodes + * + * Return: 0 on success, or an error code otherwise + */ +static int qcom_icc_rpmh_configure_qos(struct qcom_icc_provider *qp) +{ + struct qcom_icc_node *qnode; + size_t i; + int ret; + + ret = clk_bulk_prepare_enable(qp->num_clks, qp->clks); + if (ret) + return ret; + + for (i = 0; i < qp->num_nodes; i++) { + qnode = qp->nodes[i]; + if (!qnode) + continue; + + if (qnode->qosbox) + qcom_icc_set_qos(qp, qnode); + } + + clk_bulk_disable_unprepare(qp->num_clks, qp->clks); + + return ret; +} + int qcom_icc_rpmh_probe(struct platform_device *pdev) { const struct qcom_icc_desc *desc; @@ -199,7 +264,9 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) qp->dev = dev; qp->bcms = desc->bcms; + qp->nodes = desc->nodes; qp->num_bcms = desc->num_bcms; + qp->num_nodes = desc->num_nodes; qp->voter = of_bcm_voter_get(qp->dev, NULL); if (IS_ERR(qp->voter)) @@ -229,6 +296,32 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) data->nodes[i] = node; } + if (desc->config) { + struct resource *res; + void __iomem *base; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + goto skip_qos_config; + + qp->regmap = devm_regmap_init_mmio(dev, base, desc->config); + if (IS_ERR(qp->regmap)) { + dev_info(dev, "Skipping QoS, regmap failed; %ld\n", PTR_ERR(qp->regmap)); + goto skip_qos_config; + } + + qp->num_clks = devm_clk_bulk_get_all(qp->dev, &qp->clks); + if (qp->num_clks < 0) { + dev_info(dev, "Skipping QoS, failed to get clk: %d\n", qp->num_clks); + goto skip_qos_config; + } + + ret = qcom_icc_rpmh_configure_qos(qp); + if (ret) + dev_info(dev, "Failed to program QoS: %d\n", ret); + } + +skip_qos_config: ret = icc_provider_register(provider); if (ret) goto err_remove_nodes; diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index 2de29460e808..9a5142c70486 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -1,12 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_RPMH_H__ #define __DRIVERS_INTERCONNECT_QCOM_ICC_RPMH_H__ #include +#include #define to_qcom_provider(_provider) \ container_of(_provider, struct qcom_icc_provider, provider) @@ -18,6 +20,11 @@ * @bcms: list of bcms that maps to the provider * @num_bcms: number of @bcms * @voter: bcm voter targeted by this provider + * @nodes: list of icc nodes that maps to the provider + * @num_nodes: number of @nodes + * @regmap: used for QoS, register access + * @clks : clks required for register access + * @num_clks: number of @clks */ struct qcom_icc_provider { struct icc_provider provider; @@ -25,6 +32,11 @@ struct qcom_icc_provider { struct qcom_icc_bcm * const *bcms; size_t num_bcms; struct bcm_voter *voter; + struct qcom_icc_node * const *nodes; + size_t num_nodes; + struct regmap *regmap; + struct clk_bulk_data *clks; + int num_clks; }; /** @@ -41,6 +53,26 @@ struct bcm_db { u8 reserved; }; +#define MAX_PORTS 2 + +/** + * struct qcom_icc_qosbox - Qualcomm specific QoS config + * @prio: priority value assigned to requests on the node + * @urg_fwd: whether to forward the urgency promotion issued by master + * (endpoint), or discard + * @prio_fwd_disable: whether to forward the priority driven by master, or + * override by @prio + * @num_ports: number of @ports + * @port_offsets: qos register offsets + */ +struct qcom_icc_qosbox { + const u32 prio; + const bool urg_fwd; + const bool prio_fwd_disable; + const u32 num_ports; + const u32 port_offsets[MAX_PORTS]; +}; + #define MAX_LINKS 128 #define MAX_BCMS 64 #define MAX_BCM_PER_NODE 3 @@ -58,6 +90,7 @@ struct bcm_db { * @max_peak: current max aggregate value of all peak bw requests * @bcms: list of bcms associated with this logical node * @num_bcms: num of @bcms + * @qosbox: QoS config data associated with node */ struct qcom_icc_node { const char *name; @@ -70,6 +103,7 @@ struct qcom_icc_node { u64 max_peak[QCOM_ICC_NUM_BUCKETS]; struct qcom_icc_bcm *bcms[MAX_BCM_PER_NODE]; size_t num_bcms; + const struct qcom_icc_qosbox *qosbox; }; /** @@ -114,6 +148,7 @@ struct qcom_icc_fabric { }; struct qcom_icc_desc { + const struct regmap_config *config; struct qcom_icc_node * const *nodes; size_t num_nodes; struct qcom_icc_bcm * const *bcms; From fbd908bb8bc0e3714731467ac130d35492ed2187 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Fri, 7 Jun 2024 23:09:25 +0530 Subject: [PATCH 157/330] interconnect: qcom: sc7280: enable QoS configuration Enable QoS configuration for master ports with predefined values for priority and urgency forawrding. Signed-off-by: Odelu Kukatla Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240607173927.26321-3-quic_okukatla@quicinc.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sc7280.c | 274 +++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c index 7d33694368e8..759c609a20bf 100644 --- a/drivers/interconnect/qcom/sc7280.c +++ b/drivers/interconnect/qcom/sc7280.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. * */ @@ -21,6 +22,12 @@ static struct qcom_icc_node qhm_qspi = { .id = SC7280_MASTER_QSPI_0, .channels = 1, .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x7000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -30,6 +37,12 @@ static struct qcom_icc_node qhm_qup0 = { .id = SC7280_MASTER_QUP_0, .channels = 1, .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x11000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -39,6 +52,12 @@ static struct qcom_icc_node qhm_qup1 = { .id = SC7280_MASTER_QUP_1, .channels = 1, .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x8000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -57,6 +76,12 @@ static struct qcom_icc_node xm_sdc1 = { .id = SC7280_MASTER_SDCC_1, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xc000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -66,6 +91,12 @@ static struct qcom_icc_node xm_sdc2 = { .id = SC7280_MASTER_SDCC_2, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xe000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -75,6 +106,12 @@ static struct qcom_icc_node xm_sdc4 = { .id = SC7280_MASTER_SDCC_4, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x9000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -84,6 +121,12 @@ static struct qcom_icc_node xm_ufs_mem = { .id = SC7280_MASTER_UFS_MEM, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xa000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -102,6 +145,12 @@ static struct qcom_icc_node xm_usb3_0 = { .id = SC7280_MASTER_USB3_0, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xb000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A1NOC_SNOC }, }; @@ -111,6 +160,12 @@ static struct qcom_icc_node qhm_qdss_bam = { .id = SC7280_MASTER_QDSS_BAM, .channels = 1, .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x18000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A2NOC_SNOC }, }; @@ -129,6 +184,12 @@ static struct qcom_icc_node qnm_cnoc_datapath = { .id = SC7280_MASTER_CNOC_A2NOC, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x1c000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A2NOC_SNOC }, }; @@ -138,6 +199,12 @@ static struct qcom_icc_node qxm_crypto = { .id = SC7280_MASTER_CRYPTO, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x1d000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A2NOC_SNOC }, }; @@ -147,6 +214,12 @@ static struct qcom_icc_node qxm_ipa = { .id = SC7280_MASTER_IPA, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x10000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A2NOC_SNOC }, }; @@ -173,6 +246,12 @@ static struct qcom_icc_node xm_qdss_etr = { .id = SC7280_MASTER_QDSS_ETR, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x15000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_A2NOC_SNOC }, }; @@ -305,6 +384,12 @@ static struct qcom_icc_node alm_gpu_tcu = { .id = SC7280_MASTER_GPU_TCU, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd7000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 2, .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC }, }; @@ -314,6 +399,12 @@ static struct qcom_icc_node alm_sys_tcu = { .id = SC7280_MASTER_SYS_TCU, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd6000 }, + .prio = 6, + .urg_fwd = 0, + }, .num_links = 2, .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC }, }; @@ -333,6 +424,12 @@ static struct qcom_icc_node qnm_cmpnoc = { .id = SC7280_MASTER_COMPUTE_NOC, .channels = 2, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x21000, 0x61000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 2, .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC }, }; @@ -353,6 +450,12 @@ static struct qcom_icc_node qnm_gpu = { .id = SC7280_MASTER_GFX3D, .channels = 2, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x22000, 0x62000 }, + .prio = 0, + .urg_fwd = 0, + }, .num_links = 2, .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC }, }; @@ -362,6 +465,12 @@ static struct qcom_icc_node qnm_mnoc_hf = { .id = SC7280_MASTER_MNOC_HF_MEM_NOC, .channels = 2, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x23000, 0x63000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_LLCC }, }; @@ -371,6 +480,12 @@ static struct qcom_icc_node qnm_mnoc_sf = { .id = SC7280_MASTER_MNOC_SF_MEM_NOC, .channels = 1, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xcf000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 2, .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC }, }; @@ -389,6 +504,12 @@ static struct qcom_icc_node qnm_snoc_gc = { .id = SC7280_MASTER_SNOC_GC_MEM_NOC, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd3000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_LLCC }, }; @@ -398,6 +519,12 @@ static struct qcom_icc_node qnm_snoc_sf = { .id = SC7280_MASTER_SNOC_SF_MEM_NOC, .channels = 1, .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd4000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 3, .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC, SC7280_SLAVE_MEM_NOC_PCIE_SNOC }, @@ -437,6 +564,12 @@ static struct qcom_icc_node qnm_video0 = { .id = SC7280_MASTER_VIDEO_P0, .channels = 1, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x14000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC }, }; @@ -446,6 +579,12 @@ static struct qcom_icc_node qnm_video_cpu = { .id = SC7280_MASTER_VIDEO_PROC, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x15000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC }, }; @@ -455,6 +594,12 @@ static struct qcom_icc_node qxm_camnoc_hf = { .id = SC7280_MASTER_CAMNOC_HF, .channels = 2, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x10000, 0x10180 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_MNOC_HF_MEM_NOC }, }; @@ -464,6 +609,12 @@ static struct qcom_icc_node qxm_camnoc_icp = { .id = SC7280_MASTER_CAMNOC_ICP, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x11000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC }, }; @@ -473,6 +624,12 @@ static struct qcom_icc_node qxm_camnoc_sf = { .id = SC7280_MASTER_CAMNOC_SF, .channels = 1, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x12000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC }, }; @@ -482,6 +639,12 @@ static struct qcom_icc_node qxm_mdp0 = { .id = SC7280_MASTER_MDP0, .channels = 1, .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x16000 }, + .prio = 0, + .urg_fwd = 1, + }, .num_links = 1, .links = { SC7280_SLAVE_MNOC_HF_MEM_NOC }, }; @@ -536,6 +699,12 @@ static struct qcom_icc_node qxm_pimem = { .id = SC7280_MASTER_PIMEM, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x8000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_SNOC_GEM_NOC_GC }, }; @@ -545,6 +714,12 @@ static struct qcom_icc_node xm_gic = { .id = SC7280_MASTER_GIC, .channels = 1, .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xa000 }, + .prio = 2, + .urg_fwd = 0, + }, .num_links = 1, .links = { SC7280_SLAVE_SNOC_GEM_NOC_GC }, }; @@ -1502,7 +1677,16 @@ static struct qcom_icc_node * const aggre1_noc_nodes[] = { [SLAVE_SERVICE_A1NOC] = &srvc_aggre1_noc, }; +static const struct regmap_config sc7280_aggre1_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1c080, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_aggre1_noc = { + .config = &sc7280_aggre1_noc_regmap_config, .nodes = aggre1_noc_nodes, .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), .bcms = aggre1_noc_bcms, @@ -1513,6 +1697,14 @@ static struct qcom_icc_bcm * const aggre2_noc_bcms[] = { &bcm_ce0, }; +static const struct regmap_config sc7280_aggre2_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x2b080, + .fast_io = true, +}; + static struct qcom_icc_node * const aggre2_noc_nodes[] = { [MASTER_QDSS_BAM] = &qhm_qdss_bam, [MASTER_A2NOC_CFG] = &qnm_a2noc_cfg, @@ -1525,6 +1717,7 @@ static struct qcom_icc_node * const aggre2_noc_nodes[] = { }; static const struct qcom_icc_desc sc7280_aggre2_noc = { + .config = &sc7280_aggre2_noc_regmap_config, .nodes = aggre2_noc_nodes, .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), .bcms = aggre2_noc_bcms, @@ -1605,7 +1798,16 @@ static struct qcom_icc_node * const cnoc2_nodes[] = { [SLAVE_SNOC_CFG] = &qns_snoc_cfg, }; +static const struct regmap_config sc7280_cnoc2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1000, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_cnoc2 = { + .config = &sc7280_cnoc2_regmap_config, .nodes = cnoc2_nodes, .num_nodes = ARRAY_SIZE(cnoc2_nodes), .bcms = cnoc2_bcms, @@ -1637,7 +1839,16 @@ static struct qcom_icc_node * const cnoc3_nodes[] = { [SLAVE_TCU] = &xs_sys_tcu_cfg, }; +static const struct regmap_config sc7280_cnoc3_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1000, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_cnoc3 = { + .config = &sc7280_cnoc3_regmap_config, .nodes = cnoc3_nodes, .num_nodes = ARRAY_SIZE(cnoc3_nodes), .bcms = cnoc3_bcms, @@ -1653,7 +1864,16 @@ static struct qcom_icc_node * const dc_noc_nodes[] = { [SLAVE_GEM_NOC_CFG] = &qns_gemnoc, }; +static const struct regmap_config sc7280_dc_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x5080, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_dc_noc = { + .config = &sc7280_dc_noc_regmap_config, .nodes = dc_noc_nodes, .num_nodes = ARRAY_SIZE(dc_noc_nodes), .bcms = dc_noc_bcms, @@ -1689,7 +1909,16 @@ static struct qcom_icc_node * const gem_noc_nodes[] = { [SLAVE_SERVICE_GEM_NOC] = &srvc_sys_gemnoc, }; +static const struct regmap_config sc7280_gem_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xe2200, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_gem_noc = { + .config = &sc7280_gem_noc_regmap_config, .nodes = gem_noc_nodes, .num_nodes = ARRAY_SIZE(gem_noc_nodes), .bcms = gem_noc_bcms, @@ -1709,7 +1938,16 @@ static struct qcom_icc_node * const lpass_ag_noc_nodes[] = { [SLAVE_SERVICE_LPASS_AG_NOC] = &srvc_niu_lpass_agnoc, }; +static const struct regmap_config sc7280_lpass_ag_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xf080, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_lpass_ag_noc = { + .config = &sc7280_lpass_ag_noc_regmap_config, .nodes = lpass_ag_noc_nodes, .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), .bcms = lpass_ag_noc_bcms, @@ -1726,7 +1964,16 @@ static struct qcom_icc_node * const mc_virt_nodes[] = { [SLAVE_EBI1] = &ebi, }; +static const struct regmap_config sc7280_mc_virt_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x4, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_mc_virt = { + .config = &sc7280_mc_virt_regmap_config, .nodes = mc_virt_nodes, .num_nodes = ARRAY_SIZE(mc_virt_nodes), .bcms = mc_virt_bcms, @@ -1753,7 +2000,16 @@ static struct qcom_icc_node * const mmss_noc_nodes[] = { [SLAVE_SERVICE_MNOC] = &srvc_mnoc, }; +static const struct regmap_config sc7280_mmss_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1e080, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_mmss_noc = { + .config = &sc7280_mmss_noc_regmap_config, .nodes = mmss_noc_nodes, .num_nodes = ARRAY_SIZE(mmss_noc_nodes), .bcms = mmss_noc_bcms, @@ -1772,7 +2028,16 @@ static struct qcom_icc_node * const nsp_noc_nodes[] = { [SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc, }; +static const struct regmap_config sc7280_nsp_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_nsp_noc = { + .config = &sc7280_nsp_noc_regmap_config, .nodes = nsp_noc_nodes, .num_nodes = ARRAY_SIZE(nsp_noc_nodes), .bcms = nsp_noc_bcms, @@ -1797,7 +2062,16 @@ static struct qcom_icc_node * const system_noc_nodes[] = { [SLAVE_SERVICE_SNOC] = &srvc_snoc, }; +static const struct regmap_config sc7280_system_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x15480, + .fast_io = true, +}; + static const struct qcom_icc_desc sc7280_system_noc = { + .config = &sc7280_system_noc_regmap_config, .nodes = system_noc_nodes, .num_nodes = ARRAY_SIZE(system_noc_nodes), .bcms = system_noc_bcms, From cd5ce4589081190281cc2537301edd4275fe55eb Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 18 Jun 2024 16:42:18 +0200 Subject: [PATCH 158/330] interconnect: qcom: qcm2290: Fix mas_snoc_bimc RPM master ID The value was wrong, resulting in misprogramming of the hardware. Fix it. Fixes: 1a14b1ac3935 ("interconnect: qcom: Add QCM2290 driver support") Reported-by: Stephan Gerhold Closes: https://lore.kernel.org/linux-arm-msm/ZgMs_xZVzWH5uK-v@gerhold.net/ Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240618-topic-2290_icc_2-v1-1-64446888a133@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/qcm2290.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c index ba4cc08684d6..ccbdc6202c07 100644 --- a/drivers/interconnect/qcom/qcm2290.c +++ b/drivers/interconnect/qcom/qcm2290.c @@ -166,7 +166,7 @@ static struct qcom_icc_node mas_snoc_bimc = { .qos.ap_owned = true, .qos.qos_port = 6, .qos.qos_mode = NOC_QOS_MODE_BYPASS, - .mas_rpm_id = 164, + .mas_rpm_id = 3, .slv_rpm_id = -1, .num_links = ARRAY_SIZE(mas_snoc_bimc_links), .links = mas_snoc_bimc_links, From 783100f6ea0ae74a4ff3d616d4bce3b54badf347 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sat, 15 Jun 2024 09:31:59 +0300 Subject: [PATCH 159/330] mei: bus-fixup: set timeout for MKHI send operations Set a timeout for MKHI client send operations in the bus fixup routines to prevent potential lock-ups on the cl_bus_lock mutex. In rare conditions, such as when the i915 or Xe driver is stopping and not routing interrupts or when GSC FW is in unexpectedly reset the fixup routines can get stuck. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20240615063159.1460290-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 2733070acf39..9eebeffcd8fd 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -80,6 +80,8 @@ static void whitelist(struct mei_cl_device *cldev) cldev->do_match = 1; } +#define MKHI_SEND_MAX_TIMEOUT_MSEC 4000 + #define OSTYPE_LINUX 2 struct mei_os_ver { __le16 build; @@ -128,7 +130,7 @@ static int mei_osver(struct mei_cl_device *cldev) os_ver = (struct mei_os_ver *)fwcaps->data; os_ver->os_type = OSTYPE_LINUX; - return __mei_cl_send(cldev->cl, buf, size, 0, mode); + return __mei_cl_send_timeout(cldev->cl, buf, size, 0, mode, MKHI_SEND_MAX_TIMEOUT_MSEC); } #define MKHI_FWVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \ @@ -148,8 +150,8 @@ static int mei_fwver(struct mei_cl_device *cldev) req.hdr.group_id = MKHI_GEN_GROUP_ID; req.hdr.command = MKHI_GEN_GET_FW_VERSION_CMD; - ret = __mei_cl_send(cldev->cl, (u8 *)&req, sizeof(req), 0, - MEI_CL_IO_TX_BLOCKING); + ret = __mei_cl_send_timeout(cldev->cl, (u8 *)&req, sizeof(req), 0, + MEI_CL_IO_TX_BLOCKING, MKHI_SEND_MAX_TIMEOUT_MSEC); if (ret < 0) { dev_info(&cldev->dev, "Could not send ReqFWVersion cmd ret = %d\n", ret); return ret; From 98a563de231fcc91d65c6028c7f646fe28faf83a Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:09 +0300 Subject: [PATCH 160/330] iio: adc: ad_sigma_delta: add disable_one callback Sigma delta ADCs with a sequencer need to disable the previously enabled channel when reading using ad_sigma_delta_single_conversion(). This was done manually in drivers for devices with sequencers. This patch implements handling of single channel disabling after a single conversion. Reviewed-by: Nuno Sa Signed-off-by: Dumitru Ceclan Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-3-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 14 ++++++++------ drivers/iio/adc/ad7173.c | 11 ++++++----- drivers/iio/adc/ad_sigma_delta.c | 1 + include/linux/iio/adc/ad_sigma_delta.h | 14 ++++++++++++++ 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index e7b1d517d3de..3beed78496c5 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -555,10 +555,18 @@ static int ad7124_disable_all(struct ad_sigma_delta *sd) return 0; } +static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan) +{ + struct ad7124_state *st = container_of(sd, struct ad7124_state, sd); + + return ad7124_spi_write_mask(st, AD7124_CHANNEL(chan), AD7124_CHANNEL_EN_MSK, 0, 2); +} + static const struct ad_sigma_delta_info ad7124_sigma_delta_info = { .set_channel = ad7124_set_channel, .append_status = ad7124_append_status, .disable_all = ad7124_disable_all, + .disable_one = ad7124_disable_one, .set_mode = ad7124_set_mode, .has_registers = true, .addr_shift = 0, @@ -582,12 +590,6 @@ static int ad7124_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - /* After the conversion is performed, disable the channel */ - ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan->address), 2, - st->channels[chan->address].ain | AD7124_CHANNEL_EN(0)); - if (ret < 0) - return ret; - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: mutex_lock(&st->cfgs_lock); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index b26d4575e256..428676c73722 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -569,10 +569,16 @@ static int ad7173_disable_all(struct ad_sigma_delta *sd) return 0; } +static int ad7173_disable_one(struct ad_sigma_delta *sd, unsigned int chan) +{ + return ad_sd_write_reg(sd, AD7173_REG_CH(chan), 2, 0); +} + static struct ad_sigma_delta_info ad7173_sigma_delta_info = { .set_channel = ad7173_set_channel, .append_status = ad7173_append_status, .disable_all = ad7173_disable_all, + .disable_one = ad7173_disable_one, .set_mode = ad7173_set_mode, .has_registers = true, .addr_shift = 0, @@ -668,11 +674,6 @@ static int ad7173_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - /* disable channel after single conversion */ - ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(chan->address), 2, 0); - if (ret < 0) - return ret; - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_TEMP) { diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index a2b87f6b7a07..8c062b0d26e3 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -321,6 +321,7 @@ out: sigma_delta->keep_cs_asserted = false; ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + ad_sigma_delta_disable_one(sigma_delta, chan->address); sigma_delta->bus_locked = false; spi_bus_unlock(sigma_delta->spi->controller); iio_device_release_direct_mode(indio_dev); diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 383614ebd760..f8c1d2505940 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -37,6 +37,10 @@ struct iio_dev; * @append_status: Will be called to enable status append at the end of the sample, may be NULL. * @set_mode: Will be called to select the current mode, may be NULL. * @disable_all: Will be called to disable all channels, may be NULL. + * @disable_one: Will be called to disable a single channel after + * ad_sigma_delta_single_conversion(), may be NULL. + * Usage of this callback expects iio_chan_spec.address to contain + * the value required for the driver to identify the channel. * @postprocess_sample: Is called for each sampled data word, can be used to * modify or drop the sample data, it, may be NULL. * @has_registers: true if the device has writable and readable registers, false @@ -55,6 +59,7 @@ struct ad_sigma_delta_info { int (*append_status)(struct ad_sigma_delta *, bool append); int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode); int (*disable_all)(struct ad_sigma_delta *); + int (*disable_one)(struct ad_sigma_delta *, unsigned int chan); int (*postprocess_sample)(struct ad_sigma_delta *, unsigned int raw_sample); bool has_registers; unsigned int addr_shift; @@ -140,6 +145,15 @@ static inline int ad_sigma_delta_disable_all(struct ad_sigma_delta *sd) return 0; } +static inline int ad_sigma_delta_disable_one(struct ad_sigma_delta *sd, + unsigned int chan) +{ + if (sd->info->disable_one) + return sd->info->disable_one(sd, chan); + + return 0; +} + static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd, unsigned int mode) { From 137a83a66f355a9e22039ebf39581ce922119d97 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:10 +0300 Subject: [PATCH 161/330] iio: adc: ad7173: refactor channel configuration parsing Move configurations regarding number of channels from *_fw_parse_device_config to *_fw_parse_channel_config. Suggested-by: Jonathan Cameron Link: https://lore.kernel.org/all/20240303162148.3ad91aa2@jic23-huawei/ Reviewed-by: David Lechner Reviewed-by: Nuno Sa Signed-off-by: Dumitru Ceclan Link: https://patch.msgid.link/20240607-ad4111-v7-4-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 428676c73722..39801c076dcd 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -912,7 +912,23 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) struct device *dev = indio_dev->dev.parent; struct iio_chan_spec *chan_arr, *chan; unsigned int ain[2], chan_index = 0; - int ref_sel, ret; + int ref_sel, ret, num_channels; + + num_channels = device_get_child_node_count(dev); + + if (st->info->has_temp) + num_channels++; + + if (num_channels == 0) + return dev_err_probe(dev, -ENODATA, "No channels specified\n"); + + if (num_channels > st->info->num_channels) + return dev_err_probe(dev, -EINVAL, + "Too many channels specified. Maximum is %d, not including temperature channel if supported.\n", + st->info->num_channels); + + indio_dev->num_channels = num_channels; + st->num_channels = num_channels; chan_arr = devm_kcalloc(dev, sizeof(*indio_dev->channels), st->num_channels, GFP_KERNEL); @@ -1007,7 +1023,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev) { struct ad7173_state *st = iio_priv(indio_dev); struct device *dev = indio_dev->dev.parent; - unsigned int num_channels; int ret; st->regulators[0].supply = ad7173_ref_sel_str[AD7173_SETUP_REF_SEL_EXT_REF]; @@ -1066,16 +1081,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev) ad7173_sigma_delta_info.irq_line = ret; - num_channels = device_get_child_node_count(dev); - - if (st->info->has_temp) - num_channels++; - - if (num_channels == 0) - return dev_err_probe(dev, -ENODATA, "No channels specified\n"); - indio_dev->num_channels = num_channels; - st->num_channels = num_channels; - return ad7173_fw_parse_channel_config(indio_dev); } From fc5cdff0654a2f77e68c4bd1c2f8426ab4a9de1e Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:11 +0300 Subject: [PATCH 162/330] iio: adc: ad7173: refactor ain and vref selection Move validation of analog inputs and reference voltage selection to separate functions to reduce the size of the channel config parsing function and improve readability. Add defines for the number of analog inputs in a channel. Signed-off-by: Dumitru Ceclan Reviewed-by: Nuno Sa Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-5-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 62 ++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 39801c076dcd..cacc411b87ac 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -60,6 +60,7 @@ #define AD7173_CH_SETUP_AINPOS_MASK GENMASK(9, 5) #define AD7173_CH_SETUP_AINNEG_MASK GENMASK(4, 0) +#define AD7173_NO_AINS_PER_CHANNEL 2 #define AD7173_CH_ADDRESS(pos, neg) \ (FIELD_PREP(AD7173_CH_SETUP_AINPOS_MASK, pos) | \ FIELD_PREP(AD7173_CH_SETUP_AINNEG_MASK, neg)) @@ -905,13 +906,48 @@ static int ad7173_register_clk_provider(struct iio_dev *indio_dev) &st->int_clk_hw); } +static int ad7173_validate_voltage_ain_inputs(struct ad7173_state *st, + unsigned int ain0, unsigned int ain1) +{ + struct device *dev = &st->sd.spi->dev; + + if (ain0 >= st->info->num_inputs || + ain1 >= st->info->num_inputs) + return dev_err_probe(dev, -EINVAL, + "Input pin number out of range for pair (%d %d).\n", + ain0, ain1); + + return 0; +} + +static int ad7173_validate_reference(struct ad7173_state *st, int ref_sel) +{ + struct device *dev = &st->sd.spi->dev; + int ret; + + if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && !st->info->has_int_ref) + return dev_err_probe(dev, -EINVAL, + "Internal reference is not available on current model.\n"); + + if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2) + return dev_err_probe(dev, -EINVAL, + "External reference 2 is not available on current model.\n"); + + ret = ad7173_get_ref_voltage_milli(st, ref_sel); + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot use reference %u\n", + ref_sel); + + return 0; +} + static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) { struct ad7173_channel *chans_st_arr, *chan_st_priv; struct ad7173_state *st = iio_priv(indio_dev); struct device *dev = indio_dev->dev.parent; struct iio_chan_spec *chan_arr, *chan; - unsigned int ain[2], chan_index = 0; + unsigned int ain[AD7173_NO_AINS_PER_CHANNEL], chan_index = 0; int ref_sel, ret, num_channels; num_channels = device_get_child_node_count(dev); @@ -965,11 +1001,9 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) if (ret) return ret; - if (ain[0] >= st->info->num_inputs || - ain[1] >= st->info->num_inputs) - return dev_err_probe(dev, -EINVAL, - "Input pin number out of range for pair (%d %d).\n", - ain[0], ain[1]); + ret = ad7173_validate_voltage_ain_inputs(st, ain[0], ain[1]); + if (ret) + return ret; ret = fwnode_property_match_property_string(child, "adi,reference-select", @@ -980,19 +1014,9 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) else ref_sel = ret; - if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && - !st->info->has_int_ref) - return dev_err_probe(dev, -EINVAL, - "Internal reference is not available on current model.\n"); - - if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2) - return dev_err_probe(dev, -EINVAL, - "External reference 2 is not available on current model.\n"); - - ret = ad7173_get_ref_voltage_milli(st, ref_sel); - if (ret < 0) - return dev_err_probe(dev, ret, - "Cannot use reference %u\n", ref_sel); + ret = ad7173_validate_reference(st, ref_sel); + if (ret) + return ret; if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF) st->adc_mode |= AD7173_ADC_MODE_REF_EN; From ff05b4a86dea94f8689bb1e76ec03ea8ffe0e2fd Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:12 +0300 Subject: [PATCH 163/330] iio: adc: ad7173: add support for special inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for selecting REF+ and REF- inputs on all models. Add support for selecting ((AVDD1 − AVSS)/5) inputs on supported models. Signed-off-by: Dumitru Ceclan Reviewed-by: Nuno Sa Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-6-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index cacc411b87ac..f0696b4b6e56 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -66,6 +66,13 @@ FIELD_PREP(AD7173_CH_SETUP_AINNEG_MASK, neg)) #define AD7173_AIN_TEMP_POS 17 #define AD7173_AIN_TEMP_NEG 18 +#define AD7173_AIN_POW_MON_POS 19 +#define AD7173_AIN_POW_MON_NEG 20 +#define AD7173_AIN_REF_POS 21 +#define AD7173_AIN_REF_NEG 22 + +#define AD7173_IS_REF_INPUT(x) ((x) == AD7173_AIN_REF_POS || \ + (x) == AD7173_AIN_REF_NEG) #define AD7172_2_ID 0x00d0 #define AD7175_ID 0x0cd0 @@ -146,6 +153,8 @@ struct ad7173_device_info { unsigned int id; char *name; bool has_temp; + /* ((AVDD1 − AVSS)/5) */ + bool has_pow_supply_monitoring; bool has_input_buf; bool has_int_ref; bool has_ref2; @@ -216,6 +225,7 @@ static const struct ad7173_device_info ad7173_device_info[] = { .has_temp = true, .has_input_buf = true, .has_int_ref = true, + .has_pow_supply_monitoring = true, .clock = 2 * HZ_PER_MHZ, .sinc5_data_rates = ad7173_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), @@ -230,6 +240,7 @@ static const struct ad7173_device_info ad7173_device_info[] = { .has_temp = false, .has_input_buf = true, .has_ref2 = true, + .has_pow_supply_monitoring = true, .clock = 2 * HZ_PER_MHZ, .sinc5_data_rates = ad7173_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), @@ -259,6 +270,7 @@ static const struct ad7173_device_info ad7173_device_info[] = { .has_temp = true, .has_input_buf = true, .has_int_ref = true, + .has_pow_supply_monitoring = true, .clock = 16 * HZ_PER_MHZ, .sinc5_data_rates = ad7175_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), @@ -274,6 +286,7 @@ static const struct ad7173_device_info ad7173_device_info[] = { .has_input_buf = true, .has_int_ref = true, .has_ref2 = true, + .has_pow_supply_monitoring = true, .clock = 16 * HZ_PER_MHZ, .sinc5_data_rates = ad7175_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), @@ -302,6 +315,7 @@ static const struct ad7173_device_info ad7173_device_info[] = { .has_temp = true, .has_input_buf = true, .has_int_ref = true, + .has_pow_supply_monitoring = true, .clock = 16 * HZ_PER_MHZ, .odr_start_value = AD7177_ODR_START_VALUE, .sinc5_data_rates = ad7175_sinc5_data_rates, @@ -910,9 +924,18 @@ static int ad7173_validate_voltage_ain_inputs(struct ad7173_state *st, unsigned int ain0, unsigned int ain1) { struct device *dev = &st->sd.spi->dev; + bool special_input0, special_input1; - if (ain0 >= st->info->num_inputs || - ain1 >= st->info->num_inputs) + /* (AVDD1-AVSS)/5 power supply monitoring */ + if (ain0 == AD7173_AIN_POW_MON_POS && ain1 == AD7173_AIN_POW_MON_NEG && + st->info->has_pow_supply_monitoring) + return 0; + + special_input0 = AD7173_IS_REF_INPUT(ain0); + special_input1 = AD7173_IS_REF_INPUT(ain1); + + if ((ain0 >= st->info->num_inputs && !special_input0) || + (ain1 >= st->info->num_inputs && !special_input1)) return dev_err_probe(dev, -EINVAL, "Input pin number out of range for pair (%d %d).\n", ain0, ain1); From 0f360d489e33053cb1b4f2c73a15d306cbe11d81 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:13 +0300 Subject: [PATCH 164/330] iio: adc: ad7173: refactor device info structs Drop setting .has_temp and .has_input_buf to false in device info struct. Drop array of device info structs and use individual structs for all; drop models enum as no longer needed. This improves readability as the structs are pointed directly. Reviewed-by: Nuno Sa Signed-off-by: Dumitru Ceclan Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-7-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 260 ++++++++++++++++++--------------------- 1 file changed, 122 insertions(+), 138 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index f0696b4b6e56..ee3e586c2c9e 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -132,16 +132,6 @@ #define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) #define AD7173_MAX_CONFIGS 8 -enum ad7173_ids { - ID_AD7172_2, - ID_AD7172_4, - ID_AD7173_8, - ID_AD7175_2, - ID_AD7175_8, - ID_AD7176_2, - ID_AD7177_2, -}; - struct ad7173_device_info { const unsigned int *sinc5_data_rates; unsigned int num_sinc5_data_rates; @@ -214,113 +204,114 @@ static const unsigned int ad7175_sinc5_data_rates[] = { 5000, /* 20 */ }; -static const struct ad7173_device_info ad7173_device_info[] = { - [ID_AD7172_2] = { - .name = "ad7172-2", - .id = AD7172_2_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .has_pow_supply_monitoring = true, - .clock = 2 * HZ_PER_MHZ, - .sinc5_data_rates = ad7173_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), - }, - [ID_AD7172_4] = { - .name = "ad7172-4", - .id = AD7172_4_ID, - .num_inputs = 9, - .num_channels = 8, - .num_configs = 8, - .num_gpios = 4, - .has_temp = false, - .has_input_buf = true, - .has_ref2 = true, - .has_pow_supply_monitoring = true, - .clock = 2 * HZ_PER_MHZ, - .sinc5_data_rates = ad7173_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), - }, - [ID_AD7173_8] = { - .name = "ad7173-8", - .id = AD7173_ID, - .num_inputs = 17, - .num_channels = 16, - .num_configs = 8, - .num_gpios = 4, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .has_ref2 = true, - .clock = 2 * HZ_PER_MHZ, - .sinc5_data_rates = ad7173_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), - }, - [ID_AD7175_2] = { - .name = "ad7175-2", - .id = AD7175_2_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .has_pow_supply_monitoring = true, - .clock = 16 * HZ_PER_MHZ, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, - [ID_AD7175_8] = { - .name = "ad7175-8", - .id = AD7175_8_ID, - .num_inputs = 17, - .num_channels = 16, - .num_configs = 8, - .num_gpios = 4, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .has_ref2 = true, - .has_pow_supply_monitoring = true, - .clock = 16 * HZ_PER_MHZ, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, - [ID_AD7176_2] = { - .name = "ad7176-2", - .id = AD7176_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = false, - .has_input_buf = false, - .has_int_ref = true, - .clock = 16 * HZ_PER_MHZ, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, - [ID_AD7177_2] = { - .name = "ad7177-2", - .id = AD7177_ID, - .num_inputs = 5, - .num_channels = 4, - .num_configs = 4, - .num_gpios = 2, - .has_temp = true, - .has_input_buf = true, - .has_int_ref = true, - .has_pow_supply_monitoring = true, - .clock = 16 * HZ_PER_MHZ, - .odr_start_value = AD7177_ODR_START_VALUE, - .sinc5_data_rates = ad7175_sinc5_data_rates, - .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), - }, +static const struct ad7173_device_info ad7172_2_device_info = { + .name = "ad7172-2", + .id = AD7172_2_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_pow_supply_monitoring = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7172_4_device_info = { + .name = "ad7172-4", + .id = AD7172_4_ID, + .num_inputs = 9, + .num_channels = 8, + .num_configs = 8, + .num_gpios = 4, + .has_input_buf = true, + .has_ref2 = true, + .has_pow_supply_monitoring = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7173_8_device_info = { + .name = "ad7173-8", + .id = AD7173_ID, + .num_inputs = 17, + .num_channels = 16, + .num_configs = 8, + .num_gpios = 4, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_ref2 = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7175_2_device_info = { + .name = "ad7175-2", + .id = AD7175_2_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_pow_supply_monitoring = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7175_8_device_info = { + .name = "ad7175-8", + .id = AD7175_8_ID, + .num_inputs = 17, + .num_channels = 16, + .num_configs = 8, + .num_gpios = 4, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_ref2 = true, + .has_pow_supply_monitoring = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7176_2_device_info = { + .name = "ad7176-2", + .id = AD7176_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_int_ref = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad7177_2_device_info = { + .name = "ad7177-2", + .id = AD7177_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .has_pow_supply_monitoring = true, + .clock = 16 * HZ_PER_MHZ, + .odr_start_value = AD7177_ODR_START_VALUE, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), }; static const char *const ad7173_ref_sel_str[] = { @@ -1187,32 +1178,25 @@ static int ad7173_probe(struct spi_device *spi) } static const struct of_device_id ad7173_of_match[] = { - { .compatible = "adi,ad7172-2", - .data = &ad7173_device_info[ID_AD7172_2]}, - { .compatible = "adi,ad7172-4", - .data = &ad7173_device_info[ID_AD7172_4]}, - { .compatible = "adi,ad7173-8", - .data = &ad7173_device_info[ID_AD7173_8]}, - { .compatible = "adi,ad7175-2", - .data = &ad7173_device_info[ID_AD7175_2]}, - { .compatible = "adi,ad7175-8", - .data = &ad7173_device_info[ID_AD7175_8]}, - { .compatible = "adi,ad7176-2", - .data = &ad7173_device_info[ID_AD7176_2]}, - { .compatible = "adi,ad7177-2", - .data = &ad7173_device_info[ID_AD7177_2]}, + { .compatible = "adi,ad7172-2", .data = &ad7172_2_device_info }, + { .compatible = "adi,ad7172-4", .data = &ad7172_4_device_info }, + { .compatible = "adi,ad7173-8", .data = &ad7173_8_device_info }, + { .compatible = "adi,ad7175-2", .data = &ad7175_2_device_info }, + { .compatible = "adi,ad7175-8", .data = &ad7175_8_device_info }, + { .compatible = "adi,ad7176-2", .data = &ad7176_2_device_info }, + { .compatible = "adi,ad7177-2", .data = &ad7177_2_device_info }, { } }; MODULE_DEVICE_TABLE(of, ad7173_of_match); static const struct spi_device_id ad7173_id_table[] = { - { "ad7172-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_2]}, - { "ad7172-4", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_4]}, - { "ad7173-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7173_8]}, - { "ad7175-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_2]}, - { "ad7175-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_8]}, - { "ad7176-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7176_2]}, - { "ad7177-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7177_2]}, + { "ad7172-2", (kernel_ulong_t)&ad7172_2_device_info }, + { "ad7172-4", (kernel_ulong_t)&ad7172_4_device_info }, + { "ad7173-8", (kernel_ulong_t)&ad7173_8_device_info }, + { "ad7175-2", (kernel_ulong_t)&ad7175_2_device_info }, + { "ad7175-8", (kernel_ulong_t)&ad7175_8_device_info }, + { "ad7176-2", (kernel_ulong_t)&ad7176_2_device_info }, + { "ad7177-2", (kernel_ulong_t)&ad7177_2_device_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7173_id_table); From f87b076b934f720aca69cad8d95455a1f2d66215 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:14 +0300 Subject: [PATCH 165/330] iio: adc: ad7173: document sampling frequency behaviour The ADCs supported by this driver feature a sequencer that read in a loop all the enabled chanels. When setting the individual sampling frequency for each channel and enabling multiple channels, the effective of each channel will be lower than the actual set value. Document this behaviour in a comment. Reviewed-by: Nuno Sa Signed-off-by: Dumitru Ceclan Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-8-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index ee3e586c2c9e..878c1a83a2c6 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -732,6 +732,21 @@ static int ad7173_write_raw(struct iio_dev *indio_dev, return ret; switch (info) { + /* + * This attribute sets the sampling frequency for each channel individually. + * There are no issues for raw or buffered reads of an individual channel. + * + * When multiple channels are enabled in buffered mode, the effective + * sampling rate of a channel is lowered in correlation to the number + * of channels enabled and the sampling rate of the other channels. + * + * Example: 3 channels enabled with rates CH1:6211sps CH2,CH3:10sps + * While the reading of CH1 takes only 0.16ms, the reading of CH2 and CH3 + * will take 100ms each. + * + * This will cause the reading of CH1 to be actually done once every + * 200.16ms, an effective rate of 4.99sps. + */ case IIO_CHAN_INFO_SAMP_FREQ: freq = val * MILLI + val2 / MILLI; for (i = st->info->odr_start_value; i < st->info->num_sinc5_data_rates - 1; i++) From 13d12e3ad12dca5b496d8a5b8461728e63b3a205 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Fri, 7 Jun 2024 17:53:15 +0300 Subject: [PATCH 166/330] iio: adc: ad7173: Add support for AD411x devices Add support for AD4111/AD4112/AD4114/AD4115/AD4116. The AD411X family encompasses a series of low power, low noise, 24-bit, sigma-delta analog-to-digital converters that offer a versatile range of specifications. This family of ADCs integrates an analog front end suitable for processing both fully differential and single-ended, bipolar voltage inputs addressing a wide array of industrial and instrumentation requirements. - All ADCs have inputs with a precision voltage divider with a division ratio of 10. - AD4116 has 5 low level inputs without a voltage divider. - AD4111 and AD4112 support current inputs (0 mA to 20 mA) using a 50ohm shunt resistor. Signed-off-by: Dumitru Ceclan Reviewed-by: Nuno Sa Reviewed-by: David Lechner Link: https://patch.msgid.link/20240607-ad4111-v7-9-97e3855900a0@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 314 +++++++++++++++++++++++++++++++++++---- 1 file changed, 282 insertions(+), 32 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 878c1a83a2c6..7da70b7422bb 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * AD717x family SPI ADC driver + * AD717x and AD411x family SPI ADC driver * * Supported devices: + * AD4111/AD4112/AD4114/AD4115/AD4116 * AD7172-2/AD7172-4/AD7173-8/AD7175-2 * AD7175-8/AD7176-2/AD7177-2 * @@ -80,6 +81,11 @@ #define AD7175_2_ID 0x0cd0 #define AD7172_4_ID 0x2050 #define AD7173_ID 0x30d0 +#define AD4111_ID AD7173_ID +#define AD4112_ID AD7173_ID +#define AD4114_ID AD7173_ID +#define AD4116_ID 0x34d0 +#define AD4115_ID 0x38d0 #define AD7175_8_ID 0x3cd0 #define AD7177_ID 0x4fd0 #define AD7173_ID_MASK GENMASK(15, 4) @@ -110,6 +116,7 @@ #define AD7173_GPO12_DATA(x) BIT((x) + 0) #define AD7173_GPO23_DATA(x) BIT((x) + 4) +#define AD4111_GPO01_DATA(x) BIT((x) + 6) #define AD7173_GPO_DATA(x) ((x) < 2 ? AD7173_GPO12_DATA(x) : AD7173_GPO23_DATA(x)) #define AD7173_INTERFACE_DATA_STAT BIT(6) @@ -128,6 +135,16 @@ #define AD7173_VOLTAGE_INT_REF_uV 2500000 #define AD7173_TEMP_SENSIIVITY_uV_per_C 477 #define AD7177_ODR_START_VALUE 0x07 +#define AD4111_SHUNT_RESISTOR_OHM 50 +#define AD4111_DIVIDER_RATIO 10 +#define AD4111_CURRENT_CHAN_CUTOFF 16 +#define AD4111_VINCOM_INPUT 0x10 + +/* pin < num_voltage_in is a normal voltage input */ +/* pin >= num_voltage_in_div is a voltage input without a divider */ +#define AD4111_IS_VINCOM_MISMATCH(pin1, pin2) ((pin1) == AD4111_VINCOM_INPUT && \ + (pin2) < st->info->num_voltage_in && \ + (pin2) >= st->info->num_voltage_in_div) #define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) #define AD7173_MAX_CONFIGS 8 @@ -136,18 +153,27 @@ struct ad7173_device_info { const unsigned int *sinc5_data_rates; unsigned int num_sinc5_data_rates; unsigned int odr_start_value; + /* + * AD4116 has both inputs with a voltage divider and without. + * These inputs cannot be mixed in the channel configuration. + * Does not include the VINCOM input. + */ + unsigned int num_voltage_in_div; unsigned int num_channels; unsigned int num_configs; - unsigned int num_inputs; + unsigned int num_voltage_in; unsigned int clock; unsigned int id; char *name; + bool has_current_inputs; + bool has_vincom_input; bool has_temp; /* ((AVDD1 − AVSS)/5) */ bool has_pow_supply_monitoring; bool has_input_buf; bool has_int_ref; bool has_ref2; + bool higher_gpio_bits; u8 num_gpios; }; @@ -189,6 +215,24 @@ struct ad7173_state { #endif }; +static unsigned int ad4115_sinc5_data_rates[] = { + 24845000, 24845000, 20725000, 20725000, /* 0-3 */ + 15564000, 13841000, 10390000, 10390000, /* 4-7 */ + 4994000, 2499000, 1000000, 500000, /* 8-11 */ + 395500, 200000, 100000, 59890, /* 12-15 */ + 49920, 20000, 16660, 10000, /* 16-19 */ + 5000, 2500, 2500, /* 20-22 */ +}; + +static unsigned int ad4116_sinc5_data_rates[] = { + 12422360, 12422360, 12422360, 12422360, /* 0-3 */ + 10362690, 10362690, 7782100, 6290530, /* 4-7 */ + 5194800, 2496900, 1007600, 499900, /* 8-11 */ + 390600, 200300, 100000, 59750, /* 12-15 */ + 49840, 20000, 16650, 10000, /* 16-19 */ + 5000, 2500, 1250, /* 20-22 */ +}; + static const unsigned int ad7173_sinc5_data_rates[] = { 6211000, 6211000, 6211000, 6211000, 6211000, 6211000, 5181000, 4444000, /* 0-7 */ 3115000, 2597000, 1007000, 503800, 381000, 200300, 100500, 59520, /* 8-15 */ @@ -204,10 +248,110 @@ static const unsigned int ad7175_sinc5_data_rates[] = { 5000, /* 20 */ }; +static unsigned int ad4111_current_channel_config[] = { + /* Ain sel: pos neg */ + 0x1E8, /* 15:IIN0+ 8:IIN0− */ + 0x1C9, /* 14:IIN1+ 9:IIN1− */ + 0x1AA, /* 13:IIN2+ 10:IIN2− */ + 0x18B, /* 12:IIN3+ 11:IIN3− */ +}; + +static const struct ad7173_device_info ad4111_device_info = { + .name = "ad4111", + .id = AD4111_ID, + .num_voltage_in_div = 8, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 8, + .num_gpios = 2, + .higher_gpio_bits = true, + .has_temp = true, + .has_vincom_input = true, + .has_input_buf = true, + .has_current_inputs = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4112_device_info = { + .name = "ad4112", + .id = AD4112_ID, + .num_voltage_in_div = 8, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 8, + .num_gpios = 2, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_current_inputs = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4114_device_info = { + .name = "ad4114", + .id = AD4114_ID, + .num_voltage_in_div = 16, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 16, + .num_gpios = 4, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4115_device_info = { + .name = "ad4115", + .id = AD4115_ID, + .num_voltage_in_div = 16, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 16, + .num_gpios = 4, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .clock = 8 * HZ_PER_MHZ, + .sinc5_data_rates = ad4115_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates), +}; + +static const struct ad7173_device_info ad4116_device_info = { + .name = "ad4116", + .id = AD4116_ID, + .num_voltage_in_div = 11, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 16, + .num_gpios = 4, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_temp = true, + .has_input_buf = true, + .has_int_ref = true, + .clock = 4 * HZ_PER_MHZ, + .sinc5_data_rates = ad4116_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates), +}; + static const struct ad7173_device_info ad7172_2_device_info = { .name = "ad7172-2", .id = AD7172_2_ID, - .num_inputs = 5, + .num_voltage_in = 5, .num_channels = 4, .num_configs = 4, .num_gpios = 2, @@ -223,7 +367,7 @@ static const struct ad7173_device_info ad7172_2_device_info = { static const struct ad7173_device_info ad7172_4_device_info = { .name = "ad7172-4", .id = AD7172_4_ID, - .num_inputs = 9, + .num_voltage_in = 9, .num_channels = 8, .num_configs = 8, .num_gpios = 4, @@ -238,7 +382,7 @@ static const struct ad7173_device_info ad7172_4_device_info = { static const struct ad7173_device_info ad7173_8_device_info = { .name = "ad7173-8", .id = AD7173_ID, - .num_inputs = 17, + .num_voltage_in = 17, .num_channels = 16, .num_configs = 8, .num_gpios = 4, @@ -254,7 +398,7 @@ static const struct ad7173_device_info ad7173_8_device_info = { static const struct ad7173_device_info ad7175_2_device_info = { .name = "ad7175-2", .id = AD7175_2_ID, - .num_inputs = 5, + .num_voltage_in = 5, .num_channels = 4, .num_configs = 4, .num_gpios = 2, @@ -270,7 +414,7 @@ static const struct ad7173_device_info ad7175_2_device_info = { static const struct ad7173_device_info ad7175_8_device_info = { .name = "ad7175-8", .id = AD7175_8_ID, - .num_inputs = 17, + .num_voltage_in = 17, .num_channels = 16, .num_configs = 8, .num_gpios = 4, @@ -287,7 +431,7 @@ static const struct ad7173_device_info ad7175_8_device_info = { static const struct ad7173_device_info ad7176_2_device_info = { .name = "ad7176-2", .id = AD7176_ID, - .num_inputs = 5, + .num_voltage_in = 5, .num_channels = 4, .num_configs = 4, .num_gpios = 2, @@ -300,7 +444,7 @@ static const struct ad7173_device_info ad7176_2_device_info = { static const struct ad7173_device_info ad7177_2_device_info = { .name = "ad7177-2", .id = AD7177_ID, - .num_inputs = 5, + .num_voltage_in = 5, .num_channels = 4, .num_configs = 4, .num_gpios = 2, @@ -353,6 +497,15 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, return 0; } +static int ad4111_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) +{ + *mask = AD4111_GPO01_DATA(offset); + *reg = base; + return 0; +} + static void ad7173_gpio_disable(void *data) { struct ad7173_state *st = data; @@ -385,7 +538,10 @@ static int ad7173_gpio_init(struct ad7173_state *st) gpio_regmap.regmap = st->reg_gpiocon_regmap; gpio_regmap.ngpio = st->info->num_gpios; gpio_regmap.reg_set_base = AD7173_REG_GPIO; - gpio_regmap.reg_mask_xlate = ad7173_mask_xlate; + if (st->info->higher_gpio_bits) + gpio_regmap.reg_mask_xlate = ad4111_mask_xlate; + else + gpio_regmap.reg_mask_xlate = ad7173_mask_xlate; st->gpio_regmap = devm_gpio_regmap_register(dev, &gpio_regmap); ret = PTR_ERR_OR_ZERO(st->gpio_regmap); @@ -682,18 +838,33 @@ static int ad7173_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if (chan->type == IIO_TEMP) { + + switch (chan->type) { + case IIO_TEMP: temp = AD7173_VOLTAGE_INT_REF_uV * MILLI; temp /= AD7173_TEMP_SENSIIVITY_uV_per_C; *val = temp; *val2 = chan->scan_type.realbits; - } else { + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_VOLTAGE: *val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel); *val2 = chan->scan_type.realbits - !!(ch->cfg.bipolar); + + if (chan->channel < st->info->num_voltage_in_div) + *val *= AD4111_DIVIDER_RATIO; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CURRENT: + *val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel); + *val /= AD4111_SHUNT_RESISTOR_OHM; + *val2 = chan->scan_type.realbits - ch->cfg.bipolar; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; } - return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: - if (chan->type == IIO_TEMP) { + + switch (chan->type) { + case IIO_TEMP: /* 0 Kelvin -> raw sample */ temp = -ABSOLUTE_ZERO_MILLICELSIUS; temp *= AD7173_TEMP_SENSIIVITY_uV_per_C; @@ -702,10 +873,14 @@ static int ad7173_read_raw(struct iio_dev *indio_dev, AD7173_VOLTAGE_INT_REF_uV * MILLI); *val = -temp; - } else { + return IIO_VAL_INT; + case IIO_VOLTAGE: + case IIO_CURRENT: *val = -BIT(chan->scan_type.realbits - 1); + return IIO_VAL_INT; + default: + return -EINVAL; } - return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: reg = st->channels[chan->address].cfg.odr; @@ -926,6 +1101,23 @@ static int ad7173_register_clk_provider(struct iio_dev *indio_dev) &st->int_clk_hw); } +static int ad4111_validate_current_ain(struct ad7173_state *st, + const unsigned int ain[AD7173_NO_AINS_PER_CHANNEL]) +{ + struct device *dev = &st->sd.spi->dev; + + if (!st->info->has_current_inputs) + return dev_err_probe(dev, -EINVAL, + "Model %s does not support current channels\n", + st->info->name); + + if (ain[0] >= ARRAY_SIZE(ad4111_current_channel_config)) + return dev_err_probe(dev, -EINVAL, + "For current channels single-channel must be <[0-3]>\n"); + + return 0; +} + static int ad7173_validate_voltage_ain_inputs(struct ad7173_state *st, unsigned int ain0, unsigned int ain1) { @@ -937,14 +1129,33 @@ static int ad7173_validate_voltage_ain_inputs(struct ad7173_state *st, st->info->has_pow_supply_monitoring) return 0; - special_input0 = AD7173_IS_REF_INPUT(ain0); - special_input1 = AD7173_IS_REF_INPUT(ain1); + special_input0 = AD7173_IS_REF_INPUT(ain0) || + (ain0 == AD4111_VINCOM_INPUT && st->info->has_vincom_input); + special_input1 = AD7173_IS_REF_INPUT(ain1) || + (ain1 == AD4111_VINCOM_INPUT && st->info->has_vincom_input); + + if ((ain0 >= st->info->num_voltage_in && !special_input0) || + (ain1 >= st->info->num_voltage_in && !special_input1)) { + if (ain0 == AD4111_VINCOM_INPUT || ain1 == AD4111_VINCOM_INPUT) + return dev_err_probe(dev, -EINVAL, + "VINCOM not supported for %s\n", st->info->name); - if ((ain0 >= st->info->num_inputs && !special_input0) || - (ain1 >= st->info->num_inputs && !special_input1)) return dev_err_probe(dev, -EINVAL, "Input pin number out of range for pair (%d %d).\n", ain0, ain1); + } + + if (AD4111_IS_VINCOM_MISMATCH(ain0, ain1) || + AD4111_IS_VINCOM_MISMATCH(ain1, ain0)) + return dev_err_probe(dev, -EINVAL, + "VINCOM must be paired with inputs having divider.\n"); + + if (!special_input0 && !special_input1 && + ((ain0 >= st->info->num_voltage_in_div) != + (ain1 >= st->info->num_voltage_in_div))) + return dev_err_probe(dev, -EINVAL, + "Both inputs must either have a voltage divider or not have: (%d %d).\n", + ain0, ain1); return 0; } @@ -977,7 +1188,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) struct device *dev = indio_dev->dev.parent; struct iio_chan_spec *chan_arr, *chan; unsigned int ain[AD7173_NO_AINS_PER_CHANNEL], chan_index = 0; - int ref_sel, ret, num_channels; + int ref_sel, ret, is_current_chan, num_channels; num_channels = device_get_child_node_count(dev); @@ -1024,15 +1235,38 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) device_for_each_child_node_scoped(dev, child) { chan = &chan_arr[chan_index]; + *chan = ad7173_channel_template; chan_st_priv = &chans_st_arr[chan_index]; ret = fwnode_property_read_u32_array(child, "diff-channels", ain, ARRAY_SIZE(ain)); - if (ret) - return ret; + if (ret) { + ret = fwnode_property_read_u32(child, "single-channel", + ain); + if (ret) + return dev_err_probe(dev, ret, + "Channel must define one of diff-channels or single-channel.\n"); - ret = ad7173_validate_voltage_ain_inputs(st, ain[0], ain[1]); - if (ret) - return ret; + is_current_chan = fwnode_property_read_bool(child, "adi,current-channel"); + } else { + chan->differential = true; + } + + if (is_current_chan) { + ret = ad4111_validate_current_ain(st, ain); + if (ret) + return ret; + } else { + if (!chan->differential) { + ret = fwnode_property_read_u32(child, + "common-mode-channel", ain + 1); + if (ret) + return dev_err_probe(dev, ret, + "common-mode-channel must be defined for single-ended channels.\n"); + } + ret = ad7173_validate_voltage_ain_inputs(st, ain[0], ain[1]); + if (ret) + return ret; + } ret = fwnode_property_match_property_string(child, "adi,reference-select", @@ -1051,14 +1285,9 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) st->adc_mode |= AD7173_ADC_MODE_REF_EN; chan_st_priv->cfg.ref_sel = ref_sel; - *chan = ad7173_channel_template; chan->address = chan_index; chan->scan_index = chan_index; chan->channel = ain[0]; - chan->channel2 = ain[1]; - chan->differential = true; - - chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]); chan_st_priv->chan_reg = chan_index; chan_st_priv->cfg.input_buf = st->info->has_input_buf; chan_st_priv->cfg.odr = 0; @@ -1067,6 +1296,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) if (chan_st_priv->cfg.bipolar) chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET); + if (is_current_chan) { + chan->type = IIO_CURRENT; + chan->differential = false; + chan->channel2 = 0; + chan_st_priv->ain = ad4111_current_channel_config[ain[0]]; + } else { + chan_st_priv->cfg.input_buf = st->info->has_input_buf; + chan->channel2 = ain[1]; + chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]); + } + chan_index++; } return 0; @@ -1193,6 +1433,11 @@ static int ad7173_probe(struct spi_device *spi) } static const struct of_device_id ad7173_of_match[] = { + { .compatible = "ad4111", .data = &ad4111_device_info }, + { .compatible = "ad4112", .data = &ad4112_device_info }, + { .compatible = "ad4114", .data = &ad4114_device_info }, + { .compatible = "ad4115", .data = &ad4115_device_info }, + { .compatible = "ad4116", .data = &ad4116_device_info }, { .compatible = "adi,ad7172-2", .data = &ad7172_2_device_info }, { .compatible = "adi,ad7172-4", .data = &ad7172_4_device_info }, { .compatible = "adi,ad7173-8", .data = &ad7173_8_device_info }, @@ -1205,6 +1450,11 @@ static const struct of_device_id ad7173_of_match[] = { MODULE_DEVICE_TABLE(of, ad7173_of_match); static const struct spi_device_id ad7173_id_table[] = { + { "ad4111", (kernel_ulong_t)&ad4111_device_info }, + { "ad4112", (kernel_ulong_t)&ad4112_device_info }, + { "ad4114", (kernel_ulong_t)&ad4114_device_info }, + { "ad4115", (kernel_ulong_t)&ad4115_device_info }, + { "ad4116", (kernel_ulong_t)&ad4116_device_info }, { "ad7172-2", (kernel_ulong_t)&ad7172_2_device_info }, { "ad7172-4", (kernel_ulong_t)&ad7172_4_device_info }, { "ad7173-8", (kernel_ulong_t)&ad7173_8_device_info }, @@ -1229,5 +1479,5 @@ module_spi_driver(ad7173_driver); MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_AUTHOR("Dumitru Ceclan "); -MODULE_DESCRIPTION("Analog Devices AD7172/AD7173/AD7175/AD7176 ADC driver"); +MODULE_DESCRIPTION("Analog Devices AD7173 and similar ADC driver"); MODULE_LICENSE("GPL"); From 1b3d0fc286030193f66eabc46d3284994c34770f Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:41 -0400 Subject: [PATCH 167/330] iio: accel: fxls8962af-core: Make use of regmap_set_bits(), regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-1-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/fxls8962af-core.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 4fbc01bda62e..d25e31613413 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -228,8 +228,8 @@ static int fxls8962af_power_off(struct fxls8962af_data *data) static int fxls8962af_standby(struct fxls8962af_data *data) { - return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, - FXLS8962AF_SENS_CONFIG1_ACTIVE, 0); + return regmap_clear_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_ACTIVE); } static int fxls8962af_active(struct fxls8962af_data *data) @@ -785,9 +785,8 @@ static int fxls8962af_reset(struct fxls8962af_data *data) unsigned int reg; int ret; - ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, - FXLS8962AF_SENS_CONFIG1_RST, - FXLS8962AF_SENS_CONFIG1_RST); + ret = regmap_set_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_RST); if (ret) return ret; @@ -830,9 +829,8 @@ static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev) fxls8962af_standby(data); /* Enable buffer interrupt */ - ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, - FXLS8962AF_INT_EN_BUF_EN, - FXLS8962AF_INT_EN_BUF_EN); + ret = regmap_set_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN); if (ret) return ret; @@ -851,8 +849,8 @@ static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev) fxls8962af_standby(data); /* Disable buffer interrupt */ - ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, - FXLS8962AF_INT_EN_BUF_EN, 0); + ret = regmap_clear_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN); if (ret) return ret; From 41aea490533c172ed0cd4875198d9f74865fca5d Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:42 -0400 Subject: [PATCH 168/330] iio: accel: kxsd9: Make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Reviewed-by: Linus Walleij Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-2-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxsd9.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index ba99649fe195..70dfd6e354db 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -370,10 +370,7 @@ static int kxsd9_power_down(struct kxsd9_state *st) * make sure we conserve power even if there are others users on the * regulators. */ - ret = regmap_update_bits(st->map, - KXSD9_REG_CTRL_B, - KXSD9_CTRL_B_ENABLE, - 0); + ret = regmap_clear_bits(st->map, KXSD9_REG_CTRL_B, KXSD9_CTRL_B_ENABLE); if (ret) return ret; From 4ed403d8230b9c316b8ab867d8bc15fc9201af16 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:43 -0400 Subject: [PATCH 169/330] iio: accel: msa311: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-3-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/msa311.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index b8ddbfd98f11..4cdbf5424a53 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -1034,10 +1034,10 @@ static int msa311_chip_init(struct msa311_priv *msa311) "failed to unmap map0/map1 interrupts\n"); /* Disable all axes by default */ - err = regmap_update_bits(msa311->regs, MSA311_ODR_REG, - MSA311_GENMASK(F_X_AXIS_DIS) | - MSA311_GENMASK(F_Y_AXIS_DIS) | - MSA311_GENMASK(F_Z_AXIS_DIS), 0); + err = regmap_clear_bits(msa311->regs, MSA311_ODR_REG, + MSA311_GENMASK(F_X_AXIS_DIS) | + MSA311_GENMASK(F_Y_AXIS_DIS) | + MSA311_GENMASK(F_Z_AXIS_DIS)); if (err) return dev_err_probe(dev, err, "can't enable all axes\n"); From 52248aea53e1ad51942d4a425a5db7371f8d5e89 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:44 -0400 Subject: [PATCH 170/330] iio: adc: ad4130: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Reviewed-by: Nuno Sa Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-4-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index aaf1fb0ac447..e134d6497827 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -1883,8 +1883,8 @@ static int ad4130_setup(struct iio_dev *indio_dev) if (ret) return ret; - ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG, - AD4130_FIFO_CONTROL_HEADER_MASK, 0); + ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, + AD4130_FIFO_CONTROL_HEADER_MASK); if (ret) return ret; From 4796fed269f87d0ee5ca8558710bd467fdaf75fb Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:45 -0400 Subject: [PATCH 171/330] iio: adc: axp20x_adc: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-5-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/axp20x_adc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 913ea9e5d9c5..b487e577befb 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -991,9 +991,8 @@ static int axp20x_probe(struct platform_device *pdev) regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask); if (info->data->adc_en2_mask) - regmap_update_bits(info->regmap, AXP20X_ADC_EN2, - info->data->adc_en2_mask, - info->data->adc_en2_mask); + regmap_set_bits(info->regmap, AXP20X_ADC_EN2, + info->data->adc_en2_mask); /* Configure ADCs rate */ info->data->adc_rate(info, 100); From 6e195872020b8a34d713db91bb9a9bd4fc7a2ead Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:46 -0400 Subject: [PATCH 172/330] iio: adc: axp288_adc: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-6-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/axp288_adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 49fff1cabd0d..f135cf2362df 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -247,8 +247,8 @@ static int axp288_adc_initialize(struct axp288_adc_info *info) return ret; /* Turn on the ADC for all channels except TS, leave TS as is */ - return regmap_update_bits(info->regmap, AXP20X_ADC_EN1, - AXP288_ADC_EN_MASK, AXP288_ADC_EN_MASK); + return regmap_set_bits(info->regmap, AXP20X_ADC_EN1, + AXP288_ADC_EN_MASK); } static const struct iio_info axp288_adc_iio_info = { From a0e3573e4b152d780a2e3b3cf9577e32e25c585a Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:47 -0400 Subject: [PATCH 173/330] iio: adc: bcm_iproc_adc: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-7-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/bcm_iproc_adc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 5bc514bd5ebc..6bc149c51414 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -357,8 +357,8 @@ static int iproc_adc_enable(struct iio_dev *indio_dev) int ret; /* Set i_amux = 3b'000, select channel 0 */ - ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL, - IPROC_ADC_CHANNEL_SEL_MASK, 0); + ret = regmap_clear_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL, + IPROC_ADC_CHANNEL_SEL_MASK); if (ret) { dev_err(&indio_dev->dev, "failed to write IPROC_ANALOG_CONTROL %d\n", ret); @@ -543,8 +543,8 @@ static int iproc_adc_probe(struct platform_device *pdev) if (adc_priv->irqno < 0) return adc_priv->irqno; - ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2, - IPROC_ADC_AUXIN_SCAN_ENA, 0); + ret = regmap_clear_bits(adc_priv->regmap, IPROC_REGCTL2, + IPROC_ADC_AUXIN_SCAN_ENA); if (ret) { dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret); return ret; From c46a955a26faef570f02160444aa7b2cbfd7ad49 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:49 -0400 Subject: [PATCH 174/330] iio: adc: cpcap-adc: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-9-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/cpcap-adc.c | 46 +++++++++++++++---------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index b6c4ef70484e..c218acf6c9c6 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -385,9 +385,8 @@ static irqreturn_t cpcap_adc_irq_thread(int irq, void *data) struct cpcap_adc *ddata = iio_priv(indio_dev); int error; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, - CPCAP_BIT_ADTRIG_DIS); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return IRQ_NONE; @@ -424,23 +423,19 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata, if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ATOX_PS_FACTOR | - CPCAP_BIT_ADC_PS_FACTOR1 | - CPCAP_BIT_ADC_PS_FACTOR0, - 0); + error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ATOX_PS_FACTOR | + CPCAP_BIT_ADC_PS_FACTOR1 | + CPCAP_BIT_ADC_PS_FACTOR0); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, - CPCAP_BIT_ADTRIG_DIS); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ASC, - CPCAP_BIT_ASC); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, CPCAP_BIT_ASC); if (error) return; @@ -455,8 +450,8 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata, dev_err(ddata->dev, "Timeout waiting for calibration to complete\n"); - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1, - CPCAP_BIT_CAL_MODE, 0); + error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC1, + CPCAP_BIT_CAL_MODE); if (error) return; } @@ -602,26 +597,23 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata, return; if (req->timing == CPCAP_ADC_TIMING_IMM) { - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, - CPCAP_BIT_ADTRIG_DIS); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ASC, - CPCAP_BIT_ASC); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ASC); if (error) return; } else { - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_ONESHOT, - CPCAP_BIT_ADTRIG_ONESHOT); + error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_ONESHOT); if (error) return; - error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, - CPCAP_BIT_ADTRIG_DIS, 0); + error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2, + CPCAP_BIT_ADTRIG_DIS); if (error) return; } From b040275a7705aca4c307f5fd2c8b26d2bf9f0744 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:50 -0400 Subject: [PATCH 175/330] iio: adc: fsl-imx25-gcq: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-10-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/fsl-imx25-gcq.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index b680690631db..b3f037510e35 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -87,13 +87,13 @@ static irqreturn_t mx25_gcq_irq(int irq, void *data) regmap_read(priv->regs, MX25_ADCQ_SR, &stats); if (stats & MX25_ADCQ_SR_EOQ) { - regmap_update_bits(priv->regs, MX25_ADCQ_MR, - MX25_ADCQ_MR_EOQ_IRQ, MX25_ADCQ_MR_EOQ_IRQ); + regmap_set_bits(priv->regs, MX25_ADCQ_MR, + MX25_ADCQ_MR_EOQ_IRQ); complete(&priv->completed); } /* Disable conversion queue run */ - regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0); + regmap_clear_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS); /* Acknowledge all possible irqs */ regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR | @@ -115,11 +115,10 @@ static int mx25_gcq_get_raw_value(struct device *dev, regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0, MX25_ADCQ_ITEM(0, chan->channel)); - regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ, 0); + regmap_clear_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ); /* Trigger queue for one run */ - regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, - MX25_ADCQ_CR_FQS); + regmap_set_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS); time_left = wait_for_completion_interruptible_timeout( &priv->completed, MX25_GCQ_TIMEOUT); @@ -272,9 +271,8 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, MX25_ADCQ_CFG_REFN_MASK, refp | refn); } - regmap_update_bits(priv->regs, MX25_ADCQ_CR, - MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST, - MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST); + regmap_set_bits(priv->regs, MX25_ADCQ_CR, + MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST); regmap_write(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK | MX25_ADCQ_CR_QSM_FQS); From a47d466d7c8d7a44b851e3a65980b0bebedc7293 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:51 -0400 Subject: [PATCH 176/330] iio: adc: ina2xx-adc: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-11-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 9e52207352fb..727e390bd979 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -1046,8 +1046,7 @@ static void ina2xx_remove(struct i2c_client *client) iio_device_unregister(indio_dev); /* Powerdown */ - ret = regmap_update_bits(chip->regmap, INA2XX_CONFIG, - INA2XX_MODE_MASK, 0); + ret = regmap_clear_bits(chip->regmap, INA2XX_CONFIG, INA2XX_MODE_MASK); if (ret) dev_warn(&client->dev, "Failed to power down device (%pe)\n", ERR_PTR(ret)); From 0544a8c2fb32c9e7534b787f4888ccd75990e67e Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:52 -0400 Subject: [PATCH 177/330] iio: adc: intel_mrfld_adc: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-12-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/intel_mrfld_adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index c7f40ae6e608..0590a126f321 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -81,8 +81,8 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev, reinit_completion(&adc->completion); - regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0); - regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0); + regmap_clear_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL); + regmap_clear_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC); ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req, !(req & BCOVE_GPADCREQ_BUSY), From 72df0511c1d9e0435964118c41a202edbd77ba54 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:53 -0400 Subject: [PATCH 178/330] iio: adc: meson_saradc: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Reviewed-by: George Stark Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-13-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 101 ++++++++++++++------------------- 1 file changed, 44 insertions(+), 57 deletions(-) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 13b473d8c6c7..e16b0e28974e 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -546,35 +546,31 @@ static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev) reinit_completion(&priv->done); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_FIFO_IRQ_EN, - MESON_SAR_ADC_REG0_FIFO_IRQ_EN); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, - MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLING_START, - MESON_SAR_ADC_REG0_SAMPLING_START); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_START); } static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLING_STOP, - MESON_SAR_ADC_REG0_SAMPLING_STOP); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_STOP); /* wait until all modules are stopped */ meson_sar_adc_wait_busy_clear(indio_dev); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); } static int meson_sar_adc_lock(struct iio_dev *indio_dev) @@ -586,9 +582,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) { /* prevent BL30 from using the SAR ADC while we are using it */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); udelay(1); @@ -614,8 +609,8 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) /* allow BL30 to use the SAR ADC again */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); mutex_unlock(&priv->lock); } @@ -869,17 +864,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) * disable this bit as seems to be only relevant for Meson6 (based * on the vendor driver), which we don't support at the moment. */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL); /* disable all channels by default */ regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY, - MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); /* delay between two samples = (10+1) * 1uS */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, @@ -914,21 +908,17 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, regval); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW, - MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW); /* * set up the input channel muxes in MESON_SAR_ADC_AUX_SW @@ -944,12 +934,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval); if (priv->temperature_sensor_calibrated) { - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE1, - MESON_SAR_ADC_DELTA_10_TS_REVE1); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE0, - MESON_SAR_ADC_DELTA_10_TS_REVE0); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE1); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE0); /* * set bits [3:0] of the TSC (temperature sensor coefficient) @@ -976,10 +964,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) regval); } } else { - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE1, 0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, - MESON_SAR_ADC_DELTA_10_TS_REVE0, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE1); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE0); } regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN, @@ -1062,9 +1050,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) meson_sar_adc_set_bandgap(indio_dev, true); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_ADC_EN, - MESON_SAR_ADC_REG3_ADC_EN); + regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN); udelay(5); @@ -1079,8 +1066,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) return 0; err_adc_clk: - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN); meson_sar_adc_set_bandgap(indio_dev, false); regulator_disable(priv->vref); err_vref: @@ -1104,8 +1091,8 @@ static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev) clk_disable_unprepare(priv->adc_clk); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, - MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN); meson_sar_adc_set_bandgap(indio_dev, false); From e3007f6d595c6f28e809bb7dd9d42ee58e0b3bed Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:54 -0400 Subject: [PATCH 179/330] iio: adc: mp2629_adc: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-14-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mp2629_adc.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 7c66c2cd5be2..5f672765d4a2 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -131,9 +131,8 @@ static int mp2629_adc_probe(struct platform_device *pdev) info->dev = dev; platform_set_drvdata(pdev, indio_dev); - ret = regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_START | MP2629_ADC_CONTINUOUS, - MP2629_ADC_START | MP2629_ADC_CONTINUOUS); + ret = regmap_set_bits(info->regmap, MP2629_REG_ADC_CTRL, + MP2629_ADC_START | MP2629_ADC_CONTINUOUS); if (ret) { dev_err(dev, "adc enable fail: %d\n", ret); return ret; @@ -163,10 +162,9 @@ fail_map_unregister: iio_map_array_unregister(indio_dev); fail_disable: - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_CONTINUOUS, 0); - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_START, 0); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, + MP2629_ADC_CONTINUOUS); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START); return ret; } @@ -180,10 +178,9 @@ static void mp2629_adc_remove(struct platform_device *pdev) iio_map_array_unregister(indio_dev); - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_CONTINUOUS, 0); - regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, - MP2629_ADC_START, 0); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, + MP2629_ADC_CONTINUOUS); + regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START); } static const struct of_device_id mp2629_adc_of_match[] = { From 5dcd6eb3ef580e7d05fac5335df7160ae45075f3 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:48 -0400 Subject: [PATCH 180/330] iio: adc: berlin2-adc: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240617-review-v3-8-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index a4e7c7eff5ac..4cdddc6e36e9 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -129,8 +129,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) msecs_to_jiffies(1000)); /* Disable the interrupts */ - regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS, - BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_ADC_STATUS, + BERLIN2_SM_ADC_STATUS_INT_EN(channel)); if (ret == 0) ret = -ETIMEDOUT; @@ -139,8 +139,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) return ret; } - regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, - BERLIN2_SM_CTRL_ADC_START, 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_CTRL, + BERLIN2_SM_CTRL_ADC_START); data = priv->data; priv->data_available = false; @@ -180,8 +180,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) msecs_to_jiffies(1000)); /* Disable interrupts */ - regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS, - BERLIN2_SM_TSEN_STATUS_INT_EN, 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS, + BERLIN2_SM_TSEN_STATUS_INT_EN); if (ret == 0) ret = -ETIMEDOUT; @@ -190,8 +190,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) return ret; } - regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, - BERLIN2_SM_TSEN_CTRL_START, 0); + regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, + BERLIN2_SM_TSEN_CTRL_START); data = priv->data; priv->data_available = false; @@ -284,8 +284,7 @@ static const struct iio_info berlin2_adc_info = { static void berlin2_adc_powerdown(void *regmap) { - regmap_update_bits(regmap, BERLIN2_SM_CTRL, - BERLIN2_SM_CTRL_ADC_POWER, 0); + regmap_clear_bits(regmap, BERLIN2_SM_CTRL, BERLIN2_SM_CTRL_ADC_POWER); } @@ -339,9 +338,8 @@ static int berlin2_adc_probe(struct platform_device *pdev) indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels); /* Power up the ADC */ - regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, - BERLIN2_SM_CTRL_ADC_POWER, - BERLIN2_SM_CTRL_ADC_POWER); + regmap_set_bits(priv->regmap, BERLIN2_SM_CTRL, + BERLIN2_SM_CTRL_ADC_POWER); ret = devm_add_action_or_reset(&pdev->dev, berlin2_adc_powerdown, priv->regmap); From 550c246dd3111c6ba709beb523411907ed1ae695 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:55 -0400 Subject: [PATCH 181/330] iio: adc: qcom-spmi-rradc: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-15-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-spmi-rradc.c | 50 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c index 56a713766954..1402df68dd52 100644 --- a/drivers/iio/adc/qcom-spmi-rradc.c +++ b/drivers/iio/adc/qcom-spmi-rradc.c @@ -358,15 +358,15 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip) int ret; /* Clear channel log */ - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG, - RR_ADC_LOG_CLR_CTRL, RR_ADC_LOG_CLR_CTRL); + ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_LOG, + RR_ADC_LOG_CLR_CTRL); if (ret < 0) { dev_err(chip->dev, "log ctrl update to clear failed:%d\n", ret); return ret; } - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG, - RR_ADC_LOG_CLR_CTRL, 0); + ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_LOG, + RR_ADC_LOG_CLR_CTRL); if (ret < 0) { dev_err(chip->dev, "log ctrl update to not clear failed:%d\n", ret); @@ -374,9 +374,8 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip) } /* Switch to continuous mode */ - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL, - RR_ADC_CTL_CONTINUOUS_SEL, - RR_ADC_CTL_CONTINUOUS_SEL); + ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_CTL, + RR_ADC_CTL_CONTINUOUS_SEL); if (ret < 0) dev_err(chip->dev, "Update to continuous mode failed:%d\n", ret); @@ -389,8 +388,8 @@ static int rradc_disable_continuous_mode(struct rradc_chip *chip) int ret; /* Switch to non continuous mode */ - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL, - RR_ADC_CTL_CONTINUOUS_SEL, 0); + ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_CTL, + RR_ADC_CTL_CONTINUOUS_SEL); if (ret < 0) dev_err(chip->dev, "Update to non-continuous mode failed:%d\n", ret); @@ -434,8 +433,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip, return -EINVAL; } - ret = regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr, - chan->trigger_mask, chan->trigger_mask); + ret = regmap_set_bits(chip->regmap, chip->base + chan->trigger_addr, + chan->trigger_mask); if (ret < 0) { dev_err(chip->dev, "Failed to apply trigger for channel '%s' ret=%d\n", @@ -469,8 +468,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip, rradc_disable_continuous_mode(chip); disable_trigger: - regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr, - chan->trigger_mask, 0); + regmap_clear_bits(chip->regmap, chip->base + chan->trigger_addr, + chan->trigger_mask); return ret; } @@ -481,17 +480,16 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip, { int ret; - ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, - RR_ADC_BATT_ID_CTRL_CHANNEL_CONV, - RR_ADC_BATT_ID_CTRL_CHANNEL_CONV); + ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, + RR_ADC_BATT_ID_CTRL_CHANNEL_CONV); if (ret < 0) { dev_err(chip->dev, "Enabling BATT ID channel failed:%d\n", ret); return ret; } - ret = regmap_update_bits(chip->regmap, - chip->base + RR_ADC_BATT_ID_TRIGGER, - RR_ADC_TRIGGER_CTL, RR_ADC_TRIGGER_CTL); + ret = regmap_set_bits(chip->regmap, + chip->base + RR_ADC_BATT_ID_TRIGGER, + RR_ADC_TRIGGER_CTL); if (ret < 0) { dev_err(chip->dev, "BATT_ID trigger set failed:%d\n", ret); goto out_disable_batt_id; @@ -500,12 +498,12 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip, ret = rradc_read_status_in_cont_mode(chip, chan_address); /* Reset registers back to default values */ - regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER, - RR_ADC_TRIGGER_CTL, 0); + regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER, + RR_ADC_TRIGGER_CTL); out_disable_batt_id: - regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, - RR_ADC_BATT_ID_CTRL_CHANNEL_CONV, 0); + regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL, + RR_ADC_BATT_ID_CTRL_CHANNEL_CONV); return ret; } @@ -965,9 +963,9 @@ static int rradc_probe(struct platform_device *pdev) if (batt_id_delay >= 0) { batt_id_delay = FIELD_PREP(BATT_ID_SETTLE_MASK, batt_id_delay); - ret = regmap_update_bits(chip->regmap, - chip->base + RR_ADC_BATT_ID_CFG, - batt_id_delay, batt_id_delay); + ret = regmap_set_bits(chip->regmap, + chip->base + RR_ADC_BATT_ID_CFG, + batt_id_delay); if (ret < 0) { dev_err(chip->dev, "BATT_ID settling time config failed:%d\n", From cb3f8e0c636a0c221172ae49bbefc9e99dbe9711 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:56 -0400 Subject: [PATCH 182/330] iio: adc: rn5t618-adc: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-16-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rn5t618-adc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index 6bf32907f01d..ce5f3011fe00 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -137,9 +137,8 @@ static int rn5t618_adc_read(struct iio_dev *iio_dev, init_completion(&adc->conv_completion); /* single conversion */ - ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3, - RN5T618_ADCCNT3_GODONE, - RN5T618_ADCCNT3_GODONE); + ret = regmap_set_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3, + RN5T618_ADCCNT3_GODONE); if (ret < 0) return ret; From 059fbfaa5d68c8d35974e567593fbb5e8f5c69f3 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:57 -0400 Subject: [PATCH 183/330] iio: adc: sc27xx_adc: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Reviewed-by: Baolin Wang Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-17-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/sc27xx_adc.c | 41 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c index b4a2e057d80f..2535c2c3e60b 100644 --- a/drivers/iio/adc/sc27xx_adc.c +++ b/drivers/iio/adc/sc27xx_adc.c @@ -508,13 +508,13 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, } } - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, - SC27XX_ADC_EN, SC27XX_ADC_EN); + ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_EN); if (ret) goto regulator_restore; - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, - SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); + ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, + SC27XX_ADC_IRQ_CLR); if (ret) goto disable_adc; @@ -537,8 +537,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, if (ret) goto disable_adc; - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, - SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN); + ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_CHN_RUN); if (ret) goto disable_adc; @@ -559,8 +559,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, value &= SC27XX_ADC_DATA_MASK; disable_adc: - regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, - SC27XX_ADC_EN, 0); + regmap_clear_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_EN); regulator_restore: if ((data->var_data->set_volref) && (channel == 30 || channel == 31)) { ret_volref = regulator_set_voltage(data->volref, @@ -765,15 +765,14 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data) { int ret; - ret = regmap_update_bits(data->regmap, data->var_data->module_en, - SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN); + ret = regmap_set_bits(data->regmap, data->var_data->module_en, + SC27XX_MODULE_ADC_EN); if (ret) return ret; /* Enable ADC work clock and controller clock */ - ret = regmap_update_bits(data->regmap, data->var_data->clk_en, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); + ret = regmap_set_bits(data->regmap, data->var_data->clk_en, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); if (ret) goto disable_adc; @@ -789,11 +788,11 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data) return 0; disable_clk: - regmap_update_bits(data->regmap, data->var_data->clk_en, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->clk_en, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); disable_adc: - regmap_update_bits(data->regmap, data->var_data->module_en, - SC27XX_MODULE_ADC_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->module_en, + SC27XX_MODULE_ADC_EN); return ret; } @@ -803,11 +802,11 @@ static void sc27xx_adc_disable(void *_data) struct sc27xx_adc_data *data = _data; /* Disable ADC work clock and controller clock */ - regmap_update_bits(data->regmap, data->var_data->clk_en, - SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->clk_en, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); - regmap_update_bits(data->regmap, data->var_data->module_en, - SC27XX_MODULE_ADC_EN, 0); + regmap_clear_bits(data->regmap, data->var_data->module_en, + SC27XX_MODULE_ADC_EN); } static const struct sc27xx_adc_variant_data sc2731_data = { From 25091987c1890a1e96df42bb30e81e77b10744b8 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:58 -0400 Subject: [PATCH 184/330] iio: adc: stm32-dfsdm-adc: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-18-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-adc.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 9a47d2c87f05..fabd654245f5 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -759,8 +759,7 @@ static int stm32_dfsdm_start_conv(struct iio_dev *indio_dev, return 0; filter_unconfigure: - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_CFG_MASK, 0); + regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK); stop_channels: stm32_dfsdm_stop_channel(indio_dev); @@ -774,8 +773,7 @@ static void stm32_dfsdm_stop_conv(struct iio_dev *indio_dev) stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); - regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_CFG_MASK, 0); + regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK); stm32_dfsdm_stop_channel(indio_dev); } @@ -951,16 +949,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) if (adc->nconv == 1 && !indio_dev->trig) { /* Enable regular DMA transfer*/ - ret = regmap_update_bits(adc->dfsdm->regmap, - DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK, - DFSDM_CR1_RDMAEN_MASK); + ret = regmap_set_bits(adc->dfsdm->regmap, + DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK); } else { /* Enable injected DMA transfer*/ - ret = regmap_update_bits(adc->dfsdm->regmap, - DFSDM_CR1(adc->fl_id), - DFSDM_CR1_JDMAEN_MASK, - DFSDM_CR1_JDMAEN_MASK); + ret = regmap_set_bits(adc->dfsdm->regmap, + DFSDM_CR1(adc->fl_id), + DFSDM_CR1_JDMAEN_MASK); } if (ret < 0) @@ -981,8 +977,8 @@ static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev) if (!adc->dma_chan) return; - regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0); + regmap_clear_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK); dmaengine_terminate_all(adc->dma_chan); } @@ -1305,9 +1301,8 @@ static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) if (status & DFSDM_ISR_ROVRF_MASK) { if (int_en & DFSDM_CR2_ROVRIE_MASK) dev_warn(&indio_dev->dev, "Overrun detected\n"); - regmap_update_bits(regmap, DFSDM_ICR(adc->fl_id), - DFSDM_ICR_CLRROVRF_MASK, - DFSDM_ICR_CLRROVRF_MASK); + regmap_set_bits(regmap, DFSDM_ICR(adc->fl_id), + DFSDM_ICR_CLRROVRF_MASK); } return IRQ_HANDLED; From 090510b902d9e474085989b32cdc8a6260a1ad13 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:49:59 -0400 Subject: [PATCH 185/330] iio: dac: ltc2688: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-19-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ltc2688.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c index c4b1ba30f935..af50d2a95898 100644 --- a/drivers/iio/dac/ltc2688.c +++ b/drivers/iio/dac/ltc2688.c @@ -860,9 +860,8 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref) /* bring device out of reset */ gpiod_set_value_cansleep(gpio, 0); } else { - ret = regmap_update_bits(st->regmap, LTC2688_CMD_CONFIG, - LTC2688_CONFIG_RST, - LTC2688_CONFIG_RST); + ret = regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG, + LTC2688_CONFIG_RST); if (ret) return ret; } From c1cf171365dcf383042cbea3e1c3475375c1e496 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:00 -0400 Subject: [PATCH 186/330] iio: dac: stm32-dac-core: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-20-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/stm32-dac-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index e150ac729154..2d567073996b 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -200,9 +200,8 @@ static int stm32_dac_core_resume(struct device *dev) if (priv->common.hfsel) { /* restore hfsel (maybe lost under low power state) */ - ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR, - STM32H7_DAC_CR_HFSEL, - STM32H7_DAC_CR_HFSEL); + ret = regmap_set_bits(priv->common.regmap, STM32_DAC_CR, + STM32H7_DAC_CR_HFSEL); if (ret) return ret; } From e5757bd8ceed272d133bdb79c8094b400a0743e5 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:01 -0400 Subject: [PATCH 187/330] iio: gyro: bmg160_core: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-21-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/bmg160_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 0e2eb0e98235..10728d5ccae3 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -285,8 +285,8 @@ static int bmg160_chip_init(struct bmg160_data *data) data->slope_thres = val; /* Set default interrupt mode */ - ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1, - BMG160_INT1_BIT_OD, 0); + ret = regmap_clear_bits(data->regmap, BMG160_REG_INT_EN_1, + BMG160_INT1_BIT_OD); if (ret < 0) { dev_err(dev, "Error updating bits in reg_int_en_1\n"); return ret; From eceddd01ebf94519df1620607930b3e29a647fda Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:02 -0400 Subject: [PATCH 188/330] iio: gyro: mpu3050-core: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-22-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/mpu3050-core.c | 35 +++++++++++++-------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index a791ba3a693a..35af68b41408 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -197,8 +197,8 @@ static int mpu3050_start_sampling(struct mpu3050 *mpu3050) int i; /* Reset */ - ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM, - MPU3050_PWR_MGM_RESET, MPU3050_PWR_MGM_RESET); + ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_RESET); if (ret) return ret; @@ -513,12 +513,9 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p) "FIFO overflow! Emptying and resetting FIFO\n"); fifo_overflow = true; /* Reset and enable the FIFO */ - ret = regmap_update_bits(mpu3050->map, - MPU3050_USR_CTRL, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST); + ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL, + MPU3050_USR_CTRL_FIFO_EN | + MPU3050_USR_CTRL_FIFO_RST); if (ret) { dev_info(mpu3050->dev, "error resetting FIFO\n"); goto out_trigger_unlock; @@ -799,10 +796,8 @@ static int mpu3050_hw_init(struct mpu3050 *mpu3050) u64 otp; /* Reset */ - ret = regmap_update_bits(mpu3050->map, - MPU3050_PWR_MGM, - MPU3050_PWR_MGM_RESET, - MPU3050_PWR_MGM_RESET); + ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_RESET); if (ret) return ret; @@ -872,8 +867,8 @@ static int mpu3050_power_up(struct mpu3050 *mpu3050) msleep(200); /* Take device out of sleep mode */ - ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM, - MPU3050_PWR_MGM_SLEEP, 0); + ret = regmap_clear_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_SLEEP); if (ret) { regulator_bulk_disable(ARRAY_SIZE(mpu3050->regs), mpu3050->regs); dev_err(mpu3050->dev, "error setting power mode\n"); @@ -895,8 +890,8 @@ static int mpu3050_power_down(struct mpu3050 *mpu3050) * then we would be wasting power unless we go to sleep mode * first. */ - ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM, - MPU3050_PWR_MGM_SLEEP, MPU3050_PWR_MGM_SLEEP); + ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM, + MPU3050_PWR_MGM_SLEEP); if (ret) dev_err(mpu3050->dev, "error putting to sleep\n"); @@ -997,11 +992,9 @@ static int mpu3050_drdy_trigger_set_state(struct iio_trigger *trig, return ret; /* Reset and enable the FIFO */ - ret = regmap_update_bits(mpu3050->map, MPU3050_USR_CTRL, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST, - MPU3050_USR_CTRL_FIFO_EN | - MPU3050_USR_CTRL_FIFO_RST); + ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL, + MPU3050_USR_CTRL_FIFO_EN | + MPU3050_USR_CTRL_FIFO_RST); if (ret) return ret; From 0c9f6639f588c8b628375b1a9279b2354cea5fd7 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:03 -0400 Subject: [PATCH 189/330] iio: health: afe4403: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-23-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/afe4403.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 1dbe48dae74e..52326dc521ac 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -422,9 +422,8 @@ static int afe4403_suspend(struct device *dev) struct afe4403_data *afe = iio_priv(indio_dev); int ret; - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, - AFE440X_CONTROL2_PDN_AFE); + ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; @@ -449,8 +448,8 @@ static int afe4403_resume(struct device *dev) return ret; } - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, 0); + ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; From 9d0142fc9e74b8c8a4b5a0f7d15ea6a69a4376e0 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:04 -0400 Subject: [PATCH 190/330] iio: health: afe4404: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-24-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/afe4404.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 390fbb6effaf..7f69baa1ed53 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -430,9 +430,8 @@ static int afe4404_suspend(struct device *dev) struct afe4404_data *afe = iio_priv(indio_dev); int ret; - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, - AFE440X_CONTROL2_PDN_AFE); + ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; @@ -457,8 +456,8 @@ static int afe4404_resume(struct device *dev) return ret; } - ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, - AFE440X_CONTROL2_PDN_AFE, 0); + ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2, + AFE440X_CONTROL2_PDN_AFE); if (ret) return ret; From 04f168577c79969a3c0e4b08e638ffb8b1afa711 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:05 -0400 Subject: [PATCH 191/330] iio: health: max30100: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-25-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/max30100.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 1dc0df21450d..e08d143a707c 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -363,9 +363,8 @@ static int max30100_get_temp(struct max30100_data *data, int *val) int ret; /* start acquisition */ - ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG, - MAX30100_REG_MODE_CONFIG_TEMP_EN, - MAX30100_REG_MODE_CONFIG_TEMP_EN); + ret = regmap_set_bits(data->regmap, MAX30100_REG_MODE_CONFIG, + MAX30100_REG_MODE_CONFIG_TEMP_EN); if (ret) return ret; From 513735883335a6435bf04a1c62330139496513c1 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:06 -0400 Subject: [PATCH 192/330] iio: health: max30102: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-26-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/max30102.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 6616729af5b7..07a343e35a81 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -448,9 +448,8 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en) } /* start acquisition */ - ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG, - MAX30102_REG_TEMP_CONFIG_TEMP_EN, - MAX30102_REG_TEMP_CONFIG_TEMP_EN); + ret = regmap_set_bits(data->regmap, MAX30102_REG_TEMP_CONFIG, + MAX30102_REG_TEMP_CONFIG_TEMP_EN); if (ret) goto out; From 0e59dc9e6bfb6bf5fb978400d43b86cd95c0affd Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:07 -0400 Subject: [PATCH 193/330] iio: imu: inv_icm42600: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Jean-Baptiste Maneyrol Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-27-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c | 14 ++++++-------- drivers/iio/imu/inv_icm42600/inv_icm42600_core.c | 9 ++++----- drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c | 4 ++-- drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c | 4 ++-- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index a8cf74c84c3c..aae7c56481a3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -274,9 +274,8 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st) /* restore watermark interrupt */ if (restore) { - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); + ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); if (ret) return ret; } @@ -318,9 +317,8 @@ static int inv_icm42600_buffer_postenable(struct iio_dev *indio_dev) } /* set FIFO threshold interrupt */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); + ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); if (ret) goto out_unlock; @@ -375,8 +373,8 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev) goto out_unlock; /* disable FIFO threshold interrupt */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, - INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_SOURCE0, + INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN); if (ret) goto out_unlock; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 61f1f6d4c421..c3924cc6190e 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -496,9 +496,8 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st, return ret; /* sensor data in big-endian (default) */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, - INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN, - INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN); + ret = regmap_set_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN); if (ret) return ret; @@ -603,8 +602,8 @@ static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq, return ret; /* Deassert async reset for proper INT pin operation (cf datasheet) */ - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, - INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, + INV_ICM42600_INT_CONFIG1_ASYNC_RESET); if (ret) return ret; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 8d33504d770f..ebb31b385881 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -28,8 +28,8 @@ static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) INV_ICM42600_INTF_CONFIG6_MASK, INV_ICM42600_INTF_CONFIG6_I3C_EN); - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, - INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, + INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY); if (ret) return ret; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index cc2bf1799a46..eae5ff7a3cc1 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -27,8 +27,8 @@ static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st) if (ret) return ret; - ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, - INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, + INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY); if (ret) return ret; From 1131f1e7207e9d3219f992366b5182f03b3f7537 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:08 -0400 Subject: [PATCH 194/330] iio: light: adux1020: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-28-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/adux1020.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index d4eb938c3bf5..2e0170be077a 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -539,9 +539,8 @@ static int adux1020_write_event_config(struct iio_dev *indio_dev, * Trigger proximity interrupt when the intensity is above * or below threshold */ - ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE, - ADUX1020_PROX_TYPE, - ADUX1020_PROX_TYPE); + ret = regmap_set_bits(data->regmap, ADUX1020_REG_PROX_TYPE, + ADUX1020_PROX_TYPE); if (ret < 0) goto fail; @@ -748,8 +747,8 @@ static int adux1020_chip_init(struct adux1020_data *data) dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val); - ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET, - ADUX1020_SW_RESET, ADUX1020_SW_RESET); + ret = regmap_set_bits(data->regmap, ADUX1020_REG_SW_RESET, + ADUX1020_SW_RESET); if (ret < 0) return ret; @@ -764,8 +763,8 @@ static int adux1020_chip_init(struct adux1020_data *data) return ret; /* Use LED_IREF for proximity mode */ - ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT, - ADUX1020_LED_PIREF_EN, 0); + ret = regmap_clear_bits(data->regmap, ADUX1020_REG_LED_CURRENT, + ADUX1020_LED_PIREF_EN); if (ret < 0) return ret; From 9ff43d28765f17b550871d78ffe818c9a47bac1c Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:09 -0400 Subject: [PATCH 195/330] iio: light: iqs621-als: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-29-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/iqs621-als.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c index 004ea890a4b2..6de33feada3a 100644 --- a/drivers/iio/light/iqs621-als.c +++ b/drivers/iio/light/iqs621-als.c @@ -86,8 +86,8 @@ static int iqs621_als_init(struct iqs621_als_private *iqs621_als) if (iqs621_als->prox_en) event_mask |= iqs62x->dev_desc->ir_mask; - return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, - event_mask, 0); + return regmap_clear_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, + event_mask); } static int iqs621_als_notifier(struct notifier_block *notifier, From 7832023d66bc72f6b64fe33255b97c6a3530b9f4 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:10 -0400 Subject: [PATCH 196/330] iio: light: isl29018: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-30-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/isl29018.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 43484c18b101..8dfc750e68c0 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -550,9 +550,9 @@ static int isl29018_chip_init(struct isl29018_chip *chip) return -ENODEV; /* Clear brownout bit */ - status = regmap_update_bits(chip->regmap, - ISL29035_REG_DEVICE_ID, - ISL29035_BOUT_MASK, 0); + status = regmap_clear_bits(chip->regmap, + ISL29035_REG_DEVICE_ID, + ISL29035_BOUT_MASK); if (status < 0) return status; } From feeae7fd1a96660cafbe2752d1d6286ea6b94240 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:11 -0400 Subject: [PATCH 197/330] iio: light: st_uvis25_core: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-31-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/st_uvis25_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index d4e17079b2f4..fba3997574bb 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -330,8 +330,8 @@ static int st_uvis25_suspend(struct device *dev) struct iio_dev *iio_dev = dev_get_drvdata(dev); struct st_uvis25_hw *hw = iio_priv(iio_dev); - return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR, - ST_UVIS25_REG_ODR_MASK, 0); + return regmap_clear_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR, + ST_UVIS25_REG_ODR_MASK); } static int st_uvis25_resume(struct device *dev) From df4083d3888a6f09ac5a0f47215ce45f5e59cc19 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:12 -0400 Subject: [PATCH 198/330] iio: light: veml6030: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-32-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/veml6030.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 4be151308574..2e86d310952e 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -144,8 +144,8 @@ static const struct attribute_group veml6030_event_attr_group = { static int veml6030_als_pwr_on(struct veml6030_data *data) { - return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, - VEML6030_ALS_SD, 0); + return regmap_clear_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_SD); } static int veml6030_als_shut_down(struct veml6030_data *data) From e93bd1721e2fa43db59903b35b96ebbd54d37aa7 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:13 -0400 Subject: [PATCH 199/330] iio: magnetometer: ak8974: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Reviewed-by: Linus Walleij Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-33-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8974.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index d802034c5402..961b1e0bfb13 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -327,10 +327,7 @@ static int ak8974_trigmeas(struct ak8974 *ak8974) } /* Force a measurement */ - return regmap_update_bits(ak8974->map, - AK8974_CTRL3, - AK8974_CTRL3_FORCE, - AK8974_CTRL3_FORCE); + return regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_FORCE); } static int ak8974_await_drdy(struct ak8974 *ak8974) @@ -438,10 +435,7 @@ static int ak8974_selftest(struct ak8974 *ak8974) } /* Trigger self-test */ - ret = regmap_update_bits(ak8974->map, - AK8974_CTRL3, - AK8974_CTRL3_SELFTEST, - AK8974_CTRL3_SELFTEST); + ret = regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_SELFTEST); if (ret) { dev_err(dev, "could not write CTRL3\n"); return ret; From 3b6f6e57ab86fa91a58658175076ee1d6b612e0b Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:14 -0400 Subject: [PATCH 200/330] iio: magnetometer: mmc35240: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-34-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/mmc35240.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index c57932db455f..dd480a4a5f98 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -186,9 +186,8 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set) * Recharge the capacitor at VCAP pin, requested to be issued * before a SET/RESET command. */ - ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL0, - MMC35240_CTRL0_REFILL_BIT, - MMC35240_CTRL0_REFILL_BIT); + ret = regmap_set_bits(data->regmap, MMC35240_REG_CTRL0, + MMC35240_CTRL0_REFILL_BIT); if (ret < 0) return ret; usleep_range(MMC35240_WAIT_CHARGE_PUMP, MMC35240_WAIT_CHARGE_PUMP + 1); @@ -198,8 +197,7 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set) else coil_bit = MMC35240_CTRL0_RESET_BIT; - return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0, - coil_bit, coil_bit); + return regmap_set_bits(data->regmap, MMC35240_REG_CTRL0, coil_bit); } From c470071e561aec808e05707a88cbaf18227b7f2f Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:15 -0400 Subject: [PATCH 201/330] iio: pressure: bmp280-core: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Reviewed-by: Linus Walleij Tested-By: Vasileios Amoiridis Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-35-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 50d71ad83f37..49081b729618 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -1645,8 +1645,8 @@ static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val, goto exit; /* Disable programming mode bit */ - ret = regmap_update_bits(data->regmap, BMP580_REG_NVM_ADDR, - BMP580_NVM_PROG_EN, 0); + ret = regmap_clear_bits(data->regmap, BMP580_REG_NVM_ADDR, + BMP580_NVM_PROG_EN); if (ret) { dev_err(data->dev, "error resetting nvm write\n"); goto exit; From f931cab767334ed0270534b27593c100c06ea4ef Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:16 -0400 Subject: [PATCH 202/330] iio: proximity: sx9324: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-36-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9324.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index aa0d14a49d5e..629f83c37d59 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -835,9 +835,8 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev) int ret; /* run the compensation phase on all channels */ - ret = regmap_update_bits(data->regmap, SX9324_REG_STAT2, - SX9324_REG_STAT2_COMPSTAT_MASK, - SX9324_REG_STAT2_COMPSTAT_MASK); + ret = regmap_set_bits(data->regmap, SX9324_REG_STAT2, + SX9324_REG_STAT2_COMPSTAT_MASK); if (ret) return ret; From 3b8ec239b8e1db4fa35a235947995a759b7447c2 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:17 -0400 Subject: [PATCH 203/330] iio: proximity: sx9360: make use of regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-37-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9360.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 75a1c29f14eb..2b90bf45a201 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -672,9 +672,8 @@ static int sx9360_init_compensation(struct iio_dev *indio_dev) int ret; /* run the compensation phase on all channels */ - ret = regmap_update_bits(data->regmap, SX9360_REG_STAT, - SX9360_REG_STAT_COMPSTAT_MASK, - SX9360_REG_STAT_COMPSTAT_MASK); + ret = regmap_set_bits(data->regmap, SX9360_REG_STAT, + SX9360_REG_STAT_COMPSTAT_MASK); if (ret) return ret; From 734ecf98311e6f984367eb760db5f84cef645511 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:18 -0400 Subject: [PATCH 204/330] iio: proximity: sx9500: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-38-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9500.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index b89d49defd7a..92630812ece2 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -209,7 +209,7 @@ static int sx9500_inc_users(struct sx9500_data *data, int *counter, /* Bit is already active, nothing to do. */ return 0; - return regmap_update_bits(data->regmap, reg, bitmask, bitmask); + return regmap_set_bits(data->regmap, reg, bitmask); } static int sx9500_dec_users(struct sx9500_data *data, int *counter, @@ -220,7 +220,7 @@ static int sx9500_dec_users(struct sx9500_data *data, int *counter, /* There are more users, do not deactivate. */ return 0; - return regmap_update_bits(data->regmap, reg, bitmask, 0); + return regmap_clear_bits(data->regmap, reg, bitmask); } static int sx9500_inc_chan_users(struct sx9500_data *data, int chan) @@ -795,8 +795,8 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev) int i, ret; unsigned int val; - ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, - SX9500_CHAN_MASK, SX9500_CHAN_MASK); + ret = regmap_set_bits(data->regmap, SX9500_REG_PROX_CTRL0, + SX9500_CHAN_MASK); if (ret < 0) return ret; @@ -815,8 +815,8 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev) } out: - regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, - SX9500_CHAN_MASK, 0); + regmap_clear_bits(data->regmap, SX9500_REG_PROX_CTRL0, + SX9500_CHAN_MASK); return ret; } From 9ba22652b6ef6e9f5e6b68b927b1713fc309bfd5 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:19 -0400 Subject: [PATCH 205/330] iio: proximity: sx_common: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-39-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx_common.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index fe07d1444ac3..a95e9814aaf2 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -111,17 +111,16 @@ static int sx_common_enable_irq(struct sx_common_data *data, unsigned int irq) { if (!data->client->irq) return 0; - return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk, - irq << data->chip_info->irq_msk_offset, - irq << data->chip_info->irq_msk_offset); + return regmap_set_bits(data->regmap, data->chip_info->reg_irq_msk, + irq << data->chip_info->irq_msk_offset); } static int sx_common_disable_irq(struct sx_common_data *data, unsigned int irq) { if (!data->client->irq) return 0; - return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk, - irq << data->chip_info->irq_msk_offset, 0); + return regmap_clear_bits(data->regmap, data->chip_info->reg_irq_msk, + irq << data->chip_info->irq_msk_offset); } static int sx_common_update_chan_en(struct sx_common_data *data, From ac403e8ca250c27e763408357eebdd04b01c8c17 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:20 -0400 Subject: [PATCH 206/330] iio: temperature: mlx90632: make use of regmap_clear_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Acked-by: Crt Mori Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-40-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90632.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 4676e0edde4a..ae4ea587e7f9 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -334,8 +334,8 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data) unsigned int reg_status; int ret; - ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS, - MLX90632_STAT_DATA_RDY, 0); + ret = regmap_clear_bits(data->regmap, MLX90632_REG_STATUS, + MLX90632_STAT_DATA_RDY); if (ret < 0) return ret; From 04eb94997eb3ec4f2ce5dc05daa2a1db46201224 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 09:50:21 -0400 Subject: [PATCH 207/330] iio: trigger: stm32-timer-trigger: make use of regmap_clear_bits(), regmap_set_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using regmap_update_bits() and passing the mask twice, use regmap_set_bits(). Instead of using regmap_update_bits() and passing val = 0, use regmap_clear_bits(). Suggested-by: Uwe Kleine-König Signed-off-by: Trevor Gamblin Acked-by: Uwe Kleine-König Link: https://patch.msgid.link/20240617-review-v3-41-88d1338c4cca@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/stm32-timer-trigger.c | 34 +++++++++++------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index d76444030a28..0684329956d9 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -158,7 +158,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, regmap_write(priv->regmap, TIM_PSC, prescaler); regmap_write(priv->regmap, TIM_ARR, prd - 1); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); /* Force master mode to update mode */ if (stm32_timer_is_trgo2_name(trig->name)) @@ -169,10 +169,10 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, 0x2 << TIM_CR2_MMS_SHIFT); /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); /* Enable controller */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); mutex_unlock(&priv->lock); return 0; @@ -189,19 +189,19 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv, mutex_lock(&priv->lock); /* Stop timer */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); regmap_write(priv->regmap, TIM_PSC, 0); regmap_write(priv->regmap, TIM_ARR, 0); /* Force disable master mode */ if (stm32_timer_is_trgo2_name(trig->name)) - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); else - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0); + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS); /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); if (priv->enabled) { priv->enabled = false; @@ -498,11 +498,9 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, priv->enabled = true; clk_enable(priv->clk); } - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, - TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); } else { - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, - 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); if (priv->enabled) { priv->enabled = false; clk_disable(priv->clk); @@ -555,7 +553,7 @@ static int stm32_set_trigger_mode(struct iio_dev *indio_dev, { struct stm32_timer_trigger *priv = iio_priv(indio_dev); - regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, TIM_SMCR_SMS); + regmap_set_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS); return 0; } @@ -683,7 +681,7 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev, return ret; /* TIMx_ARR register shouldn't be buffered (ARPE=0) */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); regmap_write(priv->regmap, TIM_ARR, preset); return len; @@ -757,9 +755,9 @@ static void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv) * Master mode selection 2 bits can only be written and read back when * timer supports it. */ - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, TIM_CR2_MMS2); + regmap_set_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); regmap_read(priv->regmap, TIM_CR2, &val); - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); priv->has_trgo2 = !!val; } @@ -820,7 +818,7 @@ static void stm32_timer_trigger_remove(struct platform_device *pdev) /* Check if nobody else use the timer, then disable it */ regmap_read(priv->regmap, TIM_CCER, &val); if (!(val & TIM_CCER_CCXE)) - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); if (priv->enabled) clk_disable(priv->clk); @@ -841,7 +839,7 @@ static int stm32_timer_trigger_suspend(struct device *dev) regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr); /* Disable the timer */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); clk_disable(priv->clk); } From d9b329a9712280968fb4ba6dac09fabde24bf566 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Mon, 17 Jun 2024 11:18:19 -0400 Subject: [PATCH 208/330] iio: dac: adi-axi-dac: improve probe() error messaging The current error handling for calls such as devm_clk_get_enabled() in the adi-axi-dac probe() function means that, if a property such as 'clocks' (for example) is not present in the devicetree when booting a kernel with the driver enabled, the resulting error message will be vague, e.g.: |adi_axi_dac 44a00000.dac: probe with driver adi_axi_dac failed with error -2 Change the devm_clk_get_enabled(), devm_regmap_init_mmio(), and devm_iio_backend_register() checks to use dev_err_probe() with some context for easier debugging. After the change: |adi_axi_dac 44a00000.dac: error -ENOENT: failed to get clock |adi_axi_dac 44a00000.dac: probe with driver adi_axi_dac failed with error -2 Suggested-by: Nuno Sa Tested-by: Angelo Dureghello Signed-off-by: Trevor Gamblin Link: https://patch.msgid.link/20240617151820.3337034-1-tgamblin@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/adi-axi-dac.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 880d83a014a1..6d56428e623d 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -545,7 +545,8 @@ static int axi_dac_probe(struct platform_device *pdev) clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) - return PTR_ERR(clk); + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -555,7 +556,8 @@ static int axi_dac_probe(struct platform_device *pdev) st->regmap = devm_regmap_init_mmio(&pdev->dev, base, &axi_dac_regmap_config); if (IS_ERR(st->regmap)) - return PTR_ERR(st->regmap); + return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap), + "failed to init register map\n"); /* * Force disable the core. Up to the frontend to enable us. And we can @@ -601,7 +603,8 @@ static int axi_dac_probe(struct platform_device *pdev) mutex_init(&st->lock); ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st); if (ret) - return ret; + return dev_err_probe(&pdev->dev, ret, + "failed to register iio backend\n"); dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), From 54b0825fdfc96166e57f0a78b1a90b37baf1a2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Gon=C3=A7alves?= Date: Mon, 17 Jun 2024 20:32:14 +0200 Subject: [PATCH 209/330] dt-bindings: iio: adc: add ti,ads1119 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add devicetree bindings for Texas Instruments ADS1119 16-bit ADC with I2C interface. Datasheet: https://www.ti.com/lit/gpn/ads1119 Signed-off-by: João Paulo Gonçalves Signed-off-by: Francesco Dolcini Reviewed-by: Conor Dooley Link: https://patch.msgid.link/20240617183215.4080-2-francesco@dolcini.it Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/ti,ads1119.yaml | 155 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 162 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml new file mode 100644 index 000000000000..ba6850ab1f90 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads1119.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments ADS1119 ADC + +maintainers: + - João Paulo Gonçalves + +description: + The TI ADS1119 is a precision 16-bit ADC over I2C that offers single-ended and + differential measurements using a multiplexed input. It features a programmable + gain, a programmable sample rate, an internal oscillator and voltage reference, + and a 50/60Hz rejection filter. + +properties: + compatible: + const: ti,ads1119 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + avdd-supply: true + dvdd-supply: true + + vref-supply: + description: + ADC external reference voltage (VREF). + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + "#io-channel-cells": + const: 1 + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - avdd-supply + - dvdd-supply + +patternProperties: + "^channel@([0-6])$": + $ref: adc.yaml + type: object + properties: + reg: + minimum: 0 + maximum: 6 + + diff-channels: + description: + Differential input channels AIN0-AIN1, AIN2-AIN3 and AIN1-AIN2. + oneOf: + - items: + - const: 0 + - const: 1 + - items: + - const: 2 + - const: 3 + - items: + - const: 1 + - const: 2 + + single-channel: + description: + Single-ended input channels AIN0, AIN1, AIN2 and AIN3. + minimum: 0 + maximum: 3 + + oneOf: + - required: + - diff-channels + - required: + - single-channel + + required: + - reg + + unevaluatedProperties: false + +additionalProperties: false + +examples: + - | + + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@40 { + compatible = "ti,ads1119"; + reg = <0x40>; + interrupt-parent = <&gpio1>; + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + avdd-supply = <®_avdd_ads1119>; + dvdd-supply = <®_dvdd_ads1119>; + vref-supply = <®_vref_ads1119>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + channel@0 { + reg = <0>; + single-channel = <0>; + }; + + channel@1 { + reg = <1>; + diff-channels = <0 1>; + }; + + channel@2 { + reg = <2>; + single-channel = <3>; + }; + + channel@3 { + reg = <3>; + single-channel = <1>; + }; + + channel@4 { + reg = <4>; + single-channel = <2>; + }; + + channel@5 { + reg = <5>; + diff-channels = <1 2>; + }; + + channel@6 { + reg = <6>; + diff-channels = <2 3>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 24d372f7653e..2ceed9bb064d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22397,6 +22397,13 @@ M: Robert Richter S: Odd Fixes F: drivers/gpio/gpio-thunderx.c +TI ADS1119 ADC DRIVER +M: Francesco Dolcini +M: João Paulo Gonçalves +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml + TI ADS7924 ADC DRIVER M: Hugo Villeneuve L: linux-iio@vger.kernel.org From a9306887eba41c5fe7232727a8147da3d3c4f83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Gon=C3=A7alves?= Date: Mon, 17 Jun 2024 20:39:05 +0200 Subject: [PATCH 210/330] iio: adc: ti-ads1119: Add driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADS1119 is a precision, 16-bit, analog-to-digital converter (ADC) that features two differential or four single-ended inputs through a flexible input multiplexer (MUX), rail-to-rail input buffers, a programmable gain stage, a voltage reference, and an oscillator. Apart from normal single conversion, the driver also supports continuous conversion mode using a triggered buffer. However, in this mode only one channel can be scanned at a time. Datasheet: https://www.ti.com/lit/gpn/ads1119 Signed-off-by: João Paulo Gonçalves Signed-off-by: Francesco Dolcini Link: https://patch.msgid.link/20240617183905.4685-1-francesco@dolcini.it Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-ads1119.c | 825 +++++++++++++++++++++++++++++++++++ 4 files changed, 839 insertions(+) create mode 100644 drivers/iio/adc/ti-ads1119.c diff --git a/MAINTAINERS b/MAINTAINERS index 2ceed9bb064d..9517093d889d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22403,6 +22403,7 @@ M: João Paulo Gonçalves L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml +F: drivers/iio/adc/ti-ads1119.c TI ADS7924 ADC DRIVER M: Hugo Villeneuve diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 3d91015af6ea..b8184706c7d1 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1351,6 +1351,18 @@ config TI_ADS1015 This driver can also be built as a module. If so, the module will be called ti-ads1015. +config TI_ADS1119 + tristate "Texas Instruments ADS1119 ADC" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for Texas Instruments ADS1119 + ADC chip. + + This driver can also be built as a module. If so, the module will be + called ti-ads1119. + config TI_ADS7924 tristate "Texas Instruments ADS7924 ADC" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 37ac689a0209..51298c52b223 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -121,6 +121,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o +obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c new file mode 100644 index 000000000000..630f5d5f9a60 --- /dev/null +++ b/drivers/iio/adc/ti-ads1119.c @@ -0,0 +1,825 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Texas Instruments ADS1119 ADC driver. + * + * Copyright 2024 Toradex + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ADS1119_CMD_RESET 0x06 +#define ADS1119_CMD_POWERDOWN 0x02 +#define ADS1119_CMD_START_SYNC 0x08 +#define ADS1119_CMD_RDATA 0x10 +#define ADS1119_CMD_RREG_CONFIG 0x20 +#define ADS1119_CMD_RREG_STATUS 0x24 +#define ADS1119_CMD_WREG 0x40 + +#define ADS1119_CMD_RREG(reg) (0x20 | (reg) << 2) + +/* Config register */ +#define ADS1119_REG_CONFIG 0x00 +#define ADS1119_CONFIG_VREF_FIELD BIT(0) +#define ADS1119_CONFIG_CM_FIELD BIT(1) +#define ADS1119_CONFIG_DR_FIELD GENMASK(3, 2) +#define ADS1119_CONFIG_GAIN_FIELD BIT(4) +#define ADS1119_CONFIG_MUX_FIELD GENMASK(7, 5) + +#define ADS1119_VREF_INTERNAL 0 +#define ADS1119_VREF_EXTERNAL 1 +#define ADS1119_VREF_INTERNAL_VAL 2048000 + +#define ADS1119_CM_SINGLE 0 +#define ADS1119_CM_CONTINUOUS 1 + +#define ADS1119_DR_20_SPS 0 +#define ADS1119_DR_90_SPS 1 +#define ADS1119_DR_330_SPS 2 +#define ADS1119_DR_1000_SPS 3 + +#define ADS1119_GAIN_1 0 +#define ADS1119_GAIN_4 1 + +#define ADS1119_MUX_AIN0_AIN1 0 +#define ADS1119_MUX_AIN2_AIN3 1 +#define ADS1119_MUX_AIN1_AIN2 2 +#define ADS1119_MUX_AIN0 3 +#define ADS1119_MUX_AIN1 4 +#define ADS1119_MUX_AIN2 5 +#define ADS1119_MUX_AIN3 6 +#define ADS1119_MUX_SHORTED 7 + +/* Status register */ +#define ADS1119_REG_STATUS 0x01 +#define ADS1119_STATUS_DRDY_FIELD BIT(7) + +#define ADS1119_DEFAULT_GAIN 1 +#define ADS1119_DEFAULT_DATARATE 20 + +#define ADS1119_SUSPEND_DELAY 2000 + +/* Timeout based on the minimum sample rate of 20 SPS (50000us) */ +#define ADS1119_MAX_DRDY_TIMEOUT 85000 + +#define ADS1119_MAX_CHANNELS 7 +#define ADS1119_MAX_SINGLE_CHANNELS 4 + +struct ads1119_channel_config { + int gain; + int datarate; + int mux; +}; + +struct ads1119_state { + struct completion completion; + struct i2c_client *client; + struct gpio_desc *reset_gpio; + struct iio_trigger *trig; + struct ads1119_channel_config *channels_cfg; + unsigned int num_channels_cfg; + unsigned int cached_config; + int vref_uV; +}; + +static const char * const ads1119_power_supplies[] = { + "avdd", "dvdd" +}; + +static const int ads1119_available_datarates[] = { + 20, 90, 330, 1000, +}; + +static const int ads1119_available_gains[] = { + 1, 1, + 1, 4, +}; + +static int ads1119_upd_cfg_reg(struct ads1119_state *st, unsigned int fields, + unsigned int val) +{ + unsigned int config = st->cached_config; + int ret; + + config &= ~fields; + config |= val; + + ret = i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG, config); + if (ret) + return ret; + + st->cached_config = config; + + return 0; +} + +static bool ads1119_data_ready(struct ads1119_state *st) +{ + int status; + + status = i2c_smbus_read_byte_data(st->client, ADS1119_CMD_RREG_STATUS); + if (status < 0) + return false; + + return FIELD_GET(ADS1119_STATUS_DRDY_FIELD, status); +} + +static int ads1119_reset(struct ads1119_state *st) +{ + st->cached_config = 0; + + if (!st->reset_gpio) + return i2c_smbus_write_byte(st->client, ADS1119_CMD_RESET); + + gpiod_set_value_cansleep(st->reset_gpio, 1); + udelay(1); + gpiod_set_value_cansleep(st->reset_gpio, 0); + udelay(1); + + return 0; +} + +static int ads1119_set_conv_mode(struct ads1119_state *st, bool continuous) +{ + unsigned int mode; + + if (continuous) + mode = ADS1119_CM_CONTINUOUS; + else + mode = ADS1119_CM_SINGLE; + + return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_CM_FIELD, + FIELD_PREP(ADS1119_CONFIG_CM_FIELD, mode)); +} + +static int ads1119_get_hw_gain(int gain) +{ + if (gain == 4) + return ADS1119_GAIN_4; + else + return ADS1119_GAIN_1; +} + +static int ads1119_get_hw_datarate(int datarate) +{ + switch (datarate) { + case 90: + return ADS1119_DR_90_SPS; + case 330: + return ADS1119_DR_330_SPS; + case 1000: + return ADS1119_DR_1000_SPS; + case 20: + default: + return ADS1119_DR_20_SPS; + } +} + +static int ads1119_configure_channel(struct ads1119_state *st, int mux, + int gain, int datarate) +{ + int ret; + + ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_MUX_FIELD, + FIELD_PREP(ADS1119_CONFIG_MUX_FIELD, mux)); + if (ret) + return ret; + + ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_GAIN_FIELD, + FIELD_PREP(ADS1119_CONFIG_GAIN_FIELD, + ads1119_get_hw_gain(gain))); + if (ret) + return ret; + + return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_DR_FIELD, + FIELD_PREP(ADS1119_CONFIG_DR_FIELD, + ads1119_get_hw_datarate(datarate))); +} + +static int ads1119_poll_data_ready(struct ads1119_state *st, + struct iio_chan_spec const *chan) +{ + unsigned int datarate = st->channels_cfg[chan->address].datarate; + unsigned long wait_time; + bool data_ready; + + /* Poll 5 times more than the data rate */ + wait_time = DIV_ROUND_CLOSEST(MICRO, 5 * datarate); + + return read_poll_timeout(ads1119_data_ready, data_ready, + data_ready, wait_time, + ADS1119_MAX_DRDY_TIMEOUT, false, st); +} + +static int ads1119_read_data(struct ads1119_state *st, + struct iio_chan_spec const *chan, + unsigned int *val) +{ + unsigned int timeout; + int ret = 0; + + timeout = msecs_to_jiffies(ADS1119_MAX_DRDY_TIMEOUT); + + if (!st->client->irq) { + ret = ads1119_poll_data_ready(st, chan); + if (ret) + return ret; + } else if (!wait_for_completion_timeout(&st->completion, timeout)) { + return -ETIMEDOUT; + } + + ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA); + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static int ads1119_single_conversion(struct ads1119_state *st, + struct iio_chan_spec const *chan, + int *val, + bool calib_offset) +{ + struct device *dev = &st->client->dev; + int mux = st->channels_cfg[chan->address].mux; + int gain = st->channels_cfg[chan->address].gain; + int datarate = st->channels_cfg[chan->address].datarate; + unsigned int sample; + int ret; + + if (calib_offset) + mux = ADS1119_MUX_SHORTED; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto pdown; + + ret = ads1119_configure_channel(st, mux, gain, datarate); + if (ret) + goto pdown; + + ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); + if (ret) + goto pdown; + + ret = ads1119_read_data(st, chan, &sample); + if (ret) + goto pdown; + + *val = sign_extend32(sample, chan->scan_type.realbits - 1); + ret = IIO_VAL_INT; +pdown: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return ret; +} + +static int ads1119_validate_datarate(struct ads1119_state *st, int datarate) +{ + switch (datarate) { + case 20: + case 90: + case 330: + case 1000: + return datarate; + default: + return -EINVAL; + } +} + +static int ads1119_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_FRACTIONAL; + *vals = ads1119_available_gains; + *length = ARRAY_SIZE(ads1119_available_gains); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT; + *vals = ads1119_available_datarates; + *length = ARRAY_SIZE(ads1119_available_datarates); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int ads1119_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ads1119_state *st = iio_priv(indio_dev); + unsigned int index = chan->address; + + if (index >= st->num_channels_cfg) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return ads1119_single_conversion(st, chan, val, false); + unreachable(); + case IIO_CHAN_INFO_OFFSET: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return ads1119_single_conversion(st, chan, val, true); + unreachable(); + case IIO_CHAN_INFO_SCALE: + *val = st->vref_uV / 1000; + *val /= st->channels_cfg[index].gain; + *val2 = chan->scan_type.realbits - 1; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->channels_cfg[index].datarate; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ads1119_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ads1119_state *st = iio_priv(indio_dev); + unsigned int index = chan->address; + int ret; + + if (index >= st->num_channels_cfg) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = MICRO / ((val * MICRO) + val2); + if (ret != 1 && ret != 4) + return -EINVAL; + + st->channels_cfg[index].gain = ret; + return 0; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = ads1119_validate_datarate(st, val); + if (ret < 0) + return ret; + + st->channels_cfg[index].datarate = ret; + return 0; + default: + return -EINVAL; + } +} + +static int ads1119_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct ads1119_state *st = iio_priv(indio_dev); + int ret; + + if (reg > ADS1119_REG_STATUS) + return -EINVAL; + + if (readval) { + ret = i2c_smbus_read_byte_data(st->client, + ADS1119_CMD_RREG(reg)); + if (ret < 0) + return ret; + + *readval = ret; + return 0; + } + + if (reg > ADS1119_REG_CONFIG) + return -EINVAL; + + return i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG, + writeval); +} + +static const struct iio_info ads1119_info = { + .read_avail = ads1119_read_avail, + .read_raw = ads1119_read_raw, + .write_raw = ads1119_write_raw, + .debugfs_reg_access = ads1119_debugfs_reg_access, +}; + +static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ads1119_state *st = iio_priv(indio_dev); + struct device *dev = &st->client->dev; + unsigned int index; + int ret; + + index = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); + + ret = ads1119_set_conv_mode(st, true); + if (ret) + return ret; + + ret = ads1119_configure_channel(st, + st->channels_cfg[index].mux, + st->channels_cfg[index].gain, + st->channels_cfg[index].datarate); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); +} + +static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ads1119_state *st = iio_priv(indio_dev); + struct device *dev = &st->client->dev; + int ret; + + ret = ads1119_set_conv_mode(st, false); + if (ret) + return ret; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static const struct iio_buffer_setup_ops ads1119_buffer_setup_ops = { + .preenable = ads1119_triggered_buffer_preenable, + .postdisable = ads1119_triggered_buffer_postdisable, + .validate_scan_mask = &iio_validate_scan_mask_onehot, +}; + +static const struct iio_trigger_ops ads1119_trigger_ops = { + .validate_device = &iio_trigger_validate_own_device, +}; + +static irqreturn_t ads1119_irq_handler(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct ads1119_state *st = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) + iio_trigger_poll(indio_dev->trig); + else + complete(&st->completion); + + return IRQ_HANDLED; +} + +static irqreturn_t ads1119_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct ads1119_state *st = iio_priv(indio_dev); + struct { + unsigned int sample; + s64 timestamp __aligned(8); + } scan; + unsigned int index; + int ret; + + if (!iio_trigger_using_own(indio_dev)) { + index = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); + + ret = ads1119_poll_data_ready(st, &indio_dev->channels[index]); + if (ret) { + dev_err(&st->client->dev, + "Failed to poll data on trigger (%d)\n", ret); + goto done; + } + } + + ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA); + if (ret < 0) { + dev_err(&st->client->dev, + "Failed to read data on trigger (%d)\n", ret); + goto done; + } + + scan.sample = ret; + + iio_push_to_buffers_with_timestamp(indio_dev, &scan, + iio_get_time_ns(indio_dev)); +done: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int ads1119_init(struct ads1119_state *st, bool vref_external) +{ + int ret; + + ret = ads1119_reset(st); + if (ret) + return ret; + + if (vref_external) + return ads1119_upd_cfg_reg(st, + ADS1119_CONFIG_VREF_FIELD, + FIELD_PREP(ADS1119_CONFIG_VREF_FIELD, + ADS1119_VREF_EXTERNAL)); + return 0; +} + +static int ads1119_map_analog_inputs_mux(int ain_pos, int ain_neg, + bool differential) +{ + if (ain_pos >= ADS1119_MAX_SINGLE_CHANNELS) + return -EINVAL; + + if (!differential) + return ADS1119_MUX_AIN0 + ain_pos; + + if (ain_pos == 0 && ain_neg == 1) + return ADS1119_MUX_AIN0_AIN1; + else if (ain_pos == 1 && ain_neg == 2) + return ADS1119_MUX_AIN1_AIN2; + else if (ain_pos == 2 && ain_neg == 3) + return ADS1119_MUX_AIN2_AIN3; + + return -EINVAL; +} + +static int ads1119_alloc_and_config_channels(struct iio_dev *indio_dev) +{ + const struct iio_chan_spec ads1119_channel = + (const struct iio_chan_spec) { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }; + const struct iio_chan_spec ads1119_ts = IIO_CHAN_SOFT_TIMESTAMP(0); + struct ads1119_state *st = iio_priv(indio_dev); + struct iio_chan_spec *iio_channels, *chan; + struct device *dev = &st->client->dev; + unsigned int num_channels, i; + bool differential; + u32 ain[2]; + int ret; + + st->num_channels_cfg = device_get_child_node_count(dev); + if (st->num_channels_cfg > ADS1119_MAX_CHANNELS) + return dev_err_probe(dev, -EINVAL, + "Too many channels %d, max is %d\n", + st->num_channels_cfg, + ADS1119_MAX_CHANNELS); + + st->channels_cfg = devm_kcalloc(dev, st->num_channels_cfg, + sizeof(*st->channels_cfg), GFP_KERNEL); + if (!st->channels_cfg) + return -ENOMEM; + + /* Allocate one more iio channel for the timestamp */ + num_channels = st->num_channels_cfg + 1; + iio_channels = devm_kcalloc(dev, num_channels, sizeof(*iio_channels), + GFP_KERNEL); + if (!iio_channels) + return -ENOMEM; + + i = 0; + + device_for_each_child_node_scoped(dev, child) { + chan = &iio_channels[i]; + + differential = fwnode_property_present(child, "diff-channels"); + if (differential) + ret = fwnode_property_read_u32_array(child, + "diff-channels", + ain, 2); + else + ret = fwnode_property_read_u32(child, "single-channel", + &ain[0]); + + if (ret) + return dev_err_probe(dev, ret, + "Failed to get channel property\n"); + + ret = ads1119_map_analog_inputs_mux(ain[0], ain[1], + differential); + if (ret < 0) + return dev_err_probe(dev, ret, + "Invalid channel value\n"); + + st->channels_cfg[i].mux = ret; + st->channels_cfg[i].gain = ADS1119_DEFAULT_GAIN; + st->channels_cfg[i].datarate = ADS1119_DEFAULT_DATARATE; + + *chan = ads1119_channel; + chan->channel = ain[0]; + chan->address = i; + chan->scan_index = i; + + if (differential) { + chan->channel2 = ain[1]; + chan->differential = 1; + } + + dev_dbg(dev, "channel: index %d, mux %d\n", i, + st->channels_cfg[i].mux); + + i++; + } + + iio_channels[i] = ads1119_ts; + iio_channels[i].address = i; + iio_channels[i].scan_index = i; + + indio_dev->channels = iio_channels; + indio_dev->num_channels = num_channels; + + return 0; +} + +static void ads1119_powerdown(void *data) +{ + struct ads1119_state *st = data; + + i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN); +} + +static int ads1119_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct ads1119_state *st; + struct device *dev = &client->dev; + bool vref_external = true; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, + "Failed to allocate IIO device\n"); + + st = iio_priv(indio_dev); + st->client = client; + + indio_dev->name = "ads1119"; + indio_dev->info = &ads1119_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + i2c_set_clientdata(client, indio_dev); + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(ads1119_power_supplies), + ads1119_power_supplies); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get and enable supplies\n"); + + st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (st->vref_uV == -ENODEV) { + vref_external = false; + st->vref_uV = ADS1119_VREF_INTERNAL_VAL; + } else if (st->vref_uV < 0) { + return dev_err_probe(dev, st->vref_uV, "Failed to get vref\n"); + } + + st->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(st->reset_gpio), + "Failed to get reset gpio\n"); + + ret = ads1119_alloc_and_config_channels(indio_dev); + if (ret) + return ret; + + init_completion(&st->completion); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + ads1119_trigger_handler, + &ads1119_buffer_setup_ops); + if (ret) + return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n"); + + if (client->irq > 0) { + ret = devm_request_threaded_irq(dev, client->irq, + ads1119_irq_handler, + NULL, IRQF_TRIGGER_FALLING, + "ads1119", indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "Failed to allocate irq\n"); + + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return dev_err_probe(dev, -ENOMEM, + "Failed to allocate IIO trigger\n"); + + st->trig->ops = &ads1119_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register IIO trigger\n"); + } + + ret = ads1119_init(st, vref_external); + if (ret) + return dev_err_probe(dev, ret, + "Failed to initialize device\n"); + + pm_runtime_set_autosuspend_delay(dev, ADS1119_SUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pm runtime\n"); + + ret = devm_add_action_or_reset(dev, ads1119_powerdown, st); + if (ret) + return dev_err_probe(dev, ret, + "Failed to add powerdown action\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static int ads1119_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct ads1119_state *st = iio_priv(indio_dev); + + return i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN); +} + +/* + * The ADS1119 does not require a resume function because it automatically + * powers on after a reset. + * After a power down command, the ADS1119 can still communicate but turns off + * its analog parts. To resume from power down, the device will power up again + * upon receiving a start/sync command. + */ +static DEFINE_RUNTIME_DEV_PM_OPS(ads1119_pm_ops, ads1119_runtime_suspend, + NULL, NULL); + +static const struct of_device_id __maybe_unused ads1119_of_match[] = { + { .compatible = "ti,ads1119" }, + { } +}; +MODULE_DEVICE_TABLE(of, ads1119_of_match); + +static const struct i2c_device_id ads1119_id[] = { + { "ads1119", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ads1119_id); + +static struct i2c_driver ads1119_driver = { + .driver = { + .name = "ads1119", + .of_match_table = ads1119_of_match, + .pm = pm_ptr(&ads1119_pm_ops), + }, + .probe = ads1119_probe, + .id_table = ads1119_id, +}; +module_i2c_driver(ads1119_driver); + +MODULE_AUTHOR("João Paulo Gonçalves "); +MODULE_DESCRIPTION("Texas Instruments ADS1119 ADC Driver"); +MODULE_LICENSE("GPL"); From 200b81f1c42b5d8b0d4f2005ca22bc3979f0bc3f Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 21 Jun 2024 15:13:58 +0300 Subject: [PATCH 211/330] dt-bindings: iio: adf4350: add clk provider prop Add properties required for providing clock to other consumers. Signed-off-by: Antoniu Miclaus Acked-by: Conor Dooley Link: https://patch.msgid.link/20240621121403.47912-1-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/frequency/adi,adf4350.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml index 43cbf27114c7..d1d1311332f8 100644 --- a/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml +++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml @@ -28,6 +28,12 @@ properties: clock-names: const: clkin + '#clock-cells': + const: 0 + + clock-output-names: + maxItems: 1 + gpios: maxItems: 1 description: Lock detect GPIO. From a1a09713b40dfc1c0b7d1f9233a7698c93a9af05 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 21 Jun 2024 15:13:59 +0300 Subject: [PATCH 212/330] iio: frequency: adf4350: add clk provider Add clk provider feature for the adf4350. Even though the driver was sent as an IIO driver in most cases the device is actually seen as a clock provider. This patch aims to cover actual usecases requested by users in order to completely control the output frequencies from userspace. Signed-off-by: Antoniu Miclaus Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240621121403.47912-2-antoniu.miclaus@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/adf4350.c | 124 +++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 4abf80f75ef5..e13e64a5164c 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,9 @@ struct adf4350_state { struct gpio_desc *lock_detect_gpiod; struct adf4350_platform_data *pdata; struct clk *clk; + struct clk *clkout; + const char *clk_out_name; + struct clk_hw hw; unsigned long clkin; unsigned long chspc; /* Channel Spacing */ unsigned long fpfd; /* Phase Frequency Detector */ @@ -61,6 +65,8 @@ struct adf4350_state { __be32 val __aligned(IIO_DMA_MINALIGN); }; +#define to_adf4350_state(_hw) container_of(_hw, struct adf4350_state, hw) + static struct adf4350_platform_data default_pdata = { .channel_spacing = 10000, .r2_user_settings = ADF4350_REG2_PD_POLARITY_POS | @@ -381,6 +387,113 @@ static const struct iio_info adf4350_info = { .debugfs_reg_access = &adf4350_reg_access, }; +static void adf4350_clk_del_provider(void *data) +{ + struct adf4350_state *st = data; + + of_clk_del_provider(st->spi->dev.of_node); +} + +static unsigned long adf4350_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct adf4350_state *st = to_adf4350_state(hw); + unsigned long long tmp; + + tmp = (u64)(st->r0_int * st->r1_mod + st->r0_fract) * st->fpfd; + do_div(tmp, st->r1_mod * (1 << st->r4_rf_div_sel)); + + return tmp; +} + +static int adf4350_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + if (parent_rate == 0 || parent_rate > ADF4350_MAX_FREQ_REFIN) + return -EINVAL; + + st->clkin = parent_rate; + + return adf4350_set_freq(st, rate); +} + +static int adf4350_clk_prepare(struct clk_hw *hw) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN; + + return adf4350_sync_config(st); +} + +static void adf4350_clk_unprepare(struct clk_hw *hw) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; + + adf4350_sync_config(st); +} + +static int adf4350_clk_is_enabled(struct clk_hw *hw) +{ + struct adf4350_state *st = to_adf4350_state(hw); + + return (st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN); +} + +static const struct clk_ops adf4350_clk_ops = { + .recalc_rate = adf4350_clk_recalc_rate, + .set_rate = adf4350_clk_set_rate, + .prepare = adf4350_clk_prepare, + .unprepare = adf4350_clk_unprepare, + .is_enabled = adf4350_clk_is_enabled, +}; + +static int adf4350_clk_register(struct adf4350_state *st) +{ + struct spi_device *spi = st->spi; + struct clk_init_data init; + struct clk *clk; + const char *parent_name; + int ret; + + if (!device_property_present(&spi->dev, "#clock-cells")) + return 0; + + if (device_property_read_string(&spi->dev, "clock-output-names", &init.name)) { + init.name = devm_kasprintf(&spi->dev, GFP_KERNEL, "%s-clk", + fwnode_get_name(dev_fwnode(&spi->dev))); + if (!init.name) + return -ENOMEM; + } + + parent_name = of_clk_get_parent_name(spi->dev.of_node, 0); + if (!parent_name) + return -EINVAL; + + init.ops = &adf4350_clk_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT; + + st->hw.init = &init; + clk = devm_clk_register(&spi->dev, &st->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = of_clk_add_provider(spi->dev.of_node, of_clk_src_simple_get, clk); + if (ret) + return ret; + + st->clkout = clk; + + return devm_add_action_or_reset(&spi->dev, adf4350_clk_del_provider, st); +} + static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) { struct adf4350_platform_data *pdata; @@ -522,8 +635,6 @@ static int adf4350_probe(struct spi_device *spi) indio_dev->info = &adf4350_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = &adf4350_chan; - indio_dev->num_channels = 1; mutex_init(&st->lock); @@ -551,6 +662,15 @@ static int adf4350_probe(struct spi_device *spi) return ret; } + ret = adf4350_clk_register(st); + if (ret) + return ret; + + if (!st->clkout) { + indio_dev->channels = &adf4350_chan; + indio_dev->num_channels = 1; + } + ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev); if (ret) return dev_err_probe(&spi->dev, ret, From f168a6db111b83a44552a0006326178b2c92bd7d Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sat, 22 Jun 2024 18:03:45 +0530 Subject: [PATCH 213/330] iio: accel: st_accel: add support for LIS2DS12 Define sensor settings for LIS2DS12 by STMicroelectronics (WhoAmI 0x43) and add support in the I2C and SPI drivers. Datasheet: https://www.st.com/resource/en/datasheet/lis2ds12.pdf Signed-off-by: Kaustabh Chakraborty Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20240622123520.39253-1-kauschluss@disroot.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel.h | 1 + drivers/iio/accel/st_accel_core.c | 81 +++++++++++++++++++++++++++++++ drivers/iio/accel/st_accel_i2c.c | 5 ++ drivers/iio/accel/st_accel_spi.c | 5 ++ 4 files changed, 92 insertions(+) diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index e7525615712b..2659f536cef6 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -35,6 +35,7 @@ #define LIS3DHH_ACCEL_DEV_NAME "lis3dhh" #define LIS3DE_ACCEL_DEV_NAME "lis3de" #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" +#define LIS2DS12_ACCEL_DEV_NAME "lis2ds12" #define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" #define LIS302DL_ACCEL_DEV_NAME "lis302dl" #define LSM303C_ACCEL_DEV_NAME "lsm303c_accel" diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index d2104e14e255..0e371efbda70 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -925,6 +925,87 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .multi_read_bit = true, .bootime = 2, }, + { + .wai = 0x43, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LIS2DS12_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_16bit_channels, + .odr = { + .addr = 0x20, + .mask = 0xf0, + .odr_avl = { + { .hz = 10, .value = 0x01, }, + { .hz = 50, .value = 0x02, }, + { .hz = 100, .value = 0x03, }, + { .hz = 200, .value = 0x04, }, + { .hz = 400, .value = 0x05, }, + { .hz = 800, .value = 0x06, }, + }, + }, + .pw = { + .addr = 0x20, + .mask = 0xf0, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = 0x20, + .mask = 0x0c, + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(61), + }, + [1] = { + .num = ST_ACCEL_FS_AVL_4G, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(122), + }, + [2] = { + .num = ST_ACCEL_FS_AVL_8G, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(244), + }, + [3] = { + .num = ST_ACCEL_FS_AVL_16G, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(488), + }, + }, + }, + .bdu = { + .addr = 0x20, + .mask = 0x01, + }, + .drdy_irq = { + .int1 = { + .addr = 0x23, + .mask = 0x01, + }, + .int2 = { + .addr = 0x24, + .mask = 0x01, + }, + .addr_ihl = 0x22, + .mask_ihl = 0x02, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x01, + }, + }, + .sim = { + .addr = 0x21, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, { .wai = 0x41, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index fd3749871121..329a4d6fb2ec 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -102,6 +102,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lis2de12", .data = LIS2DE12_ACCEL_DEV_NAME, }, + { + .compatible = "st,lis2ds12", + .data = LIS2DS12_ACCEL_DEV_NAME, + }, { .compatible = "st,lis2hh12", .data = LIS2HH12_ACCEL_DEV_NAME, @@ -154,6 +158,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LIS2DW12_ACCEL_DEV_NAME }, { LIS3DE_ACCEL_DEV_NAME }, { LIS2DE12_ACCEL_DEV_NAME }, + { LIS2DS12_ACCEL_DEV_NAME }, { LIS2HH12_ACCEL_DEV_NAME }, { LIS302DL_ACCEL_DEV_NAME }, { LSM303C_ACCEL_DEV_NAME }, diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index f72a24f45322..825adab37105 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -64,6 +64,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lis2dh12-accel", .data = LIS2DH12_ACCEL_DEV_NAME, }, + { + .compatible = "st,lis2ds12", + .data = LIS2DS12_ACCEL_DEV_NAME, + }, { .compatible = "st,lis3l02dq", .data = LIS3L02DQ_ACCEL_DEV_NAME, @@ -151,6 +155,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM330_ACCEL_DEV_NAME }, { LSM303AGR_ACCEL_DEV_NAME }, { LIS2DH12_ACCEL_DEV_NAME }, + { LIS2DS12_ACCEL_DEV_NAME }, { LIS3L02DQ_ACCEL_DEV_NAME }, { LNG2DM_ACCEL_DEV_NAME }, { H3LIS331DL_ACCEL_DEV_NAME }, From 4aa60bd98e77be185e845e222897f082a49d4611 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sat, 22 Jun 2024 18:03:46 +0530 Subject: [PATCH 214/330] dt-bindings: iio: st-sensors: add LIS2DS12 accelerometer LIS2DS12 is an accelerometer by STMicroelectronics. It is identifiable by its WhoAmI value 0x43. Its register interface is not compatible with existing parts. For example: - The full-scale values are present in register 0x20, in bits 2 and 3 (mask 0x0c). Most other supported sensors have the register address set to 0x21, 0x23, 0x24, or 0x25. There is one sensor setting though (bearing WhoAmI 0x3b) which has it's address set to 0x20, but the mask is set to 0x20, not 0x0c. - The full-scale values 2G, 4G, 8G, and 16G correspond to the register values 0x00, 0x02, 0x03, 0x01 respectively. None of the sensor settings have the value 0x01 associated with 16G. Add the compatible string without any fallback. Signed-off-by: Kaustabh Chakraborty Link: https://patch.msgid.link/20240622123520.39253-2-kauschluss@disroot.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/st,st-sensors.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml index fff7e3d83a02..71c1ee33a393 100644 --- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml +++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml @@ -26,6 +26,7 @@ properties: - st,lis2dw12 - st,lis2hh12 - st,lis2dh12-accel + - st,lis2ds12 - st,lis302dl - st,lis331dl-accel - st,lis331dlh-accel From d80d4a3ce3aa3b0d8ac6966cb15f79d0c4a542e2 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:04 +0200 Subject: [PATCH 215/330] iio: imu: adis_buffer: split trigger handling Split trigger handling for devices that have paging and need to select the correct page to get the data. Although this actually introduces more LOC, it makes the code and the locking clear. It will also make the following move to the cleanup magic cleaner. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-1-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 45 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 871b78b225e2..5bde698cce18 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -126,6 +126,30 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, } EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, IIO_ADISLIB); +static int adis_paging_trigger_handler(struct adis *adis) +{ + int ret; + + mutex_lock(&adis->state_lock); + if (adis->current_page != 0) { + adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); + adis->tx[1] = 0; + ret = spi_write(adis->spi, adis->tx, 2); + if (ret) { + dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); + mutex_unlock(&adis->state_lock); + return ret; + } + + adis->current_page = 0; + } + + ret = spi_sync(adis->spi, &adis->msg); + mutex_unlock(&adis->state_lock); + + return ret; +} + static irqreturn_t adis_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -133,25 +157,10 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) struct adis *adis = iio_device_get_drvdata(indio_dev); int ret; - if (adis->data->has_paging) { - mutex_lock(&adis->state_lock); - if (adis->current_page != 0) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = 0; - ret = spi_write(adis->spi, adis->tx, 2); - if (ret) { - dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); - mutex_unlock(&adis->state_lock); - goto irq_done; - } - - adis->current_page = 0; - } - } - - ret = spi_sync(adis->spi, &adis->msg); if (adis->data->has_paging) - mutex_unlock(&adis->state_lock); + ret = adis_paging_trigger_handler(adis); + else + ret = spi_sync(adis->spi, &adis->msg); if (ret) { dev_err(&adis->spi->dev, "Failed to read data: %d", ret); goto irq_done; From d305b7f34ee11c4901b8da150b641bcffbd3e951 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:05 +0200 Subject: [PATCH 216/330] iio: imu: adis: move to the cleanup magic This makes locking and handling error paths simpler. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-2-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 11 +++---- drivers/iio/imu/adis_buffer.c | 8 ++---- include/linux/iio/imu/adis.h | 54 +++++++++-------------------------- 3 files changed, 19 insertions(+), 54 deletions(-) diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 495caf4ce87a..876848b42f69 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -466,17 +466,17 @@ int adis_single_conversion(struct iio_dev *indio_dev, unsigned int uval; int ret; - mutex_lock(&adis->state_lock); + guard(mutex)(&adis->state_lock); ret = __adis_read_reg(adis, chan->address, &uval, chan->scan_type.storagebits / 8); if (ret) - goto err_unlock; + return ret; if (uval & error_mask) { ret = __adis_check_status(adis); if (ret) - goto err_unlock; + return ret; } if (chan->scan_type.sign == 's') @@ -484,10 +484,7 @@ int adis_single_conversion(struct iio_dev *indio_dev, else *val = uval & ((1 << chan->scan_type.realbits) - 1); - ret = IIO_VAL_INT; -err_unlock: - mutex_unlock(&adis->state_lock); - return ret; + return IIO_VAL_INT; } EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 5bde698cce18..b7c1cc04492a 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -130,24 +130,20 @@ static int adis_paging_trigger_handler(struct adis *adis) { int ret; - mutex_lock(&adis->state_lock); + guard(mutex)(&adis->state_lock); if (adis->current_page != 0) { adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); adis->tx[1] = 0; ret = spi_write(adis->spi, adis->tx, 2); if (ret) { dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); - mutex_unlock(&adis->state_lock); return ret; } adis->current_page = 0; } - ret = spi_sync(adis->spi, &adis->msg); - mutex_unlock(&adis->state_lock); - - return ret; + return spi_sync(adis->spi, &adis->msg); } static irqreturn_t adis_trigger_handler(int irq, void *p) diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 4bb0a53cf7ea..93dad627378f 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -9,6 +9,7 @@ #ifndef __IIO_ADIS_H__ #define __IIO_ADIS_H__ +#include #include #include #include @@ -150,13 +151,8 @@ int __adis_reset(struct adis *adis); */ static inline int adis_reset(struct adis *adis) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_reset(adis); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_reset(adis); } int __adis_write_reg(struct adis *adis, unsigned int reg, @@ -248,13 +244,8 @@ static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg, static inline int adis_write_reg(struct adis *adis, unsigned int reg, unsigned int val, unsigned int size) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_write_reg(adis, reg, val, size); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_write_reg(adis, reg, val, size); } /** @@ -267,13 +258,8 @@ static inline int adis_write_reg(struct adis *adis, unsigned int reg, static int adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, unsigned int size) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_read_reg(adis, reg, val, size); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_read_reg(adis, reg, val, size); } /** @@ -365,12 +351,8 @@ int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask, static inline int adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask, const u32 val, u8 size) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_update_bits_base(adis, reg, mask, val, size); - mutex_unlock(&adis->state_lock); - return ret; + guard(mutex)(&adis->state_lock); + return __adis_update_bits_base(adis, reg, mask, val, size); } /** @@ -411,24 +393,14 @@ int __adis_enable_irq(struct adis *adis, bool enable); static inline int adis_enable_irq(struct adis *adis, bool enable) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_enable_irq(adis, enable); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_enable_irq(adis, enable); } static inline int adis_check_status(struct adis *adis) { - int ret; - - mutex_lock(&adis->state_lock); - ret = __adis_check_status(adis); - mutex_unlock(&adis->state_lock); - - return ret; + guard(mutex)(&adis->state_lock); + return __adis_check_status(adis); } static inline void adis_dev_lock(struct adis *adis) From e6cab1ad9769a6b03dd1ba7ace106c36de85b1a8 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:06 +0200 Subject: [PATCH 217/330] iio: imu: adis: add cleanup based lock helpers Add two new lock helpers that make use of the cleanup guard() and scoped_guard() macros. Thus, users won't have to worry about unlocking which is less prone to errors and allows for simpler error paths. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-3-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- include/linux/iio/imu/adis.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 93dad627378f..bc7332d12c44 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -403,6 +403,10 @@ static inline int adis_check_status(struct adis *adis) return __adis_check_status(adis); } +#define adis_dev_auto_lock(adis) guard(mutex)(&(adis)->state_lock) +#define adis_dev_auto_scoped_lock(adis) \ + scoped_guard(mutex, &(adis)->state_lock) + static inline void adis_dev_lock(struct adis *adis) { mutex_lock(&adis->state_lock); From ccd52641f9afad7cf66a667e7004ac08443bd5d6 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:07 +0200 Subject: [PATCH 218/330] iio: gyro: adis16260: make use of the new lock helpers Use the new auto cleanup based locks so error paths are simpler. While at it, turned a sprintf() call into sysfs_emit(). Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-4-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16136.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index c95cf41be34b..da83adc684d0 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -221,13 +221,12 @@ static ssize_t adis16136_read_frequency(struct device *dev, unsigned int freq; int ret; - adis_dev_lock(&adis16136->adis); + adis_dev_auto_lock(&adis16136->adis); ret = __adis16136_get_freq(adis16136, &freq); - adis_dev_unlock(&adis16136->adis); if (ret) return ret; - return sprintf(buf, "%d\n", freq); + return sysfs_emit(buf, "%d\n", freq); } static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, @@ -251,21 +250,17 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val) unsigned int freq; int i, ret; - adis_dev_lock(&adis16136->adis); + adis_dev_auto_lock(&adis16136->adis); ret = __adis16136_get_freq(adis16136, &freq); if (ret) - goto out_unlock; + return ret; for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { if (freq / adis16136_3db_divisors[i] >= val) break; } - ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); -out_unlock: - adis_dev_unlock(&adis16136->adis); - - return ret; + return __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); } static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) @@ -275,23 +270,20 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) uint16_t val16; int ret; - adis_dev_lock(&adis16136->adis); + adis_dev_auto_lock(&adis16136->adis); ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); if (ret) - goto err_unlock; + return ret; ret = __adis16136_get_freq(adis16136, &freq); if (ret) - goto err_unlock; + return ret; *val = freq / adis16136_3db_divisors[val16 & 0x07]; -err_unlock: - adis_dev_unlock(&adis16136->adis); - - return ret ? ret : IIO_VAL_INT; + return IIO_VAL_INT; } static int adis16136_read_raw(struct iio_dev *indio_dev, From 8d61d01cdec275719b70295e98e4d45c5f284f29 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:08 +0200 Subject: [PATCH 219/330] iio: gyro: adis16260: make use of the new lock helpers Use the new auto cleanup based locks so error paths are simpler. While at it, reduce a bit the scope of the lock as we did not needed it protecting all the data in the switch() branch. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-5-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16260.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 112d635b7dfd..495b64a27061 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -270,7 +270,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, { struct adis16260 *adis16260 = iio_priv(indio_dev); struct adis *adis = &adis16260->adis; - int ret; u8 addr; u8 t; @@ -288,7 +287,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, addr = adis16260_addresses[chan->scan_index][1]; return adis_write_reg_16(adis, addr, val); case IIO_CHAN_INFO_SAMP_FREQ: - adis_dev_lock(adis); if (spi_get_device_id(adis->spi)->driver_data) t = 256 / val; else @@ -298,15 +296,14 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, t = ADIS16260_SMPL_PRD_DIV_MASK; else if (t > 0) t--; - - if (t >= 0x0A) - adis->spi->max_speed_hz = ADIS16260_SPI_SLOW; - else - adis->spi->max_speed_hz = ADIS16260_SPI_FAST; - ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t); - - adis_dev_unlock(adis); - return ret; + adis_dev_auto_scoped_lock(adis) { + if (t >= 0x0A) + adis->spi->max_speed_hz = ADIS16260_SPI_SLOW; + else + adis->spi->max_speed_hz = ADIS16260_SPI_FAST; + return __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t); + } + unreachable(); } return -EINVAL; } From 9d9dae6ae8ab440835981b209ebe6ba8465b46a4 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:09 +0200 Subject: [PATCH 220/330] iio: imu: adis16400: make use of the new lock helpers Use the new auto cleanup based locks so error paths are simpler. While at it, removed 'ret' from adis16400_write_raw() by doing return adis_write_reg_16(); instead of ret = adis_write_reg_16(); return ret; Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-6-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.c | 72 ++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 3eda32e12a53..0bfd6205f5f6 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -497,41 +497,38 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); - int ret, sps; + int sps; switch (info) { case IIO_CHAN_INFO_CALIBBIAS: - ret = adis_write_reg_16(&st->adis, - adis16400_addresses[chan->scan_index], val); - return ret; + return adis_write_reg_16(&st->adis, + adis16400_addresses[chan->scan_index], + val); case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* * Need to cache values so we can update if the frequency * changes. */ - adis_dev_lock(&st->adis); - st->filt_int = val; - /* Work out update to current value */ - sps = st->variant->get_freq(st); - if (sps < 0) { - adis_dev_unlock(&st->adis); - return sps; - } + adis_dev_auto_scoped_lock(&st->adis) { + st->filt_int = val; + /* Work out update to current value */ + sps = st->variant->get_freq(st); + if (sps < 0) + return sps; - ret = __adis16400_set_filter(indio_dev, sps, - val * 1000 + val2 / 1000); - adis_dev_unlock(&st->adis); - return ret; + return __adis16400_set_filter(indio_dev, sps, + val * 1000 + val2 / 1000); + } + unreachable(); case IIO_CHAN_INFO_SAMP_FREQ: sps = val * 1000 + val2 / 1000; if (sps <= 0) return -EINVAL; - adis_dev_lock(&st->adis); - ret = st->variant->set_freq(st, sps); - adis_dev_unlock(&st->adis); - return ret; + adis_dev_auto_scoped_lock(&st->adis) + return st->variant->set_freq(st, sps); + unreachable(); default: return -EINVAL; } @@ -596,29 +593,30 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val = st->variant->temp_offset; return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - adis_dev_lock(&st->adis); - /* Need both the number of taps and the sampling frequency */ - ret = __adis_read_reg_16(&st->adis, - ADIS16400_SENS_AVG, - &val16); - if (ret) { - adis_dev_unlock(&st->adis); - return ret; + adis_dev_auto_scoped_lock(&st->adis) { + /* + * Need both the number of taps and the sampling + * frequency + */ + ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, + &val16); + if (ret) + return ret; + + ret = st->variant->get_freq(st); + if (ret) + return ret; } - ret = st->variant->get_freq(st); - adis_dev_unlock(&st->adis); - if (ret) - return ret; ret /= adis16400_3db_divisors[val16 & 0x07]; *val = ret / 1000; *val2 = (ret % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: - adis_dev_lock(&st->adis); - ret = st->variant->get_freq(st); - adis_dev_unlock(&st->adis); - if (ret) - return ret; + adis_dev_auto_scoped_lock(&st->adis) { + ret = st->variant->get_freq(st); + if (ret) + return ret; + } *val = ret / 1000; *val2 = (ret % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; From d6a60d76173d47d25a9b6d804b5bb28921a36b0f Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:10 +0200 Subject: [PATCH 221/330] iio: imu: adis16480: make use of the new lock helpers Use the new auto cleanup based locks so error paths are simpler. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-7-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 65 ++++++++++++++----------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 56ca5a09fbbf..c59ef6f7cfd4 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -345,7 +345,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) if (t == 0) return -EINVAL; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); /* * When using PPS mode, the input clock needs to be scaled so that we have an IMU * sample rate between (optimally) 4000 and 4250. After this, we can use the @@ -388,7 +388,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) sync_scale = scaled_rate / st->clk_freq; ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale); if (ret) - goto error; + return ret; sample_rate = scaled_rate; } @@ -400,10 +400,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) if (t > st->chip_info->max_dec_rate) t = st->chip_info->max_dec_rate; - ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); -error: - adis_dev_unlock(&st->adis); - return ret; + return __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); } static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) @@ -413,23 +410,21 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) int ret; unsigned int freq, sample_rate = st->clk_freq; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); if (st->clk_mode == ADIS16480_CLK_PPS) { u16 sync_scale; ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale); if (ret) - goto error; + return ret; sample_rate = st->clk_freq * sync_scale; } ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); if (ret) - goto error; - - adis_dev_unlock(&st->adis); + return ret; freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1)); @@ -437,9 +432,6 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) *val2 = (freq % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; -error: - adis_dev_unlock(&st->adis); - return ret; } enum { @@ -630,11 +622,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, offset = ad16480_filter_data[chan->scan_index][1]; enable_mask = BIT(offset + 2); - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); ret = __adis_read_reg_16(&st->adis, reg, &val); if (ret) - goto out_unlock; + return ret; if (freq == 0) { val &= ~enable_mask; @@ -656,11 +648,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, val |= enable_mask; } - ret = __adis_write_reg_16(&st->adis, reg, val); -out_unlock: - adis_dev_unlock(&st->adis); - - return ret; + return __adis_write_reg_16(&st->adis, reg, val); } static int adis16480_read_raw(struct iio_dev *indio_dev, @@ -1355,29 +1343,26 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) u32 crc; bool valid; - adis_dev_lock(adis); - if (adis->current_page != 0) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = 0; - ret = spi_write(adis->spi, adis->tx, 2); - if (ret) { - dev_err(dev, "Failed to change device page: %d\n", ret); - adis_dev_unlock(adis); - goto irq_done; + adis_dev_auto_scoped_lock(adis) { + if (adis->current_page != 0) { + adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); + adis->tx[1] = 0; + ret = spi_write(adis->spi, adis->tx, 2); + if (ret) { + dev_err(dev, "Failed to change device page: %d\n", ret); + goto irq_done; + } + + adis->current_page = 0; } - adis->current_page = 0; + ret = spi_sync(adis->spi, &adis->msg); + if (ret) { + dev_err(dev, "Failed to read data: %d\n", ret); + goto irq_done; + } } - ret = spi_sync(adis->spi, &adis->msg); - if (ret) { - dev_err(dev, "Failed to read data: %d\n", ret); - adis_dev_unlock(adis); - goto irq_done; - } - - adis_dev_unlock(adis); - /* * After making the burst request, the response can have one or two * 16-bit responses containing the BURST_ID depending on the sclk. If From ad62e8b6fd91007aa25a034c087eaee2a7c1c4c0 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:11 +0200 Subject: [PATCH 222/330] iio: imu: adis16475: make use of the new lock helpers Use the new auto cleanup based locks so error paths are simpler. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-8-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 44 ++++++++++++------------------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index cf73c6f46c79..482258ed5a3c 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -302,30 +302,25 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq) u16 dec; u32 sample_rate = st->clk_freq; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); if (st->sync_mode == ADIS16475_SYNC_SCALED) { u16 sync_scale; ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, &sync_scale); if (ret) - goto error; + return ret; sample_rate = st->clk_freq * sync_scale; } ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec); if (ret) - goto error; - - adis_dev_unlock(&st->adis); + return ret; *freq = DIV_ROUND_CLOSEST(sample_rate, dec + 1); return 0; -error: - adis_dev_unlock(&st->adis); - return ret; } static int adis16475_set_freq(struct adis16475 *st, const u32 freq) @@ -340,7 +335,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) if (!freq) return -EINVAL; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); /* * When using sync scaled mode, the input clock needs to be scaled so that we have * an IMU sample rate between (optimally) int_clk - 100 and int_clk + 100. @@ -385,7 +380,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) sync_scale = scaled_rate / st->clk_freq; ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale); if (ret) - goto error; + return ret; sample_rate = scaled_rate; } @@ -400,9 +395,8 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec); if (ret) - goto error; + return ret; - adis_dev_unlock(&st->adis); /* * If decimation is used, then gyro and accel data will have meaningful * bits on the LSB registers. This info is used on the trigger handler. @@ -410,9 +404,6 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) assign_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag, dec); return 0; -error: - adis_dev_unlock(&st->adis); - return ret; } /* The values are approximated. */ @@ -541,19 +532,15 @@ static int adis16475_buffer_postdisable(struct iio_dev *indio_dev) struct adis *adis = &st->adis; int ret; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0)); if (ret) - goto unlock; + return ret; - ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD, - ADIS16575_FIFO_FLUSH_CMD); - -unlock: - adis_dev_unlock(&st->adis); - return ret; + return __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD, + ADIS16575_FIFO_FLUSH_CMD); } static const struct iio_buffer_setup_ops adis16475_buffer_ops = { @@ -567,20 +554,18 @@ static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val) int ret; u16 wm_lvl; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM); wm_lvl = ADIS16575_WM_LVL(val - 1); ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl); if (ret) - goto unlock; + return ret; st->fifo_watermark = val; -unlock: - adis_dev_unlock(&st->adis); - return ret; + return 0; } static const u32 adis16475_calib_regs[] = { @@ -1745,7 +1730,7 @@ static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p) int ret; u16 fifo_cnt, i; - adis_dev_lock(&st->adis); + adis_dev_auto_lock(&st->adis); ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt); if (ret) @@ -1781,7 +1766,6 @@ unlock: * reading data from registers will impact the FIFO reading. */ adis16475_burst32_check(st); - adis_dev_unlock(&st->adis); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; From bb78ad627659fc7a738356951999f2ba79e68059 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 18 Jun 2024 15:32:12 +0200 Subject: [PATCH 223/330] iio: imu: adis: remove legacy lock helpers Since all users were converted to the new cleanup based helper, adis_dev_lock() and adis_dev_unlock() can now be removed from the lib. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240618-dev-iio-adis-cleanup-v1-9-bd93ce7845c7@analog.com Signed-off-by: Jonathan Cameron --- include/linux/iio/imu/adis.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index bc7332d12c44..e6a75356567a 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -407,16 +407,6 @@ static inline int adis_check_status(struct adis *adis) #define adis_dev_auto_scoped_lock(adis) \ scoped_guard(mutex, &(adis)->state_lock) -static inline void adis_dev_lock(struct adis *adis) -{ - mutex_lock(&adis->state_lock); -} - -static inline void adis_dev_unlock(struct adis *adis) -{ - mutex_unlock(&adis->state_lock); -} - int adis_single_conversion(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int error_mask, int *val); From 9a36aa0f36ab17819d8cb0974f18f32d0fcef2e8 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:48 -0500 Subject: [PATCH 224/330] iio: adc: aspeed_adc: use devm_regulator_get_enable_read_voltage() This makes use of the devm_regulator_get_enable_read_voltage() helper function to simplify the code. The error return is moved closer to the function call to make it easier to follow the logic. And a few blank lines are added for readability. Signed-off-by: David Lechner Reviewed-by: Andrew Jeffery Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-1-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/aspeed_adc.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 998e8bcc06e1..090416c0d622 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -108,7 +108,6 @@ struct adc_gain { struct aspeed_adc_data { struct device *dev; const struct aspeed_adc_model_data *model_data; - struct regulator *regulator; void __iomem *base; spinlock_t clk_lock; struct clk_hw *fixed_div_clk; @@ -404,13 +403,6 @@ static void aspeed_adc_power_down(void *data) priv_data->base + ASPEED_REG_ENGINE_CONTROL); } -static void aspeed_adc_reg_disable(void *data) -{ - struct regulator *reg = data; - - regulator_disable(reg); -} - static int aspeed_adc_vref_config(struct iio_dev *indio_dev) { struct aspeed_adc_data *data = iio_priv(indio_dev); @@ -423,18 +415,14 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev) } adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); - data->regulator = devm_regulator_get_optional(data->dev, "vref"); - if (!IS_ERR(data->regulator)) { - ret = regulator_enable(data->regulator); - if (ret) - return ret; - ret = devm_add_action_or_reset( - data->dev, aspeed_adc_reg_disable, data->regulator); - if (ret) - return ret; - data->vref_mv = regulator_get_voltage(data->regulator); - /* Conversion from uV to mV */ - data->vref_mv /= 1000; + + ret = devm_regulator_get_enable_read_voltage(data->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; + + if (ret != -ENODEV) { + data->vref_mv = ret / 1000; + if ((data->vref_mv >= 1550) && (data->vref_mv <= 2700)) writel(adc_engine_control_reg_val | FIELD_PREP( @@ -453,8 +441,6 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev) return -EOPNOTSUPP; } } else { - if (PTR_ERR(data->regulator) != -ENODEV) - return PTR_ERR(data->regulator); data->vref_mv = 2500000; of_property_read_u32(data->dev->of_node, "aspeed,int-vref-microvolt", From 0099e82b132e4fa619c45b47f2f83a823d81eaaa Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:49 -0500 Subject: [PATCH 225/330] iio: adc: hx711: use devm_regulator_get_enable_read_voltage() Use the devm_regulator_get_enable_read_voltage() helper to simplify the code. Signed-off-by: David Lechner Reviewed-by: Andreas Klinger Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-2-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hx711.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index fef97c1d226a..6efdc971689c 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -80,7 +80,6 @@ struct hx711_data { struct device *dev; struct gpio_desc *gpiod_pd_sck; struct gpio_desc *gpiod_dout; - struct regulator *reg_avdd; int gain_set; /* gain set on device */ int gain_chan_a; /* gain for channel A */ struct mutex lock; @@ -497,11 +496,7 @@ static int hx711_probe(struct platform_device *pdev) return PTR_ERR(hx711_data->gpiod_dout); } - hx711_data->reg_avdd = devm_regulator_get(dev, "avdd"); - if (IS_ERR(hx711_data->reg_avdd)) - return PTR_ERR(hx711_data->reg_avdd); - - ret = regulator_enable(hx711_data->reg_avdd); + ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); if (ret < 0) return ret; @@ -517,9 +512,6 @@ static int hx711_probe(struct platform_device *pdev) * approximately to fit into a 32 bit number: * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV] */ - ret = regulator_get_voltage(hx711_data->reg_avdd); - if (ret < 0) - goto error_regulator; /* we need 10^-9 mV */ ret *= 100; @@ -559,7 +551,7 @@ static int hx711_probe(struct platform_device *pdev) hx711_trigger, NULL); if (ret < 0) { dev_err(dev, "setup of iio triggered buffer failed\n"); - goto error_regulator; + return ret; } ret = iio_device_register(indio_dev); @@ -573,25 +565,17 @@ static int hx711_probe(struct platform_device *pdev) error_buffer: iio_triggered_buffer_cleanup(indio_dev); -error_regulator: - regulator_disable(hx711_data->reg_avdd); - return ret; } static void hx711_remove(struct platform_device *pdev) { - struct hx711_data *hx711_data; struct iio_dev *indio_dev; indio_dev = platform_get_drvdata(pdev); - hx711_data = iio_priv(indio_dev); iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - regulator_disable(hx711_data->reg_avdd); } static const struct of_device_id of_hx711_match[] = { From bfe339ee8e010aee2295be5b051673526581dd75 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:50 -0500 Subject: [PATCH 226/330] iio: adc: hx711: remove hx711_remove() By using a few more devm_ functions, we can remove the hx711_remove() function in the hx711 driver. platform_set_drvdata() is also removed since there are no more callers of platform_get_drvdata(). Signed-off-by: David Lechner Reviewed-by: Andreas Klinger Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-3-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hx711.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 6efdc971689c..8461b1fe6bad 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -539,43 +539,27 @@ static int hx711_probe(struct platform_device *pdev) hx711_data->data_ready_delay_ns = 1000000000 / hx711_data->clock_frequency; - platform_set_drvdata(pdev, indio_dev); - indio_dev->name = "hx711"; indio_dev->info = &hx711_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = hx711_chan_spec; indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec); - ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, - hx711_trigger, NULL); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + hx711_trigger, NULL); if (ret < 0) { dev_err(dev, "setup of iio triggered buffer failed\n"); return ret; } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret < 0) { dev_err(dev, "Couldn't register the device\n"); - goto error_buffer; + return ret; } return 0; - -error_buffer: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static void hx711_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev; - - indio_dev = platform_get_drvdata(pdev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); } static const struct of_device_id of_hx711_match[] = { @@ -587,7 +571,6 @@ MODULE_DEVICE_TABLE(of, of_hx711_match); static struct platform_driver hx711_driver = { .probe = hx711_probe, - .remove_new = hx711_remove, .driver = { .name = "hx711-gpio", .of_match_table = of_hx711_match, From 95e17a54e4eb63f722be70c6488cf377cae8afc6 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:51 -0500 Subject: [PATCH 227/330] iio: adc: hx711: use dev_err_probe() Use dev_err_probe() to simplify error returns in the probe function. Signed-off-by: David Lechner Reviewed-by: Andreas Klinger Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-4-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hx711.c | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 8461b1fe6bad..b3372ccff7d5 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -464,10 +464,8 @@ static int hx711_probe(struct platform_device *pdev) int i; indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data)); - if (!indio_dev) { - dev_err(dev, "failed to allocate IIO device\n"); - return -ENOMEM; - } + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, "failed to allocate IIO device\n"); hx711_data = iio_priv(indio_dev); hx711_data->dev = dev; @@ -479,22 +477,18 @@ static int hx711_probe(struct platform_device *pdev) * in the driver it is an output */ hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); - if (IS_ERR(hx711_data->gpiod_pd_sck)) { - dev_err(dev, "failed to get sck-gpiod: err=%ld\n", - PTR_ERR(hx711_data->gpiod_pd_sck)); - return PTR_ERR(hx711_data->gpiod_pd_sck); - } + if (IS_ERR(hx711_data->gpiod_pd_sck)) + return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_pd_sck), + "failed to get sck-gpiod\n"); /* * DOUT stands for serial data output of HX711 * for the driver it is an input */ hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN); - if (IS_ERR(hx711_data->gpiod_dout)) { - dev_err(dev, "failed to get dout-gpiod: err=%ld\n", - PTR_ERR(hx711_data->gpiod_dout)); - return PTR_ERR(hx711_data->gpiod_dout); - } + if (IS_ERR(hx711_data->gpiod_dout)) + return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_dout), + "failed to get dout-gpiod\n"); ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); if (ret < 0) @@ -548,16 +542,13 @@ static int hx711_probe(struct platform_device *pdev) ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, hx711_trigger, NULL); - if (ret < 0) { - dev_err(dev, "setup of iio triggered buffer failed\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "setup of iio triggered buffer failed\n"); ret = devm_iio_device_register(dev, indio_dev); - if (ret < 0) { - dev_err(dev, "Couldn't register the device\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Couldn't register the device\n"); return 0; } From 890582c2a496d71aab53b3ff39fba1fd05fe9230 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:52 -0500 Subject: [PATCH 228/330] iio: adc: ltc2309: use devm_regulator_get_enable_read_voltage() Use devm_regulator_get_enable_read_voltage() to simplify the code. Error message is changed since there is only one error return now. LTC2309_INTERNAL_REF_MV macro is added to make the internal reference voltage value self-documenting. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-5-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ltc2309.c | 43 ++++++--------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c index 8b3a89c1b840..888a71454070 100644 --- a/drivers/iio/adc/ltc2309.c +++ b/drivers/iio/adc/ltc2309.c @@ -16,6 +16,7 @@ #include #define LTC2309_ADC_RESOLUTION 12 +#define LTC2309_INTERNAL_REF_MV 4096 #define LTC2309_DIN_CH_MASK GENMASK(7, 4) #define LTC2309_DIN_SDN BIT(7) @@ -29,14 +30,12 @@ * struct ltc2309 - internal device data structure * @dev: Device reference * @client: I2C reference - * @vref: External reference source * @lock: Lock to serialize data access * @vref_mv: Internal voltage reference */ struct ltc2309 { struct device *dev; struct i2c_client *client; - struct regulator *vref; struct mutex lock; /* serialize data access */ int vref_mv; }; @@ -157,11 +156,6 @@ static const struct iio_info ltc2309_info = { .read_raw = ltc2309_read_raw, }; -static void ltc2309_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int ltc2309_probe(struct i2c_client *client) { struct iio_dev *indio_dev; @@ -175,7 +169,6 @@ static int ltc2309_probe(struct i2c_client *client) ltc2309 = iio_priv(indio_dev); ltc2309->dev = &indio_dev->dev; ltc2309->client = client; - ltc2309->vref_mv = 4096; /* Default to the internal ref */ indio_dev->name = "ltc2309"; indio_dev->modes = INDIO_DIRECT_MODE; @@ -183,36 +176,12 @@ static int ltc2309_probe(struct i2c_client *client) indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels); indio_dev->info = <c2309_info; - ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref"); - if (IS_ERR(ltc2309->vref)) { - ret = PTR_ERR(ltc2309->vref); - if (ret == -ENODEV) - ltc2309->vref = NULL; - else - return ret; - } + ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(ltc2309->dev, ret, + "failed to get vref voltage\n"); - if (ltc2309->vref) { - ret = regulator_enable(ltc2309->vref); - if (ret) - return dev_err_probe(ltc2309->dev, ret, - "failed to enable vref\n"); - - ret = devm_add_action_or_reset(ltc2309->dev, - ltc2309_regulator_disable, - ltc2309->vref); - if (ret) { - return dev_err_probe(ltc2309->dev, ret, - "failed to add regulator_disable action: %d\n", - ret); - } - - ret = regulator_get_voltage(ltc2309->vref); - if (ret < 0) - return ret; - - ltc2309->vref_mv = ret / 1000; - } + ltc2309->vref_mv = ret == -ENODEV ? LTC2309_INTERNAL_REF_MV : ret / 1000; mutex_init(<c2309->lock); From 0817c9543c345acd56e95fdf37be112248fbfc3a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:53 -0500 Subject: [PATCH 229/330] iio: adc: max1363: use devm_regulator_get_enable_read_voltage() Use devm_regulator_get_enable_read_voltage() to simplify the code. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-6-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max1363.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 8b5bc96cb9fb..bf4b6dc53fd2 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1561,18 +1561,12 @@ static const struct of_device_id max1363_of_match[] = { }; MODULE_DEVICE_TABLE(of, max1363_of_match); -static void max1363_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int max1363_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); int ret; struct max1363_state *st; struct iio_dev *indio_dev; - struct regulator *vref; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(struct max1363_state)); @@ -1589,26 +1583,12 @@ static int max1363_probe(struct i2c_client *client) st->chip_info = i2c_get_match_data(client); st->client = client; - st->vref_uv = st->chip_info->int_vref_mv * 1000; - vref = devm_regulator_get_optional(&client->dev, "vref"); - if (!IS_ERR(vref)) { - int vref_uv; + ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - ret = regulator_enable(vref); - if (ret) - return ret; - ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, vref); - if (ret) - return ret; - - st->vref = vref; - vref_uv = regulator_get_voltage(vref); - if (vref_uv <= 0) - return -EINVAL; - - st->vref_uv = vref_uv; - } + st->vref_uv = ret == -ENODEV ? st->chip_info->int_vref_mv * 1000 : ret; if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { st->send = i2c_master_send; From 71c8bea4832e7e6e0bc04b0f4e98cac27adbe19a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:54 -0500 Subject: [PATCH 230/330] iio: adc: ti-adc108s102: use devm_regulator_get_enable_read_voltage() Use devm_regulator_get_enable_read_voltage() to simplify the code. Signed-off-by: David Lechner Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-7-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc108s102.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c index 69fcbbc7e418..9758ac801310 100644 --- a/drivers/iio/adc/ti-adc108s102.c +++ b/drivers/iio/adc/ti-adc108s102.c @@ -58,7 +58,6 @@ struct adc108s102_state { struct spi_device *spi; - struct regulator *reg; u32 va_millivolt; /* SPI transfer used by triggered buffer handler*/ struct spi_transfer ring_xfer; @@ -216,11 +215,6 @@ static const struct iio_info adc108s102_info = { .update_scan_mode = &adc108s102_update_scan_mode, }; -static void adc108s102_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int adc108s102_probe(struct spi_device *spi) { struct adc108s102_state *st; @@ -236,25 +230,9 @@ static int adc108s102_probe(struct spi_device *spi) if (ACPI_COMPANION(&spi->dev)) { st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT; } else { - st->reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); - - ret = regulator_enable(st->reg); - if (ret < 0) { - dev_err(&spi->dev, "Cannot enable vref regulator\n"); - return ret; - } - ret = devm_add_action_or_reset(&spi->dev, adc108s102_reg_disable, - st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) { - dev_err(&spi->dev, "vref get voltage failed\n"); - return ret; - } + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, "failed get vref voltage\n"); st->va_millivolt = ret / 1000; } From 2867ccf4a253fe8ac54f01907f896591335c52b4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:55 -0500 Subject: [PATCH 231/330] iio: adc: ti-ads8688: use devm_regulator_get_enable_read_voltage() Use devm_regulator_get_enable_read_voltage() to simplify the code. Signed-off-by: David Lechner Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-8-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads8688.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index 9440a268a78c..fca3032c59d9 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -65,7 +65,6 @@ struct ads8688_state { struct mutex lock; const struct ads8688_chip_info *chip_info; struct spi_device *spi; - struct regulator *reg; unsigned int vref_mv; enum ads8688_range range[8]; union { @@ -423,21 +422,11 @@ static int ads8688_probe(struct spi_device *spi) st = iio_priv(indio_dev); - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return ret; - ret = regulator_get_voltage(st->reg); - if (ret < 0) - goto err_regulator_disable; - - st->vref_mv = ret / 1000; - } else { - /* Use internal reference */ - st->vref_mv = ADS8688_VREF_MV; - } + st->vref_mv = ret == -ENODEV ? ADS8688_VREF_MV : ret / 1000; st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data]; @@ -460,7 +449,7 @@ static int ads8688_probe(struct spi_device *spi) ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL); if (ret < 0) { dev_err(&spi->dev, "iio triggered buffer setup failed\n"); - goto err_regulator_disable; + return ret; } ret = iio_device_register(indio_dev); @@ -472,23 +461,15 @@ static int ads8688_probe(struct spi_device *spi) err_buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); -err_regulator_disable: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - return ret; } static void ads8688_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ads8688_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); - - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); } static const struct spi_device_id ads8688_id[] = { From a4a9fc32f8156c7e1a9d6dddd20f19ca6acab452 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:56 -0500 Subject: [PATCH 232/330] iio: adc: ti-ads8688: drop ads8688_remove() By using a few devm_ functions, we can simplify the driver and remove the ads8688_remove() function. spi_set_drvdata() is removed since there are no more callers of spi_get_drvdata(). Also use dev_err_probe() to simplify error return. Signed-off-by: David Lechner Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-9-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads8688.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index fca3032c59d9..7a79f0cebfbf 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -432,8 +432,6 @@ static int ads8688_probe(struct spi_device *spi) spi->mode = SPI_MODE_1; - spi_set_drvdata(spi, indio_dev); - st->spi = spi; indio_dev->name = spi_get_device_id(spi)->name; @@ -446,30 +444,13 @@ static int ads8688_probe(struct spi_device *spi) mutex_init(&st->lock); - ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL); - if (ret < 0) { - dev_err(&spi->dev, "iio triggered buffer setup failed\n"); - return ret; - } + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + ads8688_trigger_handler, NULL); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "iio triggered buffer setup failed\n"); - ret = iio_device_register(indio_dev); - if (ret) - goto err_buffer_cleanup; - - return 0; - -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static void ads8688_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ads8688_id[] = { @@ -492,7 +473,6 @@ static struct spi_driver ads8688_driver = { .of_match_table = ads8688_of_match, }, .probe = ads8688_probe, - .remove = ads8688_remove, .id_table = ads8688_id, }; module_spi_driver(ads8688_driver); From 3341d69268accb5294b569ec37e55212a8a28ac5 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 21 Jun 2024 17:11:57 -0500 Subject: [PATCH 233/330] iio: dac: ad3552r: use devm_regulator_get_enable_read_voltage() Use devm_regulator_get_enable_read_voltage() to simplify the code. Error message is slightly changed since there is only one error return now. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://patch.msgid.link/20240621-iio-regulator-refactor-round-2-v1-10-49e50cd0b99a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index ddc6c262f801..bd37d304ca70 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -857,15 +857,9 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, return 0; } -static void ad3552r_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad3552r_configure_device(struct ad3552r_desc *dac) { struct device *dev = &dac->spi->dev; - struct regulator *vref; int err, cnt = 0, voltage, delta = 100000; u32 vals[2], val, ch; @@ -874,30 +868,16 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac), "Error getting gpio ldac"); - vref = devm_regulator_get_optional(dev, "vref"); - if (IS_ERR(vref)) { - if (PTR_ERR(vref) != -ENODEV) - return dev_err_probe(dev, PTR_ERR(vref), - "Error getting vref"); + voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (voltage < 0 && voltage != -ENODEV) + return dev_err_probe(dev, voltage, "Error getting vref voltage\n"); + if (voltage == -ENODEV) { if (device_property_read_bool(dev, "adi,vref-out-en")) val = AD3552R_INTERNAL_VREF_PIN_2P5V; else val = AD3552R_INTERNAL_VREF_PIN_FLOATING; } else { - err = regulator_enable(vref); - if (err) { - dev_err(dev, "Failed to enable external vref supply\n"); - return err; - } - - err = devm_add_action_or_reset(dev, ad3552r_reg_disable, vref); - if (err) { - regulator_disable(vref); - return err; - } - - voltage = regulator_get_voltage(vref); if (voltage > 2500000 + delta || voltage < 2500000 - delta) { dev_warn(dev, "vref-supply must be 2.5V"); return -EINVAL; From 791ed23f735b0fb1b984772edddf1571195780d8 Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Fri, 28 Jun 2024 16:01:44 +0200 Subject: [PATCH 234/330] dt-bindings: interconnect: qcom: Add Qualcomm MSM8953 NoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the device-tree bindings for interconnect providers used on MSM8953 platform. Signed-off-by: Vladimir Lypak Reviewed-by: Krzysztof Kozlowski Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20240628-msm8953-interconnect-v3-1-a70d582182dc@mainlining.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,msm8953.yaml | 101 ++++++++++++++++++ .../dt-bindings/interconnect/qcom,msm8953.h | 93 ++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml create mode 100644 include/dt-bindings/interconnect/qcom,msm8953.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml new file mode 100644 index 000000000000..732e9fa001a4 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8953.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,msm8953.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm MSM8953 Network-On-Chip interconnect + +maintainers: + - Barnabas Czeman + +description: | + The Qualcomm MSM8953 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + + See also: + - dt-bindings/interconnect/qcom,msm8953.h + +properties: + compatible: + enum: + - qcom,msm8953-bimc + - qcom,msm8953-pcnoc + - qcom,msm8953-snoc + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + maxItems: 1 + + '#interconnect-cells': + const: 2 + +patternProperties: + '^interconnect-[a-z0-9\-]+$': + type: object + $ref: qcom,rpm-common.yaml# + unevaluatedProperties: false + description: + The interconnect providers do not have a separate QoS register space, + but share parent's space. + + properties: + compatible: + const: qcom,msm8953-snoc-mm + + required: + - compatible + - '#interconnect-cells' + +required: + - compatible + - reg + - '#interconnect-cells' + +allOf: + - $ref: qcom,rpm-common.yaml# + - if: + properties: + compatible: + const: qcom,msm8953-pcnoc + + then: + properties: + clocks: + items: + - description: PCNOC USB3 AXI Clock. + + clock-names: + const: pcnoc_usb3_axi + + required: + - clocks + - clock-names + else: + properties: + clocks: false + clock-names: false + +additionalProperties: false + +examples: + - | + #include + + snoc: interconnect@580000 { + compatible = "qcom,msm8953-snoc"; + reg = <0x580000 0x16080>; + + #interconnect-cells = <2>; + + snoc_mm: interconnect-snoc { + compatible = "qcom,msm8953-snoc-mm"; + + #interconnect-cells = <2>; + }; + }; diff --git a/include/dt-bindings/interconnect/qcom,msm8953.h b/include/dt-bindings/interconnect/qcom,msm8953.h new file mode 100644 index 000000000000..12564c434af7 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,msm8953.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Qualcomm MSM8953 interconnect IDs + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_MSM8953_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_MSM8953_H + +/* BIMC fabric */ +#define MAS_APPS_PROC 0 +#define MAS_OXILI 1 +#define MAS_SNOC_BIMC_0 2 +#define MAS_SNOC_BIMC_2 3 +#define MAS_SNOC_BIMC_1 4 +#define MAS_TCU_0 5 +#define SLV_EBI 6 +#define SLV_BIMC_SNOC 7 + +/* PCNOC fabric */ +#define MAS_SPDM 0 +#define MAS_BLSP_1 1 +#define MAS_BLSP_2 2 +#define MAS_USB3 3 +#define MAS_CRYPTO 4 +#define MAS_SDCC_1 5 +#define MAS_SDCC_2 6 +#define MAS_SNOC_PCNOC 7 +#define PCNOC_M_0 8 +#define PCNOC_M_1 9 +#define PCNOC_INT_1 10 +#define PCNOC_INT_2 11 +#define PCNOC_S_0 12 +#define PCNOC_S_1 13 +#define PCNOC_S_2 14 +#define PCNOC_S_3 15 +#define PCNOC_S_4 16 +#define PCNOC_S_6 17 +#define PCNOC_S_7 18 +#define PCNOC_S_8 19 +#define PCNOC_S_9 20 +#define SLV_SPDM 21 +#define SLV_PDM 22 +#define SLV_TCSR 23 +#define SLV_SNOC_CFG 24 +#define SLV_TLMM 25 +#define SLV_MESSAGE_RAM 26 +#define SLV_BLSP_1 27 +#define SLV_BLSP_2 28 +#define SLV_PRNG 29 +#define SLV_CAMERA_SS_CFG 30 +#define SLV_DISP_SS_CFG 31 +#define SLV_VENUS_CFG 32 +#define SLV_GPU_CFG 33 +#define SLV_SDCC_1 34 +#define SLV_SDCC_2 35 +#define SLV_CRYPTO_0_CFG 36 +#define SLV_PMIC_ARB 37 +#define SLV_USB3 38 +#define SLV_IPA_CFG 39 +#define SLV_TCU 40 +#define SLV_PCNOC_SNOC 41 + +/* SNOC fabric */ +#define MAS_QDSS_BAM 0 +#define MAS_BIMC_SNOC 1 +#define MAS_PCNOC_SNOC 2 +#define MAS_IPA 3 +#define MAS_QDSS_ETR 4 +#define QDSS_INT 5 +#define SNOC_INT_0 6 +#define SNOC_INT_1 7 +#define SNOC_INT_2 8 +#define SLV_KPSS_AHB 9 +#define SLV_WCSS 10 +#define SLV_SNOC_BIMC_1 11 +#define SLV_IMEM 12 +#define SLV_SNOC_PCNOC 13 +#define SLV_QDSS_STM 14 +#define SLV_CATS_1 15 +#define SLV_LPASS 16 + +/* SNOC-MM fabric */ +#define MAS_JPEG 0 +#define MAS_MDP 1 +#define MAS_VENUS 2 +#define MAS_VFE0 3 +#define MAS_VFE1 4 +#define MAS_CPP 5 +#define SLV_SNOC_BIMC_0 6 +#define SLV_SNOC_BIMC_2 7 +#define SLV_CATS_0 8 + +#endif /* __DT_BINDINGS_INTERCONNECT_QCOM_MSM8953_H */ From 90b400170bcd93c61c2e0ac3990b57c54250d114 Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Fri, 28 Jun 2024 16:01:45 +0200 Subject: [PATCH 235/330] interconnect: qcom: Add MSM8953 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add driver for interconnect busses found in MSM8953 based platforms. The topology consists of four NoCs that are partially controlled by a RPM processor. Note that one of NoCs (System NoC) has a counterpart (System NoC MM) that is modelled as child device to avoid resource conflicts, since it uses same MMIO space for configuration. Signed-off-by: Vladimir Lypak Reviewed-by: Krzysztof Kozlowski Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20240628-msm8953-interconnect-v3-2-a70d582182dc@mainlining.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/Kconfig | 9 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/msm8953.c | 1321 +++++++++++++++++++++++++++ 3 files changed, 1332 insertions(+) create mode 100644 drivers/interconnect/qcom/msm8953.c diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 1446a839184e..9b84cd8becef 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -35,6 +35,15 @@ config INTERCONNECT_QCOM_MSM8939 This is a driver for the Qualcomm Network-on-Chip on msm8939-based platforms. +config INTERCONNECT_QCOM_MSM8953 + tristate "Qualcomm MSM8953 interconnect driver" + depends on INTERCONNECT_QCOM + depends on QCOM_SMD_RPM + select INTERCONNECT_QCOM_SMD_RPM + help + This is a driver for the Qualcomm Network-on-Chip on msm8953-based + platforms. + config INTERCONNECT_QCOM_MSM8974 tristate "Qualcomm MSM8974 interconnect driver" depends on INTERCONNECT_QCOM diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index 2ea3113d0a4d..7a7b6a71876f 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -7,6 +7,7 @@ icc-bcm-voter-objs := bcm-voter.o qnoc-msm8909-objs := msm8909.o qnoc-msm8916-objs := msm8916.o qnoc-msm8939-objs := msm8939.o +qnoc-msm8953-objs := msm8953.o qnoc-msm8974-objs := msm8974.o qnoc-msm8996-objs := msm8996.o icc-osm-l3-objs := osm-l3.o @@ -41,6 +42,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8909) += qnoc-msm8909.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o +obj-$(CONFIG_INTERCONNECT_QCOM_MSM8953) += qnoc-msm8953.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o diff --git a/drivers/interconnect/qcom/msm8953.c b/drivers/interconnect/qcom/msm8953.c new file mode 100644 index 000000000000..9e8867c07692 --- /dev/null +++ b/drivers/interconnect/qcom/msm8953.c @@ -0,0 +1,1321 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "icc-rpm.h" + +enum { + MSM8953_MASTER_AMPSS_M0 = 1, + MSM8953_MASTER_GRAPHICS_3D, + MSM8953_SNOC_BIMC_0_MAS, + MSM8953_SNOC_BIMC_2_MAS, + MSM8953_SNOC_BIMC_1_MAS, + MSM8953_MASTER_TCU_0, + MSM8953_SLAVE_EBI_CH0, + MSM8953_BIMC_SNOC_SLV, + MSM8953_MASTER_SPDM, + MSM8953_MASTER_BLSP_1, + MSM8953_MASTER_BLSP_2, + MSM8953_MASTER_USB3, + MSM8953_MASTER_CRYPTO_CORE0, + MSM8953_MASTER_SDCC_1, + MSM8953_MASTER_SDCC_2, + MSM8953_SNOC_PNOC_MAS, + MSM8953_PNOC_M_0, + MSM8953_PNOC_M_1, + MSM8953_PNOC_INT_1, + MSM8953_PNOC_INT_2, + MSM8953_PNOC_SLV_0, + MSM8953_PNOC_SLV_1, + MSM8953_PNOC_SLV_2, + MSM8953_PNOC_SLV_3, + MSM8953_PNOC_SLV_4, + MSM8953_PNOC_SLV_6, + MSM8953_PNOC_SLV_7, + MSM8953_PNOC_SLV_8, + MSM8953_PNOC_SLV_9, + MSM8953_SLAVE_SPDM_WRAPPER, + MSM8953_SLAVE_PDM, + MSM8953_SLAVE_TCSR, + MSM8953_SLAVE_SNOC_CFG, + MSM8953_SLAVE_TLMM, + MSM8953_SLAVE_MESSAGE_RAM, + MSM8953_SLAVE_BLSP_1, + MSM8953_SLAVE_BLSP_2, + MSM8953_SLAVE_PRNG, + MSM8953_SLAVE_CAMERA_CFG, + MSM8953_SLAVE_DISPLAY_CFG, + MSM8953_SLAVE_VENUS_CFG, + MSM8953_SLAVE_GRAPHICS_3D_CFG, + MSM8953_SLAVE_SDCC_1, + MSM8953_SLAVE_SDCC_2, + MSM8953_SLAVE_CRYPTO_0_CFG, + MSM8953_SLAVE_PMIC_ARB, + MSM8953_SLAVE_USB3, + MSM8953_SLAVE_IPA_CFG, + MSM8953_SLAVE_TCU, + MSM8953_PNOC_SNOC_SLV, + MSM8953_MASTER_QDSS_BAM, + MSM8953_BIMC_SNOC_MAS, + MSM8953_PNOC_SNOC_MAS, + MSM8953_MASTER_IPA, + MSM8953_MASTER_QDSS_ETR, + MSM8953_SNOC_QDSS_INT, + MSM8953_SNOC_INT_0, + MSM8953_SNOC_INT_1, + MSM8953_SNOC_INT_2, + MSM8953_SLAVE_APPSS, + MSM8953_SLAVE_WCSS, + MSM8953_SNOC_BIMC_1_SLV, + MSM8953_SLAVE_OCIMEM, + MSM8953_SNOC_PNOC_SLV, + MSM8953_SLAVE_QDSS_STM, + MSM8953_SLAVE_OCMEM_64, + MSM8953_SLAVE_LPASS, + MSM8953_MASTER_JPEG, + MSM8953_MASTER_MDP_PORT0, + MSM8953_MASTER_VIDEO_P0, + MSM8953_MASTER_VFE, + MSM8953_MASTER_VFE1, + MSM8953_MASTER_CPP, + MSM8953_SNOC_BIMC_0_SLV, + MSM8953_SNOC_BIMC_2_SLV, + MSM8953_SLAVE_CATS_128, +}; + +static const u16 mas_apps_proc_links[] = { + MSM8953_SLAVE_EBI_CH0, + MSM8953_BIMC_SNOC_SLV +}; + +static struct qcom_icc_node mas_apps_proc = { + .name = "mas_apps_proc", + .id = MSM8953_MASTER_AMPSS_M0, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 0, + .num_links = ARRAY_SIZE(mas_apps_proc_links), + .links = mas_apps_proc_links, +}; + +static const u16 mas_oxili_links[] = { + MSM8953_SLAVE_EBI_CH0, + MSM8953_BIMC_SNOC_SLV +}; + +static struct qcom_icc_node mas_oxili = { + .name = "mas_oxili", + .id = MSM8953_MASTER_GRAPHICS_3D, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 2, + .num_links = ARRAY_SIZE(mas_oxili_links), + .links = mas_oxili_links, +}; + +static const u16 mas_snoc_bimc_0_links[] = { + MSM8953_SLAVE_EBI_CH0, + MSM8953_BIMC_SNOC_SLV +}; + +static struct qcom_icc_node mas_snoc_bimc_0 = { + .name = "mas_snoc_bimc_0", + .id = MSM8953_SNOC_BIMC_0_MAS, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 3, + .num_links = ARRAY_SIZE(mas_snoc_bimc_0_links), + .links = mas_snoc_bimc_0_links, +}; + +static const u16 mas_snoc_bimc_2_links[] = { + MSM8953_SLAVE_EBI_CH0, + MSM8953_BIMC_SNOC_SLV +}; + +static struct qcom_icc_node mas_snoc_bimc_2 = { + .name = "mas_snoc_bimc_2", + .id = MSM8953_SNOC_BIMC_2_MAS, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 4, + .num_links = ARRAY_SIZE(mas_snoc_bimc_2_links), + .links = mas_snoc_bimc_2_links, +}; + +static const u16 mas_snoc_bimc_1_links[] = { + MSM8953_SLAVE_EBI_CH0 +}; + +static struct qcom_icc_node mas_snoc_bimc_1 = { + .name = "mas_snoc_bimc_1", + .id = MSM8953_SNOC_BIMC_1_MAS, + .buswidth = 8, + .mas_rpm_id = 76, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_snoc_bimc_1_links), + .links = mas_snoc_bimc_1_links, +}; + +static const u16 mas_tcu_0_links[] = { + MSM8953_SLAVE_EBI_CH0, + MSM8953_BIMC_SNOC_SLV +}; + +static struct qcom_icc_node mas_tcu_0 = { + .name = "mas_tcu_0", + .id = MSM8953_MASTER_TCU_0, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 2, + .qos.areq_prio = 2, + .qos.qos_port = 6, + .num_links = ARRAY_SIZE(mas_tcu_0_links), + .links = mas_tcu_0_links, +}; + +static struct qcom_icc_node slv_ebi = { + .name = "slv_ebi", + .id = MSM8953_SLAVE_EBI_CH0, + .buswidth = 8, + .mas_rpm_id = -1, + .slv_rpm_id = 0, +}; + +static const u16 slv_bimc_snoc_links[] = { + MSM8953_BIMC_SNOC_MAS +}; + +static struct qcom_icc_node slv_bimc_snoc = { + .name = "slv_bimc_snoc", + .id = MSM8953_BIMC_SNOC_SLV, + .buswidth = 8, + .mas_rpm_id = -1, + .slv_rpm_id = 2, + .num_links = ARRAY_SIZE(slv_bimc_snoc_links), + .links = slv_bimc_snoc_links, +}; + +static const u16 mas_spdm_links[] = { + MSM8953_PNOC_M_0 +}; + +static struct qcom_icc_node mas_spdm = { + .name = "mas_spdm", + .id = MSM8953_MASTER_SPDM, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(mas_spdm_links), + .links = mas_spdm_links, +}; + +static const u16 mas_blsp_1_links[] = { + MSM8953_PNOC_M_1 +}; + +static struct qcom_icc_node mas_blsp_1 = { + .name = "mas_blsp_1", + .id = MSM8953_MASTER_BLSP_1, + .buswidth = 4, + .mas_rpm_id = 41, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_blsp_1_links), + .links = mas_blsp_1_links, +}; + +static const u16 mas_blsp_2_links[] = { + MSM8953_PNOC_M_1 +}; + +static struct qcom_icc_node mas_blsp_2 = { + .name = "mas_blsp_2", + .id = MSM8953_MASTER_BLSP_2, + .buswidth = 4, + .mas_rpm_id = 39, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_blsp_2_links), + .links = mas_blsp_2_links, +}; + +static const u16 mas_usb3_links[] = { + MSM8953_PNOC_INT_1 +}; + +static struct qcom_icc_node mas_usb3 = { + .name = "mas_usb3", + .id = MSM8953_MASTER_USB3, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 1, + .qos.areq_prio = 1, + .qos.qos_port = 11, + .num_links = ARRAY_SIZE(mas_usb3_links), + .links = mas_usb3_links, +}; + +static const u16 mas_crypto_links[] = { + MSM8953_PNOC_INT_1 +}; + +static struct qcom_icc_node mas_crypto = { + .name = "mas_crypto", + .id = MSM8953_MASTER_CRYPTO_CORE0, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 1, + .qos.areq_prio = 1, + .qos.qos_port = 0, + .num_links = ARRAY_SIZE(mas_crypto_links), + .links = mas_crypto_links, +}; + +static const u16 mas_sdcc_1_links[] = { + MSM8953_PNOC_INT_1 +}; + +static struct qcom_icc_node mas_sdcc_1 = { + .name = "mas_sdcc_1", + .id = MSM8953_MASTER_SDCC_1, + .buswidth = 8, + .mas_rpm_id = 33, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_sdcc_1_links), + .links = mas_sdcc_1_links, +}; + +static const u16 mas_sdcc_2_links[] = { + MSM8953_PNOC_INT_1 +}; + +static struct qcom_icc_node mas_sdcc_2 = { + .name = "mas_sdcc_2", + .id = MSM8953_MASTER_SDCC_2, + .buswidth = 8, + .mas_rpm_id = 35, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_sdcc_2_links), + .links = mas_sdcc_2_links, +}; + +static const u16 mas_snoc_pcnoc_links[] = { + MSM8953_PNOC_INT_2 +}; + +static struct qcom_icc_node mas_snoc_pcnoc = { + .name = "mas_snoc_pcnoc", + .id = MSM8953_SNOC_PNOC_MAS, + .buswidth = 8, + .mas_rpm_id = 77, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_snoc_pcnoc_links), + .links = mas_snoc_pcnoc_links, +}; + +static const u16 pcnoc_m_0_links[] = { + MSM8953_PNOC_INT_1 +}; + +static struct qcom_icc_node pcnoc_m_0 = { + .name = "pcnoc_m_0", + .id = MSM8953_PNOC_M_0, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 1, + .qos.areq_prio = 1, + .qos.qos_port = 5, + .num_links = ARRAY_SIZE(pcnoc_m_0_links), + .links = pcnoc_m_0_links, +}; + +static const u16 pcnoc_m_1_links[] = { + MSM8953_PNOC_INT_1 +}; + +static struct qcom_icc_node pcnoc_m_1 = { + .name = "pcnoc_m_1", + .id = MSM8953_PNOC_M_1, + .buswidth = 4, + .mas_rpm_id = 88, + .slv_rpm_id = 117, + .num_links = ARRAY_SIZE(pcnoc_m_1_links), + .links = pcnoc_m_1_links, +}; + +static const u16 pcnoc_int_1_links[] = { + MSM8953_PNOC_INT_2, + MSM8953_PNOC_SNOC_SLV +}; + +static struct qcom_icc_node pcnoc_int_1 = { + .name = "pcnoc_int_1", + .id = MSM8953_PNOC_INT_1, + .buswidth = 8, + .mas_rpm_id = 86, + .slv_rpm_id = 115, + .num_links = ARRAY_SIZE(pcnoc_int_1_links), + .links = pcnoc_int_1_links, +}; + +static const u16 pcnoc_int_2_links[] = { + MSM8953_PNOC_SLV_1, + MSM8953_PNOC_SLV_2, + MSM8953_PNOC_SLV_0, + MSM8953_PNOC_SLV_4, + MSM8953_PNOC_SLV_6, + MSM8953_PNOC_SLV_7, + MSM8953_PNOC_SLV_8, + MSM8953_PNOC_SLV_9, + MSM8953_SLAVE_TCU, + MSM8953_SLAVE_GRAPHICS_3D_CFG, + MSM8953_PNOC_SLV_3 +}; + +static struct qcom_icc_node pcnoc_int_2 = { + .name = "pcnoc_int_2", + .id = MSM8953_PNOC_INT_2, + .buswidth = 8, + .mas_rpm_id = 124, + .slv_rpm_id = 184, + .num_links = ARRAY_SIZE(pcnoc_int_2_links), + .links = pcnoc_int_2_links, +}; + +static const u16 pcnoc_s_0_links[] = { + MSM8953_SLAVE_PDM, + MSM8953_SLAVE_SPDM_WRAPPER +}; + +static struct qcom_icc_node pcnoc_s_0 = { + .name = "pcnoc_s_0", + .id = MSM8953_PNOC_SLV_0, + .buswidth = 4, + .mas_rpm_id = 89, + .slv_rpm_id = 118, + .num_links = ARRAY_SIZE(pcnoc_s_0_links), + .links = pcnoc_s_0_links, +}; + +static const u16 pcnoc_s_1_links[] = { + MSM8953_SLAVE_TCSR +}; + +static struct qcom_icc_node pcnoc_s_1 = { + .name = "pcnoc_s_1", + .id = MSM8953_PNOC_SLV_1, + .buswidth = 4, + .mas_rpm_id = 90, + .slv_rpm_id = 119, + .num_links = ARRAY_SIZE(pcnoc_s_1_links), + .links = pcnoc_s_1_links, +}; + +static const u16 pcnoc_s_2_links[] = { + MSM8953_SLAVE_SNOC_CFG +}; + +static struct qcom_icc_node pcnoc_s_2 = { + .name = "pcnoc_s_2", + .id = MSM8953_PNOC_SLV_2, + .buswidth = 4, + .mas_rpm_id = 91, + .slv_rpm_id = 120, + .num_links = ARRAY_SIZE(pcnoc_s_2_links), + .links = pcnoc_s_2_links, +}; + +static const u16 pcnoc_s_3_links[] = { + MSM8953_SLAVE_TLMM, + MSM8953_SLAVE_PRNG, + MSM8953_SLAVE_BLSP_1, + MSM8953_SLAVE_BLSP_2, + MSM8953_SLAVE_MESSAGE_RAM +}; + +static struct qcom_icc_node pcnoc_s_3 = { + .name = "pcnoc_s_3", + .id = MSM8953_PNOC_SLV_3, + .buswidth = 4, + .mas_rpm_id = 92, + .slv_rpm_id = 121, + .num_links = ARRAY_SIZE(pcnoc_s_3_links), + .links = pcnoc_s_3_links, +}; + +static const u16 pcnoc_s_4_links[] = { + MSM8953_SLAVE_CAMERA_CFG, + MSM8953_SLAVE_DISPLAY_CFG, + MSM8953_SLAVE_VENUS_CFG +}; + +static struct qcom_icc_node pcnoc_s_4 = { + .name = "pcnoc_s_4", + .id = MSM8953_PNOC_SLV_4, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(pcnoc_s_4_links), + .links = pcnoc_s_4_links, +}; + +static const u16 pcnoc_s_6_links[] = { + MSM8953_SLAVE_CRYPTO_0_CFG, + MSM8953_SLAVE_SDCC_2, + MSM8953_SLAVE_SDCC_1 +}; + +static struct qcom_icc_node pcnoc_s_6 = { + .name = "pcnoc_s_6", + .id = MSM8953_PNOC_SLV_6, + .buswidth = 4, + .mas_rpm_id = 94, + .slv_rpm_id = 123, + .num_links = ARRAY_SIZE(pcnoc_s_6_links), + .links = pcnoc_s_6_links, +}; + +static const u16 pcnoc_s_7_links[] = { + MSM8953_SLAVE_PMIC_ARB +}; + +static struct qcom_icc_node pcnoc_s_7 = { + .name = "pcnoc_s_7", + .id = MSM8953_PNOC_SLV_7, + .buswidth = 4, + .mas_rpm_id = 95, + .slv_rpm_id = 124, + .num_links = ARRAY_SIZE(pcnoc_s_7_links), + .links = pcnoc_s_7_links, +}; + +static const u16 pcnoc_s_8_links[] = { + MSM8953_SLAVE_USB3 +}; + +static struct qcom_icc_node pcnoc_s_8 = { + .name = "pcnoc_s_8", + .id = MSM8953_PNOC_SLV_8, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(pcnoc_s_8_links), + .links = pcnoc_s_8_links, +}; + +static const u16 pcnoc_s_9_links[] = { + MSM8953_SLAVE_IPA_CFG +}; + +static struct qcom_icc_node pcnoc_s_9 = { + .name = "pcnoc_s_9", + .id = MSM8953_PNOC_SLV_9, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(pcnoc_s_9_links), + .links = pcnoc_s_9_links, +}; + +static struct qcom_icc_node slv_spdm = { + .name = "slv_spdm", + .id = MSM8953_SLAVE_SPDM_WRAPPER, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_pdm = { + .name = "slv_pdm", + .id = MSM8953_SLAVE_PDM, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 41, +}; + +static struct qcom_icc_node slv_tcsr = { + .name = "slv_tcsr", + .id = MSM8953_SLAVE_TCSR, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 50, +}; + +static struct qcom_icc_node slv_snoc_cfg = { + .name = "slv_snoc_cfg", + .id = MSM8953_SLAVE_SNOC_CFG, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 70, +}; + +static struct qcom_icc_node slv_tlmm = { + .name = "slv_tlmm", + .id = MSM8953_SLAVE_TLMM, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 51, +}; + +static struct qcom_icc_node slv_message_ram = { + .name = "slv_message_ram", + .id = MSM8953_SLAVE_MESSAGE_RAM, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 55, +}; + +static struct qcom_icc_node slv_blsp_1 = { + .name = "slv_blsp_1", + .id = MSM8953_SLAVE_BLSP_1, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 39, +}; + +static struct qcom_icc_node slv_blsp_2 = { + .name = "slv_blsp_2", + .id = MSM8953_SLAVE_BLSP_2, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 37, +}; + +static struct qcom_icc_node slv_prng = { + .name = "slv_prng", + .id = MSM8953_SLAVE_PRNG, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 44, +}; + +static struct qcom_icc_node slv_camera_ss_cfg = { + .name = "slv_camera_ss_cfg", + .id = MSM8953_SLAVE_CAMERA_CFG, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_disp_ss_cfg = { + .name = "slv_disp_ss_cfg", + .id = MSM8953_SLAVE_DISPLAY_CFG, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_venus_cfg = { + .name = "slv_venus_cfg", + .id = MSM8953_SLAVE_VENUS_CFG, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_gpu_cfg = { + .name = "slv_gpu_cfg", + .id = MSM8953_SLAVE_GRAPHICS_3D_CFG, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_sdcc_1 = { + .name = "slv_sdcc_1", + .id = MSM8953_SLAVE_SDCC_1, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 31, +}; + +static struct qcom_icc_node slv_sdcc_2 = { + .name = "slv_sdcc_2", + .id = MSM8953_SLAVE_SDCC_2, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 33, +}; + +static struct qcom_icc_node slv_crypto_0_cfg = { + .name = "slv_crypto_0_cfg", + .id = MSM8953_SLAVE_CRYPTO_0_CFG, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_pmic_arb = { + .name = "slv_pmic_arb", + .id = MSM8953_SLAVE_PMIC_ARB, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 59, +}; + +static struct qcom_icc_node slv_usb3 = { + .name = "slv_usb3", + .id = MSM8953_SLAVE_USB3, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_ipa_cfg = { + .name = "slv_ipa_cfg", + .id = MSM8953_SLAVE_IPA_CFG, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_tcu = { + .name = "slv_tcu", + .id = MSM8953_SLAVE_TCU, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static const u16 slv_pcnoc_snoc_links[] = { + MSM8953_PNOC_SNOC_MAS +}; + +static struct qcom_icc_node slv_pcnoc_snoc = { + .name = "slv_pcnoc_snoc", + .id = MSM8953_PNOC_SNOC_SLV, + .buswidth = 8, + .mas_rpm_id = -1, + .slv_rpm_id = 45, + .num_links = ARRAY_SIZE(slv_pcnoc_snoc_links), + .links = slv_pcnoc_snoc_links, +}; + +static const u16 mas_qdss_bam_links[] = { + MSM8953_SNOC_QDSS_INT +}; + +static struct qcom_icc_node mas_qdss_bam = { + .name = "mas_qdss_bam", + .id = MSM8953_MASTER_QDSS_BAM, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 1, + .qos.areq_prio = 1, + .qos.qos_port = 11, + .num_links = ARRAY_SIZE(mas_qdss_bam_links), + .links = mas_qdss_bam_links, +}; + +static const u16 mas_bimc_snoc_links[] = { + MSM8953_SNOC_INT_0, + MSM8953_SNOC_INT_1, + MSM8953_SNOC_INT_2 +}; + +static struct qcom_icc_node mas_bimc_snoc = { + .name = "mas_bimc_snoc", + .id = MSM8953_BIMC_SNOC_MAS, + .buswidth = 8, + .mas_rpm_id = 21, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_bimc_snoc_links), + .links = mas_bimc_snoc_links, +}; + +static const u16 mas_pcnoc_snoc_links[] = { + MSM8953_SNOC_INT_0, + MSM8953_SNOC_INT_1, + MSM8953_SNOC_BIMC_1_SLV +}; + +static struct qcom_icc_node mas_pcnoc_snoc = { + .name = "mas_pcnoc_snoc", + .id = MSM8953_PNOC_SNOC_MAS, + .buswidth = 8, + .mas_rpm_id = 29, + .slv_rpm_id = -1, + .num_links = ARRAY_SIZE(mas_pcnoc_snoc_links), + .links = mas_pcnoc_snoc_links, +}; + +static const u16 mas_ipa_links[] = { + MSM8953_SNOC_INT_0, + MSM8953_SNOC_INT_1, + MSM8953_SNOC_BIMC_1_SLV +}; + +static struct qcom_icc_node mas_ipa = { + .name = "mas_ipa", + .id = MSM8953_MASTER_IPA, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 14, + .num_links = ARRAY_SIZE(mas_ipa_links), + .links = mas_ipa_links, +}; + +static const u16 mas_qdss_etr_links[] = { + MSM8953_SNOC_QDSS_INT +}; + +static struct qcom_icc_node mas_qdss_etr = { + .name = "mas_qdss_etr", + .id = MSM8953_MASTER_QDSS_ETR, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_FIXED, + .qos.prio_level = 1, + .qos.areq_prio = 1, + .qos.qos_port = 10, + .num_links = ARRAY_SIZE(mas_qdss_etr_links), + .links = mas_qdss_etr_links, +}; + +static const u16 qdss_int_links[] = { + MSM8953_SNOC_INT_1, + MSM8953_SNOC_BIMC_1_SLV +}; + +static struct qcom_icc_node qdss_int = { + .name = "qdss_int", + .id = MSM8953_SNOC_QDSS_INT, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(qdss_int_links), + .links = qdss_int_links, +}; + +static const u16 snoc_int_0_links[] = { + MSM8953_SLAVE_LPASS, + MSM8953_SLAVE_WCSS, + MSM8953_SLAVE_APPSS +}; + +static struct qcom_icc_node snoc_int_0 = { + .name = "snoc_int_0", + .id = MSM8953_SNOC_INT_0, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(snoc_int_0_links), + .links = snoc_int_0_links, +}; + +static const u16 snoc_int_1_links[] = { + MSM8953_SLAVE_QDSS_STM, + MSM8953_SLAVE_OCIMEM, + MSM8953_SNOC_PNOC_SLV +}; + +static struct qcom_icc_node snoc_int_1 = { + .name = "snoc_int_1", + .id = MSM8953_SNOC_INT_1, + .buswidth = 8, + .mas_rpm_id = 100, + .slv_rpm_id = 131, + .num_links = ARRAY_SIZE(snoc_int_1_links), + .links = snoc_int_1_links, +}; + +static const u16 snoc_int_2_links[] = { + MSM8953_SLAVE_CATS_128, + MSM8953_SLAVE_OCMEM_64 +}; + +static struct qcom_icc_node snoc_int_2 = { + .name = "snoc_int_2", + .id = MSM8953_SNOC_INT_2, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(snoc_int_2_links), + .links = snoc_int_2_links, +}; + +static struct qcom_icc_node slv_kpss_ahb = { + .name = "slv_kpss_ahb", + .id = MSM8953_SLAVE_APPSS, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_wcss = { + .name = "slv_wcss", + .id = MSM8953_SLAVE_WCSS, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static const u16 slv_snoc_bimc_1_links[] = { + MSM8953_SNOC_BIMC_1_MAS +}; + +static struct qcom_icc_node slv_snoc_bimc_1 = { + .name = "slv_snoc_bimc_1", + .id = MSM8953_SNOC_BIMC_1_SLV, + .buswidth = 8, + .mas_rpm_id = -1, + .slv_rpm_id = 104, + .num_links = ARRAY_SIZE(slv_snoc_bimc_1_links), + .links = slv_snoc_bimc_1_links, +}; + +static struct qcom_icc_node slv_imem = { + .name = "slv_imem", + .id = MSM8953_SLAVE_OCIMEM, + .buswidth = 8, + .mas_rpm_id = -1, + .slv_rpm_id = 26, +}; + +static const u16 slv_snoc_pcnoc_links[] = { + MSM8953_SNOC_PNOC_MAS +}; + +static struct qcom_icc_node slv_snoc_pcnoc = { + .name = "slv_snoc_pcnoc", + .id = MSM8953_SNOC_PNOC_SLV, + .buswidth = 8, + .mas_rpm_id = -1, + .slv_rpm_id = 28, + .num_links = ARRAY_SIZE(slv_snoc_pcnoc_links), + .links = slv_snoc_pcnoc_links, +}; + +static struct qcom_icc_node slv_qdss_stm = { + .name = "slv_qdss_stm", + .id = MSM8953_SLAVE_QDSS_STM, + .buswidth = 4, + .mas_rpm_id = -1, + .slv_rpm_id = 30, +}; + +static struct qcom_icc_node slv_cats_1 = { + .name = "slv_cats_1", + .id = MSM8953_SLAVE_OCMEM_64, + .buswidth = 8, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node slv_lpass = { + .name = "slv_lpass", + .id = MSM8953_SLAVE_LPASS, + .buswidth = 4, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static const u16 mas_jpeg_links[] = { + MSM8953_SNOC_BIMC_2_SLV +}; + +static struct qcom_icc_node mas_jpeg = { + .name = "mas_jpeg", + .id = MSM8953_MASTER_JPEG, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 6, + .num_links = ARRAY_SIZE(mas_jpeg_links), + .links = mas_jpeg_links, +}; + +static const u16 mas_mdp_links[] = { + MSM8953_SNOC_BIMC_0_SLV +}; + +static struct qcom_icc_node mas_mdp = { + .name = "mas_mdp", + .id = MSM8953_MASTER_MDP_PORT0, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 7, + .num_links = ARRAY_SIZE(mas_mdp_links), + .links = mas_mdp_links, +}; + +static const u16 mas_venus_links[] = { + MSM8953_SNOC_BIMC_2_SLV +}; + +static struct qcom_icc_node mas_venus = { + .name = "mas_venus", + .id = MSM8953_MASTER_VIDEO_P0, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 8, + .num_links = ARRAY_SIZE(mas_venus_links), + .links = mas_venus_links, +}; + +static const u16 mas_vfe0_links[] = { + MSM8953_SNOC_BIMC_0_SLV +}; + +static struct qcom_icc_node mas_vfe0 = { + .name = "mas_vfe0", + .id = MSM8953_MASTER_VFE, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 9, + .num_links = ARRAY_SIZE(mas_vfe0_links), + .links = mas_vfe0_links, +}; + +static const u16 mas_vfe1_links[] = { + MSM8953_SNOC_BIMC_0_SLV +}; + +static struct qcom_icc_node mas_vfe1 = { + .name = "mas_vfe1", + .id = MSM8953_MASTER_VFE1, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 13, + .num_links = ARRAY_SIZE(mas_vfe1_links), + .links = mas_vfe1_links, +}; + +static const u16 mas_cpp_links[] = { + MSM8953_SNOC_BIMC_2_SLV +}; + +static struct qcom_icc_node mas_cpp = { + .name = "mas_cpp", + .id = MSM8953_MASTER_CPP, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_BYPASS, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = 12, + .num_links = ARRAY_SIZE(mas_cpp_links), + .links = mas_cpp_links, +}; + +static const u16 slv_snoc_bimc_0_links[] = { + MSM8953_SNOC_BIMC_0_MAS +}; + +static struct qcom_icc_node slv_snoc_bimc_0 = { + .name = "slv_snoc_bimc_0", + .id = MSM8953_SNOC_BIMC_0_SLV, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(slv_snoc_bimc_0_links), + .links = slv_snoc_bimc_0_links, +}; + +static const u16 slv_snoc_bimc_2_links[] = { + MSM8953_SNOC_BIMC_2_MAS +}; + +static struct qcom_icc_node slv_snoc_bimc_2 = { + .name = "slv_snoc_bimc_2", + .id = MSM8953_SNOC_BIMC_2_SLV, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, + .num_links = ARRAY_SIZE(slv_snoc_bimc_2_links), + .links = slv_snoc_bimc_2_links, +}; + +static struct qcom_icc_node slv_cats_0 = { + .name = "slv_cats_0", + .id = MSM8953_SLAVE_CATS_128, + .buswidth = 16, + .qos.ap_owned = true, + .qos.qos_mode = NOC_QOS_MODE_INVALID, + .qos.prio_level = 0, + .qos.areq_prio = 0, + .qos.qos_port = -1, +}; + +static struct qcom_icc_node * const msm8953_bimc_nodes[] = { + [MAS_APPS_PROC] = &mas_apps_proc, + [MAS_OXILI] = &mas_oxili, + [MAS_SNOC_BIMC_0] = &mas_snoc_bimc_0, + [MAS_SNOC_BIMC_2] = &mas_snoc_bimc_2, + [MAS_SNOC_BIMC_1] = &mas_snoc_bimc_1, + [MAS_TCU_0] = &mas_tcu_0, + [SLV_EBI] = &slv_ebi, + [SLV_BIMC_SNOC] = &slv_bimc_snoc, +}; + +static const struct regmap_config msm8953_bimc_regmap_config = { + .fast_io = true, + .max_register = 0x5a000, + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static const struct qcom_icc_desc msm8953_bimc = { + .type = QCOM_ICC_BIMC, + .bus_clk_desc = &bimc_clk, + .nodes = msm8953_bimc_nodes, + .num_nodes = ARRAY_SIZE(msm8953_bimc_nodes), + .qos_offset = 0x8000, + .regmap_cfg = &msm8953_bimc_regmap_config +}; + +static struct qcom_icc_node * const msm8953_pcnoc_nodes[] = { + [MAS_SPDM] = &mas_spdm, + [MAS_BLSP_1] = &mas_blsp_1, + [MAS_BLSP_2] = &mas_blsp_2, + [MAS_USB3] = &mas_usb3, + [MAS_CRYPTO] = &mas_crypto, + [MAS_SDCC_1] = &mas_sdcc_1, + [MAS_SDCC_2] = &mas_sdcc_2, + [MAS_SNOC_PCNOC] = &mas_snoc_pcnoc, + [PCNOC_M_0] = &pcnoc_m_0, + [PCNOC_M_1] = &pcnoc_m_1, + [PCNOC_INT_1] = &pcnoc_int_1, + [PCNOC_INT_2] = &pcnoc_int_2, + [PCNOC_S_0] = &pcnoc_s_0, + [PCNOC_S_1] = &pcnoc_s_1, + [PCNOC_S_2] = &pcnoc_s_2, + [PCNOC_S_3] = &pcnoc_s_3, + [PCNOC_S_4] = &pcnoc_s_4, + [PCNOC_S_6] = &pcnoc_s_6, + [PCNOC_S_7] = &pcnoc_s_7, + [PCNOC_S_8] = &pcnoc_s_8, + [PCNOC_S_9] = &pcnoc_s_9, + [SLV_SPDM] = &slv_spdm, + [SLV_PDM] = &slv_pdm, + [SLV_TCSR] = &slv_tcsr, + [SLV_SNOC_CFG] = &slv_snoc_cfg, + [SLV_TLMM] = &slv_tlmm, + [SLV_MESSAGE_RAM] = &slv_message_ram, + [SLV_BLSP_1] = &slv_blsp_1, + [SLV_BLSP_2] = &slv_blsp_2, + [SLV_PRNG] = &slv_prng, + [SLV_CAMERA_SS_CFG] = &slv_camera_ss_cfg, + [SLV_DISP_SS_CFG] = &slv_disp_ss_cfg, + [SLV_VENUS_CFG] = &slv_venus_cfg, + [SLV_GPU_CFG] = &slv_gpu_cfg, + [SLV_SDCC_1] = &slv_sdcc_1, + [SLV_SDCC_2] = &slv_sdcc_2, + [SLV_CRYPTO_0_CFG] = &slv_crypto_0_cfg, + [SLV_PMIC_ARB] = &slv_pmic_arb, + [SLV_USB3] = &slv_usb3, + [SLV_IPA_CFG] = &slv_ipa_cfg, + [SLV_TCU] = &slv_tcu, + [SLV_PCNOC_SNOC] = &slv_pcnoc_snoc, +}; + +static const char * const msm8953_pcnoc_intf_clocks[] = { + "pcnoc_usb3_axi" +}; + +static const struct regmap_config msm8953_pcnoc_regmap_config = { + .fast_io = true, + .max_register = 0x12080, + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static const struct qcom_icc_desc msm8953_pcnoc = { + .type = QCOM_ICC_NOC, + .bus_clk_desc = &bus_0_clk, + .intf_clocks = msm8953_pcnoc_intf_clocks, + .num_intf_clocks = ARRAY_SIZE(msm8953_pcnoc_intf_clocks), + .nodes = msm8953_pcnoc_nodes, + .num_nodes = ARRAY_SIZE(msm8953_pcnoc_nodes), + .qos_offset = 0x7000, + .regmap_cfg = &msm8953_pcnoc_regmap_config, +}; + +static struct qcom_icc_node * const msm8953_snoc_nodes[] = { + [MAS_QDSS_BAM] = &mas_qdss_bam, + [MAS_BIMC_SNOC] = &mas_bimc_snoc, + [MAS_PCNOC_SNOC] = &mas_pcnoc_snoc, + [MAS_IPA] = &mas_ipa, + [MAS_QDSS_ETR] = &mas_qdss_etr, + [QDSS_INT] = &qdss_int, + [SNOC_INT_0] = &snoc_int_0, + [SNOC_INT_1] = &snoc_int_1, + [SNOC_INT_2] = &snoc_int_2, + [SLV_KPSS_AHB] = &slv_kpss_ahb, + [SLV_WCSS] = &slv_wcss, + [SLV_SNOC_BIMC_1] = &slv_snoc_bimc_1, + [SLV_IMEM] = &slv_imem, + [SLV_SNOC_PCNOC] = &slv_snoc_pcnoc, + [SLV_QDSS_STM] = &slv_qdss_stm, + [SLV_CATS_1] = &slv_cats_1, + [SLV_LPASS] = &slv_lpass, +}; + +static const struct regmap_config msm8953_snoc_regmap_config = { + .fast_io = true, + .max_register = 0x16080, + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static const struct qcom_icc_desc msm8953_snoc = { + .type = QCOM_ICC_NOC, + .bus_clk_desc = &bus_1_clk, + .nodes = msm8953_snoc_nodes, + .num_nodes = ARRAY_SIZE(msm8953_snoc_nodes), + .qos_offset = 0x7000, + .regmap_cfg = &msm8953_snoc_regmap_config, +}; + +static struct qcom_icc_node * const msm8953_snoc_mm_nodes[] = { + [MAS_JPEG] = &mas_jpeg, + [MAS_MDP] = &mas_mdp, + [MAS_VENUS] = &mas_venus, + [MAS_VFE0] = &mas_vfe0, + [MAS_VFE1] = &mas_vfe1, + [MAS_CPP] = &mas_cpp, + [SLV_SNOC_BIMC_0] = &slv_snoc_bimc_0, + [SLV_SNOC_BIMC_2] = &slv_snoc_bimc_2, + [SLV_CATS_0] = &slv_cats_0, +}; + +static const struct qcom_icc_desc msm8953_snoc_mm = { + .type = QCOM_ICC_NOC, + .bus_clk_desc = &bus_2_clk, + .nodes = msm8953_snoc_mm_nodes, + .num_nodes = ARRAY_SIZE(msm8953_snoc_mm_nodes), + .qos_offset = 0x7000, + .regmap_cfg = &msm8953_snoc_regmap_config, +}; + +static const struct of_device_id msm8953_noc_of_match[] = { + { .compatible = "qcom,msm8953-bimc", .data = &msm8953_bimc }, + { .compatible = "qcom,msm8953-pcnoc", .data = &msm8953_pcnoc }, + { .compatible = "qcom,msm8953-snoc", .data = &msm8953_snoc }, + { .compatible = "qcom,msm8953-snoc-mm", .data = &msm8953_snoc_mm }, + { } +}; + +static struct platform_driver msm8953_noc_driver = { + .probe = qnoc_probe, + .remove_new = qnoc_remove, + .driver = { + .name = "qnoc-msm8953", + .of_match_table = msm8953_noc_of_match, + }, +}; + +module_platform_driver(msm8953_noc_driver); +MODULE_DEVICE_TABLE(of, msm8953_noc_of_match); +MODULE_DESCRIPTION("Qualcomm MSM8953 NoC driver"); +MODULE_LICENSE("GPL"); From 92436305b663039485ced5c38a9c12c4ed2e0851 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 18 Jun 2024 13:59:12 +0200 Subject: [PATCH 236/330] dt-bindings: iio: stm32: dfsdm: fix dtbs warnings on dfsdm audio port Fix warnings on DFSDM dtbs check Unevaluated properties are not allowed ('dfsdm-dai' was unexpected) 'port' does not match any of the regexes: 'pinctrl-[0-9]+' Fixes: 11183ac07a74 ("dt-bindings: stm32: convert dfsdm to json-schema") Signed-off-by: Olivier Moysan Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240618115912.706912-1-olivier.moysan@foss.st.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml index c1b1324fa132..2722edab1d9a 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml @@ -246,6 +246,10 @@ patternProperties: From common IIO binding. Used to pipe external sigma delta modulator or internal ADC output to DFSDM channel. + port: + $ref: /schemas/sound/audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - "#sound-dai-cells" From 9641972917d69790ef55ef4d434b564955432d1f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 24 Jun 2024 20:32:10 +0100 Subject: [PATCH 237/330] iio: adc: ltc2309: Fix endian type passed to be16_to_cpu() Picked up by sparse. Cc: Liam Beguin Reviewed-by: Liam Beguin Link: https://patch.msgid.link/20240624193210.347434-1-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ltc2309.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c index 888a71454070..5f0d947d0615 100644 --- a/drivers/iio/adc/ltc2309.c +++ b/drivers/iio/adc/ltc2309.c @@ -103,7 +103,7 @@ static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, unsigned long address, int *val) { int ret; - u16 buf; + __be16 buf; u8 din; din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) | From 0214b27fc949a7bcaf57e71a7f9f534d6481d08b Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 24 Jun 2024 13:46:00 -0400 Subject: [PATCH 238/330] iio: Add iio_read_channel_label to inkern API It can be convenient for other in-kernel drivers to reuse IIO channel labels. Export the iio_read_channel_label function to allow this. The signature is different depending on where we are calling it from, so the meat is moved to do_iio_read_channel_label. Signed-off-by: Sean Anderson Acked-by: Jonathan Cameron Link: https://patch.msgid.link/20240624174601.1527244-2-sean.anderson@linux.dev Signed-off-by: Jonathan Cameron --- drivers/iio/iio_core.h | 4 ++++ drivers/iio/industrialio-core.c | 25 +++++++++++++++---------- drivers/iio/inkern.c | 6 ++++++ include/linux/iio/consumer.h | 10 ++++++++++ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 1a38b1915e7a..b7d5f4f0fada 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -34,6 +34,10 @@ void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, struct iio_ioctl_handler *h); void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h); +ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *c, + char *buf); + int __iio_add_chan_devattr(const char *postfix, struct iio_chan_spec const *chan, ssize_t (*func)(struct device *dev, diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2f185b386949..0f6cda7ffe45 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -727,20 +727,25 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) } EXPORT_SYMBOL_GPL(iio_format_value); +ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *c, + char *buf) +{ + if (indio_dev->info->read_label) + return indio_dev->info->read_label(indio_dev, c, buf); + + if (c->extend_name) + return sysfs_emit(buf, "%s\n", c->extend_name); + + return -EINVAL; +} + static ssize_t iio_read_channel_label(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - if (indio_dev->info->read_label) - return indio_dev->info->read_label(indio_dev, this_attr->c, buf); - - if (this_attr->c->extend_name) - return sysfs_emit(buf, "%s\n", this_attr->c->extend_name); - - return -EINVAL; + return do_iio_read_channel_label(dev_to_iio_dev(dev), + to_iio_dev_attr(attr)->c, buf); } static ssize_t iio_read_channel_info(struct device *dev, diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 39cf26d69d17..9f484c94bc6e 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -1010,3 +1010,9 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, chan->channel, buf, len); } EXPORT_SYMBOL_GPL(iio_write_channel_ext_info); + +ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf) +{ + return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf); +} +EXPORT_SYMBOL_GPL(iio_read_channel_label); diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index e9910b41d48e..333d1d8ccb37 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -441,4 +441,14 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan, ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, const char *buf, size_t len); +/** + * iio_read_channel_label() - read label for a given channel + * @chan: The channel being queried. + * @buf: Where to store the attribute value. Assumed to hold + * at least PAGE_SIZE bytes. + * + * Returns the number of bytes written to buf, or an error code. + */ +ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf); + #endif From 440db4075fa0cb517bb18ea7ec555d927f8fc030 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 24 Jun 2024 13:46:01 -0400 Subject: [PATCH 239/330] hwmon: iio: Add labels from IIO channels Add labels from IIO channels to our channels. This allows userspace to display more meaningful names instead of "in0" or "temp5". Although lm-sensors gracefully handles errors when reading channel labels, the ABI says the label attribute > Should only be created if the driver has hints about what this voltage > channel is being used for, and user-space doesn't. Therefore, we test to see if the channel has a label before creating the attribute. Signed-off-by: Sean Anderson Acked-by: Guenter Roeck Link: https://patch.msgid.link/20240624174601.1527244-3-sean.anderson@linux.dev Signed-off-by: Jonathan Cameron --- drivers/hwmon/iio_hwmon.c | 45 ++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 4c8a80847891..5722cb9d81f9 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -33,6 +33,17 @@ struct iio_hwmon_state { struct attribute **attrs; }; +static ssize_t iio_hwmon_read_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct iio_hwmon_state *state = dev_get_drvdata(dev); + struct iio_channel *chan = &state->channels[sattr->index]; + + return iio_read_channel_label(chan, buf); +} + /* * Assumes that IIO and hwmon operate in the same base units. * This is supposed to be true, but needs verification for @@ -68,12 +79,13 @@ static int iio_hwmon_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct iio_hwmon_state *st; struct sensor_device_attribute *a; - int ret, i; + int ret, i, attr = 0; int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1; enum iio_chan_type type; struct iio_channel *channels; struct device *hwmon_dev; char *sname; + void *buf; channels = devm_iio_channel_get_all(dev); if (IS_ERR(channels)) { @@ -85,17 +97,18 @@ static int iio_hwmon_probe(struct platform_device *pdev) } st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); - if (st == NULL) + buf = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0); + if (!st || !buf) return -ENOMEM; st->channels = channels; - /* count how many attributes we have */ + /* count how many channels we have */ while (st->channels[st->num_channels].indio_dev) st->num_channels++; st->attrs = devm_kcalloc(dev, - st->num_channels + 1, sizeof(*st->attrs), + 2 * st->num_channels + 1, sizeof(*st->attrs), GFP_KERNEL); if (st->attrs == NULL) return -ENOMEM; @@ -147,9 +160,31 @@ static int iio_hwmon_probe(struct platform_device *pdev) a->dev_attr.show = iio_hwmon_read_val; a->dev_attr.attr.mode = 0444; a->index = i; - st->attrs[i] = &a->dev_attr.attr; + st->attrs[attr++] = &a->dev_attr.attr; + + /* Let's see if we have a label... */ + if (iio_read_channel_label(&st->channels[i], buf) < 0) + continue; + + a = devm_kzalloc(dev, sizeof(*a), GFP_KERNEL); + if (a == NULL) + return -ENOMEM; + + sysfs_attr_init(&a->dev_attr.attr); + a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, + "%s%d_label", + prefix, n); + if (!a->dev_attr.attr.name) + return -ENOMEM; + + a->dev_attr.show = iio_hwmon_read_label; + a->dev_attr.attr.mode = 0444; + a->index = i; + st->attrs[attr++] = &a->dev_attr.attr; } + devm_free_pages(dev, (unsigned long)buf); + st->attr_group.attrs = st->attrs; st->groups[0] = &st->attr_group; From 93a81104629dcee04b5b39f48d43320fcda80fda Mon Sep 17 00:00:00 2001 From: Guillaume Stols Date: Fri, 28 Jun 2024 14:48:19 +0000 Subject: [PATCH 240/330] dt-bindings: iio: adc: adi,ad7606: add missing datasheet link Add AD7606-5 datasheet link. Signed-off-by: Guillaume Stols Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240628-cleanup-ad7606-v2-1-96e02f90256d@baylibre.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index 7fa46df1f4fb..d55c58400df5 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -11,6 +11,7 @@ maintainers: description: | Analog Devices AD7606 Simultaneous Sampling ADC + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7605-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf From 555b1a1f208fd200c3fb618378faa5b1c0cdd786 Mon Sep 17 00:00:00 2001 From: Guillaume Stols Date: Fri, 28 Jun 2024 14:48:20 +0000 Subject: [PATCH 241/330] dt-bindings: iio: adc: adi,ad7606: comment and sort the compatible names AD7606-8 is referred to as AD7606 by Analog Devices. This comment aims to avoid confusion. Also the compatible names were not sorted by alphabetical order. Signed-off-by: Guillaume Stols Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20240628-cleanup-ad7606-v2-2-96e02f90256d@baylibre.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index d55c58400df5..00fdaed11cbd 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -20,9 +20,9 @@ properties: compatible: enum: - adi,ad7605-4 - - adi,ad7606-8 - - adi,ad7606-6 - adi,ad7606-4 + - adi,ad7606-6 + - adi,ad7606-8 # Referred to as AD7606 (without -8) in the datasheet - adi,ad7606b - adi,ad7616 From fd2adf37c26593f3e4587bfa824bac64b1149b33 Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Wed, 26 Jun 2024 23:22:31 +0930 Subject: [PATCH 242/330] MAINTAINERS: Add AVAGO APDS9306 Add myself as maintainer of APDS9306 ambient light sensor driver. Signed-off-by: Subhajit Ghosh Link: https://patch.msgid.link/20240626135231.8937-1-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9517093d889d..cc3efe96d6d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3531,6 +3531,13 @@ F: include/linux/cfag12864b.h F: include/uapi/linux/map_to_14segment.h F: include/uapi/linux/map_to_7segment.h +AVAGO APDS9306 AMBIENT LIGHT SENSOR DRIVER +M: Subhajit Ghosh +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml +F: drivers/iio/light/apds9306.c + AVIA HX711 ANALOG DIGITAL CONVERTER IIO DRIVER M: Andreas Klinger L: linux-iio@vger.kernel.org From a3c2c5c937ed7562b6d120670f2743e979c05881 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Tue, 25 Jun 2024 13:57:55 +0530 Subject: [PATCH 243/330] iio: st_sensors: relax WhoAmI check in st_sensors_verify_id() Hard matching against the WhoAmI values isn't ideal for using devices which are compatible with existing ones. Instead of raising an error, issue a warning instead, thus allowing the driver to continue probing. Suggested-by: Jonathan Cameron Signed-off-by: Kaustabh Chakraborty Link: https://patch.msgid.link/20240625082800.62305-1-kauschluss@disroot.org Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index c77d7bdcc121..c69399ac6657 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -606,10 +606,9 @@ int st_sensors_verify_id(struct iio_dev *indio_dev) } if (sdata->sensor_settings->wai != wai) { - dev_err(&indio_dev->dev, + dev_warn(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", indio_dev->name, wai); - return -EINVAL; } } From 0d2775c18b5d7bfa33bddb575b88e53c4cfdf644 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 24 Jun 2024 15:49:36 +0300 Subject: [PATCH 244/330] iio: adc: ad7192: use devm_regulator_get_enable_read_voltage This makes use of the new devm_regulator_get_enable_read_voltage() function to reduce boilerplate code. Error messages have changed slightly since there are now fewer places where we print an error. The rest of the logic of selecting which supply to use as the reference voltage remains the same. Also 1000 is replaced by MILLI in a few places for consistency. Signed-off-by: David Lechner Signed-off-by: Alisa-Dariana Roman Reviewed-by: Conor Dooley Link: https://patch.msgid.link/20240624124941.113010-2-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 97 ++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 64 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index c7fb51a90e87..334ab90991d4 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -200,8 +200,6 @@ struct ad7192_chip_info { struct ad7192_state { const struct ad7192_chip_info *chip_info; - struct regulator *avdd; - struct regulator *vref; struct clk *mclk; u16 int_vref_mv; u32 aincom_mv; @@ -1189,18 +1187,12 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { }, }; -static void ad7192_reg_disable(void *reg) -{ - regulator_disable(reg); -} - static int ad7192_probe(struct spi_device *spi) { struct device *dev = &spi->dev; struct ad7192_state *st; struct iio_dev *indio_dev; - struct regulator *aincom; - int ret; + int ret, avdd_mv; if (!spi->irq) return dev_err_probe(dev, -ENODEV, "Failed to get IRQ\n"); @@ -1218,72 +1210,49 @@ static int ad7192_probe(struct spi_device *spi) * Newer firmware should provide a zero volt fixed supply if wired to * ground. */ - aincom = devm_regulator_get_optional(dev, "aincom"); - if (IS_ERR(aincom)) { - if (PTR_ERR(aincom) != -ENODEV) - return dev_err_probe(dev, PTR_ERR(aincom), - "Failed to get AINCOM supply\n"); + ret = devm_regulator_get_enable_read_voltage(dev, "aincom"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get AINCOM voltage\n"); - st->aincom_mv = 0; - } else { - ret = regulator_enable(aincom); - if (ret) - return dev_err_probe(dev, ret, - "Failed to enable specified AINCOM supply\n"); + st->aincom_mv = ret == -ENODEV ? 0 : ret / MILLI; - ret = devm_add_action_or_reset(dev, ad7192_reg_disable, aincom); - if (ret) - return ret; + /* AVDD can optionally be used as reference voltage */ + ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); + if (ret == -ENODEV || ret == -EINVAL) { + int ret2; - ret = regulator_get_voltage(aincom); - if (ret < 0) - return dev_err_probe(dev, ret, - "Device tree error, AINCOM voltage undefined\n"); - st->aincom_mv = ret / MILLI; + /* + * We get -EINVAL if avdd is a supply with unknown voltage. We + * still need to enable it since it is also a power supply. + */ + ret2 = devm_regulator_get_enable(dev, "avdd"); + if (ret2) + return dev_err_probe(dev, ret2, + "Failed to enable AVDD supply\n"); + } else if (ret < 0) { + return dev_err_probe(dev, ret, "Failed to get AVDD voltage\n"); } - st->avdd = devm_regulator_get(dev, "avdd"); - if (IS_ERR(st->avdd)) - return PTR_ERR(st->avdd); - - ret = regulator_enable(st->avdd); - if (ret) - return dev_err_probe(dev, ret, - "Failed to enable specified AVdd supply\n"); - - ret = devm_add_action_or_reset(dev, ad7192_reg_disable, st->avdd); - if (ret) - return ret; + avdd_mv = ret == -ENODEV || ret == -EINVAL ? 0 : ret / MILLI; ret = devm_regulator_get_enable(dev, "dvdd"); if (ret) return dev_err_probe(dev, ret, "Failed to enable specified DVdd supply\n"); - st->vref = devm_regulator_get_optional(dev, "vref"); - if (IS_ERR(st->vref)) { - if (PTR_ERR(st->vref) != -ENODEV) - return PTR_ERR(st->vref); - - ret = regulator_get_voltage(st->avdd); - if (ret < 0) - return dev_err_probe(dev, ret, - "Device tree error, AVdd voltage undefined\n"); - } else { - ret = regulator_enable(st->vref); - if (ret) - return dev_err_probe(dev, ret, - "Failed to enable specified Vref supply\n"); - - ret = devm_add_action_or_reset(dev, ad7192_reg_disable, st->vref); - if (ret) - return ret; - - ret = regulator_get_voltage(st->vref); - if (ret < 0) - return dev_err_probe(dev, ret, - "Device tree error, Vref voltage undefined\n"); + /* + * This is either REFIN1 or REFIN2 depending on adi,refin2-pins-enable. + * If this supply is not present, fall back to AVDD as reference. + */ + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (ret == -ENODEV) { + if (avdd_mv == 0) + return dev_err_probe(dev, -ENODEV, + "No reference voltage available\n"); + } else if (ret < 0) { + return ret; } - st->int_vref_mv = ret / 1000; + + st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI; st->chip_info = spi_get_device_match_data(spi); indio_dev->name = st->chip_info->name; From 13ed07f45944aedcfc2154218c34bb8ad5f5147e Mon Sep 17 00:00:00 2001 From: Alisa-Dariana Roman Date: Mon, 24 Jun 2024 15:49:41 +0300 Subject: [PATCH 245/330] MAINTAINERS: Update AD7192 driver maintainer Alexandru Tachici has not been active. Also the email address included is not reachable anymore. I was assigned to work on the driver instead. Remove Alexandru Tachici and add myself as maintainer of AD7192 driver. Signed-off-by: Alisa-Dariana Roman Reviewed-by: Conor Dooley Link: https://patch.msgid.link/20240624124941.113010-7-alisa.roman@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index cc3efe96d6d5..0cbeb03847f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1217,7 +1217,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r* F: drivers/iio/adc/ad7091r* ANALOG DEVICES INC AD7192 DRIVER -M: Alexandru Tachici +M: Alisa-Dariana Roman L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers From 3e26d9f08fbe0b73e951a5e810fdb7a332b7e37f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:22 +0200 Subject: [PATCH 246/330] iio: core: Add new DMABUF interface infrastructure Add the necessary infrastructure to the IIO core to support a new optional DMABUF based interface. With this new interface, DMABUF objects (externally created) can be attached to a IIO buffer, and subsequently used for data transfer. A userspace application can then use this interface to share DMABUF objects between several interfaces, allowing it to transfer data in a zero-copy fashion, for instance between IIO and the USB stack. The userspace application can also memory-map the DMABUF objects, and access the sample data directly. The advantage of doing this vs. the read() interface is that it avoids an extra copy of the data between the kernel and userspace. This is particularly userful for high-speed devices which produce several megabytes or even gigabytes of data per second. As part of the interface, 3 new IOCTLs have been added: IIO_BUFFER_DMABUF_ATTACH_IOCTL(int fd): Attach the DMABUF object identified by the given file descriptor to the buffer. IIO_BUFFER_DMABUF_DETACH_IOCTL(int fd): Detach the DMABUF object identified by the given file descriptor from the buffer. Note that closing the IIO buffer's file descriptor will automatically detach all previously attached DMABUF objects. IIO_BUFFER_DMABUF_ENQUEUE_IOCTL(struct iio_dmabuf *): Request a data transfer to/from the given DMABUF object. Its file descriptor, as well as the transfer size and flags are provided in the "iio_dmabuf" structure. These three IOCTLs have to be performed on the IIO buffer's file descriptor, obtained using the IIO_BUFFER_GET_FD_IOCTL() ioctl. Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240620122726.41232-4-paul@crapouillou.net Signed-off-by: Jonathan Cameron --- drivers/iio/Kconfig | 1 + drivers/iio/industrialio-buffer.c | 459 ++++++++++++++++++++++++++++++ include/linux/iio/buffer_impl.h | 33 +++ include/uapi/linux/iio/buffer.h | 22 ++ 4 files changed, 515 insertions(+) diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 9c351ffc7bed..661127aed2f9 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -14,6 +14,7 @@ if IIO config IIO_BUFFER bool "Enable buffer support within IIO" + select DMA_SHARED_BUFFER help Provide core support for various buffer based data acquisition methods. diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 0138b21b244f..d6fe105d2f40 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -9,15 +9,20 @@ * - Better memory allocation techniques? * - Alternative access techniques? */ +#include #include #include #include #include #include +#include +#include +#include #include #include #include #include +#include #include #include @@ -29,6 +34,34 @@ #include #include +#define DMABUF_ENQUEUE_TIMEOUT_MS 5000 + +MODULE_IMPORT_NS(DMA_BUF); + +struct iio_dmabuf_priv { + struct list_head entry; + struct kref ref; + + struct iio_buffer *buffer; + struct iio_dma_buffer_block *block; + + u64 context; + + /* Spinlock used for locking the dma_fence */ + spinlock_t lock; + + struct dma_buf_attachment *attach; + struct sg_table *sgt; + enum dma_data_direction dir; + atomic_t seqno; +}; + +struct iio_dma_fence { + struct dma_fence base; + struct iio_dmabuf_priv *priv; + struct work_struct work; +}; + static const char * const iio_endian_prefix[] = { [IIO_BE] = "be", [IIO_LE] = "le", @@ -333,6 +366,8 @@ void iio_buffer_init(struct iio_buffer *buffer) { INIT_LIST_HEAD(&buffer->demux_list); INIT_LIST_HEAD(&buffer->buffer_list); + INIT_LIST_HEAD(&buffer->dmabufs); + mutex_init(&buffer->dmabufs_mutex); init_waitqueue_head(&buffer->pollq); kref_init(&buffer->ref); if (!buffer->watermark) @@ -1526,14 +1561,55 @@ static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev) kfree(iio_dev_opaque->legacy_scan_el_group.attrs); } +static void iio_buffer_dmabuf_release(struct kref *ref) +{ + struct iio_dmabuf_priv *priv = container_of(ref, struct iio_dmabuf_priv, ref); + struct dma_buf_attachment *attach = priv->attach; + struct iio_buffer *buffer = priv->buffer; + struct dma_buf *dmabuf = attach->dmabuf; + + dma_resv_lock(dmabuf->resv, NULL); + dma_buf_unmap_attachment(attach, priv->sgt, priv->dir); + dma_resv_unlock(dmabuf->resv); + + buffer->access->detach_dmabuf(buffer, priv->block); + + dma_buf_detach(attach->dmabuf, attach); + dma_buf_put(dmabuf); + kfree(priv); +} + +static void iio_buffer_dmabuf_get(struct dma_buf_attachment *attach) +{ + struct iio_dmabuf_priv *priv = attach->importer_priv; + + kref_get(&priv->ref); +} + +static void iio_buffer_dmabuf_put(struct dma_buf_attachment *attach) +{ + struct iio_dmabuf_priv *priv = attach->importer_priv; + + kref_put(&priv->ref, iio_buffer_dmabuf_release); +} + static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep) { struct iio_dev_buffer_pair *ib = filep->private_data; struct iio_dev *indio_dev = ib->indio_dev; struct iio_buffer *buffer = ib->buffer; + struct iio_dmabuf_priv *priv, *tmp; wake_up(&buffer->pollq); + guard(mutex)(&buffer->dmabufs_mutex); + + /* Close all attached DMABUFs */ + list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) { + list_del_init(&priv->entry); + iio_buffer_dmabuf_put(priv->attach); + } + kfree(ib); clear_bit(IIO_BUSY_BIT_POS, &buffer->flags); iio_device_put(indio_dev); @@ -1541,11 +1617,393 @@ static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep) return 0; } +static int iio_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock) +{ + if (!nonblock) + return dma_resv_lock_interruptible(dmabuf->resv, NULL); + + if (!dma_resv_trylock(dmabuf->resv)) + return -EBUSY; + + return 0; +} + +static struct dma_buf_attachment * +iio_buffer_find_attachment(struct iio_dev_buffer_pair *ib, + struct dma_buf *dmabuf, bool nonblock) +{ + struct device *dev = ib->indio_dev->dev.parent; + struct iio_buffer *buffer = ib->buffer; + struct dma_buf_attachment *attach = NULL; + struct iio_dmabuf_priv *priv; + + guard(mutex)(&buffer->dmabufs_mutex); + + list_for_each_entry(priv, &buffer->dmabufs, entry) { + if (priv->attach->dev == dev + && priv->attach->dmabuf == dmabuf) { + attach = priv->attach; + break; + } + } + + if (attach) + iio_buffer_dmabuf_get(attach); + + return attach ?: ERR_PTR(-EPERM); +} + +static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib, + int __user *user_fd, bool nonblock) +{ + struct iio_dev *indio_dev = ib->indio_dev; + struct iio_buffer *buffer = ib->buffer; + struct dma_buf_attachment *attach; + struct iio_dmabuf_priv *priv, *each; + struct dma_buf *dmabuf; + int err, fd; + + if (!buffer->access->attach_dmabuf + || !buffer->access->detach_dmabuf + || !buffer->access->enqueue_dmabuf) + return -EPERM; + + if (copy_from_user(&fd, user_fd, sizeof(fd))) + return -EFAULT; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + priv->context = dma_fence_context_alloc(1); + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) { + err = PTR_ERR(dmabuf); + goto err_free_priv; + } + + attach = dma_buf_attach(dmabuf, indio_dev->dev.parent); + if (IS_ERR(attach)) { + err = PTR_ERR(attach); + goto err_dmabuf_put; + } + + err = iio_dma_resv_lock(dmabuf, nonblock); + if (err) + goto err_dmabuf_detach; + + priv->dir = buffer->direction == IIO_BUFFER_DIRECTION_IN + ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + priv->sgt = dma_buf_map_attachment(attach, priv->dir); + if (IS_ERR(priv->sgt)) { + err = PTR_ERR(priv->sgt); + dev_err(&indio_dev->dev, "Unable to map attachment: %d\n", err); + goto err_resv_unlock; + } + + kref_init(&priv->ref); + priv->buffer = buffer; + priv->attach = attach; + attach->importer_priv = priv; + + priv->block = buffer->access->attach_dmabuf(buffer, attach); + if (IS_ERR(priv->block)) { + err = PTR_ERR(priv->block); + goto err_dmabuf_unmap_attachment; + } + + dma_resv_unlock(dmabuf->resv); + + mutex_lock(&buffer->dmabufs_mutex); + + /* + * Check whether we already have an attachment for this driver/DMABUF + * combo. If we do, refuse to attach. + */ + list_for_each_entry(each, &buffer->dmabufs, entry) { + if (each->attach->dev == indio_dev->dev.parent + && each->attach->dmabuf == dmabuf) { + /* + * We unlocked the reservation object, so going through + * the cleanup code would mean re-locking it first. + * At this stage it is simpler to free the attachment + * using iio_buffer_dma_put(). + */ + mutex_unlock(&buffer->dmabufs_mutex); + iio_buffer_dmabuf_put(attach); + return -EBUSY; + } + } + + /* Otherwise, add the new attachment to our dmabufs list. */ + list_add(&priv->entry, &buffer->dmabufs); + mutex_unlock(&buffer->dmabufs_mutex); + + return 0; + +err_dmabuf_unmap_attachment: + dma_buf_unmap_attachment(attach, priv->sgt, priv->dir); +err_resv_unlock: + dma_resv_unlock(dmabuf->resv); +err_dmabuf_detach: + dma_buf_detach(dmabuf, attach); +err_dmabuf_put: + dma_buf_put(dmabuf); +err_free_priv: + kfree(priv); + + return err; +} + +static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib, + int __user *user_req, bool nonblock) +{ + struct iio_buffer *buffer = ib->buffer; + struct iio_dev *indio_dev = ib->indio_dev; + struct iio_dmabuf_priv *priv; + struct dma_buf *dmabuf; + int dmabuf_fd, ret = -EPERM; + + if (copy_from_user(&dmabuf_fd, user_req, sizeof(dmabuf_fd))) + return -EFAULT; + + dmabuf = dma_buf_get(dmabuf_fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + guard(mutex)(&buffer->dmabufs_mutex); + + list_for_each_entry(priv, &buffer->dmabufs, entry) { + if (priv->attach->dev == indio_dev->dev.parent + && priv->attach->dmabuf == dmabuf) { + list_del(&priv->entry); + + /* Unref the reference from iio_buffer_attach_dmabuf() */ + iio_buffer_dmabuf_put(priv->attach); + ret = 0; + break; + } + } + + dma_buf_put(dmabuf); + + return ret; +} + +static const char * +iio_buffer_dma_fence_get_driver_name(struct dma_fence *fence) +{ + return "iio"; +} + +static void iio_buffer_dma_fence_release(struct dma_fence *fence) +{ + struct iio_dma_fence *iio_fence = + container_of(fence, struct iio_dma_fence, base); + + kfree(iio_fence); +} + +static const struct dma_fence_ops iio_buffer_dma_fence_ops = { + .get_driver_name = iio_buffer_dma_fence_get_driver_name, + .get_timeline_name = iio_buffer_dma_fence_get_driver_name, + .release = iio_buffer_dma_fence_release, +}; + +static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib, + struct iio_dmabuf __user *iio_dmabuf_req, + bool nonblock) +{ + struct iio_buffer *buffer = ib->buffer; + struct iio_dmabuf iio_dmabuf; + struct dma_buf_attachment *attach; + struct iio_dmabuf_priv *priv; + struct iio_dma_fence *fence; + struct dma_buf *dmabuf; + unsigned long timeout; + bool cookie, cyclic, dma_to_ram; + long retl; + u32 seqno; + int ret; + + if (copy_from_user(&iio_dmabuf, iio_dmabuf_req, sizeof(iio_dmabuf))) + return -EFAULT; + + if (iio_dmabuf.flags & ~IIO_BUFFER_DMABUF_SUPPORTED_FLAGS) + return -EINVAL; + + cyclic = iio_dmabuf.flags & IIO_BUFFER_DMABUF_CYCLIC; + + /* Cyclic flag is only supported on output buffers */ + if (cyclic && buffer->direction != IIO_BUFFER_DIRECTION_OUT) + return -EINVAL; + + dmabuf = dma_buf_get(iio_dmabuf.fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + if (!iio_dmabuf.bytes_used || iio_dmabuf.bytes_used > dmabuf->size) { + ret = -EINVAL; + goto err_dmabuf_put; + } + + attach = iio_buffer_find_attachment(ib, dmabuf, nonblock); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto err_dmabuf_put; + } + + priv = attach->importer_priv; + + fence = kmalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) { + ret = -ENOMEM; + goto err_attachment_put; + } + + fence->priv = priv; + + seqno = atomic_add_return(1, &priv->seqno); + + /* + * The transfers are guaranteed to be processed in the order they are + * enqueued, so we can use a simple incrementing sequence number for + * the dma_fence. + */ + dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops, + &priv->lock, priv->context, seqno); + + ret = iio_dma_resv_lock(dmabuf, nonblock); + if (ret) + goto err_fence_put; + + timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS); + dma_to_ram = buffer->direction == IIO_BUFFER_DIRECTION_IN; + + /* Make sure we don't have writers */ + retl = dma_resv_wait_timeout(dmabuf->resv, + dma_resv_usage_rw(dma_to_ram), + true, timeout); + if (retl == 0) + retl = -EBUSY; + if (retl < 0) { + ret = (int)retl; + goto err_resv_unlock; + } + + if (buffer->access->lock_queue) + buffer->access->lock_queue(buffer); + + ret = dma_resv_reserve_fences(dmabuf->resv, 1); + if (ret) + goto err_queue_unlock; + + dma_resv_add_fence(dmabuf->resv, &fence->base, + dma_to_ram ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ); + dma_resv_unlock(dmabuf->resv); + + cookie = dma_fence_begin_signalling(); + + ret = buffer->access->enqueue_dmabuf(buffer, priv->block, &fence->base, + priv->sgt, iio_dmabuf.bytes_used, + cyclic); + if (ret) { + /* + * DMABUF enqueue failed, but we already added the fence. + * Signal the error through the fence completion mechanism. + */ + iio_buffer_signal_dmabuf_done(&fence->base, ret); + } + + if (buffer->access->unlock_queue) + buffer->access->unlock_queue(buffer); + + dma_fence_end_signalling(cookie); + dma_buf_put(dmabuf); + + return ret; + +err_queue_unlock: + if (buffer->access->unlock_queue) + buffer->access->unlock_queue(buffer); +err_resv_unlock: + dma_resv_unlock(dmabuf->resv); +err_fence_put: + dma_fence_put(&fence->base); +err_attachment_put: + iio_buffer_dmabuf_put(attach); +err_dmabuf_put: + dma_buf_put(dmabuf); + + return ret; +} + +static void iio_buffer_cleanup(struct work_struct *work) +{ + struct iio_dma_fence *fence = + container_of(work, struct iio_dma_fence, work); + struct iio_dmabuf_priv *priv = fence->priv; + struct dma_buf_attachment *attach = priv->attach; + + dma_fence_put(&fence->base); + iio_buffer_dmabuf_put(attach); +} + +void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int ret) +{ + struct iio_dma_fence *iio_fence = + container_of(fence, struct iio_dma_fence, base); + bool cookie = dma_fence_begin_signalling(); + + /* + * Get a reference to the fence, so that it's not freed as soon as + * it's signaled. + */ + dma_fence_get(fence); + + fence->error = ret; + dma_fence_signal(fence); + dma_fence_end_signalling(cookie); + + /* + * The fence will be unref'd in iio_buffer_cleanup. + * It can't be done here, as the unref functions might try to lock the + * resv object, which can deadlock. + */ + INIT_WORK(&iio_fence->work, iio_buffer_cleanup); + schedule_work(&iio_fence->work); +} +EXPORT_SYMBOL_GPL(iio_buffer_signal_dmabuf_done); + +static long iio_buffer_chrdev_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct iio_dev_buffer_pair *ib = filp->private_data; + void __user *_arg = (void __user *)arg; + bool nonblock = filp->f_flags & O_NONBLOCK; + + switch (cmd) { + case IIO_BUFFER_DMABUF_ATTACH_IOCTL: + return iio_buffer_attach_dmabuf(ib, _arg, nonblock); + case IIO_BUFFER_DMABUF_DETACH_IOCTL: + return iio_buffer_detach_dmabuf(ib, _arg, nonblock); + case IIO_BUFFER_DMABUF_ENQUEUE_IOCTL: + return iio_buffer_enqueue_dmabuf(ib, _arg, nonblock); + default: + return -EINVAL; + } +} + static const struct file_operations iio_buffer_chrdev_fileops = { .owner = THIS_MODULE, .llseek = noop_llseek, .read = iio_buffer_read, .write = iio_buffer_write, + .unlocked_ioctl = iio_buffer_chrdev_ioctl, + .compat_ioctl = compat_ptr_ioctl, .poll = iio_buffer_poll, .release = iio_buffer_chrdev_release, }; @@ -1994,6 +2452,7 @@ static void iio_buffer_release(struct kref *ref) { struct iio_buffer *buffer = container_of(ref, struct iio_buffer, ref); + mutex_destroy(&buffer->dmabufs_mutex); buffer->access->release(buffer); } diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index 89c3fd7c29ca..e72552e026f3 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -9,8 +9,12 @@ #include #include +struct dma_buf_attachment; +struct dma_fence; struct iio_dev; +struct iio_dma_buffer_block; struct iio_buffer; +struct sg_table; /** * INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the buffer can not be @@ -39,6 +43,16 @@ struct iio_buffer; * device stops sampling. Calles are balanced with @enable. * @release: called when the last reference to the buffer is dropped, * should free all resources allocated by the buffer. + * @attach_dmabuf: called from userspace via ioctl to attach one external + * DMABUF. + * @detach_dmabuf: called from userspace via ioctl to detach one previously + * attached DMABUF. + * @enqueue_dmabuf: called from userspace via ioctl to queue this DMABUF + * object to this buffer. Requires a valid DMABUF fd, that + * was previouly attached to this buffer. + * @lock_queue: called when the core needs to lock the buffer queue; + * it is used when enqueueing DMABUF objects. + * @unlock_queue: used to unlock a previously locked buffer queue * @modes: Supported operating modes by this buffer type * @flags: A bitmask combination of INDIO_BUFFER_FLAG_* * @@ -68,6 +82,17 @@ struct iio_buffer_access_funcs { void (*release)(struct iio_buffer *buffer); + struct iio_dma_buffer_block * (*attach_dmabuf)(struct iio_buffer *buffer, + struct dma_buf_attachment *attach); + void (*detach_dmabuf)(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block); + int (*enqueue_dmabuf)(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block, + struct dma_fence *fence, struct sg_table *sgt, + size_t size, bool cyclic); + void (*lock_queue)(struct iio_buffer *buffer); + void (*unlock_queue)(struct iio_buffer *buffer); + unsigned int modes; unsigned int flags; }; @@ -136,6 +161,12 @@ struct iio_buffer { /* @ref: Reference count of the buffer. */ struct kref ref; + + /* @dmabufs: List of DMABUF attachments */ + struct list_head dmabufs; /* P: dmabufs_mutex */ + + /* @dmabufs_mutex: Protects dmabufs */ + struct mutex dmabufs_mutex; }; /** @@ -159,6 +190,8 @@ void iio_buffer_init(struct iio_buffer *buffer); struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer); void iio_buffer_put(struct iio_buffer *buffer); +void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int ret); + #else /* CONFIG_IIO_BUFFER */ static inline void iio_buffer_get(struct iio_buffer *buffer) {} diff --git a/include/uapi/linux/iio/buffer.h b/include/uapi/linux/iio/buffer.h index 13939032b3f6..c666aa95e532 100644 --- a/include/uapi/linux/iio/buffer.h +++ b/include/uapi/linux/iio/buffer.h @@ -5,6 +5,28 @@ #ifndef _UAPI_IIO_BUFFER_H_ #define _UAPI_IIO_BUFFER_H_ +#include + +/* Flags for iio_dmabuf.flags */ +#define IIO_BUFFER_DMABUF_CYCLIC (1 << 0) +#define IIO_BUFFER_DMABUF_SUPPORTED_FLAGS 0x00000001 + +/** + * struct iio_dmabuf - Descriptor for a single IIO DMABUF object + * @fd: file descriptor of the DMABUF object + * @flags: one or more IIO_BUFFER_DMABUF_* flags + * @bytes_used: number of bytes used in this DMABUF for the data transfer. + * Should generally be set to the DMABUF's size. + */ +struct iio_dmabuf { + __u32 fd; + __u32 flags; + __u64 bytes_used; +}; + #define IIO_BUFFER_GET_FD_IOCTL _IOWR('i', 0x91, int) +#define IIO_BUFFER_DMABUF_ATTACH_IOCTL _IOW('i', 0x92, int) +#define IIO_BUFFER_DMABUF_DETACH_IOCTL _IOW('i', 0x93, int) +#define IIO_BUFFER_DMABUF_ENQUEUE_IOCTL _IOW('i', 0x94, struct iio_dmabuf) #endif /* _UAPI_IIO_BUFFER_H_ */ From d85318900c1c06a251ad3d86fba6bbab116a95d5 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:23 +0200 Subject: [PATCH 247/330] iio: buffer-dma: Enable support for DMABUFs Implement iio_dma_buffer_attach_dmabuf(), iio_dma_buffer_detach_dmabuf() and iio_dma_buffer_transfer_dmabuf(), which can then be used by the IIO DMA buffer implementations. Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240620122726.41232-5-paul@crapouillou.net Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dma.c | 178 +++++++++++++++++-- include/linux/iio/buffer-dma.h | 31 ++++ 2 files changed, 198 insertions(+), 11 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 13b1a858969e..647f417a045e 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -4,6 +4,8 @@ * Author: Lars-Peter Clausen */ +#include +#include #include #include #include @@ -14,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -94,13 +98,18 @@ static void iio_buffer_block_release(struct kref *kref) { struct iio_dma_buffer_block *block = container_of(kref, struct iio_dma_buffer_block, kref); + struct iio_dma_buffer_queue *queue = block->queue; - WARN_ON(block->state != IIO_BLOCK_STATE_DEAD); + WARN_ON(block->fileio && block->state != IIO_BLOCK_STATE_DEAD); - dma_free_coherent(block->queue->dev, PAGE_ALIGN(block->size), - block->vaddr, block->phys_addr); + if (block->fileio) { + dma_free_coherent(queue->dev, PAGE_ALIGN(block->size), + block->vaddr, block->phys_addr); + } else { + atomic_dec(&queue->num_dmabufs); + } - iio_buffer_put(&block->queue->buffer); + iio_buffer_put(&queue->buffer); kfree(block); } @@ -163,7 +172,7 @@ static struct iio_dma_buffer_queue *iio_buffer_to_queue(struct iio_buffer *buf) } static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block( - struct iio_dma_buffer_queue *queue, size_t size) + struct iio_dma_buffer_queue *queue, size_t size, bool fileio) { struct iio_dma_buffer_block *block; @@ -171,13 +180,16 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block( if (!block) return NULL; - block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size), - &block->phys_addr, GFP_KERNEL); - if (!block->vaddr) { - kfree(block); - return NULL; + if (fileio) { + block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size), + &block->phys_addr, GFP_KERNEL); + if (!block->vaddr) { + kfree(block); + return NULL; + } } + block->fileio = fileio; block->size = size; block->state = IIO_BLOCK_STATE_DONE; block->queue = queue; @@ -186,6 +198,9 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block( iio_buffer_get(&queue->buffer); + if (!fileio) + atomic_inc(&queue->num_dmabufs); + return block; } @@ -218,13 +233,20 @@ void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block) { struct iio_dma_buffer_queue *queue = block->queue; unsigned long flags; + bool cookie; + + cookie = dma_fence_begin_signalling(); spin_lock_irqsave(&queue->list_lock, flags); _iio_dma_buffer_block_done(block); spin_unlock_irqrestore(&queue->list_lock, flags); + if (!block->fileio) + iio_buffer_signal_dmabuf_done(block->fence, 0); + iio_buffer_block_put_atomic(block); iio_dma_buffer_queue_wake(queue); + dma_fence_end_signalling(cookie); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done); @@ -243,17 +265,27 @@ void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue, { struct iio_dma_buffer_block *block, *_block; unsigned long flags; + bool cookie; + + cookie = dma_fence_begin_signalling(); spin_lock_irqsave(&queue->list_lock, flags); list_for_each_entry_safe(block, _block, list, head) { list_del(&block->head); block->bytes_used = 0; _iio_dma_buffer_block_done(block); + + if (!block->fileio) + iio_buffer_signal_dmabuf_done(block->fence, -EINTR); iio_buffer_block_put_atomic(block); } spin_unlock_irqrestore(&queue->list_lock, flags); + if (queue->fileio.enabled) + queue->fileio.enabled = false; + iio_dma_buffer_queue_wake(queue); + dma_fence_end_signalling(cookie); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort); @@ -273,6 +305,16 @@ static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block) } } +static bool iio_dma_buffer_can_use_fileio(struct iio_dma_buffer_queue *queue) +{ + /* + * Note that queue->num_dmabufs cannot increase while the queue is + * locked, it can only decrease, so it does not race against + * iio_dma_buffer_alloc_block(). + */ + return queue->fileio.enabled || !atomic_read(&queue->num_dmabufs); +} + /** * iio_dma_buffer_request_update() - DMA buffer request_update callback * @buffer: The buffer which to request an update @@ -299,6 +341,12 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) mutex_lock(&queue->lock); + queue->fileio.enabled = iio_dma_buffer_can_use_fileio(queue); + + /* If DMABUFs were created, disable fileio interface */ + if (!queue->fileio.enabled) + goto out_unlock; + /* Allocations are page aligned */ if (PAGE_ALIGN(queue->fileio.block_size) == PAGE_ALIGN(size)) try_reuse = true; @@ -339,7 +387,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) } if (!block) { - block = iio_dma_buffer_alloc_block(queue, size); + block = iio_dma_buffer_alloc_block(queue, size, true); if (!block) { ret = -ENOMEM; goto out_unlock; @@ -412,8 +460,12 @@ static void iio_dma_buffer_submit_block(struct iio_dma_buffer_queue *queue, block->state = IIO_BLOCK_STATE_ACTIVE; iio_buffer_block_get(block); + ret = queue->ops->submit(queue, block); if (ret) { + if (!block->fileio) + iio_buffer_signal_dmabuf_done(block->fence, ret); + /* * This is a bit of a problem and there is not much we can do * other then wait for the buffer to be disabled and re-enabled @@ -646,6 +698,110 @@ size_t iio_dma_buffer_usage(struct iio_buffer *buf) } EXPORT_SYMBOL_GPL(iio_dma_buffer_usage); +struct iio_dma_buffer_block * +iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer, + struct dma_buf_attachment *attach) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + struct iio_dma_buffer_block *block; + + guard(mutex)(&queue->lock); + + /* + * If the buffer is enabled and in fileio mode new blocks can't be + * allocated. + */ + if (queue->fileio.enabled) + return ERR_PTR(-EBUSY); + + block = iio_dma_buffer_alloc_block(queue, attach->dmabuf->size, false); + if (!block) + return ERR_PTR(-ENOMEM); + + /* Free memory that might be in use for fileio mode */ + iio_dma_buffer_fileio_free(queue); + + return block; +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_attach_dmabuf); + +void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block) +{ + block->state = IIO_BLOCK_STATE_DEAD; + iio_buffer_block_put_atomic(block); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_detach_dmabuf); + +static int iio_dma_can_enqueue_block(struct iio_dma_buffer_block *block) +{ + struct iio_dma_buffer_queue *queue = block->queue; + + /* If in fileio mode buffers can't be enqueued. */ + if (queue->fileio.enabled) + return -EBUSY; + + switch (block->state) { + case IIO_BLOCK_STATE_QUEUED: + return -EPERM; + case IIO_BLOCK_STATE_ACTIVE: + case IIO_BLOCK_STATE_DEAD: + return -EBUSY; + case IIO_BLOCK_STATE_DONE: + break; + } + + return 0; +} + +int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block, + struct dma_fence *fence, + struct sg_table *sgt, + size_t size, bool cyclic) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + bool cookie; + int ret; + + WARN_ON(!mutex_is_locked(&queue->lock)); + + cookie = dma_fence_begin_signalling(); + + ret = iio_dma_can_enqueue_block(block); + if (ret < 0) + goto out_end_signalling; + + block->bytes_used = size; + block->cyclic = cyclic; + block->sg_table = sgt; + block->fence = fence; + + iio_dma_buffer_enqueue(queue, block); + +out_end_signalling: + dma_fence_end_signalling(cookie); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_enqueue_dmabuf); + +void iio_dma_buffer_lock_queue(struct iio_buffer *buffer) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + + mutex_lock(&queue->lock); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_lock_queue); + +void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer) +{ + struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); + + mutex_unlock(&queue->lock); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_unlock_queue); + /** * iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback * @buffer: Buffer to set the bytes-per-datum for diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h index 6e27e47077d5..5eb66a399002 100644 --- a/include/linux/iio/buffer-dma.h +++ b/include/linux/iio/buffer-dma.h @@ -7,6 +7,7 @@ #ifndef __INDUSTRIALIO_DMA_BUFFER_H__ #define __INDUSTRIALIO_DMA_BUFFER_H__ +#include #include #include #include @@ -16,6 +17,9 @@ struct iio_dma_buffer_queue; struct iio_dma_buffer_ops; struct device; +struct dma_buf_attachment; +struct dma_fence; +struct sg_table; /** * enum iio_block_state - State of a struct iio_dma_buffer_block @@ -41,6 +45,10 @@ enum iio_block_state { * @queue: Parent DMA buffer queue * @kref: kref used to manage the lifetime of block * @state: Current state of the block + * @cyclic: True if this is a cyclic buffer + * @fileio: True if this buffer is used for fileio mode + * @sg_table: DMA table for the transfer when transferring a DMABUF + * @fence: DMA fence to be signaled when a DMABUF transfer is complete */ struct iio_dma_buffer_block { /* May only be accessed by the owner of the block */ @@ -63,6 +71,12 @@ struct iio_dma_buffer_block { * queue->list_lock if the block is not owned by the core. */ enum iio_block_state state; + + bool cyclic; + bool fileio; + + struct sg_table *sg_table; + struct dma_fence *fence; }; /** @@ -72,6 +86,7 @@ struct iio_dma_buffer_block { * @pos: Read offset in the active block * @block_size: Size of each block * @next_dequeue: index of next block that will be dequeued + * @enabled: Whether the buffer is operating in fileio mode */ struct iio_dma_buffer_queue_fileio { struct iio_dma_buffer_block *blocks[2]; @@ -80,6 +95,7 @@ struct iio_dma_buffer_queue_fileio { size_t block_size; unsigned int next_dequeue; + bool enabled; }; /** @@ -95,6 +111,7 @@ struct iio_dma_buffer_queue_fileio { * the DMA controller * @incoming: List of buffers on the incoming queue * @active: Whether the buffer is currently active + * @num_dmabufs: Total number of DMABUFs attached to this queue * @fileio: FileIO state */ struct iio_dma_buffer_queue { @@ -107,6 +124,7 @@ struct iio_dma_buffer_queue { struct list_head incoming; bool active; + atomic_t num_dmabufs; struct iio_dma_buffer_queue_fileio fileio; }; @@ -144,4 +162,17 @@ int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue, void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue); void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue); +struct iio_dma_buffer_block * +iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer, + struct dma_buf_attachment *attach); +void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block); +int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer, + struct iio_dma_buffer_block *block, + struct dma_fence *fence, + struct sg_table *sgt, + size_t size, bool cyclic); +void iio_dma_buffer_lock_queue(struct iio_buffer *buffer); +void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer); + #endif From 7a86d469983ace116c320680643f4991019e87f1 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:24 +0200 Subject: [PATCH 248/330] iio: buffer-dmaengine: Support new DMABUF based userspace API Use the functions provided by the buffer-dma core to implement the DMABUF userspace API in the buffer-dmaengine IIO buffer implementation. Since we want to be able to transfer an arbitrary number of bytes and not necesarily the full DMABUF, the associated scatterlist is converted to an array of DMA addresses + lengths, which is then passed to dmaengine_prep_slave_dma_array(). Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240620122726.41232-6-paul@crapouillou.net Signed-off-by: Jonathan Cameron --- .../buffer/industrialio-buffer-dmaengine.c | 64 ++++++++++++++++--- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 918f6f8d65b6..12aa1412dfa0 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -65,25 +65,62 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, iio_buffer_to_dmaengine_buffer(&queue->buffer); struct dma_async_tx_descriptor *desc; enum dma_transfer_direction dma_dir; + struct scatterlist *sgl; + struct dma_vec *vecs; size_t max_size; dma_cookie_t cookie; + size_t len_total; + unsigned int i; + int nents; max_size = min(block->size, dmaengine_buffer->max_size); max_size = round_down(max_size, dmaengine_buffer->align); - if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) { - block->bytes_used = max_size; + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) dma_dir = DMA_DEV_TO_MEM; - } else { + else dma_dir = DMA_MEM_TO_DEV; + + if (block->sg_table) { + sgl = block->sg_table->sgl; + nents = sg_nents_for_len(sgl, block->bytes_used); + if (nents < 0) + return nents; + + vecs = kmalloc_array(nents, sizeof(*vecs), GFP_ATOMIC); + if (!vecs) + return -ENOMEM; + + len_total = block->bytes_used; + + for (i = 0; i < nents; i++) { + vecs[i].addr = sg_dma_address(sgl); + vecs[i].len = min(sg_dma_len(sgl), len_total); + len_total -= vecs[i].len; + + sgl = sg_next(sgl); + } + + desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, + vecs, nents, dma_dir, + DMA_PREP_INTERRUPT); + kfree(vecs); + } else { + max_size = min(block->size, dmaengine_buffer->max_size); + max_size = round_down(max_size, dmaengine_buffer->align); + + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) + block->bytes_used = max_size; + + if (!block->bytes_used || block->bytes_used > max_size) + return -EINVAL; + + desc = dmaengine_prep_slave_single(dmaengine_buffer->chan, + block->phys_addr, + block->bytes_used, + dma_dir, + DMA_PREP_INTERRUPT); } - - if (!block->bytes_used || block->bytes_used > max_size) - return -EINVAL; - - desc = dmaengine_prep_slave_single(dmaengine_buffer->chan, - block->phys_addr, block->bytes_used, dma_dir, - DMA_PREP_INTERRUPT); if (!desc) return -ENOMEM; @@ -133,6 +170,13 @@ static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = { .space_available = iio_dma_buffer_usage, .release = iio_dmaengine_buffer_release, + .enqueue_dmabuf = iio_dma_buffer_enqueue_dmabuf, + .attach_dmabuf = iio_dma_buffer_attach_dmabuf, + .detach_dmabuf = iio_dma_buffer_detach_dmabuf, + + .lock_queue = iio_dma_buffer_lock_queue, + .unlock_queue = iio_dma_buffer_unlock_queue, + .modes = INDIO_BUFFER_HARDWARE, .flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK, }; From ebe061b9cc80dfff68fa6a46d412d85d67b68be3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:25 +0200 Subject: [PATCH 249/330] Documentation: iio: Document high-speed DMABUF based API Document the new DMABUF based API. Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Reviewed-by: Bagas Sanjaya Link: https://patch.msgid.link/20240620122726.41232-7-paul@crapouillou.net Signed-off-by: Jonathan Cameron --- Documentation/iio/iio_dmabuf_api.rst | 54 ++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 2 files changed, 55 insertions(+) create mode 100644 Documentation/iio/iio_dmabuf_api.rst diff --git a/Documentation/iio/iio_dmabuf_api.rst b/Documentation/iio/iio_dmabuf_api.rst new file mode 100644 index 000000000000..2836cadbd495 --- /dev/null +++ b/Documentation/iio/iio_dmabuf_api.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================== +High-speed DMABUF interface for IIO +=================================== + +1. Overview +=========== + +The Industrial I/O subsystem supports access to buffers through a +file-based interface, with read() and write() access calls through the +IIO device's dev node. + +It additionally supports a DMABUF based interface, where the userspace +can attach DMABUF objects (externally created) to an IIO buffer, and +subsequently use them for data transfers. + +A userspace application can then use this interface to share DMABUF +objects between several interfaces, allowing it to transfer data in a +zero-copy fashion, for instance between IIO and the USB stack. + +The userspace application can also memory-map the DMABUF objects, and +access the sample data directly. The advantage of doing this vs. the +read() interface is that it avoids an extra copy of the data between the +kernel and userspace. This is particularly useful for high-speed devices +which produce several megabytes or even gigabytes of data per second. +It does however increase the userspace-kernelspace synchronization +overhead, as the DMA_BUF_SYNC_START and DMA_BUF_SYNC_END IOCTLs have to +be used for data integrity. + +2. User API +=========== + +As part of this interface, three new IOCTLs have been added. These three +IOCTLs have to be performed on the IIO buffer's file descriptor, which +can be obtained using the IIO_BUFFER_GET_FD_IOCTL() ioctl. + + ``IIO_BUFFER_DMABUF_ATTACH_IOCTL(int fd)`` + Attach the DMABUF object, identified by its file descriptor, to the + IIO buffer. Returns zero on success, and a negative errno value on + error. + + ``IIO_BUFFER_DMABUF_DETACH_IOCTL(int fd)`` + Detach the given DMABUF object, identified by its file descriptor, + from the IIO buffer. Returns zero on success, and a negative errno + value on error. + + Note that closing the IIO buffer's file descriptor will + automatically detach all previously attached DMABUF objects. + + ``IIO_BUFFER_DMABUF_ENQUEUE_IOCTL(struct iio_dmabuf *iio_dmabuf)`` + Enqueue a previously attached DMABUF object to the buffer queue. + Enqueued DMABUFs will be read from (if output buffer) or written to + (if input buffer) as long as the buffer is enabled. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index 4c13bfa2865c..9cb4c50cb20d 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -9,6 +9,7 @@ Industrial I/O iio_configfs iio_devbuf + iio_dmabuf_api iio_tools Industrial I/O Kernel Drivers From 340fa834ae229a952db04a57ed13fd5d35d75818 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 24 Jun 2024 15:46:08 -0500 Subject: [PATCH 250/330] iio: adc: ad7944: use devm_spi_optimize_message() Use new devm_spi_optimize_message() helper to simplify repeated code in the ad7944 driver. Signed-off-by: David Lechner Link: https://patch.msgid.link/20240624-devm_spi_optimize_message-v3-2-912138c27b66@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 4172723bb2ac..0f36138a7144 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -134,18 +134,12 @@ AD7944_DEFINE_CHIP_INFO(ad7985, ad7944, 16, 0); /* fully differential */ AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1); -static void ad7944_unoptimize_msg(void *msg) -{ - spi_unoptimize_message(msg); -} - static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *adc, const struct iio_chan_spec *chan) { unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns : adc->timing_spec->conv_ns; struct spi_transfer *xfers = adc->xfers; - int ret; /* * NB: can get better performance from some SPI controllers if we use @@ -175,11 +169,7 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc * spi_message_init_with_transfers(&adc->msg, xfers, 3); - ret = spi_optimize_message(adc->spi, &adc->msg); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); + return devm_spi_optimize_message(dev, adc->spi, &adc->msg); } static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc, @@ -188,7 +178,6 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns : adc->timing_spec->conv_ns; struct spi_transfer *xfers = adc->xfers; - int ret; /* * NB: can get better performance from some SPI controllers if we use @@ -209,11 +198,7 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc spi_message_init_with_transfers(&adc->msg, xfers, 2); - ret = spi_optimize_message(adc->spi, &adc->msg); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); + return devm_spi_optimize_message(dev, adc->spi, &adc->msg); } static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc, @@ -221,7 +206,6 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc u32 n_chain_dev) { struct spi_transfer *xfers = adc->xfers; - int ret; /* * NB: SCLK has to be low before we toggle CS to avoid triggering the @@ -249,11 +233,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc spi_message_init_with_transfers(&adc->msg, xfers, 2); - ret = spi_optimize_message(adc->spi, &adc->msg); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); + return devm_spi_optimize_message(dev, adc->spi, &adc->msg); } /** From aa9e366bb0bf457c7cff3d72276f5dfa43d5a244 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Thu, 20 Jun 2024 16:48:42 -0400 Subject: [PATCH 251/330] iio: xilinx-ams: Add labels Label all the channels using names from the reference manual. Some of the "control" channels are duplicates of other channels. The reference manual describes it like: > The AMS register set includes several measurement registers that are > written to by the PS SYSMON unit using the single-channel mode > (sequencer off). These voltage measurements are performed using the > unipolar sampling circuit with a 0 to 3V range and do not have alarms > or minimum/maximum registers. So I think these really are measuring the same voltages but in a different location. In which case, sharing labels makes sense to me. Signed-off-by: Sean Anderson Link: https://patch.msgid.link/20240620204842.817237-1-sean.anderson@linux.dev Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 107 +++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index ee45475c495b..a3980e43e67f 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -222,7 +222,7 @@ enum ams_ps_pl_seq { #define PL_SEQ(x) (AMS_PS_SEQ_MAX + (x)) #define AMS_CTRL_SEQ_BASE (AMS_PS_SEQ_MAX * 3) -#define AMS_CHAN_TEMP(_scan_index, _addr) { \ +#define AMS_CHAN_TEMP(_scan_index, _addr, _name) { \ .type = IIO_TEMP, \ .indexed = 1, \ .address = (_addr), \ @@ -232,9 +232,10 @@ enum ams_ps_pl_seq { .event_spec = ams_temp_events, \ .scan_index = _scan_index, \ .num_event_specs = ARRAY_SIZE(ams_temp_events), \ + .datasheet_name = _name, \ } -#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm) { \ +#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .address = (_addr), \ @@ -243,21 +244,24 @@ enum ams_ps_pl_seq { .event_spec = (_alarm) ? ams_voltage_events : NULL, \ .scan_index = _scan_index, \ .num_event_specs = (_alarm) ? ARRAY_SIZE(ams_voltage_events) : 0, \ + .datasheet_name = _name, \ } -#define AMS_PS_CHAN_TEMP(_scan_index, _addr) \ - AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr) -#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr) \ - AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true) +#define AMS_PS_CHAN_TEMP(_scan_index, _addr, _name) \ + AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr, _name) +#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr, _name) \ + AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true, _name) -#define AMS_PL_CHAN_TEMP(_scan_index, _addr) \ - AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr) -#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm) \ - AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm) +#define AMS_PL_CHAN_TEMP(_scan_index, _addr, _name) \ + AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr, _name) +#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) \ + AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm, _name) #define AMS_PL_AUX_CHAN_VOLTAGE(_auxno) \ - AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false) -#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr) \ - AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false) + AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false, \ + "VAUX" #_auxno) +#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr, _name) \ + AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false, \ + _name) /** * struct ams - This structure contains necessary state for xilinx-ams to operate @@ -501,6 +505,12 @@ static int ams_init_device(struct ams *ams) return 0; } +static int ams_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + return sysfs_emit(label, "%s\n", chan->datasheet_name); +} + static int ams_enable_single_channel(struct ams *ams, unsigned int offset) { u8 channel_num; @@ -1112,37 +1122,37 @@ static const struct iio_event_spec ams_voltage_events[] = { }; static const struct iio_chan_spec ams_ps_channels[] = { - AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP), - AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10), - AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS), + AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_LPD"), + AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE, "Temp_FPD"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, "VCC_PSINTLP"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, "VCC_PSINTFP"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, "VCC_PSAUX"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, "VCC_PSDDR"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, "VCC_PSIO3"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, "VCC_PSIO0"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, "VCC_PSIO1"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, "VCC_PSIO2"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, "PS_MGTRAVCC"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, "PS_MGTRAVTT"), + AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, "VCC_PSADC"), }; static const struct iio_chan_spec ams_pl_channels[] = { - AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true), - AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true), + AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_PL"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true, "VCCINT"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true, "VCCAUX"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false, "VREFP"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false, "VREFN"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true, "VCCBRAM"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true, "VCC_PSINTLP"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true, "VCC_PSINTFP"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true, "VCC_PSAUX"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true, "VCCAMS"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false, "VP_VN"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true, "VUser0"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true, "VUser1"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true, "VUser2"), + AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true, "VUser3"), AMS_PL_AUX_CHAN_VOLTAGE(0), AMS_PL_AUX_CHAN_VOLTAGE(1), AMS_PL_AUX_CHAN_VOLTAGE(2), @@ -1162,13 +1172,13 @@ static const struct iio_chan_spec ams_pl_channels[] = { }; static const struct iio_chan_spec ams_ctrl_channels[] = { - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL), - AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0, "VCC_PSPLL"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3, "VCC_PSBATT"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT, "VCCINT"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM, "VCCBRAM"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX, "VCCAUX"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL, "VCC_PSDDR_PLL"), + AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR, "VCC_PSINTFP_DDR"), }; static int ams_get_ext_chan(struct fwnode_handle *chan_node, @@ -1332,6 +1342,7 @@ static int ams_parse_firmware(struct iio_dev *indio_dev) } static const struct iio_info iio_ams_info = { + .read_label = ams_read_label, .read_raw = &ams_read_raw, .read_event_config = &ams_read_event_config, .write_event_config = &ams_write_event_config, From dbbe7eaf0e4795bf003ac06872aaf52b6b6b1310 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 6 Jun 2024 09:22:37 +0200 Subject: [PATCH 252/330] dev_printk: add new dev_err_probe() helpers This is similar to dev_err_probe() but for cases where an ERR_PTR() or ERR_CAST() is to be returned simplifying patterns like: dev_err_probe(dev, ret, ...); return ERR_PTR(ret) or dev_err_probe(dev, PTR_ERR(ptr), ...); return ERR_CAST(ptr) Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-1-51bb229edd79@analog.com Signed-off-by: Jonathan Cameron --- include/linux/dev_printk.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h index ae80a303c216..ca32b5bb28eb 100644 --- a/include/linux/dev_printk.h +++ b/include/linux/dev_printk.h @@ -277,4 +277,12 @@ do { \ __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); +/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ +#define dev_err_ptr_probe(dev, ___err, fmt, ...) \ + ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__)) + +/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */ +#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \ + ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__)) + #endif /* _DEVICE_PRINTK_H_ */ From a00838cae079b9b9b90969c2b7b031b1bfd9ab3a Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 6 Jun 2024 09:22:38 +0200 Subject: [PATCH 253/330] iio: temperature: ltc2983: convert to dev_err_probe() Use dev_err_probe() (and variants) in the probe() path. While at it, made some simple improvements: * Explicitly included the err.h and errno.h headers; * Removed some unnecessary line breaks; * Removed a redundant 'else'; * Added some missing \n to prink. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-2-51bb229edd79@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 260 +++++++++++++----------------- 1 file changed, 113 insertions(+), 147 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 24d19f3c7292..21f2cfc55bf8 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -432,10 +434,9 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle else n_entries = fwnode_property_count_u64(fn, propname); /* n_entries must be an even number */ - if (!n_entries || (n_entries % 2) != 0) { - dev_err(dev, "Number of entries either 0 or not even\n"); - return ERR_PTR(-EINVAL); - } + if (!n_entries || (n_entries % 2) != 0) + return dev_err_ptr_probe(dev, -EINVAL, + "Number of entries either 0 or not even\n"); new_custom = devm_kzalloc(dev, sizeof(*new_custom), GFP_KERNEL); if (!new_custom) @@ -443,19 +444,17 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle new_custom->size = n_entries * n_size; /* check Steinhart size */ - if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE) { - dev_err(dev, "Steinhart sensors size(%zu) must be %u\n", new_custom->size, - LTC2983_CUSTOM_STEINHART_SIZE); - return ERR_PTR(-EINVAL); - } + if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE) + return dev_err_ptr_probe(dev, -EINVAL, + "Steinhart sensors size(%zu) must be %u\n", + new_custom->size, LTC2983_CUSTOM_STEINHART_SIZE); + /* Check space on the table. */ if (st->custom_table_size + new_custom->size > - (LTC2983_CUST_SENS_TBL_END_REG - - LTC2983_CUST_SENS_TBL_START_REG) + 1) { - dev_err(dev, "No space left(%d) for new custom sensor(%zu)", - st->custom_table_size, new_custom->size); - return ERR_PTR(-EINVAL); - } + (LTC2983_CUST_SENS_TBL_END_REG - LTC2983_CUST_SENS_TBL_START_REG) + 1) + return dev_err_ptr_probe(dev, -EINVAL, + "No space left(%d) for new custom sensor(%zu)\n", + st->custom_table_size, new_custom->size); /* allocate the table */ if (is_steinhart) @@ -688,21 +687,19 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data LTC2983_THERMOCOUPLE_OC_CURR(3); break; default: - dev_err(&st->spi->dev, - "Invalid open circuit current:%u", oc_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid open circuit current:%u\n", + oc_current); } thermo->sensor_config |= LTC2983_THERMOCOUPLE_OC_CHECK(1); } /* validate channel index */ if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for differential thermocouple", - sensor->chan); - return ERR_PTR(-EINVAL); - } + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for differential thermocouple\n", + sensor->chan); struct fwnode_handle *ref __free(fwnode_handle) = fwnode_find_reference(child, "adi,cold-junction-handle", 0); @@ -710,14 +707,13 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data ref = NULL; } else { ret = fwnode_property_read_u32(ref, "reg", &thermo->cold_junction_chan); - if (ret) { + if (ret) /* * This would be catched later but we can just return * the error right away. */ - dev_err(&st->spi->dev, "Property reg must be given\n"); - return ERR_PTR(ret); - } + return dev_err_ptr_probe(&st->spi->dev, ret, + "Property reg must be given\n"); } /* check custom sensor */ @@ -753,16 +749,14 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, struct fwnode_handle *ref __free(fwnode_handle) = fwnode_find_reference(child, "adi,rsense-handle", 0); - if (IS_ERR(ref)) { - dev_err(dev, "Property adi,rsense-handle missing or invalid"); - return ERR_CAST(ref); - } + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); ret = fwnode_property_read_u32(ref, "reg", &rtd->r_sense_chan); - if (ret) { - dev_err(dev, "Property reg must be given\n"); - return ERR_PTR(ret); - } + if (ret) + return dev_err_ptr_probe(dev, ret, + "Property reg must be given\n"); ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires); if (!ret) { @@ -781,19 +775,19 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->sensor_config = LTC2983_RTD_N_WIRES(3); break; default: - dev_err(dev, "Invalid number of wires:%u\n", n_wires); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid number of wires:%u\n", + n_wires); } } if (fwnode_property_read_bool(child, "adi,rsense-share")) { /* Current rotation is only available with rsense sharing */ if (fwnode_property_read_bool(child, "adi,current-rotate")) { - if (n_wires == 2 || n_wires == 3) { - dev_err(dev, - "Rotation not allowed for 2/3 Wire RTDs"); - return ERR_PTR(-EINVAL); - } + if (n_wires == 2 || n_wires == 3) + return dev_err_ptr_probe(dev, -EINVAL, + "Rotation not allowed for 2/3 Wire RTDs\n"); + rtd->sensor_config |= LTC2983_RTD_C_ROTATE(1); } else { rtd->sensor_config |= LTC2983_RTD_R_SHARE(1); @@ -816,29 +810,22 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, if (((rtd->sensor_config & LTC2983_RTD_KELVIN_R_SENSE_MASK) == LTC2983_RTD_KELVIN_R_SENSE_MASK) && - (rtd->r_sense_chan <= min)) { + (rtd->r_sense_chan <= min)) /* kelvin rsense*/ - dev_err(dev, - "Invalid rsense chann:%d to use in kelvin rsense", - rtd->r_sense_chan); + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid rsense chann:%d to use in kelvin rsense\n", + rtd->r_sense_chan); - return ERR_PTR(-EINVAL); - } - - if (sensor->chan < min || sensor->chan > max) { - dev_err(dev, "Invalid chann:%d for the rtd config", - sensor->chan); - - return ERR_PTR(-EINVAL); - } + if (sensor->chan < min || sensor->chan > max) + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid chann:%d for the rtd config\n", + sensor->chan); } else { /* same as differential case */ - if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for RTD", sensor->chan); - - return ERR_PTR(-EINVAL); - } + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for RTD\n", + sensor->chan); } /* check custom sensor */ @@ -886,10 +873,9 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->excitation_current = 0x08; break; default: - dev_err(&st->spi->dev, - "Invalid value for excitation current(%u)", - excitation_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); } } @@ -913,16 +899,14 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s struct fwnode_handle *ref __free(fwnode_handle) = fwnode_find_reference(child, "adi,rsense-handle", 0); - if (IS_ERR(ref)) { - dev_err(dev, "Property adi,rsense-handle missing or invalid"); - return ERR_CAST(ref); - } + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); ret = fwnode_property_read_u32(ref, "reg", &thermistor->r_sense_chan); - if (ret) { - dev_err(dev, "rsense channel must be configured...\n"); - return ERR_PTR(ret); - } + if (ret) + return dev_err_ptr_probe(dev, ret, + "rsense channel must be configured...\n"); if (fwnode_property_read_bool(child, "adi,single-ended")) { thermistor->sensor_config = LTC2983_THERMISTOR_SGL(1); @@ -937,12 +921,10 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s } /* validate channel index */ if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for differential thermistor", - sensor->chan); - return ERR_PTR(-EINVAL); - } + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for differential thermistor\n", + sensor->chan); /* check custom sensor */ if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) { @@ -981,12 +963,10 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s switch (excitation_current) { case 0: /* auto range */ - if (sensor->type >= - LTC2983_SENSOR_THERMISTOR_STEINHART) { - dev_err(&st->spi->dev, - "Auto Range not allowed for custom sensors\n"); - return ERR_PTR(-EINVAL); - } + if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Auto Range not allowed for custom sensors\n"); + thermistor->excitation_current = 0x0c; break; case 250: @@ -1023,10 +1003,9 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s thermistor->excitation_current = 0x0b; break; default: - dev_err(&st->spi->dev, - "Invalid value for excitation current(%u)", - excitation_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); } } @@ -1056,12 +1035,11 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * /* validate channel index */ if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, - "Invalid chann:%d for differential thermistor", - sensor->chan); - return ERR_PTR(-EINVAL); - } + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for differential thermistor\n", + sensor->chan); + /* set common parameters */ diode->sensor.fault_handler = ltc2983_common_fault_handler; diode->sensor.assign_chan = ltc2983_diode_assign_chan; @@ -1083,10 +1061,9 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * diode->excitation_current = 0x03; break; default: - dev_err(&st->spi->dev, - "Invalid value for excitation current(%u)", - excitation_current); - return ERR_PTR(-EINVAL); + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); } } @@ -1111,17 +1088,15 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child, return ERR_PTR(-ENOMEM); /* validate channel index */ - if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, "Invalid chann:%d for r_sense", - sensor->chan); - return ERR_PTR(-EINVAL); - } + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chann:%d for r_sense\n", + sensor->chan); ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp); - if (ret) { - dev_err(&st->spi->dev, "Property adi,rsense-val-milli-ohms missing\n"); - return ERR_PTR(-EINVAL); - } + if (ret) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Property adi,rsense-val-milli-ohms missing\n"); /* * Times 1000 because we have milli-ohms and __convert_to_raw * expects scales of 1000000 which are used for all other @@ -1149,12 +1124,11 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child, if (fwnode_property_read_bool(child, "adi,single-ended")) adc->single_ended = true; - if (!adc->single_ended && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, "Invalid chan:%d for differential adc\n", - sensor->chan); - return ERR_PTR(-EINVAL); - } + if (!adc->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chan:%d for differential adc\n", + sensor->chan); + /* set common parameters */ adc->sensor.assign_chan = ltc2983_adc_assign_chan; adc->sensor.fault_handler = ltc2983_common_fault_handler; @@ -1175,12 +1149,10 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, if (fwnode_property_read_bool(child, "adi,single-ended")) temp->single_ended = true; - if (!temp->single_ended && - sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { - dev_err(&st->spi->dev, "Invalid chan:%d for differential temp\n", - sensor->chan); - return ERR_PTR(-EINVAL); - } + if (!temp->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + "Invalid chan:%d for differential temp\n", + sensor->chan); temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp", false, 4096, true); @@ -1296,8 +1268,8 @@ static int ltc2983_reg_access(struct iio_dev *indio_dev, if (readval) return regmap_read(st->regmap, reg, readval); - else - return regmap_write(st->regmap, reg, writeval); + + return regmap_write(st->regmap, reg, writeval); } static irqreturn_t ltc2983_irq_handler(int irq, void *data) @@ -1330,10 +1302,9 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) device_property_read_u32(dev, "adi,filter-notch-freq", &st->filter_notch_freq); st->num_channels = device_get_child_node_count(dev); - if (!st->num_channels) { - dev_err(&st->spi->dev, "At least one channel must be given!"); - return -EINVAL; - } + if (!st->num_channels) + return dev_err_probe(&st->spi->dev, -EINVAL, + "At least one channel must be given!\n"); st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors), GFP_KERNEL); @@ -1438,19 +1409,17 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, time = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(wait_time)); - if (!time) { - dev_err(&st->spi->dev, "EEPROM command timed out\n"); - return -ETIMEDOUT; - } + if (!time) + return dev_err_probe(&st->spi->dev, -ETIMEDOUT, + "EEPROM command timed out\n"); ret = regmap_read(st->regmap, status_reg, &val); if (ret) return ret; - if (val & status_fail_mask) { - dev_err(&st->spi->dev, "EEPROM command failed: 0x%02X\n", val); - return -EINVAL; - } + if (val & status_fail_mask) + return dev_err_probe(&st->spi->dev, -EINVAL, + "EEPROM command failed: 0x%02X\n", val); return 0; } @@ -1464,10 +1433,9 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) ret = regmap_read_poll_timeout(st->regmap, LTC2983_STATUS_REG, status, LTC2983_STATUS_UP(status) == 1, 25000, 25000 * 10); - if (ret) { - dev_err(&st->spi->dev, "Device startup timed out\n"); - return ret; - } + if (ret) + return dev_err_probe(&st->spi->dev, ret, + "Device startup timed out\n"); ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG, LTC2983_NOTCH_FREQ_MASK, @@ -1583,10 +1551,9 @@ static int ltc2983_probe(struct spi_device *spi) return -ENODEV; st->regmap = devm_regmap_init_spi(spi, <c2983_regmap_config); - if (IS_ERR(st->regmap)) { - dev_err(&spi->dev, "Failed to initialize regmap\n"); - return PTR_ERR(st->regmap); - } + if (IS_ERR(st->regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + "Failed to initialize regmap\n"); mutex_init(&st->lock); init_completion(&st->completion); @@ -1624,10 +1591,9 @@ static int ltc2983_probe(struct spi_device *spi) ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, IRQF_TRIGGER_RISING, st->info->name, st); - if (ret) { - dev_err(&spi->dev, "failed to request an irq, %d", ret); - return ret; - } + if (ret) + return dev_err_probe(&spi->dev, ret, + "failed to request an irq\n"); if (st->info->has_eeprom) { ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD, From ac5189293acb85b3d6da4fc18c3374f0daf69594 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 6 Jun 2024 09:22:39 +0200 Subject: [PATCH 254/330] iio: backend: make use of dev_err_cast_probe() Using dev_err_cast_probe() to simplify the code. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-3-51bb229edd79@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-backend.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 929aff4040ed..efe05be284b6 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -561,11 +561,9 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) } fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index); - if (IS_ERR(fwnode)) { - dev_err_probe(dev, PTR_ERR(fwnode), - "Cannot get Firmware reference\n"); - return ERR_CAST(fwnode); - } + if (IS_ERR(fwnode)) + return dev_err_cast_probe(dev, fwnode, + "Cannot get Firmware reference\n"); guard(mutex)(&iio_back_lock); list_for_each_entry(back, &iio_back_list, entry) { From 6dba0c39fa788e07d1b94edeaac35e7e02ed9a79 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 6 Jun 2024 09:22:40 +0200 Subject: [PATCH 255/330] iio: common: scmi_iio: convert to dev_err_probe() Make use of dev_err_probe() and dev_err_ptr_probe() to simplify error paths during probe. Signed-off-by: Nuno Sa Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-4-51bb229edd79@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/common/scmi_sensors/scmi_iio.c | 45 +++++++++------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index 0c2caf3570db..7190eaede7fb 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -626,12 +626,10 @@ scmi_alloc_iiodev(struct scmi_device *sdev, SCMI_PROTOCOL_SENSOR, SCMI_EVENT_SENSOR_UPDATE, &sensor->sensor_info->id, &sensor->sensor_update_nb); - if (ret) { - dev_err(&iiodev->dev, - "Error in registering sensor update notifier for sensor %s err %d", - sensor->sensor_info->name, ret); - return ERR_PTR(ret); - } + if (ret) + return dev_err_ptr_probe(&iiodev->dev, ret, + "Error in registering sensor update notifier for sensor %s\n", + sensor->sensor_info->name); scmi_iio_set_timestamp_channel(&iio_channels[i], i); iiodev->channels = iio_channels; @@ -653,10 +651,9 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev) return -ENODEV; sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph); - if (IS_ERR(sensor_ops)) { - dev_err(dev, "SCMI device has no sensor interface\n"); - return PTR_ERR(sensor_ops); - } + if (IS_ERR(sensor_ops)) + return dev_err_probe(dev, PTR_ERR(sensor_ops), + "SCMI device has no sensor interface\n"); nr_sensors = sensor_ops->count_get(ph); if (!nr_sensors) { @@ -667,8 +664,8 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev) for (i = 0; i < nr_sensors; i++) { sensor_info = sensor_ops->info_get(ph, i); if (!sensor_info) { - dev_err(dev, "SCMI sensor %d has missing info\n", i); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "SCMI sensor %d has missing info\n", i); } /* This driver only supports 3-axis accel and gyro, skipping other sensors */ @@ -683,29 +680,25 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev) scmi_iio_dev = scmi_alloc_iiodev(sdev, sensor_ops, ph, sensor_info); if (IS_ERR(scmi_iio_dev)) { - dev_err(dev, - "failed to allocate IIO device for sensor %s: %ld\n", - sensor_info->name, PTR_ERR(scmi_iio_dev)); - return PTR_ERR(scmi_iio_dev); + return dev_err_probe(dev, PTR_ERR(scmi_iio_dev), + "failed to allocate IIO device for sensor %s\n", + sensor_info->name); } err = devm_iio_kfifo_buffer_setup(&scmi_iio_dev->dev, scmi_iio_dev, &scmi_iio_buffer_ops); if (err < 0) { - dev_err(dev, - "IIO buffer setup error at sensor %s: %d\n", - sensor_info->name, err); - return err; + return dev_err_probe(dev, err, + "IIO buffer setup error at sensor %s\n", + sensor_info->name); } err = devm_iio_device_register(dev, scmi_iio_dev); - if (err) { - dev_err(dev, - "IIO device registration failed at sensor %s: %d\n", - sensor_info->name, err); - return err; - } + if (err) + return dev_err_probe(dev, err, + "IIO device registration failed at sensor %s\n", + sensor_info->name); } return err; } From 5f81aa76771eb43769c919064d4d5a52424857c3 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 2 Jun 2024 15:05:20 -0700 Subject: [PATCH 256/330] counter: ftm-quaddec: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/counter/ftm-quaddec.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240602-md-ftm-quaddec-v1-1-1bbdf705ad31@quicinc.com Signed-off-by: William Breathitt Gray --- drivers/counter/ftm-quaddec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c index aea6622a9b13..200876f3ec04 100644 --- a/drivers/counter/ftm-quaddec.c +++ b/drivers/counter/ftm-quaddec.c @@ -322,6 +322,7 @@ static struct platform_driver ftm_quaddec_driver = { module_platform_driver(ftm_quaddec_driver); +MODULE_DESCRIPTION("Flex Timer Module Quadrature decoder"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kjeld Flarup "); MODULE_AUTHOR("Patrick Havelange "); From 10365dd4c1842d0da422b56c5aa3827db0ca08d8 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 9 Jun 2024 16:49:33 -0500 Subject: [PATCH 257/330] counter: ti-eqep: implement over/underflow events This adds support to the TI eQEP counter driver for subscribing to overflow and underflow events using the counter chrdev interface. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240609-counter-ti-eqep-over-under-events-v1-1-74fe1632f5ab@baylibre.com Signed-off-by: William Breathitt Gray --- drivers/counter/ti-eqep.c | 106 +++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index 825ae22c3ebc..a27622efebb0 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,44 @@ #define QEPCTL_UTE BIT(1) #define QEPCTL_WDE BIT(0) +#define QEINT_UTO BIT(11) +#define QEINT_IEL BIT(10) +#define QEINT_SEL BIT(9) +#define QEINT_PCM BIT(8) +#define QEINT_PCR BIT(7) +#define QEINT_PCO BIT(6) +#define QEINT_PCU BIT(5) +#define QEINT_WTO BIT(4) +#define QEINT_QDC BIT(3) +#define QEINT_PHE BIT(2) +#define QEINT_PCE BIT(1) + +#define QFLG_UTO BIT(11) +#define QFLG_IEL BIT(10) +#define QFLG_SEL BIT(9) +#define QFLG_PCM BIT(8) +#define QFLG_PCR BIT(7) +#define QFLG_PCO BIT(6) +#define QFLG_PCU BIT(5) +#define QFLG_WTO BIT(4) +#define QFLG_QDC BIT(3) +#define QFLG_PHE BIT(2) +#define QFLG_PCE BIT(1) +#define QFLG_INT BIT(0) + +#define QCLR_UTO BIT(11) +#define QCLR_IEL BIT(10) +#define QCLR_SEL BIT(9) +#define QCLR_PCM BIT(8) +#define QCLR_PCR BIT(7) +#define QCLR_PCO BIT(6) +#define QCLR_PCU BIT(5) +#define QCLR_WTO BIT(4) +#define QCLR_QDC BIT(3) +#define QCLR_PHE BIT(2) +#define QCLR_PCE BIT(1) +#define QCLR_INT BIT(0) + /* EQEP Inputs */ enum { TI_EQEP_SIGNAL_QEPA, /* QEPA/XCLK */ @@ -239,12 +278,49 @@ static int ti_eqep_action_read(struct counter_device *counter, } } +static int ti_eqep_events_configure(struct counter_device *counter) +{ + struct ti_eqep_cnt *priv = counter_priv(counter); + struct counter_event_node *event_node; + u32 qeint = 0; + + list_for_each_entry(event_node, &counter->events_list, l) { + switch (event_node->event) { + case COUNTER_EVENT_OVERFLOW: + qeint |= QEINT_PCO; + break; + case COUNTER_EVENT_UNDERFLOW: + qeint |= QEINT_PCU; + break; + } + } + + return regmap_write(priv->regmap16, QEINT, qeint); +} + +static int ti_eqep_watch_validate(struct counter_device *counter, + const struct counter_watch *watch) +{ + switch (watch->event) { + case COUNTER_EVENT_OVERFLOW: + case COUNTER_EVENT_UNDERFLOW: + if (watch->channel != 0) + return -EINVAL; + + return 0; + default: + return -EINVAL; + } +} + static const struct counter_ops ti_eqep_counter_ops = { .count_read = ti_eqep_count_read, .count_write = ti_eqep_count_write, .function_read = ti_eqep_function_read, .function_write = ti_eqep_function_write, .action_read = ti_eqep_action_read, + .events_configure = ti_eqep_events_configure, + .watch_validate = ti_eqep_watch_validate, }; static int ti_eqep_position_ceiling_read(struct counter_device *counter, @@ -355,6 +431,25 @@ static struct counter_count ti_eqep_counts[] = { }, }; +static irqreturn_t ti_eqep_irq_handler(int irq, void *dev_id) +{ + struct counter_device *counter = dev_id; + struct ti_eqep_cnt *priv = counter_priv(counter); + u32 qflg; + + regmap_read(priv->regmap16, QFLG, &qflg); + + if (qflg & QFLG_PCO) + counter_push_event(counter, COUNTER_EVENT_OVERFLOW, 0); + + if (qflg & QFLG_PCU) + counter_push_event(counter, COUNTER_EVENT_UNDERFLOW, 0); + + regmap_write(priv->regmap16, QCLR, qflg); + + return IRQ_HANDLED; +} + static const struct regmap_config ti_eqep_regmap32_config = { .name = "32-bit", .reg_bits = 32, @@ -378,7 +473,7 @@ static int ti_eqep_probe(struct platform_device *pdev) struct ti_eqep_cnt *priv; void __iomem *base; struct clk *clk; - int err; + int err, irq; counter = devm_counter_alloc(dev, sizeof(*priv)); if (!counter) @@ -399,6 +494,15 @@ static int ti_eqep_probe(struct platform_device *pdev) if (IS_ERR(priv->regmap16)) return PTR_ERR(priv->regmap16); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + err = devm_request_threaded_irq(dev, irq, NULL, ti_eqep_irq_handler, + IRQF_ONESHOT, dev_name(dev), counter); + if (err < 0) + return dev_err_probe(dev, err, "failed to request IRQ\n"); + counter->name = dev_name(dev); counter->parent = dev; counter->ops = &ti_eqep_counter_ops; From bc4666be63bdc7c562cfb2e9ea42cdb2c444a5b2 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 9 Jun 2024 15:06:15 -0500 Subject: [PATCH 258/330] counter: ti-eqep: remove unused struct member Since commit 8817c2d03a85 ("counter: ti-eqep: Convert to counter_priv() wrapper") the counter field in struct ti_eqep_cnt is not used anymore. Remove it. Signed-off-by: David Lechner Reviewed-by: Judith Mendez Link: https://lore.kernel.org/r/20240609-ti-eqep-cleanup-v1-1-9d67939c763a@baylibre.com Signed-off-by: William Breathitt Gray --- drivers/counter/ti-eqep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index a27622efebb0..db28fc42cf16 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -122,7 +122,6 @@ enum ti_eqep_count_func { }; struct ti_eqep_cnt { - struct counter_device counter; struct regmap *regmap32; struct regmap *regmap16; }; From 1a84aaadb06b46f044eebf0de3bd3ac77a6ec52e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 9 Jun 2024 15:06:16 -0500 Subject: [PATCH 259/330] counter: ti-eqep: remove counter_priv() wrapper The ti_eqep_count_from_counter() function is just a wrapper around counter_priv(). counter_priv() can be used directly, so we don't need the wrapper function. Remove it. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240609-ti-eqep-cleanup-v1-2-9d67939c763a@baylibre.com Signed-off-by: William Breathitt Gray --- drivers/counter/ti-eqep.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index db28fc42cf16..d8a789cf5417 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -126,15 +126,10 @@ struct ti_eqep_cnt { struct regmap *regmap16; }; -static struct ti_eqep_cnt *ti_eqep_count_from_counter(struct counter_device *counter) -{ - return counter_priv(counter); -} - static int ti_eqep_count_read(struct counter_device *counter, struct counter_count *count, u64 *val) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); u32 cnt; regmap_read(priv->regmap32, QPOSCNT, &cnt); @@ -146,7 +141,7 @@ static int ti_eqep_count_read(struct counter_device *counter, static int ti_eqep_count_write(struct counter_device *counter, struct counter_count *count, u64 val) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); u32 max; regmap_read(priv->regmap32, QPOSMAX, &max); @@ -160,7 +155,7 @@ static int ti_eqep_function_read(struct counter_device *counter, struct counter_count *count, enum counter_function *function) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); u32 qdecctl; regmap_read(priv->regmap16, QDECCTL, &qdecctl); @@ -187,7 +182,7 @@ static int ti_eqep_function_write(struct counter_device *counter, struct counter_count *count, enum counter_function function) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); enum ti_eqep_count_func qsrc; switch (function) { @@ -217,7 +212,7 @@ static int ti_eqep_action_read(struct counter_device *counter, struct counter_synapse *synapse, enum counter_synapse_action *action) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); enum counter_function function; u32 qdecctl; int err; @@ -326,7 +321,7 @@ static int ti_eqep_position_ceiling_read(struct counter_device *counter, struct counter_count *count, u64 *ceiling) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); u32 qposmax; regmap_read(priv->regmap32, QPOSMAX, &qposmax); @@ -340,7 +335,7 @@ static int ti_eqep_position_ceiling_write(struct counter_device *counter, struct counter_count *count, u64 ceiling) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); if (ceiling != (u32)ceiling) return -ERANGE; @@ -353,7 +348,7 @@ static int ti_eqep_position_ceiling_write(struct counter_device *counter, static int ti_eqep_position_enable_read(struct counter_device *counter, struct counter_count *count, u8 *enable) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); u32 qepctl; regmap_read(priv->regmap16, QEPCTL, &qepctl); @@ -366,7 +361,7 @@ static int ti_eqep_position_enable_read(struct counter_device *counter, static int ti_eqep_position_enable_write(struct counter_device *counter, struct counter_count *count, u8 enable) { - struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter); + struct ti_eqep_cnt *priv = counter_priv(counter); regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, enable ? -1 : 0); From 151ebcf0797b1a3ba53c8843dc21748c80e098c7 Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Wed, 12 Jun 2024 08:55:31 -0500 Subject: [PATCH 260/330] dt-bindings: counter: Add new ti,am62-eqep compatible Add new compatible ti,am62-eqep for TI K3 devices. If a device uses this compatible, require power-domains property. Since there is only one functional and interface clock for eqep, clock-names is not really required, so removed from required section, make it optional for ti,am3352-eqep compatible, and update the example. The clock-name also changed for TI K3 SoCs so do not allow clock-names property for the new compatible. Signed-off-by: Judith Mendez Acked-by: Conor Dooley Reviewed-by: David Lechner Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240612135538.2447938-2-jm@ti.com Signed-off-by: William Breathitt Gray --- .../devicetree/bindings/counter/ti-eqep.yaml | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/counter/ti-eqep.yaml b/Documentation/devicetree/bindings/counter/ti-eqep.yaml index 85f1ff83afe7..c882ab5fcf1f 100644 --- a/Documentation/devicetree/bindings/counter/ti-eqep.yaml +++ b/Documentation/devicetree/bindings/counter/ti-eqep.yaml @@ -11,7 +11,9 @@ maintainers: properties: compatible: - const: ti,am3352-eqep + enum: + - ti,am3352-eqep + - ti,am62-eqep reg: maxItems: 1 @@ -21,19 +23,35 @@ properties: maxItems: 1 clocks: - description: The clock that determines the SYSCLKOUT rate for the eQEP - peripheral. + description: The functional and interface clock that determines the clock + rate for the eQEP peripheral. maxItems: 1 clock-names: const: sysclkout + power-domains: + maxItems: 1 + +allOf: + - if: + properties: + compatible: + contains: + enum: + - ti,am62-eqep + then: + properties: + clock-names: false + + required: + - power-domains + required: - compatible - reg - interrupts - clocks - - clock-names additionalProperties: false @@ -43,7 +61,6 @@ examples: compatible = "ti,am3352-eqep"; reg = <0x180 0x80>; clocks = <&l4ls_gclk>; - clock-names = "sysclkout"; interrupts = <79>; }; From 210457b651acd61fced405cf7fef12a482932ca1 Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Wed, 12 Jun 2024 08:55:32 -0500 Subject: [PATCH 261/330] counter/ti-eqep: Add new ti-am62-eqep compatible Add new compatible for ti-am62-eqep for TI K3 SoC's. Signed-off-by: Judith Mendez Reviewed-by: David Lechner Link: https://lore.kernel.org/r/20240612135538.2447938-3-jm@ti.com Signed-off-by: William Breathitt Gray --- drivers/counter/ti-eqep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index d8a789cf5417..313b91456f26 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -541,6 +541,7 @@ static void ti_eqep_remove(struct platform_device *pdev) static const struct of_device_id ti_eqep_of_match[] = { { .compatible = "ti,am3352-eqep", }, + { .compatible = "ti,am62-eqep", }, { }, }; MODULE_DEVICE_TABLE(of, ti_eqep_of_match); From 2e5657aa59669698f0f3bf7742d83577a18eb830 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 1 Jul 2024 02:32:35 +0000 Subject: [PATCH 262/330] hwtracing: use for_each_endpoint_of_node() We already have for_each_endpoint_of_node(), don't use of_graph_get_next_endpoint() directly. Replace it. Signed-off-by: Kuninori Morimoto Reviewed-by: Suzuki K Poulose Reviewed-by: Laurent Pinchart Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/878qyl970c.wl-kuninori.morimoto.gx@renesas.com --- drivers/hwtracing/coresight/coresight-platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 57a009552cc5..64e171eaad82 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -275,7 +275,7 @@ static int of_get_coresight_platform_data(struct device *dev, */ if (!parent) { /* - * Avoid warnings in of_graph_get_next_endpoint() + * Avoid warnings in for_each_endpoint_of_node() * if the device doesn't have any graph connections */ if (!of_graph_is_present(node)) @@ -286,7 +286,7 @@ static int of_get_coresight_platform_data(struct device *dev, } /* Iterate through each output port to discover topology */ - while ((ep = of_graph_get_next_endpoint(parent, ep))) { + for_each_endpoint_of_node(parent, ep) { /* * Legacy binding mixes input/output ports under the * same parent. So, skip the input ports if we are dealing From 988609f2aaf1c0dd1498eef6dec21c8a5fa34046 Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Wed, 12 Jun 2024 08:55:38 -0500 Subject: [PATCH 263/330] counter: ti-eqep: Allow eQEP driver to be built for K3 devices TI K3 SoC's support eQEP hardware, so add ARCH_K3 to the depends so the TI eQEP driver can be built for K3 devices. Signed-off-by: Judith Mendez Reviewed-by: David Lechner Link: https://lore.kernel.org/r/20240612135538.2447938-9-jm@ti.com Signed-off-by: William Breathitt Gray --- drivers/counter/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 497bc05dca4d..d30d22dfe577 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -138,7 +138,7 @@ config TI_ECAP_CAPTURE config TI_EQEP tristate "TI eQEP counter driver" - depends on (SOC_AM33XX || COMPILE_TEST) + depends on SOC_AM33XX || ARCH_K3 || COMPILE_TEST select REGMAP_MMIO help Select this option to enable the Texas Instruments Enhanced Quadrature From f08d4bdad612dcff6827f8cd2b20f13413c392d3 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 26 Jun 2024 11:02:37 +0530 Subject: [PATCH 264/330] bus: mhi: host: pci_generic: Use unique 'mhi_pci_dev_info' for product families Currently, a single 'mhi_pci_dev_info' is shared across different product families. Even though it makes the device functional, it misleads the users by sharing the common product name. For instance, below message will be printed for Foxconn SDX62 modem during boot: "MHI PCI device found: foxconn-sdx65" But this is quite misleading to the users since the actual modem plugged in could be 'T99W373' which is based on SDX62. So fix this issue by using a unique 'mhi_pci_dev_info' for product families. This allows us to specify a unique product name for each product family. Also, once this name is exposed to client drivers, they may use this name to identify the modems and use any modem specific configuration. Modems of unknown product families are not impacted by this change. CC: Slark Xiao Reviewed-by: Slark Xiao Link: https://lore.kernel.org/r/20240626053237.4227-1-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/host/pci_generic.c | 88 ++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 08844ee79654..35ae7cd0711f 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -419,15 +419,6 @@ static const struct mhi_controller_config modem_foxconn_sdx55_config = { .event_cfg = mhi_foxconn_sdx55_events, }; -static const struct mhi_pci_dev_info mhi_foxconn_sdx24_info = { - .name = "foxconn-sdx24", - .config = &modem_foxconn_sdx55_config, - .bar_num = MHI_PCI_DEFAULT_BAR_NUM, - .dma_data_width = 32, - .mru_default = 32768, - .sideband_wake = false, -}; - static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { .name = "foxconn-sdx55", .fw = "qcom/sdx55m/sbl1.mbn", @@ -439,8 +430,57 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { .sideband_wake = false, }; -static const struct mhi_pci_dev_info mhi_foxconn_sdx65_info = { - .name = "foxconn-sdx65", +static const struct mhi_pci_dev_info mhi_foxconn_t99w175_info = { + .name = "foxconn-t99w175", + .fw = "qcom/sdx55m/sbl1.mbn", + .edl = "qcom/sdx55m/edl.mbn", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_dw5930e_info = { + .name = "foxconn-dw5930e", + .fw = "qcom/sdx55m/sbl1.mbn", + .edl = "qcom/sdx55m/edl.mbn", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_t99w368_info = { + .name = "foxconn-t99w368", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_t99w373_info = { + .name = "foxconn-t99w373", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_t99w510_info = { + .name = "foxconn-t99w510", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_dw5932e_info = { + .name = "foxconn-dw5932e", .config = &modem_foxconn_sdx55_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, .dma_data_width = 32, @@ -646,40 +686,40 @@ static const struct pci_device_id mhi_pci_id_table[] = { .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, /* T99W175 (sdx55), Both for eSIM and Non-eSIM */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0ab), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w175_info }, /* DW5930e (sdx55), With eSIM, It's also T99W175 */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b0), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_dw5930e_info }, /* DW5930e (sdx55), Non-eSIM, It's also T99W175 */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_dw5930e_info }, /* T99W175 (sdx55), Based on Qualcomm new baseline */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0bf), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w175_info }, /* T99W175 (sdx55) */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0c3), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w175_info }, /* T99W368 (sdx65) */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d8), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w368_info }, /* T99W373 (sdx62) */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d9), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w373_info }, /* T99W510 (sdx24), variant 1 */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f0), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w510_info }, /* T99W510 (sdx24), variant 2 */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f1), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w510_info }, /* T99W510 (sdx24), variant 3 */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f2), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w510_info }, /* DW5932e-eSIM (sdx62), With eSIM */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f5), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_dw5932e_info }, /* DW5932e (sdx62), Non-eSIM */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f9), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_dw5932e_info }, /* MV31-W (Cinterion) */ { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3), .driver_data = (kernel_ulong_t) &mhi_mv31_info }, @@ -694,7 +734,7 @@ static const struct pci_device_id mhi_pci_id_table[] = { .driver_data = (kernel_ulong_t) &mhi_mv32_info }, /* T99W175 (sdx55), HP variant */ { PCI_DEVICE(0x03f0, 0x0a6c), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w175_info }, { } }; MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); From 4d8aa430624006ba06254aa607f8756a75e42c8d Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 4 Jun 2024 14:30:04 +0200 Subject: [PATCH 265/330] dt-bindings: iio: adc: Add MediaTek MT6359 PMIC AUXADC Add a new binding for the MT6350 Series (MT6357/8/9) PMIC AUXADC, providing various ADC channels for both internal temperatures and voltages, audio accessory detection (hp/mic/hp+mic and buttons, usually on a 3.5mm jack) other than some basic battery statistics on boards where the battery is managed by this PMIC. Also add the necessary dt-binding headers for devicetree consumers. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Link: https://patch.msgid.link/20240604123008.327424-2-angelogioacchino.delregno@collabora.com Signed-off-by: Jonathan Cameron --- .../iio/adc/mediatek,mt6359-auxadc.yaml | 33 +++++++++++++++++++ .../iio/adc/mediatek,mt6357-auxadc.h | 21 ++++++++++++ .../iio/adc/mediatek,mt6358-auxadc.h | 22 +++++++++++++ .../iio/adc/mediatek,mt6359-auxadc.h | 22 +++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml new file mode 100644 index 000000000000..6497c416094d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/mediatek,mt6359-auxadc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6350 series PMIC AUXADC + +maintainers: + - AngeloGioacchino Del Regno + +description: + The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found + in some MediaTek PMICs, performing various PMIC related measurements + such as battery and PMIC internal voltage regulators temperatures, + accessory detection resistance (usually, for a 3.5mm audio jack) + other than voltages for various PMIC internal components. + +properties: + compatible: + enum: + - mediatek,mt6357-auxadc + - mediatek,mt6358-auxadc + - mediatek,mt6359-auxadc + + "#io-channel-cells": + const: 1 + +required: + - compatible + - "#io-channel-cells" + +additionalProperties: false diff --git a/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h new file mode 100644 index 000000000000..03ebb1d23953 --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef _DT_BINDINGS_MEDIATEK_MT6357_AUXADC_H +#define _DT_BINDINGS_MEDIATEK_MT6357_AUXADC_H + +/* ADC Channel Index */ +#define MT6357_AUXADC_BATADC 0 +#define MT6357_AUXADC_ISENSE 1 +#define MT6357_AUXADC_VCDT 2 +#define MT6357_AUXADC_BAT_TEMP 3 +#define MT6357_AUXADC_CHIP_TEMP 4 +#define MT6357_AUXADC_ACCDET 5 +#define MT6357_AUXADC_VDCXO 6 +#define MT6357_AUXADC_TSX_TEMP 7 +#define MT6357_AUXADC_HPOFS_CAL 8 +#define MT6357_AUXADC_DCXO_TEMP 9 +#define MT6357_AUXADC_VCORE_TEMP 10 +#define MT6357_AUXADC_VPROC_TEMP 11 +#define MT6357_AUXADC_VBAT 12 + +#endif diff --git a/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h new file mode 100644 index 000000000000..efa08398fafd --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef _DT_BINDINGS_MEDIATEK_MT6358_AUXADC_H +#define _DT_BINDINGS_MEDIATEK_MT6358_AUXADC_H + +/* ADC Channel Index */ +#define MT6358_AUXADC_BATADC 0 +#define MT6358_AUXADC_VCDT 1 +#define MT6358_AUXADC_BAT_TEMP 2 +#define MT6358_AUXADC_CHIP_TEMP 3 +#define MT6358_AUXADC_ACCDET 4 +#define MT6358_AUXADC_VDCXO 5 +#define MT6358_AUXADC_TSX_TEMP 6 +#define MT6358_AUXADC_HPOFS_CAL 7 +#define MT6358_AUXADC_DCXO_TEMP 8 +#define MT6358_AUXADC_VBIF 9 +#define MT6358_AUXADC_VCORE_TEMP 10 +#define MT6358_AUXADC_VPROC_TEMP 11 +#define MT6358_AUXADC_VGPU_TEMP 12 +#define MT6358_AUXADC_VBAT 13 + +#endif diff --git a/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h new file mode 100644 index 000000000000..59826393ee7e --- /dev/null +++ b/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef _DT_BINDINGS_MEDIATEK_MT6359_AUXADC_H +#define _DT_BINDINGS_MEDIATEK_MT6359_AUXADC_H + +/* ADC Channel Index */ +#define MT6359_AUXADC_BATADC 0 +#define MT6359_AUXADC_BAT_TEMP 1 +#define MT6359_AUXADC_CHIP_TEMP 2 +#define MT6359_AUXADC_ACCDET 3 +#define MT6359_AUXADC_VDCXO 4 +#define MT6359_AUXADC_TSX_TEMP 5 +#define MT6359_AUXADC_HPOFS_CAL 6 +#define MT6359_AUXADC_DCXO_TEMP 7 +#define MT6359_AUXADC_VBIF 8 +#define MT6359_AUXADC_VCORE_TEMP 9 +#define MT6359_AUXADC_VPROC_TEMP 10 +#define MT6359_AUXADC_VGPU_TEMP 11 +#define MT6359_AUXADC_VBAT 12 +#define MT6359_AUXADC_IBAT 13 + +#endif From e38a82df2c9924577d39ce5ccee9e9edcadc3b5d Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 4 Jun 2024 14:30:06 +0200 Subject: [PATCH 266/330] math.h: Add unsigned 8 bits fractional numbers type Some users may be requiring only rather small numbers as both numerator and denominator: add signed and unsigned 8 bits structs {s8,u8}_fract. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20240604123008.327424-4-angelogioacchino.delregno@collabora.com Signed-off-by: Jonathan Cameron --- include/linux/math.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/math.h b/include/linux/math.h index dd4152711de7..f5f18dc3616b 100644 --- a/include/linux/math.h +++ b/include/linux/math.h @@ -112,6 +112,8 @@ struct type##_fract { \ __##type numerator; \ __##type denominator; \ }; +__STRUCT_FRACT(s8) +__STRUCT_FRACT(u8) __STRUCT_FRACT(s16) __STRUCT_FRACT(u16) __STRUCT_FRACT(s32) From 3587914bf61df7924933530353d840378cdc4973 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 4 Jun 2024 14:30:07 +0200 Subject: [PATCH 267/330] iio: adc: Add support for MediaTek MT6357/8/9 Auxiliary ADC Add a driver to support reading the Auxiliary ADC IP found in the MediaTek MT6357, MT6358 and MT6359 Power Management ICs, featuring a different register layout, configuration reset and ADC reading sequence from the other already supported MediaTek SoC or PMIC (aux)ADC HW. This driver provides multiple ADC channels for system monitoring, such as battery voltage, PMIC temperature, PMIC-internal voltage regulators temperature, and others. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20240604123008.327424-5-angelogioacchino.delregno@collabora.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mt6359-auxadc.c | 606 ++++++++++++++++++++++++++++++++ 3 files changed, 619 insertions(+) create mode 100644 drivers/iio/adc/mt6359-auxadc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index b8184706c7d1..f60fe85a30d5 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -892,6 +892,18 @@ config MCP3911 This driver can also be built as a module. If so, the module will be called mcp3911. +config MEDIATEK_MT6359_AUXADC + tristate "MediaTek MT6359 PMIC AUXADC driver" + depends on MFD_MT6397 + help + Say yes here to enable support for MediaTek MT6357, MT6358 and + MT6359 PMICs Auxiliary ADC. + This driver provides multiple channels for system monitoring, + such as battery voltage, PMIC temperature, and others. + + This driver can also be built as a module. If so, the module will be + called mt6359-auxadc. + config MEDIATEK_MT6360_ADC tristate "Mediatek MT6360 ADC driver" depends on MFD_MT6360 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 51298c52b223..d370e066544e 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3564) += mcp3564.o obj-$(CONFIG_MCP3911) += mcp3911.o +obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c new file mode 100644 index 000000000000..a4970cfb49a5 --- /dev/null +++ b/drivers/iio/adc/mt6359-auxadc.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MediaTek MT6359 PMIC AUXADC IIO driver + * + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd + * Author: AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#define AUXADC_AVG_TIME_US 10 +#define AUXADC_POLL_DELAY_US 100 +#define AUXADC_TIMEOUT_US 32000 +#define AUXADC_VOLT_FULL 1800 +#define IMP_STOP_DELAY_US 150 +#define IMP_POLL_DELAY_US 1000 + +/* For PMIC_RG_RESET_VAL and MT6358_IMP0_CLEAR, the bits specific purpose is unknown. */ +#define PMIC_RG_RESET_VAL (BIT(0) | BIT(3)) +#define PMIC_AUXADC_RDY_BIT BIT(15) +#define MT6357_IMP_ADC_NUM 30 +#define MT6358_IMP_ADC_NUM 28 + +#define MT6358_DCM_CK_SW_EN GENMASK(1, 0) +#define MT6358_IMP0_CLEAR (BIT(14) | BIT(7)) +#define MT6358_IMP0_IRQ_RDY BIT(8) +#define MT6358_IMP1_AUTOREPEAT_EN BIT(15) + +#define MT6359_IMP0_CONV_EN BIT(0) +#define MT6359_IMP1_IRQ_RDY BIT(15) + +enum mtk_pmic_auxadc_regs { + PMIC_AUXADC_ADC0, + PMIC_AUXADC_DCM_CON, + PMIC_AUXADC_IMP0, + PMIC_AUXADC_IMP1, + PMIC_AUXADC_IMP3, + PMIC_AUXADC_RQST0, + PMIC_AUXADC_RQST1, + PMIC_HK_TOP_WKEY, + PMIC_HK_TOP_RST_CON0, + PMIC_FGADC_R_CON0, + PMIC_AUXADC_REGS_MAX +}; + +enum mtk_pmic_auxadc_channels { + PMIC_AUXADC_CHAN_BATADC, + PMIC_AUXADC_CHAN_ISENSE, + PMIC_AUXADC_CHAN_VCDT, + PMIC_AUXADC_CHAN_BAT_TEMP, + PMIC_AUXADC_CHAN_BATID, + PMIC_AUXADC_CHAN_CHIP_TEMP, + PMIC_AUXADC_CHAN_VCORE_TEMP, + PMIC_AUXADC_CHAN_VPROC_TEMP, + PMIC_AUXADC_CHAN_VGPU_TEMP, + PMIC_AUXADC_CHAN_ACCDET, + PMIC_AUXADC_CHAN_VDCXO, + PMIC_AUXADC_CHAN_TSX_TEMP, + PMIC_AUXADC_CHAN_HPOFS_CAL, + PMIC_AUXADC_CHAN_DCXO_TEMP, + PMIC_AUXADC_CHAN_VBIF, + PMIC_AUXADC_CHAN_IBAT, + PMIC_AUXADC_CHAN_VBAT, + PMIC_AUXADC_CHAN_MAX +}; + +/** + * struct mt6359_auxadc - Main driver structure + * @dev: Device pointer + * @regmap: Regmap from SoC PMIC Wrapper + * @chip_info: PMIC specific chip info + * @lock: Mutex to serialize AUXADC reading vs configuration + * @timed_out: Signals whether the last read timed out + */ +struct mt6359_auxadc { + struct device *dev; + struct regmap *regmap; + const struct mtk_pmic_auxadc_info *chip_info; + struct mutex lock; + bool timed_out; +}; + +/** + * struct mtk_pmic_auxadc_chan - PMIC AUXADC channel data + * @req_idx: Request register number + * @req_mask: Bitmask to activate a channel + * @num_samples: Number of AUXADC samples for averaging + * @r_ratio: Resistance ratio fractional + */ +struct mtk_pmic_auxadc_chan { + u8 req_idx; + u16 req_mask; + u16 num_samples; + struct u8_fract r_ratio; +}; + +/** + * struct mtk_pmic_auxadc_info - PMIC specific chip info + * @model_name: PMIC model name + * @channels: IIO specification of ADC channels + * @num_channels: Number of ADC channels + * @desc: PMIC AUXADC channel data + * @regs: List of PMIC specific registers + * @sec_unlock_key: Security unlock key for HK_TOP writes + * @imp_adc_num: ADC channel for battery impedance readings + * @read_imp: Callback to read impedance channels + */ +struct mtk_pmic_auxadc_info { + const char *model_name; + const struct iio_chan_spec *channels; + u8 num_channels; + const struct mtk_pmic_auxadc_chan *desc; + const u16 *regs; + u16 sec_unlock_key; + u8 imp_adc_num; + int (*read_imp)(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat); +}; + +#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _samples, _rnum, _rdiv) \ + [PMIC_AUXADC_CHAN_##_ch_idx] = { \ + .req_idx = _req_idx, \ + .req_mask = BIT(_req_bit), \ + .num_samples = _samples, \ + .r_ratio = { _rnum, _rdiv } \ + } + +#define MTK_PMIC_IIO_CHAN(_model, _name, _ch_idx, _adc_idx, _nbits, _ch_type) \ +{ \ + .type = _ch_type, \ + .channel = _model##_AUXADC_##_ch_idx, \ + .address = _adc_idx, \ + .scan_index = PMIC_AUXADC_CHAN_##_ch_idx, \ + .datasheet_name = __stringify(_name), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = _nbits, \ + .storagebits = 16, \ + .endianness = IIO_CPU \ + }, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) \ +} + +static const struct iio_chan_spec mt6357_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(MT6357, bat_adc, BATADC, 0, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6357, isense, ISENSE, 1, 12, IIO_CURRENT), + MTK_PMIC_IIO_CHAN(MT6357, cdt_v, VCDT, 2, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, acc_det, ACCDET, 5, 12, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6357, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6357, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6357, dcxo_temp, DCXO_TEMP, 36, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, vcore_temp, VCORE_TEMP, 40, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6357, vproc_temp, VPROC_TEMP, 41, 12, IIO_TEMP), + + /* Battery impedance channels */ + MTK_PMIC_IIO_CHAN(MT6357, batt_v, VBAT, 0, 15, IIO_VOLTAGE), +}; + +static const struct mtk_pmic_auxadc_chan mt6357_auxadc_ch_desc[] = { + MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1), + MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, 128, 3, 1), + MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1), + MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 1, 1), + MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1), + MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1), + MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1), + MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1), + MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, 8, 1, 1), + + /* Battery impedance channels */ + MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 3, 1), +}; + +static const u16 mt6357_auxadc_regs[] = { + [PMIC_HK_TOP_RST_CON0] = 0x0f90, + [PMIC_AUXADC_DCM_CON] = 0x122e, + [PMIC_AUXADC_ADC0] = 0x1088, + [PMIC_AUXADC_IMP0] = 0x119c, + [PMIC_AUXADC_IMP1] = 0x119e, + [PMIC_AUXADC_RQST0] = 0x110e, + [PMIC_AUXADC_RQST1] = 0x1114, +}; + +static const struct iio_chan_spec mt6358_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(MT6358, bat_adc, BATADC, 0, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6358, cdt_v, VCDT, 2, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, acc_det, ACCDET, 5, 12, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6358, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6358, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6358, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, bif_v, VBIF, 11, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6358, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6358, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP), + + /* Battery impedance channels */ + MTK_PMIC_IIO_CHAN(MT6358, batt_v, VBAT, 0, 15, IIO_VOLTAGE), +}; + +static const struct mtk_pmic_auxadc_chan mt6358_auxadc_ch_desc[] = { + MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1), + MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1), + MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 2, 1), + MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1), + MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2), + MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1), + MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1), + MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1), + MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 2, 1), + MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1), + + /* Battery impedance channels */ + MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2), +}; + +static const u16 mt6358_auxadc_regs[] = { + [PMIC_HK_TOP_RST_CON0] = 0x0f90, + [PMIC_AUXADC_DCM_CON] = 0x1260, + [PMIC_AUXADC_ADC0] = 0x1088, + [PMIC_AUXADC_IMP0] = 0x1208, + [PMIC_AUXADC_IMP1] = 0x120a, + [PMIC_AUXADC_RQST0] = 0x1108, + [PMIC_AUXADC_RQST1] = 0x110a, +}; + +static const struct iio_chan_spec mt6359_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(MT6359, bat_adc, BATADC, 0, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6359, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, acc_det, ACCDET, 5, 12, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6359, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6359, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE), + MTK_PMIC_IIO_CHAN(MT6359, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, bif_v, VBIF, 11, 12, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6359, vcore_temp, VCORE_TEMP, 30, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, vproc_temp, VPROC_TEMP, 31, 12, IIO_TEMP), + MTK_PMIC_IIO_CHAN(MT6359, vgpu_temp, VGPU_TEMP, 32, 12, IIO_TEMP), + + /* Battery impedance channels */ + MTK_PMIC_IIO_CHAN(MT6359, batt_v, VBAT, 0, 15, IIO_VOLTAGE), + MTK_PMIC_IIO_CHAN(MT6359, batt_i, IBAT, 0, 15, IIO_CURRENT), +}; + +static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = { + MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 7, 2), + MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 5, 2), + MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1), + MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2), + MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1), + MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1), + MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1), + MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 5, 2), + MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1), + MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1), + + /* Battery impedance channels */ + MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2), + MTK_PMIC_ADC_CHAN(IBAT, 0, 0, 128, 7, 2), +}; + +static const u16 mt6359_auxadc_regs[] = { + [PMIC_FGADC_R_CON0] = 0x0d88, + [PMIC_HK_TOP_WKEY] = 0x0fb4, + [PMIC_HK_TOP_RST_CON0] = 0x0f90, + [PMIC_AUXADC_RQST0] = 0x1108, + [PMIC_AUXADC_RQST1] = 0x110a, + [PMIC_AUXADC_ADC0] = 0x1088, + [PMIC_AUXADC_IMP0] = 0x1208, + [PMIC_AUXADC_IMP1] = 0x120a, + [PMIC_AUXADC_IMP3] = 0x120e, +}; + +static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + + regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR); + regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR); + regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN); + regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN); +} + +static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + u32 val; + int ret; + + regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN); + regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN); + + ret = regmap_read_poll_timeout(adc_dev->regmap, cinfo->regs[PMIC_AUXADC_IMP0], + val, val & MT6358_IMP0_IRQ_RDY, + IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US); + if (ret) { + mt6358_stop_imp_conv(adc_dev); + return ret; + } + + return 0; +} + +static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + u16 reg_adc0 = cinfo->regs[PMIC_AUXADC_ADC0]; + u32 val_v; + int ret; + + ret = mt6358_start_imp_conv(adc_dev); + if (ret) + return ret; + + /* Read the params before stopping */ + regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v); + + mt6358_stop_imp_conv(adc_dev); + + if (vbat) + *vbat = val_v; + if (ibat) + *ibat = 0; + + return 0; +} + +static int mt6359_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + u32 val, val_v, val_i; + int ret; + + /* Start conversion */ + regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6359_IMP0_CONV_EN); + ret = regmap_read_poll_timeout(regmap, cinfo->regs[PMIC_AUXADC_IMP1], + val, val & MT6359_IMP1_IRQ_RDY, + IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US); + + /* Stop conversion regardless of the result */ + regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], 0); + if (ret) + return ret; + + /* If it succeeded, wait for the registers to be populated */ + fsleep(IMP_STOP_DELAY_US); + + ret = regmap_read(regmap, cinfo->regs[PMIC_AUXADC_IMP3], &val_v); + if (ret) + return ret; + + ret = regmap_read(regmap, cinfo->regs[PMIC_FGADC_R_CON0], &val_i); + if (ret) + return ret; + + if (vbat) + *vbat = val_v; + if (ibat) + *ibat = val_i; + + return 0; +} + +static const struct mtk_pmic_auxadc_info mt6357_chip_info = { + .model_name = "MT6357", + .channels = mt6357_auxadc_channels, + .num_channels = ARRAY_SIZE(mt6357_auxadc_channels), + .desc = mt6357_auxadc_ch_desc, + .regs = mt6357_auxadc_regs, + .imp_adc_num = MT6357_IMP_ADC_NUM, + .read_imp = mt6358_read_imp, +}; + +static const struct mtk_pmic_auxadc_info mt6358_chip_info = { + .model_name = "MT6358", + .channels = mt6358_auxadc_channels, + .num_channels = ARRAY_SIZE(mt6358_auxadc_channels), + .desc = mt6358_auxadc_ch_desc, + .regs = mt6358_auxadc_regs, + .imp_adc_num = MT6358_IMP_ADC_NUM, + .read_imp = mt6358_read_imp, +}; + +static const struct mtk_pmic_auxadc_info mt6359_chip_info = { + .model_name = "MT6359", + .channels = mt6359_auxadc_channels, + .num_channels = ARRAY_SIZE(mt6359_auxadc_channels), + .desc = mt6359_auxadc_ch_desc, + .regs = mt6359_auxadc_regs, + .sec_unlock_key = 0x6359, + .read_imp = mt6359_read_imp, +}; + +static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + struct regmap *regmap = adc_dev->regmap; + + /* Unlock HK_TOP writes */ + if (cinfo->sec_unlock_key) + regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], cinfo->sec_unlock_key); + + /* Assert ADC reset */ + regmap_set_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL); + + /* De-assert ADC reset. No wait required, as pwrap takes care of that for us. */ + regmap_clear_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL); + + /* Lock HK_TOP writes again */ + if (cinfo->sec_unlock_key) + regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], 0); +} + +static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev, + const struct iio_chan_spec *chan, int *out) +{ + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index]; + struct regmap *regmap = adc_dev->regmap; + u32 val; + int ret; + + /* Request to start sampling for ADC channel */ + ret = regmap_write(regmap, cinfo->regs[desc->req_idx], desc->req_mask); + if (ret) + return ret; + + /* Wait until all samples are averaged */ + fsleep(desc->num_samples * AUXADC_AVG_TIME_US); + + ret = regmap_read_poll_timeout(regmap, + cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1), + val, val & PMIC_AUXADC_RDY_BIT, + AUXADC_POLL_DELAY_US, AUXADC_TIMEOUT_US); + if (ret) + return ret; + + /* Stop sampling */ + regmap_write(regmap, cinfo->regs[desc->req_idx], 0); + + *out = val & GENMASK(chan->scan_type.realbits - 1, 0); + return 0; +} + +static int mt6359_auxadc_read_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label) +{ + return sysfs_emit(label, "%s\n", chan->datasheet_name); +} + +static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6359_auxadc *adc_dev = iio_priv(indio_dev); + const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info; + const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index]; + int ret; + + if (mask == IIO_CHAN_INFO_SCALE) { + *val = desc->r_ratio.numerator * AUXADC_VOLT_FULL; + + if (desc->r_ratio.denominator > 1) { + *val2 = desc->r_ratio.denominator; + return IIO_VAL_FRACTIONAL; + } + + return IIO_VAL_INT; + } + + scoped_guard(mutex, &adc_dev->lock) { + switch (chan->scan_index) { + case PMIC_AUXADC_CHAN_IBAT: + ret = adc_dev->chip_info->read_imp(adc_dev, NULL, val); + break; + case PMIC_AUXADC_CHAN_VBAT: + ret = adc_dev->chip_info->read_imp(adc_dev, val, NULL); + break; + default: + ret = mt6359_auxadc_read_adc(adc_dev, chan, val); + break; + } + } + + if (ret) { + /* + * If we get more than one timeout, it's possible that the + * AUXADC is stuck: perform a full reset to recover it. + */ + if (ret == -ETIMEDOUT) { + if (adc_dev->timed_out) { + dev_warn(adc_dev->dev, "Resetting stuck ADC!\r\n"); + mt6359_auxadc_reset(adc_dev); + } + adc_dev->timed_out = true; + } + return ret; + } + adc_dev->timed_out = false; + + return IIO_VAL_INT; +} + +static const struct iio_info mt6359_auxadc_iio_info = { + .read_label = mt6359_auxadc_read_label, + .read_raw = mt6359_auxadc_read_raw, +}; + +static int mt6359_auxadc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *mt6397_mfd_dev = dev->parent; + struct mt6359_auxadc *adc_dev; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + /* Regmap is from SoC PMIC Wrapper, parent of the mt6397 MFD */ + regmap = dev_get_regmap(mt6397_mfd_dev->parent, NULL); + if (!regmap) + return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev)); + if (!indio_dev) + return -ENOMEM; + + adc_dev = iio_priv(indio_dev); + adc_dev->regmap = regmap; + adc_dev->dev = dev; + + adc_dev->chip_info = device_get_match_data(dev); + if (!adc_dev->chip_info) + return -EINVAL; + + mutex_init(&adc_dev->lock); + + mt6359_auxadc_reset(adc_dev); + + indio_dev->name = adc_dev->chip_info->model_name; + indio_dev->info = &mt6359_auxadc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adc_dev->chip_info->channels; + indio_dev->num_channels = adc_dev->chip_info->num_channels; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "failed to register iio device\n"); + + return 0; +} + +static const struct of_device_id mt6359_auxadc_of_match[] = { + { .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info }, + { .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info }, + { .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match); + +static struct platform_driver mt6359_auxadc_driver = { + .driver = { + .name = "mt6359-auxadc", + .of_match_table = mt6359_auxadc_of_match, + }, + .probe = mt6359_auxadc_probe, +}; +module_platform_driver(mt6359_auxadc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("AngeloGioacchino Del Regno "); +MODULE_DESCRIPTION("MediaTek MT6359 PMIC AUXADC Driver"); From 529d2e1900642eba6df28307e26e19793e227546 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 2 Jul 2024 19:43:46 +0100 Subject: [PATCH 268/330] iio: adc: ad7173: Fix uninitialized symbol is_current_chan Move the definition down and make it a boolean that is initialized to false. Fixes: 13d12e3ad12d ("iio: adc: ad7173: Add support for AD411x devices") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202406232046.DKfBJq6o-lkp@intel.com/ Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 7da70b7422bb..9544bf7142ad 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -1188,7 +1188,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) struct device *dev = indio_dev->dev.parent; struct iio_chan_spec *chan_arr, *chan; unsigned int ain[AD7173_NO_AINS_PER_CHANNEL], chan_index = 0; - int ref_sel, ret, is_current_chan, num_channels; + int ref_sel, ret, num_channels; num_channels = device_get_child_node_count(dev); @@ -1234,6 +1234,8 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) } device_for_each_child_node_scoped(dev, child) { + bool is_current_chan = false; + chan = &chan_arr[chan_index]; *chan = ad7173_channel_template; chan_st_priv = &chans_st_arr[chan_index]; From bf30a75e6e0001c3d473f2bf46d026eb0c4a0bd2 Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Mon, 1 Jul 2024 10:12:14 +0800 Subject: [PATCH 269/330] bus: mhi: host: Add support for Foxconn SDX72 modems Add support for Foxconn SDX72 based modems, T99W515 and DW5934E. Existing SDX55 channel/event configs are reused with the custom ready_timeout_ms value to workaround firmware issue. Signed-off-by: Slark Xiao Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20240701021216.17734-1-slark_xiao@163.com [mani: reworded subject and description] Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/host/pci_generic.c | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 35ae7cd0711f..1fb1c2f2fe12 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -399,6 +399,8 @@ static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = { MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), + MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), }; @@ -419,6 +421,16 @@ static const struct mhi_controller_config modem_foxconn_sdx55_config = { .event_cfg = mhi_foxconn_sdx55_events, }; +static const struct mhi_controller_config modem_foxconn_sdx72_config = { + .max_channels = 128, + .timeout_ms = 20000, + .ready_timeout_ms = 50000, + .num_channels = ARRAY_SIZE(mhi_foxconn_sdx55_channels), + .ch_cfg = mhi_foxconn_sdx55_channels, + .num_events = ARRAY_SIZE(mhi_foxconn_sdx55_events), + .event_cfg = mhi_foxconn_sdx55_events, +}; + static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { .name = "foxconn-sdx55", .fw = "qcom/sdx55m/sbl1.mbn", @@ -488,6 +500,28 @@ static const struct mhi_pci_dev_info mhi_foxconn_dw5932e_info = { .sideband_wake = false, }; +static const struct mhi_pci_dev_info mhi_foxconn_t99w515_info = { + .name = "foxconn-t99w515", + .edl = "fox/sdx72m/edl.mbn", + .edl_trigger = true, + .config = &modem_foxconn_sdx72_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_dw5934e_info = { + .name = "foxconn-dw5934e", + .edl = "fox/sdx72m/edl.mbn", + .edl_trigger = true, + .config = &modem_foxconn_sdx72_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + static const struct mhi_channel_config mhi_mv3x_channels[] = { MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 64, 0), MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 64, 0), @@ -720,6 +754,15 @@ static const struct pci_device_id mhi_pci_id_table[] = { /* DW5932e (sdx62), Non-eSIM */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f9), .driver_data = (kernel_ulong_t) &mhi_foxconn_dw5932e_info }, + /* T99W515 (sdx72) */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe118), + .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w515_info }, + /* DW5934e(sdx72), With eSIM */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe11d), + .driver_data = (kernel_ulong_t) &mhi_foxconn_dw5934e_info }, + /* DW5934e(sdx72), Non-eSIM */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe11e), + .driver_data = (kernel_ulong_t) &mhi_foxconn_dw5934e_info }, /* MV31-W (Cinterion) */ { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3), .driver_data = (kernel_ulong_t) &mhi_mv31_info }, From 633478695d6b52e0b52f1273d8d11275b627b87d Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Mon, 1 Jul 2024 10:12:15 +0800 Subject: [PATCH 270/330] bus: mhi: host: Allow controller drivers to specify name for the MHI controller MHI devices usually have a product/device name to identify each device uniquely. So let's specify that name in 'struct mhi_controller' so that the client drivers can use this name to uniquely identify the devices and apply any device specific quirks. Signed-off-by: Slark Xiao Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20240701021216.17734-2-slark_xiao@163.com [mani: reworked subject and description] Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/host/pci_generic.c | 1 + include/linux/mhi.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 1fb1c2f2fe12..14a11880bcea 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -1086,6 +1086,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl->runtime_get = mhi_pci_runtime_get; mhi_cntrl->runtime_put = mhi_pci_runtime_put; mhi_cntrl->mru = info->mru_default; + mhi_cntrl->name = info->name; if (info->edl_trigger) mhi_cntrl->edl_trigger = mhi_pci_generic_edl_trigger; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index b573f15762f8..fabd6ed8d258 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -290,6 +290,7 @@ struct mhi_controller_config { /** * struct mhi_controller - Master MHI controller structure + * @name: Device name of the MHI controller * @cntrl_dev: Pointer to the struct device of physical bus acting as the MHI * controller (required) * @mhi_dev: MHI device instance for the controller @@ -367,6 +368,7 @@ struct mhi_controller_config { * they can be populated depending on the usecase. */ struct mhi_controller { + const char *name; struct device *cntrl_dev; struct mhi_device *mhi_dev; struct dentry *debugfs_dentry; From 65bc58c3dcad0d9bd17762e22603894a2d2880d6 Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Mon, 1 Jul 2024 10:12:16 +0800 Subject: [PATCH 271/330] net: wwan: mhi: make default data link id configurable For SDX72 MBIM mode, it starts data mux id from 112 instead of 0. This would lead to device can't ping outside successfully. Also MBIM side would report "bad packet session (112)". In order to fix this issue, we decide to use the device name of MHI controller to do a match in wwan side. Then wwan driver could set a corresponding mux_id value according to the MHI product. Signed-off-by: Slark Xiao Acked-by: Jakub Kicinski Link: https://lore.kernel.org/r/20240701021216.17734-3-slark_xiao@163.com Signed-off-by: Manivannan Sadhasivam --- drivers/net/wwan/mhi_wwan_mbim.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c index f2aef84fc08d..d5a9360323d2 100644 --- a/drivers/net/wwan/mhi_wwan_mbim.c +++ b/drivers/net/wwan/mhi_wwan_mbim.c @@ -42,6 +42,8 @@ #define MHI_MBIM_LINK_HASH_SIZE 8 #define LINK_HASH(session) ((session) % MHI_MBIM_LINK_HASH_SIZE) +#define WDS_BIND_MUX_DATA_PORT_MUX_ID 112 + struct mhi_mbim_link { struct mhi_mbim_context *mbim; struct net_device *ndev; @@ -93,6 +95,15 @@ static struct mhi_mbim_link *mhi_mbim_get_link_rcu(struct mhi_mbim_context *mbim return NULL; } +static int mhi_mbim_get_link_mux_id(struct mhi_controller *cntrl) +{ + if (strcmp(cntrl->name, "foxconn-dw5934e") == 0 || + strcmp(cntrl->name, "foxconn-t99w515") == 0) + return WDS_BIND_MUX_DATA_PORT_MUX_ID; + + return 0; +} + static struct sk_buff *mbim_tx_fixup(struct sk_buff *skb, unsigned int session, u16 tx_seq) { @@ -596,7 +607,7 @@ static int mhi_mbim_probe(struct mhi_device *mhi_dev, const struct mhi_device_id { struct mhi_controller *cntrl = mhi_dev->mhi_cntrl; struct mhi_mbim_context *mbim; - int err; + int err, link_id; mbim = devm_kzalloc(&mhi_dev->dev, sizeof(*mbim), GFP_KERNEL); if (!mbim) @@ -617,8 +628,11 @@ static int mhi_mbim_probe(struct mhi_device *mhi_dev, const struct mhi_device_id /* Number of transfer descriptors determines size of the queue */ mbim->rx_queue_sz = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE); + /* Get the corresponding mux_id from mhi */ + link_id = mhi_mbim_get_link_mux_id(cntrl); + /* Register wwan link ops with MHI controller representing WWAN instance */ - return wwan_register_ops(&cntrl->mhi_dev->dev, &mhi_mbim_wwan_ops, mbim, 0); + return wwan_register_ops(&cntrl->mhi_dev->dev, &mhi_mbim_wwan_ops, mbim, link_id); } static void mhi_mbim_remove(struct mhi_device *mhi_dev) From 15d9da3f818cae676f822a04407d3c17b53357d2 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Wed, 12 Jun 2024 04:25:13 +0000 Subject: [PATCH 272/330] binder: use bitmap for faster descriptor lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When creating new binder references, the driver assigns a descriptor id that is shared with userspace. Regrettably, the driver needs to keep the descriptors small enough to accommodate userspace potentially using them as Vector indexes. Currently, the driver performs a linear search on the rb-tree of references to find the smallest available descriptor id. This approach, however, scales poorly as the number of references grows. This patch introduces the usage of bitmaps to boost the performance of descriptor assignments. This optimization results in notable performance gains, particularly in processes with a large number of references. The following benchmark with 100,000 references showcases the difference in latency between the dbitmap implementation and the legacy approach: [ 587.145098] get_ref_desc_olocked: 15us (dbitmap on) [ 602.788623] get_ref_desc_olocked: 47343us (dbitmap off) Note the bitmap size is dynamically adjusted in line with the number of references, ensuring efficient memory usage. In cases where growing the bitmap is not possible, the driver falls back to the slow legacy method. A previous attempt to solve this issue was proposed in [1]. However, such method involved adding new ioctls which isn't great, plus older userspace code would not have benefited from the optimizations either. Link: https://lore.kernel.org/all/20240417191418.1341988-1-cmllamas@google.com/ [1] Cc: Tim Murray Cc: Arve Hjønnevåg Cc: Alice Ryhl Cc: Martijn Coenen Cc: Todd Kjos Cc: John Stultz Cc: Steven Moreland Suggested-by: Nick Chen Reviewed-by: Alice Ryhl Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20240612042535.1556708-1-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 112 ++++++++++++++++--- drivers/android/binder_internal.h | 5 +- drivers/android/dbitmap.h | 176 ++++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+), 14 deletions(-) create mode 100644 drivers/android/dbitmap.h diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b21a7b246a0d..0c2161b1f057 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1045,6 +1045,66 @@ static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, return NULL; } +/* Find the smallest unused descriptor the "slow way" */ +static u32 slow_desc_lookup_olocked(struct binder_proc *proc) +{ + struct binder_ref *ref; + struct rb_node *n; + u32 desc; + + desc = 1; + for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) { + ref = rb_entry(n, struct binder_ref, rb_node_desc); + if (ref->data.desc > desc) + break; + desc = ref->data.desc + 1; + } + + return desc; +} + +/* + * Find an available reference descriptor ID. The proc->outer_lock might + * be released in the process, in which case -EAGAIN is returned and the + * @desc should be considered invalid. + */ +static int get_ref_desc_olocked(struct binder_proc *proc, + struct binder_node *node, + u32 *desc) +{ + struct dbitmap *dmap = &proc->dmap; + unsigned long *new, bit; + unsigned int nbits; + + /* 0 is reserved for the context manager */ + if (node == proc->context->binder_context_mgr_node) { + *desc = 0; + return 0; + } + + if (!dbitmap_enabled(dmap)) { + *desc = slow_desc_lookup_olocked(proc); + return 0; + } + + if (dbitmap_acquire_first_zero_bit(dmap, &bit) == 0) { + *desc = bit; + return 0; + } + + /* + * The dbitmap is full and needs to grow. The proc->outer_lock + * is briefly released to allocate the new bitmap safely. + */ + nbits = dbitmap_grow_nbits(dmap); + binder_proc_unlock(proc); + new = bitmap_zalloc(nbits, GFP_KERNEL); + binder_proc_lock(proc); + dbitmap_grow(dmap, new, nbits); + + return -EAGAIN; +} + /** * binder_get_ref_for_node_olocked() - get the ref associated with given node * @proc: binder_proc that owns the ref @@ -1068,12 +1128,14 @@ static struct binder_ref *binder_get_ref_for_node_olocked( struct binder_node *node, struct binder_ref *new_ref) { - struct binder_context *context = proc->context; - struct rb_node **p = &proc->refs_by_node.rb_node; - struct rb_node *parent = NULL; struct binder_ref *ref; - struct rb_node *n; + struct rb_node *parent; + struct rb_node **p; + u32 desc; +retry: + p = &proc->refs_by_node.rb_node; + parent = NULL; while (*p) { parent = *p; ref = rb_entry(parent, struct binder_ref, rb_node_node); @@ -1088,6 +1150,10 @@ static struct binder_ref *binder_get_ref_for_node_olocked( if (!new_ref) return NULL; + /* might release the proc->outer_lock */ + if (get_ref_desc_olocked(proc, node, &desc) == -EAGAIN) + goto retry; + binder_stats_created(BINDER_STAT_REF); new_ref->data.debug_id = atomic_inc_return(&binder_last_id); new_ref->proc = proc; @@ -1095,14 +1161,7 @@ static struct binder_ref *binder_get_ref_for_node_olocked( rb_link_node(&new_ref->rb_node_node, parent, p); rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); - new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1; - for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { - ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (ref->data.desc > new_ref->data.desc) - break; - new_ref->data.desc = ref->data.desc + 1; - } - + new_ref->data.desc = desc; p = &proc->refs_by_desc.rb_node; while (*p) { parent = *p; @@ -1131,6 +1190,7 @@ static struct binder_ref *binder_get_ref_for_node_olocked( static void binder_cleanup_ref_olocked(struct binder_ref *ref) { + struct dbitmap *dmap = &ref->proc->dmap; bool delete_node = false; binder_debug(BINDER_DEBUG_INTERNAL_REFS, @@ -1138,6 +1198,8 @@ static void binder_cleanup_ref_olocked(struct binder_ref *ref) ref->proc->pid, ref->data.debug_id, ref->data.desc, ref->node->debug_id); + if (dbitmap_enabled(dmap)) + dbitmap_clear_bit(dmap, ref->data.desc); rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); @@ -1298,6 +1360,25 @@ static void binder_free_ref(struct binder_ref *ref) kfree(ref); } +/* shrink descriptor bitmap if needed */ +static void try_shrink_dmap(struct binder_proc *proc) +{ + unsigned long *new; + int nbits; + + binder_proc_lock(proc); + nbits = dbitmap_shrink_nbits(&proc->dmap); + binder_proc_unlock(proc); + + if (!nbits) + return; + + new = bitmap_zalloc(nbits, GFP_KERNEL); + binder_proc_lock(proc); + dbitmap_shrink(&proc->dmap, new, nbits); + binder_proc_unlock(proc); +} + /** * binder_update_ref_for_handle() - inc/dec the ref for given handle * @proc: proc containing the ref @@ -1334,8 +1415,10 @@ static int binder_update_ref_for_handle(struct binder_proc *proc, *rdata = ref->data; binder_proc_unlock(proc); - if (delete_ref) + if (delete_ref) { binder_free_ref(ref); + try_shrink_dmap(proc); + } return ret; err_no_ref: @@ -4931,6 +5014,7 @@ static void binder_free_proc(struct binder_proc *proc) put_task_struct(proc->tsk); put_cred(proc->cred); binder_stats_deleted(BINDER_STAT_PROC); + dbitmap_free(&proc->dmap); kfree(proc); } @@ -5634,6 +5718,8 @@ static int binder_open(struct inode *nodp, struct file *filp) proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; + + dbitmap_init(&proc->dmap); spin_lock_init(&proc->inner_lock); spin_lock_init(&proc->outer_lock); get_task_struct(current->group_leader); diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 5b7c80b99ae8..7d4fc53f7a73 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -14,6 +14,7 @@ #include #include #include "binder_alloc.h" +#include "dbitmap.h" struct binder_context { struct binder_node *binder_context_mgr_node; @@ -368,6 +369,8 @@ struct binder_ref { * @freeze_wait: waitqueue of processes waiting for all outstanding * transactions to be processed * (protected by @inner_lock) + * @dmap dbitmap to manage available reference descriptors + * (protected by @outer_lock) * @todo: list of work for this process * (protected by @inner_lock) * @stats: per-process binder statistics @@ -417,7 +420,7 @@ struct binder_proc { bool sync_recv; bool async_recv; wait_queue_head_t freeze_wait; - + struct dbitmap dmap; struct list_head todo; struct binder_stats stats; struct list_head delivered_death; diff --git a/drivers/android/dbitmap.h b/drivers/android/dbitmap.h new file mode 100644 index 000000000000..b8ac7b4764fd --- /dev/null +++ b/drivers/android/dbitmap.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2024 Google LLC + * + * dbitmap - dynamically sized bitmap library. + * + * Used by the binder driver to optimize the allocation of the smallest + * available descriptor ID. Each bit in the bitmap represents the state + * of an ID, with the exception of BIT(0) which is used exclusively to + * reference binder's context manager. + * + * A dbitmap can grow or shrink as needed. This part has been designed + * considering that users might need to briefly release their locks in + * order to allocate memory for the new bitmap. These operations then, + * are verified to determine if the grow or shrink is sill valid. + * + * This library does not provide protection against concurrent access + * by itself. Binder uses the proc->outer_lock for this purpose. + */ + +#ifndef _LINUX_DBITMAP_H +#define _LINUX_DBITMAP_H +#include + +#define NBITS_MIN BITS_PER_TYPE(unsigned long) + +struct dbitmap { + unsigned int nbits; + unsigned long *map; +}; + +static inline int dbitmap_enabled(struct dbitmap *dmap) +{ + return !!dmap->nbits; +} + +static inline void dbitmap_free(struct dbitmap *dmap) +{ + dmap->nbits = 0; + kfree(dmap->map); +} + +/* Returns the nbits that a dbitmap can shrink to, 0 if not possible. */ +static inline unsigned int dbitmap_shrink_nbits(struct dbitmap *dmap) +{ + unsigned int bit; + + if (dmap->nbits <= NBITS_MIN) + return 0; + + /* + * Determine if the bitmap can shrink based on the position of + * its last set bit. If the bit is within the first quarter of + * the bitmap then shrinking is possible. In this case, the + * bitmap should shrink to half its current size. + */ + bit = find_last_bit(dmap->map, dmap->nbits); + if (bit < (dmap->nbits >> 2)) + return dmap->nbits >> 1; + + /* + * Note that find_last_bit() returns dmap->nbits when no bits + * are set. While this is technically not possible here since + * BIT(0) is always set, this check is left for extra safety. + */ + if (bit == dmap->nbits) + return NBITS_MIN; + + return 0; +} + +/* Replace the internal bitmap with a new one of different size */ +static inline void +dbitmap_replace(struct dbitmap *dmap, unsigned long *new, unsigned int nbits) +{ + bitmap_copy(new, dmap->map, min(dmap->nbits, nbits)); + kfree(dmap->map); + dmap->map = new; + dmap->nbits = nbits; +} + +static inline void +dbitmap_shrink(struct dbitmap *dmap, unsigned long *new, unsigned int nbits) +{ + if (!new) + return; + + /* + * Verify that shrinking to @nbits is still possible. The @new + * bitmap might have been allocated without locks, so this call + * could now be outdated. In this case, free @new and move on. + */ + if (!dbitmap_enabled(dmap) || dbitmap_shrink_nbits(dmap) != nbits) { + kfree(new); + return; + } + + dbitmap_replace(dmap, new, nbits); +} + +/* Returns the nbits that a dbitmap can grow to. */ +static inline unsigned int dbitmap_grow_nbits(struct dbitmap *dmap) +{ + return dmap->nbits << 1; +} + +static inline void +dbitmap_grow(struct dbitmap *dmap, unsigned long *new, unsigned int nbits) +{ + /* + * Verify that growing to @nbits is still possible. The @new + * bitmap might have been allocated without locks, so this call + * could now be outdated. In this case, free @new and move on. + */ + if (!dbitmap_enabled(dmap) || nbits <= dmap->nbits) { + kfree(new); + return; + } + + /* + * Check for ENOMEM after confirming the grow operation is still + * required. This ensures we only disable the dbitmap when it's + * necessary. Once the dbitmap is disabled, binder will fallback + * to slow_desc_lookup_olocked(). + */ + if (!new) { + dbitmap_free(dmap); + return; + } + + dbitmap_replace(dmap, new, nbits); +} + +/* + * Finds and sets the first zero bit in the bitmap. Upon success @bit + * is populated with the index and 0 is returned. Otherwise, -ENOSPC + * is returned to indicate that a dbitmap_grow() is needed. + */ +static inline int +dbitmap_acquire_first_zero_bit(struct dbitmap *dmap, unsigned long *bit) +{ + unsigned long n; + + n = find_first_zero_bit(dmap->map, dmap->nbits); + if (n == dmap->nbits) + return -ENOSPC; + + *bit = n; + set_bit(n, dmap->map); + + return 0; +} + +static inline void +dbitmap_clear_bit(struct dbitmap *dmap, unsigned long bit) +{ + /* BIT(0) should always set for the context manager */ + if (bit) + clear_bit(bit, dmap->map); +} + +static inline int dbitmap_init(struct dbitmap *dmap) +{ + dmap->map = bitmap_zalloc(NBITS_MIN, GFP_KERNEL); + if (!dmap->map) { + dmap->nbits = 0; + return -ENOMEM; + } + + dmap->nbits = NBITS_MIN; + /* BIT(0) is reserved for the context manager */ + set_bit(0, dmap->map); + + return 0; +} +#endif From 36c55ce8703ceedfd8cbea1f46d787978f3d2f66 Mon Sep 17 00:00:00 2001 From: Lei Liu Date: Wed, 19 Jun 2024 19:38:40 +0800 Subject: [PATCH 273/330] binder_alloc: Replace kcalloc with kvcalloc to mitigate OOM issues In binder_alloc, there is a frequent need for order3 memory allocation, especially on small-memory mobile devices, which can lead to OOM and cause foreground applications to be killed, resulting in flashbacks. We use kvcalloc to allocate memory, which can reduce system OOM occurrences, as well as decrease the time and probability of failure for order3 memory allocations. Additionally, It has little impact on the throughput of the binder. (as verified by Google's binder_benchmark testing tool). We have conducted multiple tests on an 8GB memory phone, kvcalloc has little performance degradation and resolves frequent OOM issues, Below is a partial excerpt of the test data. throughput(TH_PUT) = (size * Iterations)/Time kcalloc->kvcalloc: Sample with kcalloc(): adb shell stop/ kcalloc /8+256G --------------------------------------------------------------------- Benchmark Time CPU Iterations TH-PUT TH-PUTCPU (ns) (ns) (GB/s) (GB/s) --------------------------------------------------------------------- BM_sendVec_binder4 39126 18550 38894 3.976282 8.38684 BM_sendVec_binder8 38924 18542 37786 7.766108 16.3028 BM_sendVec_binder16 38328 18228 36700 15.32039 32.2141 BM_sendVec_binder32 38154 18215 38240 32.07213 67.1798 BM_sendVec_binder64 39093 18809 36142 59.16885 122.977 BM_sendVec_binder128 40169 19188 36461 116.1843 243.2253 BM_sendVec_binder256 40695 19559 35951 226.1569 470.5484 BM_sendVec_binder512 41446 20211 34259 423.2159 867.8743 BM_sendVec_binder1024 44040 22939 28904 672.0639 1290.278 BM_sendVec_binder2048 47817 25821 26595 1139.063 2109.393 BM_sendVec_binder4096 54749 30905 22742 1701.423 3014.115 BM_sendVec_binder8192 68316 42017 16684 2000.634 3252.858 BM_sendVec_binder16384 95435 64081 10961 1881.752 2802.469 BM_sendVec_binder32768 148232 107504 6510 1439.093 1984.295 BM_sendVec_binder65536 326499 229874 3178 637.8991 906.0329 NORAML TEST SUM 10355.79 17188.15 stressapptest eat 2G SUM 10088.39 16625.97 Sample with kvcalloc(): adb shell stop/ kvcalloc /8+256G ---------------------------------------------------------------------- Benchmark Time CPU Iterations TH-PUT TH-PUTCPU (ns) (ns) (GB/s) (GB/s) ---------------------------------------------------------------------- BM_sendVec_binder4 39673 18832 36598 3.689965 7.773577 BM_sendVec_binder8 39869 18969 37188 7.462038 15.68369 BM_sendVec_binder16 39774 18896 36627 14.73405 31.01355 BM_sendVec_binder32 40225 19125 36995 29.43045 61.90013 BM_sendVec_binder64 40549 19529 35148 55.47544 115.1862 BM_sendVec_binder128 41580 19892 35384 108.9262 227.6871 BM_sendVec_binder256 41584 20059 34060 209.6806 434.6857 BM_sendVec_binder512 42829 20899 32493 388.4381 796.0389 BM_sendVec_binder1024 45037 23360 29251 665.0759 1282.236 BM_sendVec_binder2048 47853 25761 27091 1159.433 2153.735 BM_sendVec_binder4096 55574 31745 22405 1651.328 2890.877 BM_sendVec_binder8192 70706 43693 16400 1900.105 3074.836 BM_sendVec_binder16384 96161 64362 10793 1838.921 2747.468 BM_sendVec_binder32768 147875 107292 6296 1395.147 1922.858 BM_sendVec_binder65536 330324 232296 3053 605.7126 861.3209 NORAML TEST SUM 10033.56 16623.35 stressapptest eat 2G SUM 9958.43 16497.55 Signed-off-by: Lei Liu Acked-by: Carlos Llamas Link: https://lore.kernel.org/r/20240619113841.3362-1-liulei.rjpt@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 2e1f261ec5c8..b00961944ab1 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -836,9 +836,9 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, alloc->buffer = vma->vm_start; - alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE, - sizeof(alloc->pages[0]), - GFP_KERNEL); + alloc->pages = kvcalloc(alloc->buffer_size / PAGE_SIZE, + sizeof(alloc->pages[0]), + GFP_KERNEL); if (alloc->pages == NULL) { ret = -ENOMEM; failure_string = "alloc page array"; @@ -869,7 +869,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, return 0; err_alloc_buf_struct_failed: - kfree(alloc->pages); + kvfree(alloc->pages); alloc->pages = NULL; err_alloc_pages_failed: alloc->buffer = 0; @@ -939,7 +939,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) __free_page(alloc->pages[i].page_ptr); page_count++; } - kfree(alloc->pages); + kvfree(alloc->pages); } spin_unlock(&alloc->lock); if (alloc->mm) From 71f592d204ba2199a8d4fe174a1024cceb9e9096 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 4 Jun 2024 23:22:36 +0200 Subject: [PATCH 274/330] misc: apds990x: use 'time_left' variable with wait_event_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_event_interruptible_timeout() causing patterns like: timeout = wait_event_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240604212240.4529-2-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/apds990x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index 92b92be91d60..5fb29ebbb422 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -625,15 +625,15 @@ static ssize_t apds990x_lux_show(struct device *dev, struct apds990x_chip *chip = dev_get_drvdata(dev); ssize_t ret; u32 result; - long timeout; + long time_left; if (pm_runtime_suspended(dev)) return -EIO; - timeout = wait_event_interruptible_timeout(chip->wait, - !chip->lux_wait_fresh_res, - msecs_to_jiffies(APDS_TIMEOUT)); - if (!timeout) + time_left = wait_event_interruptible_timeout(chip->wait, + !chip->lux_wait_fresh_res, + msecs_to_jiffies(APDS_TIMEOUT)); + if (!time_left) return -EIO; mutex_lock(&chip->mutex); From 531a185d549e1c6225d7e1e553ba1c14dc391d69 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 4 Jun 2024 23:22:37 +0200 Subject: [PATCH 275/330] misc: bh1770glc: use 'time_left' variable with wait_event_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_event_interruptible_timeout() causing patterns like: timeout = wait_event_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240604212240.4529-3-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/bh1770glc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 1629b62fd052..e1048d616306 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -680,15 +680,15 @@ static ssize_t bh1770_lux_result_show(struct device *dev, { struct bh1770_chip *chip = dev_get_drvdata(dev); ssize_t ret; - long timeout; + long time_left; if (pm_runtime_suspended(dev)) return -EIO; /* Chip is not enabled at all */ - timeout = wait_event_interruptible_timeout(chip->wait, - !chip->lux_wait_result, - msecs_to_jiffies(BH1770_TIMEOUT)); - if (!timeout) + time_left = wait_event_interruptible_timeout(chip->wait, + !chip->lux_wait_result, + msecs_to_jiffies(BH1770_TIMEOUT)); + if (!time_left) return -EIO; mutex_lock(&chip->mutex); From 4c0fb1af44b98872320bfb0612b1d05be827fc91 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 4 Jun 2024 23:22:38 +0200 Subject: [PATCH 276/330] misc: tifm: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240604212240.4529-4-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/tifm_7xx1.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 7dd86a9858ab..1d54680d6ed2 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -229,7 +229,7 @@ static int __maybe_unused tifm_7xx1_resume(struct device *dev_d) struct pci_dev *dev = to_pci_dev(dev_d); struct tifm_adapter *fm = pci_get_drvdata(dev); int rc; - unsigned long timeout; + unsigned long time_left; unsigned int good_sockets = 0, bad_sockets = 0; unsigned long flags; /* Maximum number of entries is 4 */ @@ -265,8 +265,8 @@ static int __maybe_unused tifm_7xx1_resume(struct device *dev_d) if (good_sockets) { fm->finish_me = &finish_resume; spin_unlock_irqrestore(&fm->lock, flags); - timeout = wait_for_completion_timeout(&finish_resume, HZ); - dev_dbg(&dev->dev, "wait returned %lu\n", timeout); + time_left = wait_for_completion_timeout(&finish_resume, HZ); + dev_dbg(&dev->dev, "wait returned %lu\n", time_left); writel(TIFM_IRQ_FIFOMASK(good_sockets) | TIFM_IRQ_CARDMASK(good_sockets), fm->addr + FM_CLEAR_INTERRUPT_ENABLE); From d97fb2571a4babec09c5d1bc701a36824ccfa805 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 4 Jun 2024 23:22:39 +0200 Subject: [PATCH 277/330] misc: ti-st: st_kim: use 'time_left' variable with wait_for_completion_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_interruptible_timeout() causing patterns like: timeout = wait_for_completion_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240604212240.4529-5-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index c4f963cf96f2..ff172cf4614d 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -198,7 +198,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) { unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0; static const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 }; - long timeout; + long time_left; pr_debug("%s", __func__); @@ -208,11 +208,11 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) return -EIO; } - timeout = wait_for_completion_interruptible_timeout( + time_left = wait_for_completion_interruptible_timeout( &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME)); - if (timeout <= 0) { + if (time_left <= 0) { pr_err(" waiting for ver info- timed out or received signal"); - return timeout ? -ERESTARTSYS : -ETIMEDOUT; + return time_left ? -ERESTARTSYS : -ETIMEDOUT; } reinit_completion(&kim_gdata->kim_rcvd); /* From 538a00a9fcb2dcb6b16d37e5cef7e8d66911b413 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 17 Jun 2024 22:15:56 -0700 Subject: [PATCH 278/330] dtlk: add missing MODULE_DESCRIPTION() macro With ARCH=m68k, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/dtlk.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240617-md-m68k-drivers-char-dtlk-v1-1-a53a237f1f06@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/dtlk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 6946c1cad9f6..5a1a73310e97 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -660,4 +660,5 @@ static char dtlk_write_tts(char ch) return 0; } +MODULE_DESCRIPTION("RC Systems DoubleTalk PC speech card driver"); MODULE_LICENSE("GPL"); From 341bdda64533f11a0cfe87cad3c607019256d6f0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 17 Jun 2024 22:02:11 -0700 Subject: [PATCH 279/330] dsp56k: add missing MODULE_DESCRIPTION() macro With ARCH=m68k, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/dsp56k.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240617-md-m68k-drivers-char-dsp56k-v1-1-56e435ffa664@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/dsp56k.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index bda27e595da1..1c2c8439797c 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -530,5 +530,6 @@ static void __exit dsp56k_cleanup_driver(void) } module_exit(dsp56k_cleanup_driver); +MODULE_DESCRIPTION("Atari DSP56001 Device Driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("dsp56k/bootstrap.bin"); From f060860419172776bb346b608ce7c0923efe2433 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 30 May 2024 21:55:33 -0700 Subject: [PATCH 280/330] intel_th: msu-sink: add missing MODULE_DESCRIPTION() make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hwtracing/intel_th/intel_th_msu_sink.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240530-md-intel_th_msu_sink-v1-1-ae796336e7b9@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/msu-sink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/intel_th/msu-sink.c b/drivers/hwtracing/intel_th/msu-sink.c index 891b28ea25fe..256ce3260ad9 100644 --- a/drivers/hwtracing/intel_th/msu-sink.c +++ b/drivers/hwtracing/intel_th/msu-sink.c @@ -116,4 +116,5 @@ static const struct msu_buffer sink_mbuf = { module_intel_th_msu_buffer(sink_mbuf); +MODULE_DESCRIPTION("example software sink buffer for Intel TH MSU"); MODULE_LICENSE("GPL v2"); From d2c5426e5af577f571e8b1b8da090b3d3f7eedfc Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Wed, 26 Jun 2024 13:41:09 -0700 Subject: [PATCH 281/330] greybus: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/greybus/greybus.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/greybus/gb-es2.o Add all missing invocations of the MODULE_DESCRIPTION() macro. Acked-by: Alex Elder Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240626-md-drivers-greybus-v2-1-d520ffb9a489@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/greybus/core.c | 1 + drivers/greybus/es2.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/greybus/core.c b/drivers/greybus/core.c index 95c09d4f3a86..33a47e73f0fa 100644 --- a/drivers/greybus/core.c +++ b/drivers/greybus/core.c @@ -375,5 +375,6 @@ static void __exit gb_exit(void) tracepoint_synchronize_unregister(); } module_exit(gb_exit); +MODULE_DESCRIPTION("Greybus core driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Greg Kroah-Hartman "); diff --git a/drivers/greybus/es2.c b/drivers/greybus/es2.c index 1ee78d0d90b4..69e46b1dff1f 100644 --- a/drivers/greybus/es2.c +++ b/drivers/greybus/es2.c @@ -1456,5 +1456,6 @@ static struct usb_driver es2_ap_driver = { module_usb_driver(es2_ap_driver); +MODULE_DESCRIPTION("Greybus AP USB driver for ES2 controller chips"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Greg Kroah-Hartman "); From e9d053f4222e79958fbea3c71c563a2d528d0d5e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 15 Jun 2024 14:44:08 -0700 Subject: [PATCH 282/330] dca: add missing MODULE_DESCRIPTION() macro With ARCH=x86, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/dca/dca.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240615-dca-md-v2-1-c4062275a3f1@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/dca/dca-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index ed3dac546dd6..f5cedf816be1 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -17,6 +17,7 @@ #define DCA_VERSION "1.12.1" MODULE_VERSION(DCA_VERSION); +MODULE_DESCRIPTION("Intel Direct Cache Access (DCA) service module"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Intel Corporation"); From 6e03b4ae257d97714c30f264854ef701fba6c689 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 15 Jun 2024 14:34:06 -0700 Subject: [PATCH 283/330] platform/goldfish: goldfish_pipe: add missing MODULE_DESCRIPTION() macro With arch=x86, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/platform/goldfish/goldfish_pipe.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240615-goldfish_pipe-md-v2-1-b4323a969594@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 061aa9647c19..c2aab0cfab33 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -946,4 +946,5 @@ static struct platform_driver goldfish_pipe_driver = { module_platform_driver(goldfish_pipe_driver); MODULE_AUTHOR("David Turner "); +MODULE_DESCRIPTION("Goldfish virtual device for QEMU pipes"); MODULE_LICENSE("GPL v2"); From 822d7335f2a65fe60789e648f5ee3653ad3dd245 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 15 Jun 2024 14:14:36 -0700 Subject: [PATCH 284/330] bsr: add missing MODULE_DESCRIPTION() macro With ARCH=powerpc, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/bsr.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240615-md-powerpc-drivers-char-v1-1-bff22fd778a4@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/bsr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 70d31aed9011..837109ef6766 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -342,5 +342,6 @@ static void __exit bsr_exit(void) module_init(bsr_init); module_exit(bsr_exit); +MODULE_DESCRIPTION("IBM POWER Barrier Synchronization Register Driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sonny Rao "); From b45c696c27d6a93917f980a55eaf96a4d08f0e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 24 Jun 2024 14:51:01 +0200 Subject: [PATCH 285/330] misc: Drop explicit initialization of struct i2c_device_id::driver_data to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These drivers don't use the driver_data member of struct i2c_device_id, so don't explicitly initialize this member. This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own. While add it, also remove commas after the sentinel entries. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240624125101.1242750-2-u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/apds9802als.c | 2 +- drivers/misc/apds990x.c | 2 +- drivers/misc/bh1770glc.c | 4 ++-- drivers/misc/ds1682.c | 2 +- drivers/misc/hmc6352.c | 2 +- drivers/misc/ics932s401.c | 2 +- drivers/misc/isl29003.c | 2 +- drivers/misc/isl29020.c | 2 +- drivers/misc/tsl2550.c | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 693f0e539f37..6db4db975b9a 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c @@ -285,7 +285,7 @@ static UNIVERSAL_DEV_PM_OPS(apds9802als_pm_ops, apds9802als_suspend, #endif /* CONFIG_PM */ static const struct i2c_device_id apds9802als_id[] = { - { DRIVER_NAME, 0 }, + { DRIVER_NAME }, { } }; diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index 5fb29ebbb422..6d4edd69db12 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1253,7 +1253,7 @@ static int apds990x_runtime_resume(struct device *dev) #endif static const struct i2c_device_id apds990x_id[] = { - {"apds990x", 0 }, + { "apds990x" }, {} }; diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index e1048d616306..0c052b05ab6a 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1361,8 +1361,8 @@ static int bh1770_runtime_resume(struct device *dev) #endif static const struct i2c_device_id bh1770_id[] = { - {"bh1770glc", 0 }, - {"sfh7770", 0 }, + { "bh1770glc" }, + { "sfh7770" }, {} }; diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c index 5f8dcd0e3848..4175df7ef011 100644 --- a/drivers/misc/ds1682.c +++ b/drivers/misc/ds1682.c @@ -271,7 +271,7 @@ static void ds1682_remove(struct i2c_client *client) } static const struct i2c_device_id ds1682_id[] = { - { "ds1682", 0 }, + { "ds1682" }, { } }; MODULE_DEVICE_TABLE(i2c, ds1682_id); diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c index 759eaeb64307..ff92c6edff6b 100644 --- a/drivers/misc/hmc6352.c +++ b/drivers/misc/hmc6352.c @@ -121,7 +121,7 @@ static void hmc6352_remove(struct i2c_client *client) } static const struct i2c_device_id hmc6352_id[] = { - { "hmc6352", 0 }, + { "hmc6352" }, { } }; diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c index ee6296b98078..4cdb1087838f 100644 --- a/drivers/misc/ics932s401.c +++ b/drivers/misc/ics932s401.c @@ -95,7 +95,7 @@ static int ics932s401_detect(struct i2c_client *client, static void ics932s401_remove(struct i2c_client *client); static const struct i2c_device_id ics932s401_id[] = { - { "ics932s401", 0 }, + { "ics932s401" }, { } }; MODULE_DEVICE_TABLE(i2c, ics932s401_id); diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index ebf0635aee64..9f26db467a81 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -449,7 +449,7 @@ static SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume); #endif /* CONFIG_PM_SLEEP */ static const struct i2c_device_id isl29003_id[] = { - { "isl29003", 0 }, + { "isl29003" }, {} }; MODULE_DEVICE_TABLE(i2c, isl29003_id); diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c index c5976fa8c825..1643ba2ff964 100644 --- a/drivers/misc/isl29020.c +++ b/drivers/misc/isl29020.c @@ -177,7 +177,7 @@ static void isl29020_remove(struct i2c_client *client) } static const struct i2c_device_id isl29020_id[] = { - { "isl29020", 0 }, + { "isl29020" }, { } }; diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index a3bc2823143e..2ad4387c9837 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -420,7 +420,7 @@ static SIMPLE_DEV_PM_OPS(tsl2550_pm_ops, tsl2550_suspend, tsl2550_resume); #endif /* CONFIG_PM_SLEEP */ static const struct i2c_device_id tsl2550_id[] = { - { "tsl2550", 0 }, + { "tsl2550" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl2550_id); From 2f3fd91b9e6e744fce3cde4e1f8dd6f320548c0e Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 24 Jun 2024 11:01:04 +0200 Subject: [PATCH 286/330] mcb: remove unused struct 'mcb_parse_priv' 'mcb_parse_priv' has been unused since the initial commit 3764e82e5150 ("drivers: Introduce MEN Chameleon Bus"). Remove it. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Johannes Thumshirn Link: https://lore.kernel.org/r/20240624090104.12871-2-jth@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-parse.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c index 1ae37e693de0..a5f8ab9a0910 100644 --- a/drivers/mcb/mcb-parse.c +++ b/drivers/mcb/mcb-parse.c @@ -8,11 +8,6 @@ #include "mcb-internal.h" -struct mcb_parse_priv { - phys_addr_t mapbase; - void __iomem *base; -}; - #define for_each_chameleon_cell(dtype, p) \ for ((dtype) = get_next_dtype((p)); \ (dtype) != CHAMELEON_DTYPE_END; \ From f9a748fa5ce0958bea2a03c25f092fbc22e72c67 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 2 May 2024 16:48:21 +0100 Subject: [PATCH 287/330] parport: Remove 'drivers' list The list has been empty since: 'commit 3275158fa52a ("parport: remove use of devmodel")' This also means we can remove the 'list_head' from struct parport_driver. Signed-off-by: Dr. David Alan Gilbert Acked-by: Sudip Mukherjee Link: https://lore.kernel.org/r/20240502154823.67235-2-linux@treblig.org Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 9 --------- include/linux/parport.h | 1 - 2 files changed, 10 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index b7148517e076..2d34f783b36e 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -49,8 +49,6 @@ static DEFINE_SPINLOCK(parportlist_lock); static LIST_HEAD(all_ports); static DEFINE_SPINLOCK(full_list_lock); -static LIST_HEAD(drivers); - static DEFINE_MUTEX(registration_lock); /* What you can do to a port that's gone away.. */ @@ -165,10 +163,6 @@ static int driver_check(struct device_driver *dev_drv, void *_port) static void attach_driver_chain(struct parport *port) { /* caller has exclusive registration_lock */ - struct parport_driver *drv; - - list_for_each_entry(drv, &drivers, list) - drv->attach(port); /* * call the driver_check function of the drivers registered in @@ -191,10 +185,7 @@ static int driver_detach(struct device_driver *_drv, void *_port) /* Call detach(port) for each registered driver. */ static void detach_driver_chain(struct parport *port) { - struct parport_driver *drv; /* caller has exclusive registration_lock */ - list_for_each_entry(drv, &drivers, list) - drv->detach(port); /* * call the detach function of the drivers registered in diff --git a/include/linux/parport.h b/include/linux/parport.h index fff39bc30629..2a4424b60156 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -258,7 +258,6 @@ struct parport_driver { int (*probe)(struct pardevice *); struct device_driver driver; bool devmodel; - struct list_head list; }; #define to_parport_driver(n) container_of(n, struct parport_driver, driver) From ed06e054906c5e7853a36d9ddad8fc94dbb8c252 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 2 May 2024 16:48:22 +0100 Subject: [PATCH 288/330] parport: Remove attach function pointer The attach function pointers haven't actually been called since: 'commit 3275158fa52a ("parport: remove use of devmodel")' topped adding entries to the drivers list. If you're converting a driver, look at the 'match_port' function pointer instead. (There are lots of comment references to 'attach' all over, but they probably need some deeper understanding to check the semantics to see if they can be replaced by match_port). Signed-off-by: Dr. David Alan Gilbert Acked-by: Sudip Mukherjee Link: https://lore.kernel.org/r/20240502154823.67235-3-linux@treblig.org Signed-off-by: Greg Kroah-Hartman --- include/linux/parport.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/parport.h b/include/linux/parport.h index 2a4424b60156..190de3569e25 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -252,7 +252,6 @@ struct parport { struct parport_driver { const char *name; - void (*attach) (struct parport *); void (*detach) (struct parport *); void (*match_port)(struct parport *); int (*probe)(struct pardevice *); From dfd19866d1a3f681cc12aae67ab05011eb3aa3d8 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 2 May 2024 16:48:23 +0100 Subject: [PATCH 289/330] parport: Remove parport_driver.devmodel 'devmodel' hasn't actually been used since: 'commit 3275158fa52a ("parport: remove use of devmodel")' and everyone now has it set to true and has been fixed up; remove the flag. (There are still comments all over about it) Signed-off-by: Dr. David Alan Gilbert Acked-by: Sudip Mukherjee Link: https://lore.kernel.org/r/20240502154823.67235-4-linux@treblig.org Signed-off-by: Greg Kroah-Hartman --- drivers/ata/pata_parport/pata_parport.c | 1 - drivers/auxdisplay/ks0108.c | 1 - drivers/auxdisplay/panel.c | 1 - drivers/char/lp.c | 1 - drivers/char/ppdev.c | 1 - drivers/i2c/busses/i2c-parport.c | 1 - drivers/input/joystick/db9.c | 1 - drivers/input/joystick/gamecon.c | 1 - drivers/input/joystick/turbografx.c | 1 - drivers/input/joystick/walkera0701.c | 1 - drivers/input/serio/parkbd.c | 1 - drivers/net/hamradio/baycom_epp.c | 1 - drivers/net/hamradio/baycom_par.c | 1 - drivers/net/plip/plip.c | 1 - drivers/parport/daisy.c | 1 - drivers/pps/clients/pps_parport.c | 1 - drivers/pps/generators/pps_gen_parport.c | 1 - drivers/scsi/imm.c | 1 - drivers/scsi/ppa.c | 1 - drivers/spi/spi-butterfly.c | 1 - drivers/spi/spi-lm70llp.c | 1 - include/linux/parport.h | 4 ---- sound/drivers/mts64.c | 1 - sound/drivers/portman2x4.c | 1 - 24 files changed, 27 deletions(-) diff --git a/drivers/ata/pata_parport/pata_parport.c b/drivers/ata/pata_parport/pata_parport.c index 9a2cb9ca9d1d..93ebf566b54e 100644 --- a/drivers/ata/pata_parport/pata_parport.c +++ b/drivers/ata/pata_parport/pata_parport.c @@ -768,7 +768,6 @@ static struct parport_driver pata_parport_driver = { .name = DRV_NAME, .match_port = pata_parport_attach, .detach = pata_parport_detach, - .devmodel = true, }; static __init int pata_parport_init(void) diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index 234f9dbe6e30..51587f0fdaae 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -162,7 +162,6 @@ static struct parport_driver ks0108_parport_driver = { .name = "ks0108", .match_port = ks0108_parport_attach, .detach = ks0108_parport_detach, - .devmodel = true, }; module_parport_driver(ks0108_parport_driver); diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c index 049ff443e790..a731f28455b4 100644 --- a/drivers/auxdisplay/panel.c +++ b/drivers/auxdisplay/panel.c @@ -1706,7 +1706,6 @@ static struct parport_driver panel_driver = { .name = "panel", .match_port = panel_attach, .detach = panel_detach, - .devmodel = true, }; module_parport_driver(panel_driver); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 5faebe0365c5..24417a00dfe9 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -1016,7 +1016,6 @@ static struct parport_driver lp_driver = { .name = "lp", .match_port = lp_attach, .detach = lp_detach, - .devmodel = true, }; static int __init lp_init(void) diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 3655aa859185..eaff98dbaa8c 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -839,7 +839,6 @@ static struct parport_driver pp_driver = { .probe = pp_probe, .match_port = pp_attach, .detach = pp_detach, - .devmodel = true, }; static int __init ppdev_init(void) diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0af86a542568..3249bbd5eb43 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -400,7 +400,6 @@ static struct parport_driver i2c_parport_driver = { .name = "i2c-parport", .match_port = i2c_parport_attach, .detach = i2c_parport_detach, - .devmodel = true, }; module_parport_driver(i2c_parport_driver); diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 4fba28b1a1e7..3ef66e458544 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -673,7 +673,6 @@ static struct parport_driver db9_parport_driver = { .name = "db9", .match_port = db9_attach, .detach = db9_detach, - .devmodel = true, }; static int __init db9_init(void) diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 41d5dac05448..7ed4892749fa 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -1016,7 +1016,6 @@ static struct parport_driver gc_parport_driver = { .name = "gamecon", .match_port = gc_attach, .detach = gc_detach, - .devmodel = true, }; static int __init gc_init(void) diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index dfb9c684651f..baa14acaa3a8 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -274,7 +274,6 @@ static struct parport_driver tgfx_parport_driver = { .name = "turbografx", .match_port = tgfx_attach, .detach = tgfx_detach, - .devmodel = true, }; static int __init tgfx_init(void) diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c index 27d95d6cf56e..59eea813f258 100644 --- a/drivers/input/joystick/walkera0701.c +++ b/drivers/input/joystick/walkera0701.c @@ -293,7 +293,6 @@ static struct parport_driver walkera0701_parport_driver = { .name = "walkera0701", .match_port = walkera0701_attach, .detach = walkera0701_detach, - .devmodel = true, }; module_parport_driver(walkera0701_parport_driver); diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 0d54895428f5..ac1f9ea3f969 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -218,6 +218,5 @@ static struct parport_driver parkbd_parport_driver = { .name = "parkbd", .match_port = parkbd_attach, .detach = parkbd_detach, - .devmodel = true, }; module_parport_driver(parkbd_parport_driver); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index ccfc83857c26..9e366f275406 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -1193,7 +1193,6 @@ static int baycom_epp_par_probe(struct pardevice *par_dev) static struct parport_driver baycom_epp_par_driver = { .name = "bce", .probe = baycom_epp_par_probe, - .devmodel = true, }; static void __init baycom_epp_dev_setup(struct net_device *dev) diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index fd7da5bb1fa5..00ebc25d0b22 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -503,7 +503,6 @@ static int baycom_par_probe(struct pardevice *par_dev) static struct parport_driver baycom_par_driver = { .name = "bcp", .probe = baycom_par_probe, - .devmodel = true, }; static int __init init_baycompar(void) diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c index cc7d1113ece0..e39bfaefe8c5 100644 --- a/drivers/net/plip/plip.c +++ b/drivers/net/plip/plip.c @@ -1358,7 +1358,6 @@ static struct parport_driver plip_driver = { .probe = plip_probe, .match_port = plip_attach, .detach = plip_detach, - .devmodel = true, }; static void __exit plip_cleanup_module (void) diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c index 6d78ec3a762f..2231dbfd870d 100644 --- a/drivers/parport/daisy.c +++ b/drivers/parport/daisy.c @@ -97,7 +97,6 @@ static int daisy_drv_probe(struct pardevice *par_dev) static struct parport_driver daisy_driver = { .name = "daisy_drv", .probe = daisy_drv_probe, - .devmodel = true, }; /* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c index af972cdc04b5..63d03a0df5cc 100644 --- a/drivers/pps/clients/pps_parport.c +++ b/drivers/pps/clients/pps_parport.c @@ -216,7 +216,6 @@ static struct parport_driver pps_parport_driver = { .name = KBUILD_MODNAME, .match_port = parport_attach, .detach = parport_detach, - .devmodel = true, }; module_parport_driver(pps_parport_driver); diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c index b3e084b75c23..d46eed159495 100644 --- a/drivers/pps/generators/pps_gen_parport.c +++ b/drivers/pps/generators/pps_gen_parport.c @@ -232,7 +232,6 @@ static struct parport_driver pps_gen_parport_driver = { .name = KBUILD_MODNAME, .match_port = parport_attach, .detach = parport_detach, - .devmodel = true, }; module_parport_driver(pps_gen_parport_driver); diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 21339da505f1..60e4f101c2bf 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1275,7 +1275,6 @@ static struct parport_driver imm_driver = { .name = "imm", .match_port = imm_attach, .detach = imm_detach, - .devmodel = true, }; module_parport_driver(imm_driver); diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 8300f0bdddb3..3741972bc768 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -1151,7 +1151,6 @@ static struct parport_driver ppa_driver = { .name = "ppa", .match_port = ppa_attach, .detach = ppa_detach, - .devmodel = true, }; module_parport_driver(ppa_driver); diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index 1d267e6c22a4..84eb454ed443 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -315,7 +315,6 @@ static struct parport_driver butterfly_driver = { .name = "spi_butterfly", .match_port = butterfly_attach, .detach = butterfly_detach, - .devmodel = true, }; module_parport_driver(butterfly_driver); diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index 3c0c24ed1f3d..e61e89b4119f 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -318,7 +318,6 @@ static struct parport_driver spi_lm70llp_drv = { .name = DRVNAME, .match_port = spi_lm70llp_attach, .detach = spi_lm70llp_detach, - .devmodel = true, }; module_parport_driver(spi_lm70llp_drv); diff --git a/include/linux/parport.h b/include/linux/parport.h index 190de3569e25..464c2ad28039 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -256,7 +256,6 @@ struct parport_driver { void (*match_port)(struct parport *); int (*probe)(struct pardevice *); struct device_driver driver; - bool devmodel; }; #define to_parport_driver(n) container_of(n, struct parport_driver, driver) @@ -299,9 +298,6 @@ int __must_check __parport_register_driver(struct parport_driver *, * to receive notifications about ports being found in the * system, as well as ports no longer available. * - * If devmodel is true then the new device model is used - * for registration. - * * The @driver structure is allocated by the caller and must not be * deallocated until after calling parport_unregister_driver(). * diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 5cfd0e99a13f..b1b333d1cf39 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -882,7 +882,6 @@ static struct parport_driver mts64_parport_driver = { .probe = snd_mts64_dev_probe, .match_port = snd_mts64_attach, .detach = snd_mts64_detach, - .devmodel = true, }; /********************************************************************* diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 619e3f594477..6fd9e8870021 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -668,7 +668,6 @@ static struct parport_driver portman_parport_driver = { .probe = snd_portman_dev_probe, .match_port = snd_portman_attach, .detach = snd_portman_detach, - .devmodel = true, }; /********************************************************************* From 55d57ef6fa97ca631d393cccc641cbe1b16cc382 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 25 Jun 2024 08:34:58 +0200 Subject: [PATCH 290/330] eeprom: ee1004: Use devres for bus data cleanup Use devm_add_action_or_reset() to clean up the bus data at driver removal or when an error occurs during probe. This will allow us to use other devres-based APIs later. Tested on a Dell Inspiron 3505. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20240625063459.429953-1-W_Armin@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 42 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index bf4f65dc6d9a..b1f760cc3be0 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -9,6 +9,7 @@ * Copyright (C) 2008 Wolfram Sang, Pengutronix */ +#include #include #include #include @@ -207,6 +208,16 @@ static void ee1004_cleanup(int idx, struct ee1004_bus_data *bd) } } +static void ee1004_cleanup_bus_data(void *data) +{ + struct ee1004_bus_data *bd = data; + + /* Remove page select clients if this is the last device */ + mutex_lock(&ee1004_bus_lock); + ee1004_cleanup(EE1004_NUM_PAGES, bd); + mutex_unlock(&ee1004_bus_lock); +} + static int ee1004_probe(struct i2c_client *client) { struct ee1004_bus_data *bd; @@ -228,6 +239,10 @@ static int ee1004_probe(struct i2c_client *client) "Only %d busses supported", EE1004_MAX_BUSSES); } + err = devm_add_action_or_reset(&client->dev, ee1004_cleanup_bus_data, bd); + if (err < 0) + return err; + i2c_set_clientdata(client, bd); if (++bd->dev_count == 1) { @@ -237,16 +252,18 @@ static int ee1004_probe(struct i2c_client *client) cl = i2c_new_dummy_device(client->adapter, EE1004_ADDR_SET_PAGE + cnr); if (IS_ERR(cl)) { - err = PTR_ERR(cl); - goto err_clients; + mutex_unlock(&ee1004_bus_lock); + return PTR_ERR(cl); } bd->set_page[cnr] = cl; } /* Remember current page to avoid unneeded page select */ err = ee1004_get_current_page(bd); - if (err < 0) - goto err_clients; + if (err < 0) { + mutex_unlock(&ee1004_bus_lock); + return err; + } dev_dbg(&client->dev, "Currently selected page: %d\n", err); bd->current_page = err; } @@ -260,22 +277,6 @@ static int ee1004_probe(struct i2c_client *client) EE1004_EEPROM_SIZE); return 0; - - err_clients: - ee1004_cleanup(cnr, bd); - mutex_unlock(&ee1004_bus_lock); - - return err; -} - -static void ee1004_remove(struct i2c_client *client) -{ - struct ee1004_bus_data *bd = i2c_get_clientdata(client); - - /* Remove page select clients if this is the last device */ - mutex_lock(&ee1004_bus_lock); - ee1004_cleanup(EE1004_NUM_PAGES, bd); - mutex_unlock(&ee1004_bus_lock); } /*-------------------------------------------------------------------------*/ @@ -286,7 +287,6 @@ static struct i2c_driver ee1004_driver = { .dev_groups = ee1004_groups, }, .probe = ee1004_probe, - .remove = ee1004_remove, .id_table = ee1004_ids, }; module_i2c_driver(ee1004_driver); From 79d0df36b54179ac2192e56ad7fdb29c952f35e2 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 25 Jun 2024 08:34:59 +0200 Subject: [PATCH 291/330] eeprom: ee1004: Add nvmem support Currently the driver does not register a nvmem provider, which means that userspace programs cannot access the ee1004 EEPROM through the standard nvmem sysfs API. Fix this by replacing the custom sysfs attribute with a standard nvmem interface, which also takes care of backwards compatibility. Tested on a Dell Inspiron 3505. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20240625063459.429953-2-W_Armin@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/Kconfig | 2 ++ drivers/misc/eeprom/ee1004.c | 58 +++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 4e61ac18cc96..9df12399bda3 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -109,6 +109,8 @@ config EEPROM_IDT_89HPESX config EEPROM_EE1004 tristate "SPD EEPROMs on DDR4 memory modules" depends on I2C && SYSFS + select NVMEM + select NVMEM_SYSFS help Enable this driver to get read support to SPD EEPROMs following the JEDEC EE1004 standard. These are typically found on DDR4 diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index b1f760cc3be0..2e69024380b6 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -16,6 +16,7 @@ #include #include #include +#include /* * DDR4 memory modules use special EEPROMs following the Jedec EE1004 @@ -145,13 +146,17 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf); } -static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static int ee1004_read(void *priv, unsigned int off, void *val, size_t count) { - struct i2c_client *client = kobj_to_i2c_client(kobj); - size_t requested = count; - int ret = 0; + struct i2c_client *client = priv; + char *buf = val; + int ret; + + if (unlikely(!count)) + return count; + + if (off + count > EE1004_EEPROM_SIZE) + return -EINVAL; /* * Read data from chip, protecting against concurrent access to @@ -161,28 +166,21 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, while (count) { ret = ee1004_eeprom_read(client, buf, off, count); - if (ret < 0) - goto out; + if (ret < 0) { + mutex_unlock(&ee1004_bus_lock); + return ret; + } buf += ret; off += ret; count -= ret; } -out: + mutex_unlock(&ee1004_bus_lock); - return ret < 0 ? ret : requested; + return 0; } -static BIN_ATTR_RO(eeprom, EE1004_EEPROM_SIZE); - -static struct bin_attribute *ee1004_attrs[] = { - &bin_attr_eeprom, - NULL -}; - -BIN_ATTRIBUTE_GROUPS(ee1004); - static void ee1004_probe_temp_sensor(struct i2c_client *client) { struct i2c_board_info info = { .type = "jc42" }; @@ -220,7 +218,24 @@ static void ee1004_cleanup_bus_data(void *data) static int ee1004_probe(struct i2c_client *client) { + struct nvmem_config config = { + .dev = &client->dev, + .name = dev_name(&client->dev), + .id = NVMEM_DEVID_NONE, + .owner = THIS_MODULE, + .type = NVMEM_TYPE_EEPROM, + .read_only = true, + .root_only = false, + .reg_read = ee1004_read, + .size = EE1004_EEPROM_SIZE, + .word_size = 1, + .stride = 1, + .priv = client, + .compat = true, + .base_dev = &client->dev, + }; struct ee1004_bus_data *bd; + struct nvmem_device *ndev; int err, cnr = 0; /* Make sure we can operate on this adapter */ @@ -272,6 +287,10 @@ static int ee1004_probe(struct i2c_client *client) mutex_unlock(&ee1004_bus_lock); + ndev = devm_nvmem_register(&client->dev, &config); + if (IS_ERR(ndev)) + return PTR_ERR(ndev); + dev_info(&client->dev, "%u byte EE1004-compliant SPD EEPROM, read-only\n", EE1004_EEPROM_SIZE); @@ -284,7 +303,6 @@ static int ee1004_probe(struct i2c_client *client) static struct i2c_driver ee1004_driver = { .driver = { .name = "ee1004", - .dev_groups = ee1004_groups, }, .probe = ee1004_probe, .id_table = ee1004_ids, From 249b4deaff71cfc6ac9a8e436af876be6d84052b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 29 Jun 2024 10:37:15 -0700 Subject: [PATCH 292/330] eeprom: ee1004: Call i2c_new_scanned_device to instantiate thermal sensor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instantiating a device by calling i2c_new_client_device() assumes that the device is not already instantiated. If that is not the case, it will return an error and generate a misleading kernel log message. i2c i2c-0: Failed to register i2c client jc42 at 0x18 (-16) This can be reproduced by unloading the ee1004 driver and loading it again. Avoid this by calling i2c_new_scanned_device() instead, which returns silently if a device is already instantiated or does not exist. Fixes: 393bd1000f81 ("eeprom: ee1004: add support for temperature sensor") Cc: Heiner Kallweit Cc: Thomas Weißschuh Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20240629173716.20389-1-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 2e69024380b6..140bcb20f091 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -184,6 +184,8 @@ static int ee1004_read(void *priv, unsigned int off, void *val, size_t count) static void ee1004_probe_temp_sensor(struct i2c_client *client) { struct i2c_board_info info = { .type = "jc42" }; + unsigned short addr = 0x18 | (client->addr & 7); + unsigned short addr_list[] = { addr, I2C_CLIENT_END }; u8 byte14; int ret; @@ -192,9 +194,7 @@ static void ee1004_probe_temp_sensor(struct i2c_client *client) if (ret != 1 || !(byte14 & BIT(7))) return; - info.addr = 0x18 | (client->addr & 7); - - i2c_new_client_device(client->adapter, &info); + i2c_new_scanned_device(client->adapter, &info, addr_list, NULL); } static void ee1004_cleanup(int idx, struct ee1004_bus_data *bd) From 6150e5e1ae2d8ad72f52217f8f41fe446cae9e27 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 29 Jun 2024 10:37:16 -0700 Subject: [PATCH 293/330] eeprom: ee1004: Instantiate jc42 devices for DIMMS implementing Rev.1 SPD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DDR4 DIMMS implementing SPD Annex L, Revision 1 do not implement SPD byte 14 (Module Temperature Sensor); this byte was only added in revision 2 of the standard. This only applies to DDR4, not DDR4E or LPDDR4, since those DDR types were only introduced in revision 3 of the standard. Use this information to instantiate the jc42 device if the module is a DDR4 following SPD revision 1.0 and a device is detected at the expected thermal sensor address, even if the Module Temperature Sensor byte suggests that the thermal sensor is not supported. Cc: Heiner Kallweit Cc: Thomas Weißschuh Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20240629173716.20389-2-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 140bcb20f091..d4aeeb2b2169 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -186,14 +186,31 @@ static void ee1004_probe_temp_sensor(struct i2c_client *client) struct i2c_board_info info = { .type = "jc42" }; unsigned short addr = 0x18 | (client->addr & 7); unsigned short addr_list[] = { addr, I2C_CLIENT_END }; - u8 byte14; + u8 data[2]; int ret; /* byte 14, bit 7 is set if temp sensor is present */ - ret = ee1004_eeprom_read(client, &byte14, 14, 1); - if (ret != 1 || !(byte14 & BIT(7))) + ret = ee1004_eeprom_read(client, data, 14, 1); + if (ret != 1) return; + if (!(data[0] & BIT(7))) { + /* + * If the SPD data suggests that there is no temperature + * sensor, it may still be there for SPD revision 1.0. + * See SPD Annex L, Revision 1 and 2, for details. + * Check DIMM type and SPD revision; if it is a DDR4 + * with SPD revision 1.0, check the thermal sensor address + * and instantiate the jc42 driver if a chip is found at + * that address. + * It is not necessary to check if there is a chip at the + * temperature sensor address since i2c_new_scanned_device() + * will do that and return silently if no chip is found. + */ + ret = ee1004_eeprom_read(client, data, 1, 2); + if (ret != 2 || data[0] != 0x10 || data[1] != 0x0c) + return; + } i2c_new_scanned_device(client->adapter, &info, addr_list, NULL); } From a1944676767e855869b6af8e1c7e185372feaf31 Mon Sep 17 00:00:00 2001 From: Gerhard Engleder Date: Sun, 30 Jun 2024 21:47:39 +0200 Subject: [PATCH 294/330] misc: keba: Add basic KEBA CP500 system FPGA support The KEBA CP500 system FPGA is a PCIe device, which consists of multiple IP cores. Every IP core has its own auxiliary driver. The cp500 driver registers an auxiliary device for each device and the corresponding drivers are loaded by the Linux driver infrastructure. Currently 3 variants of this device exists. Every variant has its own PCI device ID, which is used to determine the list of available IP cores. In this first version only the auxiliary device for the I2C controller is registered. Besides the auxiliary device registration some other basic functions of the FPGA are implemented; e.g, FPGA version sysfs file, keep FPGA configuration on reset sysfs file, error message for errors on the internal AXI bus of the FPGA. Signed-off-by: Gerhard Engleder Link: https://lore.kernel.org/r/20240630194740.7137-2-gerhard@engleder-embedded.com Signed-off-by: Greg Kroah-Hartman --- .../ABI/stable/sysfs-driver-misc-cp500 | 25 + drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/keba/Kconfig | 12 + drivers/misc/keba/Makefile | 3 + drivers/misc/keba/cp500.c | 458 ++++++++++++++++++ include/linux/misc/keba.h | 25 + 7 files changed, 525 insertions(+) create mode 100644 Documentation/ABI/stable/sysfs-driver-misc-cp500 create mode 100644 drivers/misc/keba/Kconfig create mode 100644 drivers/misc/keba/Makefile create mode 100644 drivers/misc/keba/cp500.c create mode 100644 include/linux/misc/keba.h diff --git a/Documentation/ABI/stable/sysfs-driver-misc-cp500 b/Documentation/ABI/stable/sysfs-driver-misc-cp500 new file mode 100644 index 000000000000..525bd18a2db4 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-driver-misc-cp500 @@ -0,0 +1,25 @@ +What: /sys/devices/pciXXXX:XX/0000:XX:XX.X/0000:XX:XX.X/version +Date: June 2024 +KernelVersion: 6.11 +Contact: Gerhard Engleder +Description: Version of the FPGA configuration bitstream as printable string. + This file is read only. +Users: KEBA + +What: /sys/devices/pciXXXX:XX/0000:XX:XX.X/0000:XX:XX.X/keep_cfg +Date: June 2024 +KernelVersion: 6.11 +Contact: Gerhard Engleder +Description: Flag which signals if FPGA shall keep or reload configuration + bitstream on reset. Normal FPGA behavior and default is to keep + configuration bitstream and to only reset the configured logic. + + Reloading configuration on reset enables an update of the + configuration bitstream with a simple reboot. Otherwise it is + necessary to power cycle the device to reload the new + configuration bitstream. + + This file is read/write. The values are as follows: + 1 = keep configuration bitstream on reset, default + 0 = reload configuration bitstream on reset +Users: KEBA diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index faf983680040..ca0c6a728a00 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -602,4 +602,5 @@ source "drivers/misc/cardreader/Kconfig" source "drivers/misc/uacce/Kconfig" source "drivers/misc/pvpanic/Kconfig" source "drivers/misc/mchp_pci1xxxx/Kconfig" +source "drivers/misc/keba/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 153a3f4837e8..af125aa25a50 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -69,3 +69,4 @@ obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o obj-$(CONFIG_NSM) += nsm.o +obj-y += keba/ diff --git a/drivers/misc/keba/Kconfig b/drivers/misc/keba/Kconfig new file mode 100644 index 000000000000..0ebca1d07ef4 --- /dev/null +++ b/drivers/misc/keba/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +config KEBA_CP500 + tristate "KEBA CP500 system FPGA support" + depends on PCI + help + This driver supports the KEBA CP500 system FPGA, which is used in + KEBA CP500 devices. It registers all sub devices present on the CP500 + system FPGA as separate devices. A driver is needed for each sub + device. + + This driver can also be built as a module. If so, the module will be + called cp500. diff --git a/drivers/misc/keba/Makefile b/drivers/misc/keba/Makefile new file mode 100644 index 000000000000..0a8b846cda7d --- /dev/null +++ b/drivers/misc/keba/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_KEBA_CP500) += cp500.o diff --git a/drivers/misc/keba/cp500.c b/drivers/misc/keba/cp500.c new file mode 100644 index 000000000000..9ba46f0f9392 --- /dev/null +++ b/drivers/misc/keba/cp500.c @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) KEBA Industrial Automation Gmbh 2024 + * + * Driver for KEBA system FPGA + * + * The KEBA system FPGA implements various devices. This driver registers + * auxiliary devices for every device within the FPGA. + */ + +#include +#include +#include +#include +#include + +#define CP500 "cp500" + +#define PCI_VENDOR_ID_KEBA 0xCEBA +#define PCI_DEVICE_ID_KEBA_CP035 0x2706 +#define PCI_DEVICE_ID_KEBA_CP505 0x2703 +#define PCI_DEVICE_ID_KEBA_CP520 0x2696 + +#define CP500_SYS_BAR 0 +#define CP500_ECM_BAR 1 + +/* BAR 0 registers */ +#define CP500_VERSION_REG 0x00 +#define CP500_RECONFIG_REG 0x11 /* upper 8-bits of STARTUP register */ +#define CP500_AXI_REG 0x40 + +/* Bits in BUILD_REG */ +#define CP500_BUILD_TEST 0x8000 /* FPGA test version */ + +/* Bits in RECONFIG_REG */ +#define CP500_RECFG_REQ 0x01 /* reconfigure FPGA on next reset */ + +/* MSIX */ +#define CP500_AXI_MSIX 3 +#define CP500_NUM_MSIX 8 +#define CP500_NUM_MSIX_NO_MMI 2 +#define CP500_NUM_MSIX_NO_AXI 3 + +/* EEPROM */ +#define CP500_HW_CPU_EEPROM_NAME "cp500_cpu_eeprom" + +#define CP500_IS_CP035(dev) ((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP035) +#define CP500_IS_CP505(dev) ((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP505) +#define CP500_IS_CP520(dev) ((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP520) + +struct cp500_dev_info { + off_t offset; + size_t size; +}; + +struct cp500_devs { + struct cp500_dev_info startup; + struct cp500_dev_info i2c; +}; + +/* list of devices within FPGA of CP035 family (CP035, CP056, CP057) */ +static struct cp500_devs cp035_devices = { + .startup = { 0x0000, SZ_4K }, + .i2c = { 0x4000, SZ_4K }, +}; + +/* list of devices within FPGA of CP505 family (CP503, CP505, CP507) */ +static struct cp500_devs cp505_devices = { + .startup = { 0x0000, SZ_4K }, + .i2c = { 0x5000, SZ_4K }, +}; + +/* list of devices within FPGA of CP520 family (CP520, CP530) */ +static struct cp500_devs cp520_devices = { + .startup = { 0x0000, SZ_4K }, + .i2c = { 0x5000, SZ_4K }, +}; + +struct cp500 { + struct pci_dev *pci_dev; + struct cp500_devs *devs; + int msix_num; + struct { + int major; + int minor; + int build; + } version; + + /* system FPGA BAR */ + resource_size_t sys_hwbase; + struct keba_i2c_auxdev *i2c; + + /* ECM EtherCAT BAR */ + resource_size_t ecm_hwbase; + + void __iomem *system_startup_addr; +}; + +/* I2C devices */ +static struct i2c_board_info cp500_i2c_info[] = { + { /* temperature sensor */ + I2C_BOARD_INFO("emc1403", 0x4c), + }, + { /* + * CPU EEPROM + * CP035 family: CPU board + * CP505 family: bridge board + * CP520 family: carrier board + */ + I2C_BOARD_INFO("24c32", 0x50), + .dev_name = CP500_HW_CPU_EEPROM_NAME, + }, + { /* interface board EEPROM */ + I2C_BOARD_INFO("24c32", 0x51), + }, + { /* + * EEPROM (optional) + * CP505 family: CPU board + * CP520 family: MMI board + */ + I2C_BOARD_INFO("24c32", 0x52), + }, + { /* extension module 0 EEPROM (optional) */ + I2C_BOARD_INFO("24c32", 0x53), + }, + { /* extension module 1 EEPROM (optional) */ + I2C_BOARD_INFO("24c32", 0x54), + }, + { /* extension module 2 EEPROM (optional) */ + I2C_BOARD_INFO("24c32", 0x55), + }, + { /* extension module 3 EEPROM (optional) */ + I2C_BOARD_INFO("24c32", 0x56), + } +}; + +static ssize_t cp500_get_fpga_version(struct cp500 *cp500, char *buf, + size_t max_len) +{ + int n; + + if (CP500_IS_CP035(cp500)) + n = scnprintf(buf, max_len, "CP035"); + else if (CP500_IS_CP505(cp500)) + n = scnprintf(buf, max_len, "CP505"); + else + n = scnprintf(buf, max_len, "CP500"); + + n += scnprintf(buf + n, max_len - n, "_FPGA_%d.%02d", + cp500->version.major, cp500->version.minor); + + /* test versions have test bit set */ + if (cp500->version.build & CP500_BUILD_TEST) + n += scnprintf(buf + n, max_len - n, "Test%d", + cp500->version.build & ~CP500_BUILD_TEST); + + n += scnprintf(buf + n, max_len - n, "\n"); + + return n; +} + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct cp500 *cp500 = dev_get_drvdata(dev); + + return cp500_get_fpga_version(cp500, buf, PAGE_SIZE); +} +static DEVICE_ATTR_RO(version); + +static ssize_t keep_cfg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct cp500 *cp500 = dev_get_drvdata(dev); + unsigned long keep_cfg = 1; + + /* + * FPGA configuration stream is kept during reset when RECONFIG bit is + * zero + */ + if (ioread8(cp500->system_startup_addr + CP500_RECONFIG_REG) & + CP500_RECFG_REQ) + keep_cfg = 0; + + return sysfs_emit(buf, "%lu\n", keep_cfg); +} + +static ssize_t keep_cfg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cp500 *cp500 = dev_get_drvdata(dev); + unsigned long keep_cfg; + + if (kstrtoul(buf, 10, &keep_cfg) < 0) + return -EINVAL; + + /* + * In normal operation "keep_cfg" is "1". This means that the FPGA keeps + * its configuration stream during a reset. + * In case of a firmware update of the FPGA, the configuration stream + * needs to be reloaded. This can be done without a powercycle by + * writing a "0" into the "keep_cfg" attribute. After a reset/reboot th + * new configuration stream will be loaded. + */ + if (keep_cfg) + iowrite8(0, cp500->system_startup_addr + CP500_RECONFIG_REG); + else + iowrite8(CP500_RECFG_REQ, + cp500->system_startup_addr + CP500_RECONFIG_REG); + + return count; +} +static DEVICE_ATTR_RW(keep_cfg); + +static struct attribute *attrs[] = { + &dev_attr_version.attr, + &dev_attr_keep_cfg.attr, + NULL +}; +static const struct attribute_group attrs_group = { .attrs = attrs }; + +static void cp500_i2c_release(struct device *dev) +{ + struct keba_i2c_auxdev *i2c = + container_of(dev, struct keba_i2c_auxdev, auxdev.dev); + + kfree(i2c); +} + +static int cp500_register_i2c(struct cp500 *cp500) +{ + int retval; + + cp500->i2c = kzalloc(sizeof(*cp500->i2c), GFP_KERNEL); + if (!cp500->i2c) + return -ENOMEM; + + cp500->i2c->auxdev.name = "i2c"; + cp500->i2c->auxdev.id = 0; + cp500->i2c->auxdev.dev.release = cp500_i2c_release; + cp500->i2c->auxdev.dev.parent = &cp500->pci_dev->dev; + cp500->i2c->io = (struct resource) { + /* I2C register area */ + .start = (resource_size_t) cp500->sys_hwbase + + cp500->devs->i2c.offset, + .end = (resource_size_t) cp500->sys_hwbase + + cp500->devs->i2c.offset + + cp500->devs->i2c.size - 1, + .flags = IORESOURCE_MEM, + }; + cp500->i2c->info_size = ARRAY_SIZE(cp500_i2c_info); + cp500->i2c->info = cp500_i2c_info; + + retval = auxiliary_device_init(&cp500->i2c->auxdev); + if (retval) { + kfree(cp500->i2c); + cp500->i2c = NULL; + + return retval; + } + retval = __auxiliary_device_add(&cp500->i2c->auxdev, "keba"); + if (retval) { + auxiliary_device_uninit(&cp500->i2c->auxdev); + cp500->i2c = NULL; + + return retval; + } + + return 0; +} + +static void cp500_register_auxiliary_devs(struct cp500 *cp500) +{ + struct device *dev = &cp500->pci_dev->dev; + + if (cp500_register_i2c(cp500)) + dev_warn(dev, "Failed to register i2c!\n"); +} + +static void cp500_unregister_dev(struct auxiliary_device *auxdev) +{ + auxiliary_device_delete(auxdev); + auxiliary_device_uninit(auxdev); +} + +static void cp500_unregister_auxiliary_devs(struct cp500 *cp500) +{ + + if (cp500->i2c) { + cp500_unregister_dev(&cp500->i2c->auxdev); + cp500->i2c = NULL; + } +} + +static irqreturn_t cp500_axi_handler(int irq, void *dev) +{ + struct cp500 *cp500 = dev; + u32 axi_address = ioread32(cp500->system_startup_addr + CP500_AXI_REG); + + /* + * FPGA signals AXI response error, print AXI address to indicate which + * IP core was affected + */ + dev_err(&cp500->pci_dev->dev, "AXI response error at 0x%08x\n", + axi_address); + + return IRQ_HANDLED; +} + +static int cp500_enable(struct cp500 *cp500) +{ + int axi_irq = -1; + int ret; + + if (cp500->msix_num > CP500_NUM_MSIX_NO_AXI) { + axi_irq = pci_irq_vector(cp500->pci_dev, CP500_AXI_MSIX); + ret = request_irq(axi_irq, cp500_axi_handler, 0, + CP500, cp500); + if (ret != 0) { + dev_err(&cp500->pci_dev->dev, + "Failed to register AXI response error!\n"); + return ret; + } + } + + return 0; +} + +static void cp500_disable(struct cp500 *cp500) +{ + int axi_irq; + + if (cp500->msix_num > CP500_NUM_MSIX_NO_AXI) { + axi_irq = pci_irq_vector(cp500->pci_dev, CP500_AXI_MSIX); + free_irq(axi_irq, cp500); + } +} + +static int cp500_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + struct device *dev = &pci_dev->dev; + struct resource startup; + struct cp500 *cp500; + u32 cp500_vers; + char buf[64]; + int ret; + + cp500 = devm_kzalloc(dev, sizeof(*cp500), GFP_KERNEL); + if (!cp500) + return -ENOMEM; + cp500->pci_dev = pci_dev; + cp500->sys_hwbase = pci_resource_start(pci_dev, CP500_SYS_BAR); + cp500->ecm_hwbase = pci_resource_start(pci_dev, CP500_ECM_BAR); + if (!cp500->sys_hwbase || !cp500->ecm_hwbase) + return -ENODEV; + + if (CP500_IS_CP035(cp500)) + cp500->devs = &cp035_devices; + else if (CP500_IS_CP505(cp500)) + cp500->devs = &cp505_devices; + else if (CP500_IS_CP520(cp500)) + cp500->devs = &cp520_devices; + else + return -ENODEV; + + ret = pci_enable_device(pci_dev); + if (ret) + return ret; + pci_set_master(pci_dev); + + startup = *pci_resource_n(pci_dev, CP500_SYS_BAR); + startup.end = startup.start + cp500->devs->startup.size - 1; + cp500->system_startup_addr = devm_ioremap_resource(&pci_dev->dev, + &startup); + if (IS_ERR(cp500->system_startup_addr)) { + ret = PTR_ERR(cp500->system_startup_addr); + goto out_disable; + } + + cp500->msix_num = pci_alloc_irq_vectors(pci_dev, CP500_NUM_MSIX_NO_MMI, + CP500_NUM_MSIX, PCI_IRQ_MSIX); + if (cp500->msix_num < CP500_NUM_MSIX_NO_MMI) { + dev_err(&pci_dev->dev, + "Hardware does not support enough MSI-X interrupts\n"); + ret = -ENODEV; + goto out_disable; + } + + cp500_vers = ioread32(cp500->system_startup_addr + CP500_VERSION_REG); + cp500->version.major = (cp500_vers & 0xff); + cp500->version.minor = (cp500_vers >> 8) & 0xff; + cp500->version.build = (cp500_vers >> 16) & 0xffff; + cp500_get_fpga_version(cp500, buf, sizeof(buf)); + + dev_info(&pci_dev->dev, "FPGA version %s", buf); + + pci_set_drvdata(pci_dev, cp500); + + ret = sysfs_create_group(&pci_dev->dev.kobj, &attrs_group); + if (ret != 0) + goto out_free_irq; + + ret = cp500_enable(cp500); + if (ret != 0) + goto out_remove_group; + + cp500_register_auxiliary_devs(cp500); + + return 0; + +out_remove_group: + sysfs_remove_group(&pci_dev->dev.kobj, &attrs_group); +out_free_irq: + pci_free_irq_vectors(pci_dev); +out_disable: + pci_clear_master(pci_dev); + pci_disable_device(pci_dev); + + return ret; +} + +static void cp500_remove(struct pci_dev *pci_dev) +{ + struct cp500 *cp500 = pci_get_drvdata(pci_dev); + + cp500_unregister_auxiliary_devs(cp500); + + cp500_disable(cp500); + + sysfs_remove_group(&pci_dev->dev.kobj, &attrs_group); + + pci_set_drvdata(pci_dev, 0); + + pci_free_irq_vectors(pci_dev); + + pci_clear_master(pci_dev); + pci_disable_device(pci_dev); +} + +static struct pci_device_id cp500_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_KEBA, PCI_DEVICE_ID_KEBA_CP035) }, + { PCI_DEVICE(PCI_VENDOR_ID_KEBA, PCI_DEVICE_ID_KEBA_CP505) }, + { PCI_DEVICE(PCI_VENDOR_ID_KEBA, PCI_DEVICE_ID_KEBA_CP520) }, + { } +}; +MODULE_DEVICE_TABLE(pci, cp500_ids); + +static struct pci_driver cp500_driver = { + .name = CP500, + .id_table = cp500_ids, + .probe = cp500_probe, + .remove = cp500_remove, +}; +module_pci_driver(cp500_driver); + +MODULE_AUTHOR("Gerhard Engleder "); +MODULE_DESCRIPTION("KEBA CP500 system FPGA driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/misc/keba.h b/include/linux/misc/keba.h new file mode 100644 index 000000000000..323b31a847c5 --- /dev/null +++ b/include/linux/misc/keba.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2024, KEBA Industrial Automation Gmbh */ + +#ifndef _LINUX_MISC_KEBA_H +#define _LINUX_MISC_KEBA_H + +#include + +struct i2c_board_info; + +/** + * struct keba_i2c_auxdev - KEBA I2C auxiliary device + * @auxdev: auxiliary device object + * @io: address range of I2C controller IO memory + * @info_size: number of I2C devices to be probed + * @info: I2C devices to be probed + */ +struct keba_i2c_auxdev { + struct auxiliary_device auxdev; + struct resource io; + int info_size; + struct i2c_board_info *info; +}; + +#endif /* _LINUX_MISC_KEBA_H */ From 173c044752b79949335298a3c2566b19831750c1 Mon Sep 17 00:00:00 2001 From: Sebastian Ene Date: Wed, 3 Jul 2024 15:37:31 +0000 Subject: [PATCH 295/330] dt-bindings: vcpu_stall_detector: Add a PPI interrupt to the virtual device The vcpu stall detector allows the host to monitor the availability of a guest VM. Introduce a PPI interrupt which can be injected from the host into the virtual gic to let the guest reboot itself. Acked-by: Conor Dooley Signed-off-by: Sebastian Ene Link: https://lore.kernel.org/r/20240703153732.3214238-2-sebastianene@google.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/misc/qemu,vcpu-stall-detector.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/misc/qemu,vcpu-stall-detector.yaml b/Documentation/devicetree/bindings/misc/qemu,vcpu-stall-detector.yaml index 1aebeb696ee0..e12d80be00cd 100644 --- a/Documentation/devicetree/bindings/misc/qemu,vcpu-stall-detector.yaml +++ b/Documentation/devicetree/bindings/misc/qemu,vcpu-stall-detector.yaml @@ -29,6 +29,9 @@ properties: Defaults to 10 if unset. default: 10 + interrupts: + maxItems: 1 + timeout-sec: description: | The stall detector expiration timeout measured in seconds. @@ -43,9 +46,12 @@ additionalProperties: false examples: - | + #include + vmwdt@9030000 { compatible = "qemu,vcpu-stall-detector"; reg = <0x9030000 0x10000>; clock-frequency = <10>; timeout-sec = <8>; + interrupts = ; }; From d2b88700ead3be641d565a359fd522f71b4737e4 Mon Sep 17 00:00:00 2001 From: Sebastian Ene Date: Wed, 3 Jul 2024 15:37:32 +0000 Subject: [PATCH 296/330] misc: Register a PPI for the vcpu stall detection virtual device Request a PPI for each vCPU during probe which will be used by the host to communicate a stall detected event on the vCPU. When the host raises this interrupt from the virtual machine monitor, the guest is expected to handle the interrupt and panic. Signed-off-by: Sebastian Ene Link: https://lore.kernel.org/r/20240703153732.3214238-3-sebastianene@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vcpu_stall_detector.c | 31 ++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/misc/vcpu_stall_detector.c b/drivers/misc/vcpu_stall_detector.c index e2015c87f03f..41b8c2119e20 100644 --- a/drivers/misc/vcpu_stall_detector.c +++ b/drivers/misc/vcpu_stall_detector.c @@ -32,6 +32,7 @@ struct vcpu_stall_detect_config { u32 clock_freq_hz; u32 stall_timeout_sec; + int ppi_irq; void __iomem *membase; struct platform_device *dev; @@ -77,6 +78,12 @@ vcpu_stall_detect_timer_fn(struct hrtimer *hrtimer) return HRTIMER_RESTART; } +static irqreturn_t vcpu_stall_detector_irq(int irq, void *dev) +{ + panic("vCPU stall detector"); + return IRQ_HANDLED; +} + static int start_stall_detector_cpu(unsigned int cpu) { u32 ticks, ping_timeout_ms; @@ -132,7 +139,7 @@ static int stop_stall_detector_cpu(unsigned int cpu) static int vcpu_stall_detect_probe(struct platform_device *pdev) { - int ret; + int ret, irq; struct resource *r; void __iomem *membase; u32 clock_freq_hz = VCPU_STALL_DEFAULT_CLOCK_HZ; @@ -169,9 +176,22 @@ static int vcpu_stall_detect_probe(struct platform_device *pdev) vcpu_stall_config = (struct vcpu_stall_detect_config) { .membase = membase, .clock_freq_hz = clock_freq_hz, - .stall_timeout_sec = stall_timeout_sec + .stall_timeout_sec = stall_timeout_sec, + .ppi_irq = -1, }; + irq = platform_get_irq_optional(pdev, 0); + if (irq > 0) { + ret = request_percpu_irq(irq, + vcpu_stall_detector_irq, + "vcpu_stall_detector", + vcpu_stall_detectors); + if (ret) + goto err; + + vcpu_stall_config.ppi_irq = irq; + } + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "virt/vcpu_stall_detector:online", start_stall_detector_cpu, @@ -184,6 +204,9 @@ static int vcpu_stall_detect_probe(struct platform_device *pdev) vcpu_stall_config.hp_online = ret; return 0; err: + if (vcpu_stall_config.ppi_irq > 0) + free_percpu_irq(vcpu_stall_config.ppi_irq, + vcpu_stall_detectors); return ret; } @@ -193,6 +216,10 @@ static void vcpu_stall_detect_remove(struct platform_device *pdev) cpuhp_remove_state(vcpu_stall_config.hp_online); + if (vcpu_stall_config.ppi_irq > 0) + free_percpu_irq(vcpu_stall_config.ppi_irq, + vcpu_stall_detectors); + for_each_possible_cpu(cpu) stop_stall_detector_cpu(cpu); } From 8b6bd8391f91dc85621547fe3c0af8086a012bcb Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Thu, 4 Jul 2024 18:25:15 +0530 Subject: [PATCH 297/330] interconnect: qcom: Fix DT backwards compatibility for QoS Add qos_clks_required flag to skip QoS configuration if clocks property is not populated in devicetree for providers which require clocks to be enabled for accessing registers. This is to keep the QoS configuration backwards compatible with devices that have older DTB. Reported-by: Bjorn Andersson Closes: https://lore.kernel.org/all/ciji6nlxn752ina4tmh6kwvek52nxpnguomqek6plwvwgvoqef@yrtexkpmn5br/ Signed-off-by: Odelu Kukatla Tested-by: Bjorn Andersson Fixes: fbd908bb8bc0 ("interconnect: qcom: sc7280: enable QoS configuration") Link: https://lore.kernel.org/r/20240704125515.22194-1-quic_okukatla@quicinc.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpmh.c | 2 +- drivers/interconnect/qcom/icc-rpmh.h | 1 + drivers/interconnect/qcom/sc7280.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index ceea9522df83..b8f49cfca6e0 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -311,7 +311,7 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) } qp->num_clks = devm_clk_bulk_get_all(qp->dev, &qp->clks); - if (qp->num_clks < 0) { + if (qp->num_clks < 0 || (!qp->num_clks && desc->qos_clks_required)) { dev_info(dev, "Skipping QoS, failed to get clk: %d\n", qp->num_clks); goto skip_qos_config; } diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index 9a5142c70486..14db89850fb3 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -153,6 +153,7 @@ struct qcom_icc_desc { size_t num_nodes; struct qcom_icc_bcm * const *bcms; size_t num_bcms; + bool qos_clks_required; }; int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c index 759c609a20bf..167971f8e8be 100644 --- a/drivers/interconnect/qcom/sc7280.c +++ b/drivers/interconnect/qcom/sc7280.c @@ -1691,6 +1691,7 @@ static const struct qcom_icc_desc sc7280_aggre1_noc = { .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), .bcms = aggre1_noc_bcms, .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), + .qos_clks_required = true, }; static struct qcom_icc_bcm * const aggre2_noc_bcms[] = { @@ -1722,6 +1723,7 @@ static const struct qcom_icc_desc sc7280_aggre2_noc = { .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), .bcms = aggre2_noc_bcms, .num_bcms = ARRAY_SIZE(aggre2_noc_bcms), + .qos_clks_required = true, }; static struct qcom_icc_bcm * const clk_virt_bcms[] = { From c553bad4c5fc5ae44bd2fcaa73e1d6bedfb1c35c Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 5 Jul 2024 08:48:38 +0100 Subject: [PATCH 298/330] nvmem: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvmem/nvmem-apple-efuses.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvmem/nvmem_brcm_nvram.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/nvmem/nvmem_u-boot-env.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/apple-efuses.c | 1 + drivers/nvmem/brcm_nvram.c | 1 + drivers/nvmem/u-boot-env.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/nvmem/apple-efuses.c b/drivers/nvmem/apple-efuses.c index d3d49d22338b..1d1bf84a099f 100644 --- a/drivers/nvmem/apple-efuses.c +++ b/drivers/nvmem/apple-efuses.c @@ -78,4 +78,5 @@ static struct platform_driver apple_efuses_driver = { module_platform_driver(apple_efuses_driver); MODULE_AUTHOR("Sven Peter "); +MODULE_DESCRIPTION("Apple SoC eFuse driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c index 5cdf339cfbec..3d8c87835f4d 100644 --- a/drivers/nvmem/brcm_nvram.c +++ b/drivers/nvmem/brcm_nvram.c @@ -253,5 +253,6 @@ static int __init brcm_nvram_init(void) subsys_initcall_sync(brcm_nvram_init); MODULE_AUTHOR("Rafał Miłecki"); +MODULE_DESCRIPTION("Broadcom I/O-mapped NVRAM support driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(of, brcm_nvram_of_match_table); diff --git a/drivers/nvmem/u-boot-env.c b/drivers/nvmem/u-boot-env.c index befbab156cda..936e39b20b38 100644 --- a/drivers/nvmem/u-boot-env.c +++ b/drivers/nvmem/u-boot-env.c @@ -249,5 +249,6 @@ static struct platform_driver u_boot_env_driver = { module_platform_driver(u_boot_env_driver); MODULE_AUTHOR("Rafał Miłecki"); +MODULE_DESCRIPTION("U-Boot environment variables support module"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table); From e499d4b7d8c08784e4e49d9e32ebade2cf4596dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 5 Jul 2024 08:48:39 +0100 Subject: [PATCH 299/330] dt-bindings: nvmem: mediatek: efuse: add support for MT7981 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add compatible for MT7981 SoC. Signed-off-by: Rafał Miłecki Acked-by: Krzysztof Kozlowski Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml index cf5f9e22bb7e..a773101d8538 100644 --- a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml @@ -28,6 +28,7 @@ properties: - enum: - mediatek,mt7622-efuse - mediatek,mt7623-efuse + - mediatek,mt7981-efuse - mediatek,mt7986-efuse - mediatek,mt8173-efuse - mediatek,mt8183-efuse From 5fecb932607d83d37a703c731268e9d9051457f5 Mon Sep 17 00:00:00 2001 From: MarileneGarcia Date: Fri, 5 Jul 2024 08:48:40 +0100 Subject: [PATCH 300/330] nvmem: meson-efuse: Replacing the use of of_node_put to __free Use __free for device_node values, and thus drop calls to of_node_put. The goal is to reduce memory management issues by using this scope-based of_node_put() cleanup to simplify function exit handling. When using __free a resource is allocated within a block, it is automatically freed at the end of the block. Suggested-by: Julia Lawall Signed-off-by: MarileneGarcia Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/meson-efuse.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c index 33678d0af2c2..52ed9a62ca5b 100644 --- a/drivers/nvmem/meson-efuse.c +++ b/drivers/nvmem/meson-efuse.c @@ -42,20 +42,19 @@ static int meson_efuse_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct meson_sm_firmware *fw; - struct device_node *sm_np; struct nvmem_device *nvmem; struct nvmem_config *econfig; struct clk *clk; unsigned int size; + struct device_node *sm_np __free(device_node) = + of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0); - sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0); if (!sm_np) { dev_err(&pdev->dev, "no secure-monitor node\n"); return -ENODEV; } fw = meson_sm_get(sm_np); - of_node_put(sm_np); if (!fw) return -EPROBE_DEFER; From 2933e79db3c00a8cdc56f6bb050a857fec1875ad Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 5 Jul 2024 08:48:41 +0100 Subject: [PATCH 301/330] nvmem: rockchip-otp: set add_legacy_fixed_of_cells config option The Rockchip OTP describes its layout via devicetree subnodes, so set the appropriate property. Fixes: 2cc3b37f5b6d ("nvmem: add explicit config option to read old syntax fixed OF cells") Signed-off-by: Heiko Stuebner Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-5-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/rockchip-otp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c index cb9aa5428350..7107d68a2f8c 100644 --- a/drivers/nvmem/rockchip-otp.c +++ b/drivers/nvmem/rockchip-otp.c @@ -255,6 +255,7 @@ static int rockchip_otp_read(void *context, unsigned int offset, static struct nvmem_config otp_config = { .name = "rockchip-otp", .owner = THIS_MODULE, + .add_legacy_fixed_of_cells = true, .read_only = true, .stride = 1, .word_size = 1, From 39f95600d8c53355b212a117e91a6ba15e0cac47 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 5 Jul 2024 08:48:42 +0100 Subject: [PATCH 302/330] nvmem: rockchip-otp: Set type to OTP The Rockchip OTP is obviously an OTP memory, so document this fact. Signed-off-by: Heiko Stuebner Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-6-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/rockchip-otp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c index 7107d68a2f8c..ebc3f0b24166 100644 --- a/drivers/nvmem/rockchip-otp.c +++ b/drivers/nvmem/rockchip-otp.c @@ -256,6 +256,7 @@ static struct nvmem_config otp_config = { .name = "rockchip-otp", .owner = THIS_MODULE, .add_legacy_fixed_of_cells = true, + .type = NVMEM_TYPE_OTP, .read_only = true, .stride = 1, .word_size = 1, From ba64a04474d2989f397982c48e405cfd785e2dd5 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 5 Jul 2024 08:48:43 +0100 Subject: [PATCH 303/330] nvmem: rockchip-efuse: set type to OTP This device currently reports an "Unknown" type in sysfs. Since it is an eFuse hardware device, set its type to OTP. Signed-off-by: Heiko Stuebner Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/rockchip-efuse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c index 2b40978ddb18..013e67136f3b 100644 --- a/drivers/nvmem/rockchip-efuse.c +++ b/drivers/nvmem/rockchip-efuse.c @@ -206,6 +206,7 @@ static int rockchip_rk3399_efuse_read(void *context, unsigned int offset, static struct nvmem_config econfig = { .name = "rockchip-efuse", .add_legacy_fixed_of_cells = true, + .type = NVMEM_TYPE_OTP, .stride = 1, .word_size = 1, .read_only = true, From 70907fd5ed00e0ccb7213882b4d901794cc749e7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 5 Jul 2024 08:48:44 +0100 Subject: [PATCH 304/330] dt-bindings: nvmem: amlogic,meson-gx-efuse: add optional power-domains On newer SoCs, the eFuse hardware can require a power-domain to operate, add it as optional. Signed-off-by: Neil Armstrong Acked-by: Rob Herring (Arm) Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-8-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml b/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml index 9801fe6f91b5..99ddc9a4af05 100644 --- a/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml @@ -28,6 +28,9 @@ properties: description: phandle to the secure-monitor node $ref: /schemas/types.yaml#/definitions/phandle + power-domains: + maxItems: 1 + required: - compatible - clocks From 2cf7e4dcfb3bbd3fcea5d8918e294b9855ab639b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 5 Jul 2024 08:48:45 +0100 Subject: [PATCH 305/330] dt-bindings: nvmem: mediatek: efuse: add support for MT7988 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add compatible for MT7988 SoC. Signed-off-by: Rafał Miłecki Acked-by: Krzysztof Kozlowski Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-9-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml index a773101d8538..32b8c1eb4e80 100644 --- a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml @@ -30,6 +30,7 @@ properties: - mediatek,mt7623-efuse - mediatek,mt7981-efuse - mediatek,mt7986-efuse + - mediatek,mt7988-efuse - mediatek,mt8173-efuse - mediatek,mt8183-efuse - mediatek,mt8186-efuse From 6188f233161c6a5b2d1c396a221dfafc77dc9eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 5 Jul 2024 08:48:46 +0100 Subject: [PATCH 306/330] nvmem: core: add single sysfs group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sysfs core provides a function to easily register a single group. Use it and remove the now unnecessary nvmem_cells_groups array. Signed-off-by: Thomas Weißschuh Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-10-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index e1ec3b7200d7..96e76d88204c 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -367,11 +367,6 @@ static const struct attribute_group *nvmem_dev_groups[] = { NULL, }; -static const struct attribute_group *nvmem_cells_groups[] = { - &nvmem_cells_group, - NULL, -}; - static struct bin_attribute bin_attr_nvmem_eeprom_compat = { .attr = { .name = "eeprom", @@ -478,7 +473,7 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem) nvmem_cells_group.bin_attrs = cells_attrs; - ret = device_add_groups(&nvmem->dev, nvmem_cells_groups); + ret = device_add_group(&nvmem->dev, &nvmem_cells_group); if (ret) goto unlock_mutex; From 6839fed062b7898665983368c88269a6fb1fc10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 5 Jul 2024 08:48:47 +0100 Subject: [PATCH 307/330] nvmem: core: remove global nvmem_cells_group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nvmem_cells_groups is a global variable that is also mutated. This is complicated and error-prone. Instead use a normal stack variable. Signed-off-by: Thomas Weißschuh Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-11-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 96e76d88204c..015e6b9e0b60 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -357,11 +357,6 @@ static const struct attribute_group nvmem_bin_group = { .is_bin_visible = nvmem_bin_attr_is_visible, }; -/* Cell attributes will be dynamically allocated */ -static struct attribute_group nvmem_cells_group = { - .name = "cells", -}; - static const struct attribute_group *nvmem_dev_groups[] = { &nvmem_bin_group, NULL, @@ -424,23 +419,24 @@ static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem) { - struct bin_attribute **cells_attrs, *attrs; + struct attribute_group group = { + .name = "cells", + }; struct nvmem_cell_entry *entry; + struct bin_attribute *attrs; unsigned int ncells = 0, i = 0; int ret = 0; mutex_lock(&nvmem_mutex); - if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated) { - nvmem_cells_group.bin_attrs = NULL; + if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated) goto unlock_mutex; - } /* Allocate an array of attributes with a sentinel */ ncells = list_count_nodes(&nvmem->cells); - cells_attrs = devm_kcalloc(&nvmem->dev, ncells + 1, - sizeof(struct bin_attribute *), GFP_KERNEL); - if (!cells_attrs) { + group.bin_attrs = devm_kcalloc(&nvmem->dev, ncells + 1, + sizeof(struct bin_attribute *), GFP_KERNEL); + if (!group.bin_attrs) { ret = -ENOMEM; goto unlock_mutex; } @@ -467,13 +463,11 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem) goto unlock_mutex; } - cells_attrs[i] = &attrs[i]; + group.bin_attrs[i] = &attrs[i]; i++; } - nvmem_cells_group.bin_attrs = cells_attrs; - - ret = device_add_group(&nvmem->dev, &nvmem_cells_group); + ret = device_add_group(&nvmem->dev, &group); if (ret) goto unlock_mutex; From 588773802c386d38f9c4e91acd47369e89d95a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 5 Jul 2024 08:48:48 +0100 Subject: [PATCH 308/330] nvmem: core: drop unnecessary range checks in sysfs callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same checks have already been done in sysfs_kf_bin_write() and sysfs_kf_bin_read() just before the callbacks are invoked. Signed-off-by: Thomas Weißschuh Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-12-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 015e6b9e0b60..ec31c1fe9a99 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -203,19 +203,12 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, dev = kobj_to_dev(kobj); nvmem = to_nvmem_device(dev); - /* Stop the user from reading */ - if (pos >= nvmem->size) - return 0; - if (!IS_ALIGNED(pos, nvmem->stride)) return -EINVAL; if (count < nvmem->word_size) return -EINVAL; - if (pos + count > nvmem->size) - count = nvmem->size - pos; - count = round_down(count, nvmem->word_size); if (!nvmem->reg_read) @@ -243,19 +236,12 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, dev = kobj_to_dev(kobj); nvmem = to_nvmem_device(dev); - /* Stop the user from writing */ - if (pos >= nvmem->size) - return -EFBIG; - if (!IS_ALIGNED(pos, nvmem->stride)) return -EINVAL; if (count < nvmem->word_size) return -EINVAL; - if (pos + count > nvmem->size) - count = nvmem->size - pos; - count = round_down(count, nvmem->word_size); if (!nvmem->reg_write) From ac871d6bd83581999297b6162e074db4a294bbd5 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 5 Jul 2024 08:48:49 +0100 Subject: [PATCH 309/330] nvmem: Replace spaces with tab in documentation Replace two spaces with tab in the sysfs attribute documentation. No functional change. Signed-off-by: Marek Vasut Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-13-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-bus-nvmem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/stable/sysfs-bus-nvmem b/Documentation/ABI/stable/sysfs-bus-nvmem index c399323f37de..854bd11d72ac 100644 --- a/Documentation/ABI/stable/sysfs-bus-nvmem +++ b/Documentation/ABI/stable/sysfs-bus-nvmem @@ -1,6 +1,6 @@ What: /sys/bus/nvmem/devices/.../nvmem Date: July 2015 -KernelVersion: 4.2 +KernelVersion: 4.2 Contact: Srinivas Kandagatla Description: This file allows user to read/write the raw NVMEM contents. From a5f65c7735bd783689ceb42cffccb1ad0365d4b5 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 5 Jul 2024 08:48:50 +0100 Subject: [PATCH 310/330] nvmem: Document type attribute Document a type attribute used by userspace to discern different types of NVMEM devices. The implementation is already present, the ABI document is missing, add it. Reviewed-by: Alexandre Belloni Signed-off-by: Marek Vasut Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-14-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-bus-nvmem | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-bus-nvmem b/Documentation/ABI/stable/sysfs-bus-nvmem index 854bd11d72ac..3f0a95250aa8 100644 --- a/Documentation/ABI/stable/sysfs-bus-nvmem +++ b/Documentation/ABI/stable/sysfs-bus-nvmem @@ -20,3 +20,14 @@ Description: ... * 0001000 + +What: /sys/bus/nvmem/devices/.../type +Date: November 2018 +KernelVersion: 5.0 +Contact: Alexandre Belloni +Description: + This read-only attribute allows user to read the NVMEM + device type. Supported types are "Unknown", "EEPROM", + "OTP", "Battery backed", "FRAM". + Note: This file is only present if CONFIG_NVMEM_SYSFS + is enabled. From 08c367e45b6d322956878774f0b88bf5e52c6d54 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 5 Jul 2024 08:48:51 +0100 Subject: [PATCH 311/330] nvmem: Use sysfs_emit() for type attribute Use sysfs_emit() instead of sprintf() to follow best practice per Documentation/filesystems/sysfs.rst " show() should only use sysfs_emit()... " Signed-off-by: Marek Vasut Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-15-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index ec31c1fe9a99..89f632f91768 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -179,7 +179,7 @@ static ssize_t type_show(struct device *dev, { struct nvmem_device *nvmem = to_nvmem_device(dev); - return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); + return sysfs_emit(buf, "%s\n", nvmem_type_str[nvmem->type]); } static DEVICE_ATTR_RO(type); From 9d7eb234ac7a56b88aea8a52ed81553a730fe25c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 5 Jul 2024 08:48:52 +0100 Subject: [PATCH 312/330] nvmem: core: Implement force_ro sysfs attribute Implement "force_ro" sysfs attribute to allow users to set read-write devices as read-only and back to read-write from userspace. The choice of the name is based on MMC core 'force_ro' attribute. This solves a situation where an AT24 I2C EEPROM with GPIO based nWP signal may have to be occasionally updated. Such I2C EEPROM device is usually set as read-only during most of the regular system operation, but in case it has to be updated in a controlled manner, it could be unlocked using this new "force_ro" sysfs attribute and then re-locked again. The "read-only" DT property and config->read_only configuration is respected and is used to set default state of the device, read-only or read-write, for devices which do implement .reg_write function. For devices which do not implement .reg_write function, the device is unconditionally read-only and the "force_ro" attribute is not visible. Signed-off-by: Marek Vasut Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705074852.423202-16-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-bus-nvmem | 17 ++++++++++ drivers/nvmem/core.c | 43 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-bus-nvmem b/Documentation/ABI/stable/sysfs-bus-nvmem index 3f0a95250aa8..aa89adf18bc5 100644 --- a/Documentation/ABI/stable/sysfs-bus-nvmem +++ b/Documentation/ABI/stable/sysfs-bus-nvmem @@ -1,3 +1,20 @@ +What: /sys/bus/nvmem/devices/.../force_ro +Date: June 2024 +KernelVersion: 6.11 +Contact: Marek Vasut +Description: + This read/write attribute allows users to set read-write + devices as read-only and back to read-write from userspace. + This can be used to unlock and relock write-protection of + devices which are generally locked, except during sporadic + programming operation. + Read returns '0' or '1' for read-write or read-only modes + respectively. + Write parses one of 'YyTt1NnFf0', or [oO][NnFf] for "on" + and "off", i.e. what kstrbool() supports. + Note: This file is only present if CONFIG_NVMEM_SYSFS + is enabled. + What: /sys/bus/nvmem/devices/.../nvmem Date: July 2015 KernelVersion: 4.2 diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 89f632f91768..12df7d037d37 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -184,7 +184,30 @@ static ssize_t type_show(struct device *dev, static DEVICE_ATTR_RO(type); +static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nvmem_device *nvmem = to_nvmem_device(dev); + + return sysfs_emit(buf, "%d\n", nvmem->read_only); +} + +static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nvmem_device *nvmem = to_nvmem_device(dev); + int ret = kstrtobool(buf, &nvmem->read_only); + + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR_RW(force_ro); + static struct attribute *nvmem_attrs[] = { + &dev_attr_force_ro.attr, &dev_attr_type.attr, NULL, }; @@ -285,6 +308,25 @@ static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, return nvmem_bin_attr_get_umode(nvmem); } +static umode_t nvmem_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct device *dev = kobj_to_dev(kobj); + struct nvmem_device *nvmem = to_nvmem_device(dev); + + /* + * If the device has no .reg_write operation, do not allow + * configuration as read-write. + * If the device is set as read-only by configuration, it + * can be forced into read-write mode using the 'force_ro' + * attribute. + */ + if (attr == &dev_attr_force_ro.attr && !nvmem->reg_write) + return 0; /* Attribute not visible */ + + return attr->mode; +} + static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, const char *id, int index); @@ -341,6 +383,7 @@ static const struct attribute_group nvmem_bin_group = { .bin_attrs = nvmem_bin_attributes, .attrs = nvmem_attrs, .is_bin_visible = nvmem_bin_attr_is_visible, + .is_visible = nvmem_attr_is_visible, }; static const struct attribute_group *nvmem_dev_groups[] = { From f0f53369af368b7ffc8a12bff508d7c958cce8b2 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 5 Jul 2024 08:58:55 +0100 Subject: [PATCH 313/330] misc: fastrpc: Use memdup_user() Switching to memdup_user() overwrites the allocated memory only once, whereas kzalloc() followed by copy_from_user() initializes the allocated memory to zero and then immediately overwrites it. Fixes the following Coccinelle/coccicheck warning reported by memdup_user.cocci: WARNING opportunity for memdup_user Signed-off-by: Thorsten Blum Acked-by: Arnd Bergmann Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705075900.424100-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 4c67e2c5a82e..694fc083b1bd 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -1259,17 +1259,12 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, goto err; } - name = kzalloc(init.namelen, GFP_KERNEL); - if (!name) { - err = -ENOMEM; + name = memdup_user(u64_to_user_ptr(init.name), init.namelen); + if (IS_ERR(name)) { + err = PTR_ERR(name); goto err; } - if (copy_from_user(name, (void __user *)(uintptr_t)init.name, init.namelen)) { - err = -EFAULT; - goto err_name; - } - if (!fl->cctx->remote_heap) { err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen, &fl->cctx->remote_heap); From a150c68ae6369ea65b786fefd0b8aa0b075c041a Mon Sep 17 00:00:00 2001 From: Ekansh Gupta Date: Fri, 5 Jul 2024 08:58:56 +0100 Subject: [PATCH 314/330] misc: fastrpc: Add missing dev_err newlines Few dev_err calls are missing newlines. This can result in unrelated lines getting appended which might make logs difficult to understand. Add trailing newlines to avoid this. Signed-off-by: Ekansh Gupta Reviewed-by: Dmitry Baryshkov Reviewed-by: Caleb Connolly Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705075900.424100-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 694fc083b1bd..2653a193ff2f 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -325,7 +325,7 @@ static void fastrpc_free_map(struct kref *ref) err = qcom_scm_assign_mem(map->phys, map->size, &src_perms, &perm, 1); if (err) { - dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", + dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n", map->phys, map->size, err); return; } @@ -816,7 +816,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, map->attr = attr; err = qcom_scm_assign_mem(map->phys, (u64)map->size, &src_perms, dst_perms, 2); if (err) { - dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d", + dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d\n", map->phys, map->size, err); goto map_err; } @@ -1222,7 +1222,7 @@ static bool is_session_rejected(struct fastrpc_user *fl, bool unsigned_pd_reques * that does not support unsigned PD offload */ if (!fl->cctx->unsigned_support || !unsigned_pd_request) { - dev_err(&fl->cctx->rpdev->dev, "Error: Untrusted application trying to offload to signed PD"); + dev_err(&fl->cctx->rpdev->dev, "Error: Untrusted application trying to offload to signed PD\n"); return true; } } @@ -1280,7 +1280,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, &src_perms, fl->cctx->vmperms, fl->cctx->vmcount); if (err) { - dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d", + dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d\n", fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err); goto err_map; } @@ -1332,7 +1332,7 @@ err_invoke: (u64)fl->cctx->remote_heap->size, &src_perms, &dst_perms, 1); if (err) - dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", + dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n", fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err); } err_map: From 65cf378a2bec9d140f506e4f62b0128fe6659e71 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 5 Jul 2024 08:58:57 +0100 Subject: [PATCH 315/330] misc: fastrpc: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/misc/fastrpc.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Reviewed-by: Bryan O'Donoghue Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705075900.424100-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 2653a193ff2f..5fb302b8ae5d 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -2473,5 +2473,6 @@ static void fastrpc_exit(void) } module_exit(fastrpc_exit); +MODULE_DESCRIPTION("Qualcomm FastRPC"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(DMA_BUF); From c3c0363bc72d4d0907a6d446d7424b3f022ce82a Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Fri, 5 Jul 2024 08:58:58 +0100 Subject: [PATCH 316/330] misc: fastrpc: support complete DMA pool access to the DSP To support FastRPC Context Banks which aren't mapped via the SMMU, make the whole reserved memory region available to the DSP to allow access to coherent buffers. This is performed by assigning the memory to the DSP via a hypervisor call to set the correct permissions for the Virtual Machines on the DSP. This is only necessary when a memory region is provided for SLPI DSPs so guard this with a domain ID check. Signed-off-by: Dylan Van Assche Reviewed-by: Caleb Connolly Reviewed-by: Dmitry Baryshkov Reviewed-by: Ekansh Gupta Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705075900.424100-5-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 5fb302b8ae5d..1c045f9a75a4 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -2250,6 +2250,8 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) int i, err, domain_id = -1, vmcount; const char *domain; bool secure_dsp; + struct device_node *rmem_node; + struct reserved_mem *rmem; unsigned int vmids[FASTRPC_MAX_VMIDS]; err = of_property_read_string(rdev->of_node, "label", &domain); @@ -2292,6 +2294,23 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) } } + rmem_node = of_parse_phandle(rdev->of_node, "memory-region", 0); + if (domain_id == SDSP_DOMAIN_ID && rmem_node) { + u64 src_perms; + + rmem = of_reserved_mem_lookup(rmem_node); + if (!rmem) { + err = -EINVAL; + goto fdev_error; + } + + src_perms = BIT(QCOM_SCM_VMID_HLOS); + + qcom_scm_assign_mem(rmem->base, rmem->size, &src_perms, + data->vmperms, data->vmcount); + + } + secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain")); data->secure = secure_dsp; From ba2174057252b296ed73fdfa60235a9e20e807ce Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Fri, 5 Jul 2024 08:58:59 +0100 Subject: [PATCH 317/330] misc: fastrpc: use coherent pool for untranslated Compute Banks Use fastrpc_remote_heap_alloc to allocate from the FastRPC device instead of the Compute Bank when the session ID is 0. This ensures that the allocation is inside the coherent DMA pool which is already accessible to the DSP. This is necessary to support FastRPC devices which do not have dedicated Compute Banks such as the SLPI on the SDM845. The latter uses an allocated CMA region instead of FastRPC Compute Banks. Signed-off-by: Dylan Van Assche Reviewed-by: Caleb Connolly Reviewed-by: Ekansh Gupta Reviewed-by: Dmitry Baryshkov Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705075900.424100-6-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 1c045f9a75a4..95931abc3770 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -953,7 +953,10 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) ctx->msg_sz = pkt_size; - err = fastrpc_buf_alloc(ctx->fl, dev, pkt_size, &ctx->buf); + if (ctx->fl->sctx->sid) + err = fastrpc_buf_alloc(ctx->fl, dev, pkt_size, &ctx->buf); + else + err = fastrpc_remote_heap_alloc(ctx->fl, dev, pkt_size, &ctx->buf); if (err) return err; From c66c0e7c511cde3f129af4792751074905fc248a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 5 Jul 2024 08:59:00 +0100 Subject: [PATCH 318/330] MAINTAINERS: CC dri-devel list on Qualcomm FastRPC patches FastRPC is a way to offload method invocation to the DSPs on Qualcomm platforms. As the driver uses dma-bufs, add dri-devel mailing list to the MAINTAINERS's entry, so that DRM maintainers are notified about the uAPI changes. This follows the usual practice established by the "DMA BUFFER SHARING FRAMEWORK" entry in the file. Suggested-by: Bjorn Andersson Signed-off-by: Dmitry Baryshkov Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705075900.424100-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index aae88b7a6c32..06ecfa64a39a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18515,6 +18515,7 @@ QUALCOMM FASTRPC DRIVER M: Srinivas Kandagatla M: Amol Maheshwari L: linux-arm-msm@vger.kernel.org +L: dri-devel@lists.freedesktop.org S: Maintained F: Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml F: drivers/misc/fastrpc.c From f7e46d45c597fa083e266252392908f3ea0e7ef4 Mon Sep 17 00:00:00 2001 From: Amit Vadhavana Date: Fri, 5 Jul 2024 09:02:34 +0100 Subject: [PATCH 319/330] slimbus: Fix struct and documentation alignment in stream.c The placement of the `segdist_codes` array documentation was corrected to conform with kernel documentation guidelines. The `@segdist_codes` was placed incorrectly within the struct `segdist_code` documentation block, which led to a potential misinterpretation of the code structure. The `segdist_codes` array documentation was moved outside the struct block, and a separate comment block was provided for it. This change ensures that clarity and proper alignment with kernel documentation standards are maintained. A kernel-doc warning was addressed: ./drivers/slimbus/stream.c:49: warning: Excess struct member 'segdist_codes' description in 'segdist_code' Signed-off-by: Amit Vadhavana Reviewed-by: Ricardo B. Marliere Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240705080234.424587-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/stream.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/slimbus/stream.c b/drivers/slimbus/stream.c index 1d6b38657917..863ab3075d7e 100644 --- a/drivers/slimbus/stream.c +++ b/drivers/slimbus/stream.c @@ -18,15 +18,17 @@ * and the first slot of the next consecutive Segment. * @segdist_code: Segment Distribution Code SD[11:0] * @seg_offset_mask: Segment offset mask in SD[11:0] - * @segdist_codes: List of all possible Segmet Distribution codes. */ -static const struct segdist_code { +struct segdist_code { int ratem; int seg_interval; int segdist_code; u32 seg_offset_mask; -} segdist_codes[] = { +}; + +/* segdist_codes - List of all possible Segment Distribution codes. */ +static const struct segdist_code segdist_codes[] = { {1, 1536, 0x200, 0xdff}, {2, 768, 0x100, 0xcff}, {4, 384, 0x080, 0xc7f}, From e56af94b9b5487a71f8c705c83ac5f7bc28ae1a2 Mon Sep 17 00:00:00 2001 From: Gerhard Engleder Date: Mon, 8 Jul 2024 20:00:49 +0200 Subject: [PATCH 320/330] misc: keba: Fix missing AUXILIARY_BUS dependency The cp500 driver creates auxiliary devices. Kernel configs without CONFIG_AUXILIARY_BUS lead to warnings like this: cp500.c: undefined reference to `auxiliary_device_init' cp500.c: undefined reference to `__auxiliary_device_add' Add missing dependency to AUXILIARY_BUS to KEBA_CP500 Kconfig. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202407081327.2DR4Ltu9-lkp@intel.com/ Fixes: a1944676767e ("misc: keba: Add basic KEBA CP500 system FPGA support") Signed-off-by: Gerhard Engleder Link: https://lore.kernel.org/r/20240708180049.12713-1-gerhard@engleder-embedded.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/keba/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/keba/Kconfig b/drivers/misc/keba/Kconfig index 0ebca1d07ef4..5fbcbc2252ac 100644 --- a/drivers/misc/keba/Kconfig +++ b/drivers/misc/keba/Kconfig @@ -2,6 +2,7 @@ config KEBA_CP500 tristate "KEBA CP500 system FPGA support" depends on PCI + select AUXILIARY_BUS help This driver supports the KEBA CP500 system FPGA, which is used in KEBA CP500 devices. It registers all sub devices present on the CP500 From 5f67eef6dff39421215e9134f1eaae51b67a73b7 Mon Sep 17 00:00:00 2001 From: Vamsi Attunuru Date: Sat, 6 Jul 2024 08:30:09 -0700 Subject: [PATCH 321/330] misc: mrvl-cn10k-dpi: add Octeon CN10K DPI administrative driver Adds a misc driver for Marvell CN10K DPI(DMA Engine) device's physical function which initializes DPI DMA hardware's global configuration and enables hardware mailbox channels between physical function (PF) and it's virtual functions (VF). VF device drivers (User space drivers) use this hw mailbox to communicate any required device configuration on it's respective VF device. Accordingly, this DPI PF driver provisions the VF device resources. At the hardware level, the DPI physical function (PF) acts as a management interface to setup the VF device resources, VF devices are only provisioned to handle or control the actual DMA Engine's data transfer capabilities. Signed-off-by: Vamsi Attunuru Reviewed-by: Srujana Challa Link: https://lore.kernel.org/r/20240706153009.3775333-1-vattunuru@marvell.com Signed-off-by: Greg Kroah-Hartman --- Documentation/misc-devices/index.rst | 1 + Documentation/misc-devices/mrvl_cn10k_dpi.rst | 52 ++ .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 5 + drivers/misc/Kconfig | 14 + drivers/misc/Makefile | 1 + drivers/misc/Makefile.rej | 7 + drivers/misc/mrvl_cn10k_dpi.c | 676 ++++++++++++++++++ include/uapi/misc/mrvl_cn10k_dpi.h | 39 + 9 files changed, 796 insertions(+) create mode 100644 Documentation/misc-devices/mrvl_cn10k_dpi.rst create mode 100644 drivers/misc/Makefile.rej create mode 100644 drivers/misc/mrvl_cn10k_dpi.c create mode 100644 include/uapi/misc/mrvl_cn10k_dpi.h diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index 2d0ce9138588..8c5b226d8313 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -21,6 +21,7 @@ fit into other categories. isl29003 lis3lv02d max6875 + mrvl_cn10k_dpi oxsemi-tornado pci-endpoint-test spear-pcie-gadget diff --git a/Documentation/misc-devices/mrvl_cn10k_dpi.rst b/Documentation/misc-devices/mrvl_cn10k_dpi.rst new file mode 100644 index 000000000000..a75e372723d8 --- /dev/null +++ b/Documentation/misc-devices/mrvl_cn10k_dpi.rst @@ -0,0 +1,52 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============================================== +Marvell CN10K DMA packet interface (DPI) driver +=============================================== + +Overview +======== + +DPI is a DMA packet interface hardware block in Marvell's CN10K silicon. +DPI hardware comprises a physical function (PF), its virtual functions, +mailbox logic, and a set of DMA engines & DMA command queues. + +DPI PF function is an administrative function which services the mailbox +requests from its VF functions and provisions DMA engine resources to +it's VF functions. + +mrvl_cn10k_dpi.ko misc driver loads on DPI PF device and services the +mailbox commands submitted by the VF devices and accordingly initializes +the DMA engines and VF device's DMA command queues. Also, driver creates +/dev/mrvl-cn10k-dpi node to set DMA engine and PEM (PCIe interface) port +attributes like fifo length, molr, mps & mrrs. + +DPI PF driver is just an administrative driver to setup its VF device's +queues and provisions the hardware resources, it cannot initiate any +DMA operations. Only VF devices are provisioned with DMA capabilities. + +Driver location +=============== + +drivers/misc/mrvl_cn10k_dpi.c + +Driver IOCTLs +============= + +:c:macro::`DPI_MPS_MRRS_CFG` +ioctl that sets max payload size & max read request size parameters of +a pem port to which DMA engines are wired. + + +:c:macro::`DPI_ENGINE_CFG` +ioctl that sets DMA engine's fifo sizes & max outstanding load request +thresholds. + +User space code example +======================= + +DPI VF devices are probed and accessed from user space applications using +vfio-pci driver. Below is a sample dpi dma application to demonstrate on +how applications use mailbox and ioctl services from DPI PF kernel driver. + +https://github.com/MarvellEmbeddedProcessors/dpi-sample-app diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index a141e8e65c5d..def539770439 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -362,6 +362,7 @@ Code Seq# Include File Comments 0xB6 all linux/fpga-dfl.h 0xB7 all uapi/linux/remoteproc_cdev.h 0xB7 all uapi/linux/nsfs.h > +0xB8 01-02 uapi/misc/mrvl_cn10k_dpi.h Marvell CN10K DPI driver 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h 0xCA 10-2F uapi/misc/ocxl.h diff --git a/MAINTAINERS b/MAINTAINERS index 06ecfa64a39a..4174d2869e7e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13477,6 +13477,11 @@ S: Supported F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml F: drivers/mmc/host/sdhci-xenon* +MARVELL OCTEON CN10K DPI DRIVER +M: Vamsi Attunuru +S: Supported +F: drivers/misc/mrvl_cn10k_dpi.c + MATROX FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org S: Orphan diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ca0c6a728a00..64fcca9e44d7 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -585,6 +585,20 @@ config NSM To compile this driver as a module, choose M here. The module will be called nsm. +config MARVELL_CN10K_DPI + tristate "Octeon CN10K DPI driver" + depends on PCI + help + Enables Octeon CN10K DMA packet interface (DPI) driver which + intializes DPI hardware's physical function (PF) device's + global configuration and its virtual function (VFs) resource + configuration to enable DMA transfers. DPI PF device does not + have any data movement functionality, it only serves VF's + resource configuration requests. + + To compile this driver as a module, choose M here: the module + will be called mrvl_cn10k_dpi. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index af125aa25a50..c2f990862d2b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -69,4 +69,5 @@ obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o obj-$(CONFIG_NSM) += nsm.o +obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o obj-y += keba/ diff --git a/drivers/misc/Makefile.rej b/drivers/misc/Makefile.rej new file mode 100644 index 000000000000..a6aaed13f950 --- /dev/null +++ b/drivers/misc/Makefile.rej @@ -0,0 +1,7 @@ +--- drivers/misc/Makefile ++++ drivers/misc/Makefile +@@ -69,3 +69,4 @@ obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o + obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o + obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o + obj-$(CONFIG_NSM) += nsm.o ++obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o diff --git a/drivers/misc/mrvl_cn10k_dpi.c b/drivers/misc/mrvl_cn10k_dpi.c new file mode 100644 index 000000000000..7d5433121ff6 --- /dev/null +++ b/drivers/misc/mrvl_cn10k_dpi.c @@ -0,0 +1,676 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell Octeon CN10K DPI driver + * + * Copyright (C) 2024 Marvell. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* PCI device IDs */ +#define PCI_DEVID_MRVL_CN10K_DPI_PF 0xA080 +#define PCI_SUBDEVID_MRVL_CN10K_DPI_PF 0xB900 + +/* PCI BAR Number */ +#define PCI_DPI_CFG_BAR 0 + +/* MSI-X interrupts */ +#define DPI_MAX_REQQ_INT 0x20 +#define DPI_MAX_CC_INT 0x40 + +/* MBOX MSI-X interrupt vector index */ +#define DPI_MBOX_PF_VF_INT_IDX 0x75 + +#define DPI_MAX_IRQS (DPI_MBOX_PF_VF_INT_IDX + 1) + +#define DPI_MAX_VFS 0x20 + +#define DPI_MAX_ENG_FIFO_SZ 0x20 +#define DPI_MAX_ENG_MOLR 0x400 + +#define DPI_DMA_IDS_DMA_NPA_PF_FUNC(x) FIELD_PREP(GENMASK_ULL(31, 16), x) +#define DPI_DMA_IDS_INST_STRM(x) FIELD_PREP(GENMASK_ULL(47, 40), x) +#define DPI_DMA_IDS_DMA_STRM(x) FIELD_PREP(GENMASK_ULL(39, 32), x) +#define DPI_DMA_ENG_EN_MOLR(x) FIELD_PREP(GENMASK_ULL(41, 32), x) +#define DPI_EBUS_PORTX_CFG_MPS(x) FIELD_PREP(GENMASK(6, 4), x) +#define DPI_DMA_IDS_DMA_SSO_PF_FUNC(x) FIELD_PREP(GENMASK(15, 0), x) +#define DPI_DMA_IDS2_INST_AURA(x) FIELD_PREP(GENMASK(19, 0), x) +#define DPI_DMA_IBUFF_CSIZE_CSIZE(x) FIELD_PREP(GENMASK(13, 0), x) +#define DPI_EBUS_PORTX_CFG_MRRS(x) FIELD_PREP(GENMASK(2, 0), x) +#define DPI_ENG_BUF_BLKS(x) FIELD_PREP(GENMASK(5, 0), x) +#define DPI_DMA_CONTROL_DMA_ENB GENMASK_ULL(53, 48) + +#define DPI_DMA_CONTROL_O_MODE BIT_ULL(14) +#define DPI_DMA_CONTROL_LDWB BIT_ULL(32) +#define DPI_DMA_CONTROL_WQECSMODE1 BIT_ULL(37) +#define DPI_DMA_CONTROL_ZBWCSEN BIT_ULL(39) +#define DPI_DMA_CONTROL_WQECSOFF(ofst) (((u64)ofst) << 40) +#define DPI_DMA_CONTROL_WQECSDIS BIT_ULL(47) +#define DPI_DMA_CONTROL_PKT_EN BIT_ULL(56) +#define DPI_DMA_IBUFF_CSIZE_NPA_FREE BIT(16) + +#define DPI_CTL_EN BIT_ULL(0) +#define DPI_DMA_CC_INT BIT_ULL(0) +#define DPI_DMA_QRST BIT_ULL(0) + +#define DPI_REQQ_INT_INSTRFLT BIT_ULL(0) +#define DPI_REQQ_INT_RDFLT BIT_ULL(1) +#define DPI_REQQ_INT_WRFLT BIT_ULL(2) +#define DPI_REQQ_INT_CSFLT BIT_ULL(3) +#define DPI_REQQ_INT_INST_DBO BIT_ULL(4) +#define DPI_REQQ_INT_INST_ADDR_NULL BIT_ULL(5) +#define DPI_REQQ_INT_INST_FILL_INVAL BIT_ULL(6) +#define DPI_REQQ_INT_INSTR_PSN BIT_ULL(7) + +#define DPI_REQQ_INT \ + (DPI_REQQ_INT_INSTRFLT | \ + DPI_REQQ_INT_RDFLT | \ + DPI_REQQ_INT_WRFLT | \ + DPI_REQQ_INT_CSFLT | \ + DPI_REQQ_INT_INST_DBO | \ + DPI_REQQ_INT_INST_ADDR_NULL | \ + DPI_REQQ_INT_INST_FILL_INVAL | \ + DPI_REQQ_INT_INSTR_PSN) + +#define DPI_PF_RAS_EBI_DAT_PSN BIT_ULL(0) +#define DPI_PF_RAS_NCB_DAT_PSN BIT_ULL(1) +#define DPI_PF_RAS_NCB_CMD_PSN BIT_ULL(2) + +#define DPI_PF_RAS_INT \ + (DPI_PF_RAS_EBI_DAT_PSN | \ + DPI_PF_RAS_NCB_DAT_PSN | \ + DPI_PF_RAS_NCB_CMD_PSN) + +/* Message fields in word_l of DPI mailbox structure */ +#define DPI_MBOX_VFID(msg) FIELD_GET(GENMASK_ULL(7, 0), msg) +#define DPI_MBOX_CMD(msg) FIELD_GET(GENMASK_ULL(11, 8), msg) +#define DPI_MBOX_CBUF_SIZE(msg) FIELD_GET(GENMASK_ULL(27, 12), msg) +#define DPI_MBOX_CBUF_AURA(msg) FIELD_GET(GENMASK_ULL(47, 28), msg) +#define DPI_MBOX_SSO_PFFUNC(msg) FIELD_GET(GENMASK_ULL(63, 48), msg) + +/* Message fields in word_h of DPI mailbox structure */ +#define DPI_MBOX_NPA_PFFUNC(msg) FIELD_GET(GENMASK_ULL(15, 0), msg) +#define DPI_MBOX_WQES_COMPL(msg) FIELD_GET(GENMASK_ULL(16, 16), msg) +#define DPI_MBOX_WQES_OFFSET(msg) FIELD_GET(GENMASK_ULL(23, 17), msg) + +#define DPI_DMAX_IBUFF_CSIZE(x) (0x0ULL | ((x) << 11)) +#define DPI_DMAX_IDS(x) (0x18ULL | ((x) << 11)) +#define DPI_DMAX_IDS2(x) (0x20ULL | ((x) << 11)) +#define DPI_DMAX_QRST(x) (0x30ULL | ((x) << 11)) + +#define DPI_CTL 0x10010ULL +#define DPI_DMA_CONTROL 0x10018ULL +#define DPI_PF_RAS 0x10308ULL +#define DPI_PF_RAS_ENA_W1C 0x10318ULL +#define DPI_MBOX_VF_PF_INT 0x16300ULL +#define DPI_MBOX_VF_PF_INT_W1S 0x16308ULL +#define DPI_MBOX_VF_PF_INT_ENA_W1C 0x16310ULL +#define DPI_MBOX_VF_PF_INT_ENA_W1S 0x16318ULL + +#define DPI_DMA_ENGX_EN(x) (0x10040ULL | ((x) << 3)) +#define DPI_ENGX_BUF(x) (0x100C0ULL | ((x) << 3)) +#define DPI_EBUS_PORTX_CFG(x) (0x10100ULL | ((x) << 3)) +#define DPI_DMA_CCX_INT(x) (0x11000ULL | ((x) << 3)) +#define DPI_DMA_CCX_INT_ENA_W1C(x) (0x11800ULL | ((x) << 3)) +#define DPI_REQQX_INT(x) (0x12C00ULL | ((x) << 5)) +#define DPI_REQQX_INT_ENA_W1C(x) (0x13800ULL | ((x) << 5)) +#define DPI_MBOX_PF_VF_DATA0(x) (0x16000ULL | ((x) << 4)) +#define DPI_MBOX_PF_VF_DATA1(x) (0x16008ULL | ((x) << 4)) + +#define DPI_WCTL_FIF_THR 0x17008ULL + +#define DPI_EBUS_MAX_PORTS 2 + +#define DPI_EBUS_MRRS_MIN 128 +#define DPI_EBUS_MRRS_MAX 1024 +#define DPI_EBUS_MPS_MIN 128 +#define DPI_EBUS_MPS_MAX 1024 +#define DPI_WCTL_FIFO_THRESHOLD 0x30 + +#define DPI_QUEUE_OPEN 0x1 +#define DPI_QUEUE_CLOSE 0x2 +#define DPI_REG_DUMP 0x3 +#define DPI_GET_REG_CFG 0x4 +#define DPI_QUEUE_OPEN_V2 0x5 + +enum dpi_mbox_rsp_type { + DPI_MBOX_TYPE_CMD, + DPI_MBOX_TYPE_RSP_ACK, + DPI_MBOX_TYPE_RSP_NACK, +}; + +struct dpivf_config { + u32 aura; + u16 csize; + u16 sso_pf_func; + u16 npa_pf_func; +}; + +struct dpipf_vf { + struct dpivf_config vf_config; + bool setup_done; + u8 this_vfid; +}; + +/* DPI device mailbox */ +struct dpi_mbox { + struct work_struct work; + /* lock to serialize mbox requests */ + struct mutex lock; + struct dpipf *pf; + u8 __iomem *pf_vf_data_reg; + u8 __iomem *vf_pf_data_reg; +}; + +struct dpipf { + struct miscdevice miscdev; + void __iomem *reg_base; + struct pci_dev *pdev; + struct dpipf_vf vf[DPI_MAX_VFS]; + /* Mailbox to talk to VFs */ + struct dpi_mbox *mbox[DPI_MAX_VFS]; +}; + +struct dpi_mbox_message { + uint64_t word_l; + uint64_t word_h; +}; + +static inline void dpi_reg_write(struct dpipf *dpi, u64 offset, u64 val) +{ + writeq(val, dpi->reg_base + offset); +} + +static inline u64 dpi_reg_read(struct dpipf *dpi, u64 offset) +{ + return readq(dpi->reg_base + offset); +} + +static void dpi_wqe_cs_offset(struct dpipf *dpi, u8 offset) +{ + u64 reg; + + reg = dpi_reg_read(dpi, DPI_DMA_CONTROL); + reg &= ~DPI_DMA_CONTROL_WQECSDIS; + reg |= DPI_DMA_CONTROL_ZBWCSEN | DPI_DMA_CONTROL_WQECSMODE1; + reg |= DPI_DMA_CONTROL_WQECSOFF(offset); + dpi_reg_write(dpi, DPI_DMA_CONTROL, reg); +} + +static int dpi_queue_init(struct dpipf *dpi, struct dpipf_vf *dpivf, u8 vf) +{ + u16 sso_pf_func = dpivf->vf_config.sso_pf_func; + u16 npa_pf_func = dpivf->vf_config.npa_pf_func; + u16 csize = dpivf->vf_config.csize; + u32 aura = dpivf->vf_config.aura; + unsigned long timeout; + u64 reg; + + dpi_reg_write(dpi, DPI_DMAX_QRST(vf), DPI_DMA_QRST); + + /* Wait for a maximum of 3 sec */ + timeout = jiffies + msecs_to_jiffies(3000); + while (!time_after(jiffies, timeout)) { + reg = dpi_reg_read(dpi, DPI_DMAX_QRST(vf)); + if (!(reg & DPI_DMA_QRST)) + break; + + /* Reset would take time for the request cache to drain */ + usleep_range(500, 1000); + } + + if (reg & DPI_DMA_QRST) { + dev_err(&dpi->pdev->dev, "Queue reset failed\n"); + return -EBUSY; + } + + dpi_reg_write(dpi, DPI_DMAX_IDS2(vf), 0); + dpi_reg_write(dpi, DPI_DMAX_IDS(vf), 0); + + reg = DPI_DMA_IBUFF_CSIZE_CSIZE(csize) | DPI_DMA_IBUFF_CSIZE_NPA_FREE; + dpi_reg_write(dpi, DPI_DMAX_IBUFF_CSIZE(vf), reg); + + reg = dpi_reg_read(dpi, DPI_DMAX_IDS2(vf)); + reg |= DPI_DMA_IDS2_INST_AURA(aura); + dpi_reg_write(dpi, DPI_DMAX_IDS2(vf), reg); + + reg = dpi_reg_read(dpi, DPI_DMAX_IDS(vf)); + reg |= DPI_DMA_IDS_DMA_NPA_PF_FUNC(npa_pf_func); + reg |= DPI_DMA_IDS_DMA_SSO_PF_FUNC(sso_pf_func); + reg |= DPI_DMA_IDS_DMA_STRM(vf + 1); + reg |= DPI_DMA_IDS_INST_STRM(vf + 1); + dpi_reg_write(dpi, DPI_DMAX_IDS(vf), reg); + + return 0; +} + +static void dpi_queue_fini(struct dpipf *dpi, u8 vf) +{ + dpi_reg_write(dpi, DPI_DMAX_QRST(vf), DPI_DMA_QRST); + + /* Reset IDS and IDS2 registers */ + dpi_reg_write(dpi, DPI_DMAX_IDS2(vf), 0); + dpi_reg_write(dpi, DPI_DMAX_IDS(vf), 0); +} + +static irqreturn_t dpi_mbox_intr_handler(int irq, void *data) +{ + struct dpipf *dpi = data; + u64 reg; + u32 vf; + + reg = dpi_reg_read(dpi, DPI_MBOX_VF_PF_INT); + if (reg) { + for (vf = 0; vf < pci_num_vf(dpi->pdev); vf++) { + if (reg & BIT_ULL(vf)) + schedule_work(&dpi->mbox[vf]->work); + } + dpi_reg_write(dpi, DPI_MBOX_VF_PF_INT, reg); + } + + return IRQ_HANDLED; +} + +static int queue_config(struct dpipf *dpi, struct dpipf_vf *dpivf, struct dpi_mbox_message *msg) +{ + int ret = 0; + + switch (DPI_MBOX_CMD(msg->word_l)) { + case DPI_QUEUE_OPEN: + case DPI_QUEUE_OPEN_V2: + dpivf->vf_config.aura = DPI_MBOX_CBUF_AURA(msg->word_l); + dpivf->vf_config.csize = DPI_MBOX_CMD(msg->word_l) == DPI_QUEUE_OPEN ? + DPI_MBOX_CBUF_SIZE(msg->word_l) >> 3 : + DPI_MBOX_CBUF_SIZE(msg->word_l); + dpivf->vf_config.sso_pf_func = DPI_MBOX_SSO_PFFUNC(msg->word_l); + dpivf->vf_config.npa_pf_func = DPI_MBOX_NPA_PFFUNC(msg->word_h); + ret = dpi_queue_init(dpi, dpivf, DPI_MBOX_VFID(msg->word_l)); + if (!ret) { + if (DPI_MBOX_WQES_COMPL(msg->word_h)) + dpi_wqe_cs_offset(dpi, DPI_MBOX_WQES_OFFSET(msg->word_h)); + dpivf->setup_done = true; + } + break; + case DPI_QUEUE_CLOSE: + memset(&dpivf->vf_config, 0, sizeof(struct dpivf_config)); + dpi_queue_fini(dpi, DPI_MBOX_VFID(msg->word_l)); + dpivf->setup_done = false; + break; + default: + return -EINVAL; + } + + return ret; +} + +static void dpi_pfvf_mbox_work(struct work_struct *work) +{ + struct dpi_mbox *mbox = container_of(work, struct dpi_mbox, work); + struct dpi_mbox_message msg; + struct dpipf_vf *dpivf; + struct dpipf *dpi; + int vfid, ret; + + dpi = mbox->pf; + memset(&msg, 0, sizeof(msg)); + + mutex_lock(&mbox->lock); + msg.word_l = readq(mbox->vf_pf_data_reg); + if (msg.word_l == (u64)-1) + goto exit; + + vfid = DPI_MBOX_VFID(msg.word_l); + if (vfid >= pci_num_vf(dpi->pdev)) + goto exit; + + dpivf = &dpi->vf[vfid]; + msg.word_h = readq(mbox->pf_vf_data_reg); + + ret = queue_config(dpi, dpivf, &msg); + if (ret < 0) + writeq(DPI_MBOX_TYPE_RSP_NACK, mbox->pf_vf_data_reg); + else + writeq(DPI_MBOX_TYPE_RSP_ACK, mbox->pf_vf_data_reg); +exit: + mutex_unlock(&mbox->lock); +} + +/* Setup registers for a PF mailbox */ +static void dpi_setup_mbox_regs(struct dpipf *dpi, int vf) +{ + struct dpi_mbox *mbox = dpi->mbox[vf]; + + mbox->pf_vf_data_reg = dpi->reg_base + DPI_MBOX_PF_VF_DATA0(vf); + mbox->vf_pf_data_reg = dpi->reg_base + DPI_MBOX_PF_VF_DATA1(vf); +} + +static int dpi_pfvf_mbox_setup(struct dpipf *dpi) +{ + int vf; + + for (vf = 0; vf < DPI_MAX_VFS; vf++) { + dpi->mbox[vf] = devm_kzalloc(&dpi->pdev->dev, sizeof(*dpi->mbox[vf]), GFP_KERNEL); + + if (!dpi->mbox[vf]) + return -ENOMEM; + + mutex_init(&dpi->mbox[vf]->lock); + INIT_WORK(&dpi->mbox[vf]->work, dpi_pfvf_mbox_work); + dpi->mbox[vf]->pf = dpi; + dpi_setup_mbox_regs(dpi, vf); + } + + return 0; +} + +static void dpi_pfvf_mbox_destroy(struct dpipf *dpi) +{ + unsigned int vf; + + for (vf = 0; vf < DPI_MAX_VFS; vf++) { + if (work_pending(&dpi->mbox[vf]->work)) + cancel_work_sync(&dpi->mbox[vf]->work); + + dpi->mbox[vf] = NULL; + } +} + +static void dpi_init(struct dpipf *dpi) +{ + unsigned int engine, port; + u8 mrrs_val, mps_val; + u64 reg; + + for (engine = 0; engine < DPI_MAX_ENGINES; engine++) { + if (engine == 4 || engine == 5) + reg = DPI_ENG_BUF_BLKS(16); + else + reg = DPI_ENG_BUF_BLKS(8); + + dpi_reg_write(dpi, DPI_ENGX_BUF(engine), reg); + } + + reg = DPI_DMA_CONTROL_ZBWCSEN | DPI_DMA_CONTROL_PKT_EN | DPI_DMA_CONTROL_LDWB | + DPI_DMA_CONTROL_O_MODE | DPI_DMA_CONTROL_DMA_ENB; + + dpi_reg_write(dpi, DPI_DMA_CONTROL, reg); + dpi_reg_write(dpi, DPI_CTL, DPI_CTL_EN); + + mrrs_val = 2; /* 512B */ + mps_val = 1; /* 256B */ + + for (port = 0; port < DPI_EBUS_MAX_PORTS; port++) { + reg = dpi_reg_read(dpi, DPI_EBUS_PORTX_CFG(port)); + reg &= ~(DPI_EBUS_PORTX_CFG_MRRS(7) | DPI_EBUS_PORTX_CFG_MPS(7)); + reg |= DPI_EBUS_PORTX_CFG_MPS(mps_val) | DPI_EBUS_PORTX_CFG_MRRS(mrrs_val); + dpi_reg_write(dpi, DPI_EBUS_PORTX_CFG(port), reg); + } + + dpi_reg_write(dpi, DPI_WCTL_FIF_THR, DPI_WCTL_FIFO_THRESHOLD); +} + +static void dpi_fini(struct dpipf *dpi) +{ + unsigned int engine; + + for (engine = 0; engine < DPI_MAX_ENGINES; engine++) + dpi_reg_write(dpi, DPI_ENGX_BUF(engine), 0); + + dpi_reg_write(dpi, DPI_DMA_CONTROL, 0); + dpi_reg_write(dpi, DPI_CTL, 0); +} + +static void dpi_free_irq_vectors(void *pdev) +{ + pci_free_irq_vectors((struct pci_dev *)pdev); +} + +static int dpi_irq_init(struct dpipf *dpi) +{ + struct pci_dev *pdev = dpi->pdev; + struct device *dev = &pdev->dev; + int i, ret; + + /* Clear all RAS interrupts */ + dpi_reg_write(dpi, DPI_PF_RAS, DPI_PF_RAS_INT); + + /* Clear all RAS interrupt enable bits */ + dpi_reg_write(dpi, DPI_PF_RAS_ENA_W1C, DPI_PF_RAS_INT); + + for (i = 0; i < DPI_MAX_REQQ_INT; i++) { + dpi_reg_write(dpi, DPI_REQQX_INT(i), DPI_REQQ_INT); + dpi_reg_write(dpi, DPI_REQQX_INT_ENA_W1C(i), DPI_REQQ_INT); + } + + for (i = 0; i < DPI_MAX_CC_INT; i++) { + dpi_reg_write(dpi, DPI_DMA_CCX_INT(i), DPI_DMA_CC_INT); + dpi_reg_write(dpi, DPI_DMA_CCX_INT_ENA_W1C(i), DPI_DMA_CC_INT); + } + + ret = pci_alloc_irq_vectors(pdev, DPI_MAX_IRQS, DPI_MAX_IRQS, PCI_IRQ_MSIX); + if (ret != DPI_MAX_IRQS) { + dev_err(dev, "DPI: Failed to alloc %d msix irqs\n", DPI_MAX_IRQS); + return ret; + } + + ret = devm_add_action_or_reset(dev, dpi_free_irq_vectors, pdev); + if (ret) { + dev_err(dev, "DPI: Failed to add irq free action\n"); + return ret; + } + + ret = devm_request_irq(dev, pci_irq_vector(pdev, DPI_MBOX_PF_VF_INT_IDX), + dpi_mbox_intr_handler, 0, "dpi-mbox", dpi); + if (ret) { + dev_err(dev, "DPI: request_irq failed for mbox; err=%d\n", ret); + return ret; + } + + dpi_reg_write(dpi, DPI_MBOX_VF_PF_INT_ENA_W1S, GENMASK_ULL(31, 0)); + + return 0; +} + +static int dpi_mps_mrrs_config(struct dpipf *dpi, void __user *arg) +{ + struct dpi_mps_mrrs_cfg cfg; + u8 mrrs_val, mps_val; + u64 reg; + + if (copy_from_user(&cfg, arg, sizeof(struct dpi_mps_mrrs_cfg))) + return -EFAULT; + + if (cfg.max_read_req_sz < DPI_EBUS_MRRS_MIN || cfg.max_read_req_sz > DPI_EBUS_MRRS_MAX || + !is_power_of_2(cfg.max_read_req_sz)) + return -EINVAL; + + if (cfg.max_payload_sz < DPI_EBUS_MPS_MIN || cfg.max_payload_sz > DPI_EBUS_MPS_MAX || + !is_power_of_2(cfg.max_payload_sz)) + return -EINVAL; + + if (cfg.port >= DPI_EBUS_MAX_PORTS) + return -EINVAL; + + /* Make sure reserved fields are set to 0 */ + if (cfg.reserved) + return -EINVAL; + + mrrs_val = fls(cfg.max_read_req_sz >> 8); + mps_val = fls(cfg.max_payload_sz >> 8); + + reg = dpi_reg_read(dpi, DPI_EBUS_PORTX_CFG(cfg.port)); + reg &= ~(DPI_EBUS_PORTX_CFG_MRRS(0x7) | DPI_EBUS_PORTX_CFG_MPS(0x7)); + reg |= DPI_EBUS_PORTX_CFG_MPS(mps_val) | DPI_EBUS_PORTX_CFG_MRRS(mrrs_val); + dpi_reg_write(dpi, DPI_EBUS_PORTX_CFG(cfg.port), reg); + + return 0; +} + +static int dpi_engine_config(struct dpipf *dpi, void __user *arg) +{ + struct dpi_engine_cfg cfg; + unsigned int engine; + u8 *eng_buf; + u64 reg; + + if (copy_from_user(&cfg, arg, sizeof(struct dpi_engine_cfg))) + return -EFAULT; + + /* Make sure reserved fields are set to 0 */ + if (cfg.reserved) + return -EINVAL; + + eng_buf = (u8 *)&cfg.fifo_mask; + + for (engine = 0; engine < DPI_MAX_ENGINES; engine++) { + if (eng_buf[engine] > DPI_MAX_ENG_FIFO_SZ) + return -EINVAL; + dpi_reg_write(dpi, DPI_ENGX_BUF(engine), eng_buf[engine]); + + if (cfg.update_molr) { + if (cfg.molr[engine] > DPI_MAX_ENG_MOLR) + return -EINVAL; + reg = DPI_DMA_ENG_EN_MOLR(cfg.molr[engine]); + dpi_reg_write(dpi, DPI_DMA_ENGX_EN(engine), reg); + } else { + /* Make sure unused fields are set to 0 */ + if (cfg.molr[engine]) + return -EINVAL; + } + } + + return 0; +} + +static long dpi_dev_ioctl(struct file *fptr, unsigned int cmd, unsigned long data) +{ + void __user *arg = (void __user *)data; + struct dpipf *dpi; + int ret; + + dpi = container_of(fptr->private_data, struct dpipf, miscdev); + + switch (cmd) { + case DPI_MPS_MRRS_CFG: + ret = dpi_mps_mrrs_config(dpi, arg); + break; + case DPI_ENGINE_CFG: + ret = dpi_engine_config(dpi, arg); + break; + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +static const struct file_operations dpi_device_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dpi_dev_ioctl, + .compat_ioctl = compat_ptr_ioctl, +}; + +static int dpi_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct dpipf *dpi; + int ret; + + dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); + if (!dpi) + return -ENOMEM; + + dpi->pdev = pdev; + + ret = pcim_enable_device(pdev); + if (ret) { + dev_err(dev, "DPI: Failed to enable PCI device\n"); + return ret; + } + + ret = pcim_iomap_regions(pdev, BIT(0) | BIT(4), KBUILD_MODNAME); + if (ret) { + dev_err(dev, "DPI: Failed to request MMIO region\n"); + return ret; + } + + dpi->reg_base = pcim_iomap_table(pdev)[PCI_DPI_CFG_BAR]; + + /* Initialize global PF registers */ + dpi_init(dpi); + + /* Setup PF-VF mailbox */ + ret = dpi_pfvf_mbox_setup(dpi); + if (ret) { + dev_err(dev, "DPI: Failed to setup pf-vf mbox\n"); + goto err_dpi_fini; + } + + /* Register interrupts */ + ret = dpi_irq_init(dpi); + if (ret) { + dev_err(dev, "DPI: Failed to initialize irq vectors\n"); + goto err_dpi_mbox_free; + } + + pci_set_drvdata(pdev, dpi); + dpi->miscdev.minor = MISC_DYNAMIC_MINOR; + dpi->miscdev.name = KBUILD_MODNAME; + dpi->miscdev.fops = &dpi_device_fops; + dpi->miscdev.parent = dev; + + ret = misc_register(&dpi->miscdev); + if (ret) { + dev_err(dev, "DPI: Failed to register misc device\n"); + goto err_dpi_mbox_free; + } + + return 0; + +err_dpi_mbox_free: + dpi_pfvf_mbox_destroy(dpi); +err_dpi_fini: + dpi_fini(dpi); + return ret; +} + +static void dpi_remove(struct pci_dev *pdev) +{ + struct dpipf *dpi = pci_get_drvdata(pdev); + + misc_deregister(&dpi->miscdev); + pci_sriov_configure_simple(pdev, 0); + dpi_pfvf_mbox_destroy(dpi); + dpi_fini(dpi); + pci_set_drvdata(pdev, NULL); +} + +static const struct pci_device_id dpi_id_table[] = { + { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_MRVL_CN10K_DPI_PF, + PCI_VENDOR_ID_CAVIUM, PCI_SUBDEVID_MRVL_CN10K_DPI_PF) }, + { 0, } /* end of table */ +}; + +static struct pci_driver dpi_driver = { + .name = KBUILD_MODNAME, + .id_table = dpi_id_table, + .probe = dpi_probe, + .remove = dpi_remove, + .sriov_configure = pci_sriov_configure_simple, +}; + +module_pci_driver(dpi_driver); +MODULE_DEVICE_TABLE(pci, dpi_id_table); +MODULE_AUTHOR("Marvell."); +MODULE_DESCRIPTION("Marvell Octeon CN10K DPI Driver"); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/misc/mrvl_cn10k_dpi.h b/include/uapi/misc/mrvl_cn10k_dpi.h new file mode 100644 index 000000000000..8db902eaa907 --- /dev/null +++ b/include/uapi/misc/mrvl_cn10k_dpi.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Marvell Octeon CN10K DPI driver + * + * Copyright (C) 2024 Marvell. + * + */ + +#ifndef __MRVL_CN10K_DPI_H__ +#define __MRVL_CN10K_DPI_H__ + +#include + +#define DPI_MAX_ENGINES 6 + +struct dpi_mps_mrrs_cfg { + __u16 max_read_req_sz; /* Max read request size */ + __u16 max_payload_sz; /* Max payload size */ + __u16 port; /* Ebus port */ + __u16 reserved; /* Reserved */ +}; + +struct dpi_engine_cfg { + __u64 fifo_mask; /* FIFO size mask in KBytes */ + __u16 molr[DPI_MAX_ENGINES]; /* Max outstanding load requests */ + __u16 update_molr; /* '1' to update engine MOLR */ + __u16 reserved; /* Reserved */ +}; + +/* DPI ioctl numbers */ +#define DPI_MAGIC_NUM 0xB8 + +/* Set MPS & MRRS parameters */ +#define DPI_MPS_MRRS_CFG _IOW(DPI_MAGIC_NUM, 1, struct dpi_mps_mrrs_cfg) + +/* Set Engine FIFO configuration */ +#define DPI_ENGINE_CFG _IOW(DPI_MAGIC_NUM, 2, struct dpi_engine_cfg) + +#endif /* __MRVL_CN10K_DPI_H__ */ From feb1f0cba17a05c145cbe9dcf6c4736990e106d7 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 1 Jun 2024 17:12:01 -0700 Subject: [PATCH 322/330] samples: configfs: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in samples/configfs/configfs_sample.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Nacked-by: Christoph Hellwig Link: https://lore.kernel.org/r/20240601-md-samples-configfs-v1-1-83ef2d3c0088@quicinc.com Signed-off-by: Greg Kroah-Hartman --- samples/configfs/configfs_sample.c | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/configfs/configfs_sample.c b/samples/configfs/configfs_sample.c index 37a657b25d58..fd5d163828c5 100644 --- a/samples/configfs/configfs_sample.c +++ b/samples/configfs/configfs_sample.c @@ -364,4 +364,5 @@ static void __exit configfs_example_exit(void) module_init(configfs_example_init); module_exit(configfs_example_exit); +MODULE_DESCRIPTION("Sample configfs module"); MODULE_LICENSE("GPL"); From ab11dac93d2d568d151b1918d7b84c2d02bacbd5 Mon Sep 17 00:00:00 2001 From: tuhaowen Date: Mon, 8 Jul 2024 16:04:30 +0800 Subject: [PATCH 323/330] dev/parport: fix the array out-of-bounds risk Fixed array out-of-bounds issues caused by sprintf by replacing it with snprintf for safer data copying, ensuring the destination buffer is not overflowed. Below is the stack trace I encountered during the actual issue: [ 66.575408s] [pid:5118,cpu4,QThread,4]Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: do_hardware_base_addr+0xcc/0xd0 [parport] [ 66.575408s] [pid:5118,cpu4,QThread,5]CPU: 4 PID: 5118 Comm: QThread Tainted: G S W O 5.10.97-arm64-desktop #7100.57021.2 [ 66.575439s] [pid:5118,cpu4,QThread,6]TGID: 5087 Comm: EFileApp [ 66.575439s] [pid:5118,cpu4,QThread,7]Hardware name: HUAWEI HUAWEI QingYun PGUX-W515x-B081/SP1PANGUXM, BIOS 1.00.07 04/29/2024 [ 66.575439s] [pid:5118,cpu4,QThread,8]Call trace: [ 66.575469s] [pid:5118,cpu4,QThread,9] dump_backtrace+0x0/0x1c0 [ 66.575469s] [pid:5118,cpu4,QThread,0] show_stack+0x14/0x20 [ 66.575469s] [pid:5118,cpu4,QThread,1] dump_stack+0xd4/0x10c [ 66.575500s] [pid:5118,cpu4,QThread,2] panic+0x1d8/0x3bc [ 66.575500s] [pid:5118,cpu4,QThread,3] __stack_chk_fail+0x2c/0x38 [ 66.575500s] [pid:5118,cpu4,QThread,4] do_hardware_base_addr+0xcc/0xd0 [parport] Signed-off-by: tuhaowen Cc: stable Link: https://lore.kernel.org/r/20240708080430.8221-1-tuhaowen@uniontech.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/procfs.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index bd388560ed59..c2e371c50dcf 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c @@ -51,12 +51,12 @@ static int do_active_device(struct ctl_table *table, int write, for (dev = port->devices; dev ; dev = dev->next) { if(dev == port->cad) { - len += sprintf(buffer, "%s\n", dev->name); + len += snprintf(buffer, sizeof(buffer), "%s\n", dev->name); } } if(!len) { - len += sprintf(buffer, "%s\n", "none"); + len += snprintf(buffer, sizeof(buffer), "%s\n", "none"); } if (len > *lenp) @@ -87,19 +87,19 @@ static int do_autoprobe(struct ctl_table *table, int write, } if ((str = info->class_name) != NULL) - len += sprintf (buffer + len, "CLASS:%s;\n", str); + len += snprintf (buffer + len, sizeof(buffer) - len, "CLASS:%s;\n", str); if ((str = info->model) != NULL) - len += sprintf (buffer + len, "MODEL:%s;\n", str); + len += snprintf (buffer + len, sizeof(buffer) - len, "MODEL:%s;\n", str); if ((str = info->mfr) != NULL) - len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str); + len += snprintf (buffer + len, sizeof(buffer) - len, "MANUFACTURER:%s;\n", str); if ((str = info->description) != NULL) - len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str); + len += snprintf (buffer + len, sizeof(buffer) - len, "DESCRIPTION:%s;\n", str); if ((str = info->cmdset) != NULL) - len += sprintf (buffer + len, "COMMAND SET:%s;\n", str); + len += snprintf (buffer + len, sizeof(buffer) - len, "COMMAND SET:%s;\n", str); if (len > *lenp) len = *lenp; @@ -117,7 +117,7 @@ static int do_hardware_base_addr(struct ctl_table *table, int write, void *result, size_t *lenp, loff_t *ppos) { struct parport *port = (struct parport *)table->extra1; - char buffer[20]; + char buffer[64]; int len = 0; if (*ppos) { @@ -128,7 +128,7 @@ static int do_hardware_base_addr(struct ctl_table *table, int write, if (write) /* permissions prevent this anyway */ return -EACCES; - len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi); + len += snprintf (buffer, sizeof(buffer), "%lu\t%lu\n", port->base, port->base_hi); if (len > *lenp) len = *lenp; @@ -155,7 +155,7 @@ static int do_hardware_irq(struct ctl_table *table, int write, if (write) /* permissions prevent this anyway */ return -EACCES; - len += sprintf (buffer, "%d\n", port->irq); + len += snprintf (buffer, sizeof(buffer), "%d\n", port->irq); if (len > *lenp) len = *lenp; @@ -182,7 +182,7 @@ static int do_hardware_dma(struct ctl_table *table, int write, if (write) /* permissions prevent this anyway */ return -EACCES; - len += sprintf (buffer, "%d\n", port->dma); + len += snprintf (buffer, sizeof(buffer), "%d\n", port->dma); if (len > *lenp) len = *lenp; @@ -213,7 +213,7 @@ static int do_hardware_modes(struct ctl_table *table, int write, #define printmode(x) \ do { \ if (port->modes & PARPORT_MODE_##x) \ - len += sprintf(buffer + len, "%s%s", f++ ? "," : "", #x); \ + len += snprintf(buffer + len, sizeof(buffer) - len, "%s%s", f++ ? "," : "", #x); \ } while (0) int f = 0; printmode(PCSPP); From 5919d93fbecea729e6c1cfe96ea6360a1f146297 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 9 Jun 2024 17:40:17 -0700 Subject: [PATCH 324/330] spmi: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spmi/hisi-spmi-controller.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spmi/spmi-pmic-arb.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240609-md-drivers-spmi-v1-1-f1d5b24e7a66@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/spmi/hisi-spmi-controller.c | 1 + drivers/spmi/spmi-pmic-arb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c index fa068b34b040..3cafdf22c909 100644 --- a/drivers/spmi/hisi-spmi-controller.c +++ b/drivers/spmi/hisi-spmi-controller.c @@ -344,6 +344,7 @@ static void __exit spmi_controller_exit(void) } module_exit(spmi_controller_exit); +MODULE_DESCRIPTION("Hisilicon 3670 SPMI Controller driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION("1.0"); MODULE_ALIAS("platform:spmi_controller"); diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 791cdc160c51..f240fcc5a4e1 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1891,5 +1891,6 @@ static struct platform_driver spmi_pmic_arb_driver = { }; module_platform_driver(spmi_pmic_arb_driver); +MODULE_DESCRIPTION("Qualcomm MSM SPMI Controller (PMIC Arbiter) driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spmi_pmic_arb"); From 15eec4e1d07229fe570ad3a1344ad4a39d26106b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 15 Jun 2024 14:01:12 -0700 Subject: [PATCH 325/330] agp: uninorth: add missing MODULE_DESCRIPTION() macro With ARCH=powerpc, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/uninorth-agp.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/r/20240615-md-powerpc-drivers-char-agp-v1-1-b79bfd07da42@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/agp/uninorth-agp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 84411b13c49f..b8d7115b8c9e 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -726,4 +726,5 @@ MODULE_PARM_DESC(aperture, "\t\tDefault: " DEFAULT_APERTURE_STRING "M"); MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras"); +MODULE_DESCRIPTION("Apple UniNorth & U3 AGP support"); MODULE_LICENSE("GPL"); From 89067019d7dbc65d86cf3a4d8f84ed2ad4bed12b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 2 Jun 2024 13:25:28 -0700 Subject: [PATCH 326/330] virtio: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/virtio/virtio_dma_buf.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240602-md-virtio_dma_buf-v1-1-ce602d47e257@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/virtio/virtio_dma_buf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/virtio/virtio_dma_buf.c b/drivers/virtio/virtio_dma_buf.c index 2521a75009c3..3034a2f605c8 100644 --- a/drivers/virtio/virtio_dma_buf.c +++ b/drivers/virtio/virtio_dma_buf.c @@ -85,5 +85,6 @@ int virtio_dma_buf_get_uuid(struct dma_buf *dma_buf, } EXPORT_SYMBOL(virtio_dma_buf_get_uuid); +MODULE_DESCRIPTION("dma-bufs for virtio exported objects"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(DMA_BUF); From a5e43e2d202de39196de9fba689c34f8270782eb Mon Sep 17 00:00:00 2001 From: Vamsi Attunuru Date: Thu, 11 Jul 2024 05:01:15 -0700 Subject: [PATCH 327/330] misc: Kconfig: add a new dependency for MARVELL_CN10K_DPI DPI hardware is an on-chip PCIe device on Marvell's arm64 SoC platforms. As Arnd suggested, CN10K belongs to ARCH_THUNDER lineage. Patch makes mrvl_cn10k_dpi driver dependent on CONFIG_ARCH_THUNDER. Signed-off-by: Vamsi Attunuru Link: https://lore.kernel.org/r/20240711120115.4069401-1-vattunuru@marvell.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 64fcca9e44d7..f3bb75384627 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -588,6 +588,7 @@ config NSM config MARVELL_CN10K_DPI tristate "Octeon CN10K DPI driver" depends on PCI + depends on ARCH_THUNDER || COMPILE_TEST help Enables Octeon CN10K DMA packet interface (DPI) driver which intializes DPI hardware's physical function (PF) device's From 31643d84b8c3d9c846aa0e20bc033e46c68c7e7d Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Thu, 11 Jul 2024 20:14:51 +0000 Subject: [PATCH 328/330] binder: fix hang of unregistered readers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the introduction of binder_available_for_proc_work_ilocked() in commit 1b77e9dcc3da ("ANDROID: binder: remove proc waitqueue") a binder thread can only "wait_for_proc_work" after its thread->looper has been marked as BINDER_LOOPER_STATE_{ENTERED|REGISTERED}. This means an unregistered reader risks waiting indefinitely for work since it never gets added to the proc->waiting_threads. If there are no further references to its waitqueue either the task will hang. The same applies to readers using the (e)poll interface. I couldn't find the rationale behind this restriction. So this patch restores the previous behavior of allowing unregistered threads to "wait_for_proc_work". Note that an error message for this scenario, which had previously become unreachable, is now re-enabled. Fixes: 1b77e9dcc3da ("ANDROID: binder: remove proc waitqueue") Cc: stable@vger.kernel.org Cc: Martijn Coenen Cc: Arve Hjønnevåg Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20240711201452.2017543-1-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 0c2161b1f057..f26286e3713e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -570,9 +570,7 @@ static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) { return !thread->transaction_stack && - binder_worklist_empty_ilocked(&thread->todo) && - (thread->looper & (BINDER_LOOPER_STATE_ENTERED | - BINDER_LOOPER_STATE_REGISTERED)); + binder_worklist_empty_ilocked(&thread->todo); } static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc, From ff14bfb7bc0480c343356b82c126290a4774bcbe Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 12 Jul 2024 16:41:47 +0200 Subject: [PATCH 329/330] misc: delete Makefile.rej I accidentally added drivers/misc/Makefile.rej when applying the mrvl-cn10k-dpi by hand. Remove it as it's not needed. Reported-by: Stephen Rothwell Fixes: 5f67eef6dff3 ("misc: mrvl-cn10k-dpi: add Octeon CN10K DPI administrative driver") Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Makefile.rej | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 drivers/misc/Makefile.rej diff --git a/drivers/misc/Makefile.rej b/drivers/misc/Makefile.rej deleted file mode 100644 index a6aaed13f950..000000000000 --- a/drivers/misc/Makefile.rej +++ /dev/null @@ -1,7 +0,0 @@ ---- drivers/misc/Makefile -+++ drivers/misc/Makefile -@@ -69,3 +69,4 @@ obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o - obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o - obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o - obj-$(CONFIG_NSM) += nsm.o -+obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o From 5418e6dfc905b3ccc1e01bdad97d948697b20100 Mon Sep 17 00:00:00 2001 From: Vamsi Attunuru Date: Wed, 17 Jul 2024 09:37:39 -0700 Subject: [PATCH 330/330] misc: Kconfig: exclude mrvl-cn10k-dpi compilation for 32-bit systems Upon adding CONFIG_ARCH_THUNDER & CONFIG_COMPILE_TEST dependency, compilation errors arise on 32-bit ARM with writeq() & readq() calls which are used for accessing 64-bit values. Since DPI hardware only works with 64-bit register accesses, using CONFIG_64BIT dependency to skip compilation on 32-bit systems. Fixes: a5e43e2d202d ("misc: Kconfig: add a new dependency for MARVELL_CN10K_DPI") Signed-off-by: Vamsi Attunuru Tested-by: Nathan Chancellor Tested-by: Jeff Johnson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240717163739.181236-1-vattunuru@marvell.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index f3bb75384627..41c3d2821a78 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -588,7 +588,7 @@ config NSM config MARVELL_CN10K_DPI tristate "Octeon CN10K DPI driver" depends on PCI - depends on ARCH_THUNDER || COMPILE_TEST + depends on ARCH_THUNDER || (COMPILE_TEST && 64BIT) help Enables Octeon CN10K DMA packet interface (DPI) driver which intializes DPI hardware's physical function (PF) device's