Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | // SPDX-License-Identifier: GPL-2.0 /* * Texas Instruments LMP92064 SPI ADC driver * * Copyright (c) 2022 Leonard Göhrs <kernel@pengutronix.de>, Pengutronix * * Based on linux/drivers/iio/adc/ti-tsc2046.c * Copyright (c) 2021 Oleksij Rempel <kernel@pengutronix.de>, Pengutronix */ #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> #include <linux/iio/driver.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #define TI_LMP92064_REG_CONFIG_A 0x0000 #define TI_LMP92064_REG_CONFIG_B 0x0001 #define TI_LMP92064_REG_CHIP_REV 0x0006 #define TI_LMP92064_REG_MFR_ID1 0x000C #define TI_LMP92064_REG_MFR_ID2 0x000D #define TI_LMP92064_REG_REG_UPDATE 0x000F #define TI_LMP92064_REG_CONFIG_REG 0x0100 #define TI_LMP92064_REG_STATUS 0x0103 #define TI_LMP92064_REG_DATA_VOUT_LSB 0x0200 #define TI_LMP92064_REG_DATA_VOUT_MSB 0x0201 #define TI_LMP92064_REG_DATA_COUT_LSB 0x0202 #define TI_LMP92064_REG_DATA_COUT_MSB 0x0203 #define TI_LMP92064_VAL_CONFIG_A 0x99 #define TI_LMP92064_VAL_CONFIG_B 0x00 #define TI_LMP92064_VAL_STATUS_OK 0x01 /* * Channel number definitions for the two channels of the device * - IN Current (INC) * - IN Voltage (INV) */ #define TI_LMP92064_CHAN_INC 0 #define TI_LMP92064_CHAN_INV 1 static const struct regmap_range lmp92064_readable_reg_ranges[] = { regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CHIP_REV), regmap_reg_range(TI_LMP92064_REG_MFR_ID1, TI_LMP92064_REG_MFR_ID2), regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE), regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG), regmap_reg_range(TI_LMP92064_REG_STATUS, TI_LMP92064_REG_STATUS), regmap_reg_range(TI_LMP92064_REG_DATA_VOUT_LSB, TI_LMP92064_REG_DATA_COUT_MSB), }; static const struct regmap_access_table lmp92064_readable_regs = { .yes_ranges = lmp92064_readable_reg_ranges, .n_yes_ranges = ARRAY_SIZE(lmp92064_readable_reg_ranges), }; static const struct regmap_range lmp92064_writable_reg_ranges[] = { regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CONFIG_B), regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE), regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG), }; static const struct regmap_access_table lmp92064_writable_regs = { .yes_ranges = lmp92064_writable_reg_ranges, .n_yes_ranges = ARRAY_SIZE(lmp92064_writable_reg_ranges), }; static const struct regmap_config lmp92064_spi_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = TI_LMP92064_REG_DATA_COUT_MSB, .rd_table = &lmp92064_readable_regs, .wr_table = &lmp92064_writable_regs, }; struct lmp92064_adc_priv { int shunt_resistor_uohm; struct spi_device *spi; struct regmap *regmap; }; static const struct iio_chan_spec lmp92064_adc_channels[] = { { .type = IIO_CURRENT, .address = TI_LMP92064_CHAN_INC, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .scan_index = TI_LMP92064_CHAN_INC, .scan_type = { .sign = 'u', .realbits = 12, .storagebits = 16, }, .datasheet_name = "INC", }, { .type = IIO_VOLTAGE, .address = TI_LMP92064_CHAN_INV, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .scan_index = TI_LMP92064_CHAN_INV, .scan_type = { .sign = 'u', .realbits = 12, .storagebits = 16, }, .datasheet_name = "INV", }, IIO_CHAN_SOFT_TIMESTAMP(2), }; static const unsigned long lmp92064_scan_masks[] = { BIT(TI_LMP92064_CHAN_INC) | BIT(TI_LMP92064_CHAN_INV), 0 }; static int lmp92064_read_meas(struct lmp92064_adc_priv *priv, u16 *res) { __be16 raw[2]; int ret; /* * The ADC only latches in new samples if all DATA registers are read * in descending sequential order. * The ADC auto-decrements the register index with each clocked byte. * Read both channels in single SPI transfer by selecting the highest * register using the command below and clocking out all four data * bytes. */ ret = regmap_bulk_read(priv->regmap, TI_LMP92064_REG_DATA_COUT_MSB, &raw, sizeof(raw)); if (ret) { dev_err(&priv->spi->dev, "regmap_bulk_read failed: %pe\n", ERR_PTR(ret)); return ret; } res[0] = be16_to_cpu(raw[0]); res[1] = be16_to_cpu(raw[1]); return 0; } static int lmp92064_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct lmp92064_adc_priv *priv = iio_priv(indio_dev); u16 raw[2]; int ret; switch (mask) { case IIO_CHAN_INFO_RAW: ret = lmp92064_read_meas(priv, raw); if (ret < 0) return ret; *val = (chan->address == TI_LMP92064_CHAN_INC) ? raw[0] : raw[1]; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (chan->address == TI_LMP92064_CHAN_INC) { /* * processed (mA) = raw * current_lsb (mA) * current_lsb (mA) = shunt_voltage_lsb (nV) / shunt_resistor (uOhm) * shunt_voltage_lsb (nV) = 81920000 / 4096 = 20000 */ *val = 20000; *val2 = priv->shunt_resistor_uohm; } else { /* * processed (mV) = raw * voltage_lsb (mV) * voltage_lsb (mV) = 2048 / 4096 */ *val = 2048; *val2 = 4096; } return IIO_VAL_FRACTIONAL; default: return -EINVAL; } } static irqreturn_t lmp92064_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct lmp92064_adc_priv *priv = iio_priv(indio_dev); struct { u16 values[2]; int64_t timestamp __aligned(8); } data; int ret; memset(&data, 0, sizeof(data)); ret = lmp92064_read_meas(priv, data.values); if (ret) goto err; iio_push_to_buffers_with_timestamp(indio_dev, &data, iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } static int lmp92064_reset(struct lmp92064_adc_priv *priv, struct gpio_desc *gpio_reset) { unsigned int status; int ret, i; if (gpio_reset) { /* * Perform a hard reset if gpio_reset is available. * The datasheet specifies a very low 3.5ns reset pulse duration and does not * specify how long to wait after a reset to access the device. * Use more conservative pulse lengths to allow analog RC filtering of the * reset line at the board level (as recommended in the datasheet). */ gpiod_set_value_cansleep(gpio_reset, 1); usleep_range(1, 10); gpiod_set_value_cansleep(gpio_reset, 0); usleep_range(500, 750); } else { /* * Perform a soft-reset if not. * Also write default values to the config registers that are not * affected by soft reset. */ ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_A, TI_LMP92064_VAL_CONFIG_A); if (ret < 0) return ret; ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_B, TI_LMP92064_VAL_CONFIG_B); if (ret < 0) return ret; } /* * Wait for the device to signal readiness to prevent reading bogus data * and make sure device is actually connected. * The datasheet does not specify how long this takes but usually it is * not more than 3-4 iterations of this loop. */ for (i = 0; i < 10; i++) { ret = regmap_read(priv->regmap, TI_LMP92064_REG_STATUS, &status); if (ret < 0) return ret; if (status == TI_LMP92064_VAL_STATUS_OK) return 0; usleep_range(1000, 2000); } /* * No (correct) response received. * Device is mostly likely not connected to the bus. */ return -ENXIO; } static const struct iio_info lmp92064_adc_info = { .read_raw = lmp92064_read_raw, }; static int lmp92064_adc_probe(struct spi_device *spi) { struct device *dev = &spi->dev; struct lmp92064_adc_priv *priv; struct gpio_desc *gpio_reset; struct iio_dev *indio_dev; u32 shunt_resistor_uohm; struct regmap *regmap; int ret; ret = spi_setup(spi); if (ret < 0) return dev_err_probe(dev, ret, "Error in SPI setup\n"); regmap = devm_regmap_init_spi(spi, &lmp92064_spi_regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to set up SPI regmap\n"); indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; priv = iio_priv(indio_dev); priv->spi = spi; priv->regmap = regmap; ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &shunt_resistor_uohm); if (ret < 0) return dev_err_probe(dev, ret, "Failed to get shunt-resistor value\n"); /* * The shunt resistance is passed to userspace as the denominator of an iio * fraction. Make sure it is in range for that. */ if (shunt_resistor_uohm == 0 || shunt_resistor_uohm > INT_MAX) { dev_err(dev, "Shunt resistance is out of range\n"); return -EINVAL; } priv->shunt_resistor_uohm = shunt_resistor_uohm; ret = devm_regulator_get_enable(dev, "vdd"); if (ret) return ret; ret = devm_regulator_get_enable(dev, "vdig"); if (ret) return ret; gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio_reset)) return dev_err_probe(dev, PTR_ERR(gpio_reset), "Failed to get GPIO reset pin\n"); ret = lmp92064_reset(priv, gpio_reset); if (ret < 0) return dev_err_probe(dev, ret, "Failed to reset device\n"); indio_dev->name = "lmp92064"; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = lmp92064_adc_channels; indio_dev->num_channels = ARRAY_SIZE(lmp92064_adc_channels); indio_dev->info = &lmp92064_adc_info; indio_dev->available_scan_masks = lmp92064_scan_masks; ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, lmp92064_trigger_handler, NULL); if (ret) return dev_err_probe(dev, ret, "Failed to setup buffered read\n"); return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id lmp92064_id_table[] = { { "lmp92064" }, {} }; MODULE_DEVICE_TABLE(spi, lmp92064_id_table); static const struct of_device_id lmp92064_of_table[] = { { .compatible = "ti,lmp92064" }, {} }; MODULE_DEVICE_TABLE(of, lmp92064_of_table); static struct spi_driver lmp92064_adc_driver = { .driver = { .name = "lmp92064", .of_match_table = lmp92064_of_table, }, .probe = lmp92064_adc_probe, .id_table = lmp92064_id_table, }; module_spi_driver(lmp92064_adc_driver); MODULE_AUTHOR("Leonard Göhrs <kernel@pengutronix.de>"); MODULE_DESCRIPTION("TI LMP92064 ADC"); MODULE_LICENSE("GPL"); |