Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: adc: ad4695: add custom regmap bus callbacks

Add a custom implementation of regmap read/write callbacks using the SPI
bus. This allows them to be performed at a lower SCLK rate than data
reads. Previously, all SPI transfers were being performed at a lower
speed, but with this change sample data is read at the max bus speed
while the register reads/writes remain at the lower rate.

Also remove .can_multi_write from the AD4695 driver's regmap_configs, as
this isn't implemented or needed.

For some background context, see:

https://lore.kernel.org/linux-iio/20241028163907.00007e12@Huawei.com/

Suggested-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Reviewed-by: David Lechner <dlechner@baylibre.com>
Tested-by: David Lechner <dlechner@baylibre.com>
Link: https://patch.msgid.link/20241113-tgamblin-ad4695_improvements-v2-3-b6bb7c758fc4@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Trevor Gamblin and committed by
Jonathan Cameron
1093f83b 998d20e4

+68 -8
+1 -1
drivers/iio/adc/Kconfig
··· 51 51 config AD4695 52 52 tristate "Analog Device AD4695 ADC Driver" 53 53 depends on SPI 54 - select REGMAP_SPI 55 54 select IIO_BUFFER 56 55 select IIO_TRIGGERED_BUFFER 56 + select REGMAP 57 57 help 58 58 Say yes here to build support for Analog Devices AD4695 and similar 59 59 analog to digital converters (ADC).
+67 -7
drivers/iio/adc/ad4695.c
··· 150 150 /* Commands to send for single conversion. */ 151 151 u16 cnv_cmd; 152 152 u8 cnv_cmd2; 153 + /* Buffer for storing data from regmap bus reads/writes */ 154 + u8 regmap_bus_data[4]; 153 155 }; 154 156 155 157 static const struct regmap_range ad4695_regmap_rd_ranges[] = { ··· 196 194 .max_register = AD4695_REG_AS_SLOT(127), 197 195 .rd_table = &ad4695_regmap_rd_table, 198 196 .wr_table = &ad4695_regmap_wr_table, 199 - .can_multi_write = true, 200 197 }; 201 198 202 199 static const struct regmap_range ad4695_regmap16_rd_ranges[] = { ··· 227 226 .max_register = AD4695_REG_GAIN_IN(15), 228 227 .rd_table = &ad4695_regmap16_rd_table, 229 228 .wr_table = &ad4695_regmap16_wr_table, 230 - .can_multi_write = true, 229 + }; 230 + 231 + static int ad4695_regmap_bus_reg_write(void *context, const void *data, 232 + size_t count) 233 + { 234 + struct ad4695_state *st = context; 235 + struct spi_transfer xfer = { 236 + .speed_hz = AD4695_REG_ACCESS_SCLK_HZ, 237 + .len = count, 238 + .tx_buf = st->regmap_bus_data, 239 + }; 240 + 241 + if (count > ARRAY_SIZE(st->regmap_bus_data)) 242 + return -EINVAL; 243 + 244 + memcpy(st->regmap_bus_data, data, count); 245 + 246 + return spi_sync_transfer(st->spi, &xfer, 1); 247 + } 248 + 249 + static int ad4695_regmap_bus_reg_read(void *context, const void *reg, 250 + size_t reg_size, void *val, 251 + size_t val_size) 252 + { 253 + struct ad4695_state *st = context; 254 + struct spi_transfer xfers[] = { 255 + { 256 + .speed_hz = AD4695_REG_ACCESS_SCLK_HZ, 257 + .len = reg_size, 258 + .tx_buf = &st->regmap_bus_data[0], 259 + }, { 260 + .speed_hz = AD4695_REG_ACCESS_SCLK_HZ, 261 + .len = val_size, 262 + .rx_buf = &st->regmap_bus_data[2], 263 + }, 264 + }; 265 + int ret; 266 + 267 + if (reg_size > 2) 268 + return -EINVAL; 269 + 270 + if (val_size > 2) 271 + return -EINVAL; 272 + 273 + memcpy(&st->regmap_bus_data[0], reg, reg_size); 274 + 275 + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); 276 + if (ret) 277 + return ret; 278 + 279 + memcpy(val, &st->regmap_bus_data[2], val_size); 280 + 281 + return 0; 282 + } 283 + 284 + static const struct regmap_bus ad4695_regmap_bus = { 285 + .write = ad4695_regmap_bus_reg_write, 286 + .read = ad4695_regmap_bus_reg_read, 287 + .read_flag_mask = 0x80, 288 + .reg_format_endian_default = REGMAP_ENDIAN_BIG, 289 + .val_format_endian_default = REGMAP_ENDIAN_BIG, 231 290 }; 232 291 233 292 static const struct iio_chan_spec ad4695_channel_template = { ··· 1122 1061 if (!st->chip_info) 1123 1062 return -EINVAL; 1124 1063 1125 - /* Registers cannot be read at the max allowable speed */ 1126 - spi->max_speed_hz = AD4695_REG_ACCESS_SCLK_HZ; 1127 - 1128 - st->regmap = devm_regmap_init_spi(spi, &ad4695_regmap_config); 1064 + st->regmap = devm_regmap_init(dev, &ad4695_regmap_bus, st, 1065 + &ad4695_regmap_config); 1129 1066 if (IS_ERR(st->regmap)) 1130 1067 return dev_err_probe(dev, PTR_ERR(st->regmap), 1131 1068 "Failed to initialize regmap\n"); 1132 1069 1133 - st->regmap16 = devm_regmap_init_spi(spi, &ad4695_regmap16_config); 1070 + st->regmap16 = devm_regmap_init(dev, &ad4695_regmap_bus, st, 1071 + &ad4695_regmap16_config); 1134 1072 if (IS_ERR(st->regmap16)) 1135 1073 return dev_err_probe(dev, PTR_ERR(st->regmap16), 1136 1074 "Failed to initialize regmap16\n");