diff options
Diffstat (limited to 'drivers/iio/dac/ad5449.c')
| -rw-r--r-- | drivers/iio/dac/ad5449.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c new file mode 100644 index 000000000000..c4731b7b577b --- /dev/null +++ b/drivers/iio/dac/ad5449.c | |||
| @@ -0,0 +1,376 @@ | |||
| 1 | /* | ||
| 2 | * AD5415, AD5426, AD5429, AD5432, AD5439, AD5443, AD5449 Digital to Analog | ||
| 3 | * Converter driver. | ||
| 4 | * | ||
| 5 | * Copyright 2012 Analog Devices Inc. | ||
| 6 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
| 7 | * | ||
| 8 | * Licensed under the GPL-2. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/err.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/spi/spi.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <linux/sysfs.h> | ||
| 18 | #include <linux/regulator/consumer.h> | ||
| 19 | #include <asm/unaligned.h> | ||
| 20 | |||
| 21 | #include <linux/iio/iio.h> | ||
| 22 | #include <linux/iio/sysfs.h> | ||
| 23 | |||
| 24 | #include <linux/platform_data/ad5449.h> | ||
| 25 | |||
| 26 | #define AD5449_MAX_CHANNELS 2 | ||
| 27 | #define AD5449_MAX_VREFS 2 | ||
| 28 | |||
| 29 | #define AD5449_CMD_NOOP 0x0 | ||
| 30 | #define AD5449_CMD_LOAD_AND_UPDATE(x) (0x1 + (x) * 3) | ||
| 31 | #define AD5449_CMD_READ(x) (0x2 + (x) * 3) | ||
| 32 | #define AD5449_CMD_LOAD(x) (0x3 + (x) * 3) | ||
| 33 | #define AD5449_CMD_CTRL 13 | ||
| 34 | |||
| 35 | #define AD5449_CTRL_SDO_OFFSET 10 | ||
| 36 | #define AD5449_CTRL_DAISY_CHAIN BIT(9) | ||
| 37 | #define AD5449_CTRL_HCLR_TO_MIDSCALE BIT(8) | ||
| 38 | #define AD5449_CTRL_SAMPLE_RISING BIT(7) | ||
| 39 | |||
| 40 | /** | ||
| 41 | * struct ad5449_chip_info - chip specific information | ||
| 42 | * @channels: Channel specification | ||
| 43 | * @num_channels: Number of channels | ||
| 44 | * @has_ctrl: Chip has a control register | ||
| 45 | */ | ||
| 46 | struct ad5449_chip_info { | ||
| 47 | const struct iio_chan_spec *channels; | ||
| 48 | unsigned int num_channels; | ||
| 49 | bool has_ctrl; | ||
| 50 | }; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * struct ad5449 - driver instance specific data | ||
| 54 | * @spi: the SPI device for this driver instance | ||
| 55 | * @chip_info: chip model specific constants, available modes etc | ||
| 56 | * @vref_reg: vref supply regulators | ||
| 57 | * @has_sdo: whether the SDO line is connected | ||
| 58 | * @dac_cache: Cache for the DAC values | ||
| 59 | * @data: spi transfer buffers | ||
| 60 | */ | ||
| 61 | struct ad5449 { | ||
| 62 | struct spi_device *spi; | ||
| 63 | const struct ad5449_chip_info *chip_info; | ||
| 64 | struct regulator_bulk_data vref_reg[AD5449_MAX_VREFS]; | ||
| 65 | |||
| 66 | bool has_sdo; | ||
| 67 | uint16_t dac_cache[AD5449_MAX_CHANNELS]; | ||
| 68 | |||
| 69 | /* | ||
| 70 | * DMA (thus cache coherency maintenance) requires the | ||
| 71 | * transfer buffers to live in their own cache lines. | ||
| 72 | */ | ||
| 73 | __be16 data[2] ____cacheline_aligned; | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum ad5449_type { | ||
| 77 | ID_AD5426, | ||
| 78 | ID_AD5429, | ||
| 79 | ID_AD5432, | ||
| 80 | ID_AD5439, | ||
| 81 | ID_AD5443, | ||
| 82 | ID_AD5449, | ||
| 83 | }; | ||
| 84 | |||
| 85 | static int ad5449_write(struct iio_dev *indio_dev, unsigned int addr, | ||
| 86 | unsigned int val) | ||
| 87 | { | ||
| 88 | struct ad5449 *st = iio_priv(indio_dev); | ||
| 89 | int ret; | ||
| 90 | |||
| 91 | mutex_lock(&indio_dev->mlock); | ||
| 92 | st->data[0] = cpu_to_be16((addr << 12) | val); | ||
| 93 | ret = spi_write(st->spi, st->data, 2); | ||
| 94 | mutex_unlock(&indio_dev->mlock); | ||
| 95 | |||
| 96 | return ret; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr, | ||
| 100 | unsigned int *val) | ||
| 101 | { | ||
| 102 | struct ad5449 *st = iio_priv(indio_dev); | ||
| 103 | int ret; | ||
| 104 | struct spi_message msg; | ||
| 105 | struct spi_transfer t[] = { | ||
| 106 | { | ||
| 107 | .tx_buf = &st->data[0], | ||
| 108 | .len = 2, | ||
| 109 | .cs_change = 1, | ||
| 110 | }, { | ||
| 111 | .tx_buf = &st->data[1], | ||
| 112 | .rx_buf = &st->data[1], | ||
| 113 | .len = 2, | ||
| 114 | }, | ||
| 115 | }; | ||
| 116 | |||
| 117 | spi_message_init(&msg); | ||
| 118 | spi_message_add_tail(&t[0], &msg); | ||
| 119 | spi_message_add_tail(&t[1], &msg); | ||
| 120 | |||
| 121 | mutex_lock(&indio_dev->mlock); | ||
| 122 | st->data[0] = cpu_to_be16(addr << 12); | ||
| 123 | st->data[1] = cpu_to_be16(AD5449_CMD_NOOP); | ||
| 124 | |||
| 125 | ret = spi_sync(st->spi, &msg); | ||
| 126 | if (ret < 0) | ||
| 127 | goto out_unlock; | ||
| 128 | |||
| 129 | *val = be16_to_cpu(st->data[1]); | ||
| 130 | |||
| 131 | out_unlock: | ||
| 132 | mutex_unlock(&indio_dev->mlock); | ||
| 133 | return ret; | ||
| 134 | } | ||
| 135 | |||
| 136 | static int ad5449_read_raw(struct iio_dev *indio_dev, | ||
| 137 | struct iio_chan_spec const *chan, int *val, int *val2, long info) | ||
| 138 | { | ||
| 139 | struct ad5449 *st = iio_priv(indio_dev); | ||
| 140 | struct regulator_bulk_data *reg; | ||
| 141 | int scale_uv; | ||
| 142 | int ret; | ||
| 143 | |||
| 144 | switch (info) { | ||
| 145 | case IIO_CHAN_INFO_RAW: | ||
| 146 | if (st->has_sdo) { | ||
| 147 | ret = ad5449_read(indio_dev, | ||
| 148 | AD5449_CMD_READ(chan->address), val); | ||
| 149 | if (ret) | ||
| 150 | return ret; | ||
| 151 | *val &= 0xfff; | ||
| 152 | } else { | ||
| 153 | *val = st->dac_cache[chan->address]; | ||
| 154 | } | ||
| 155 | |||
| 156 | return IIO_VAL_INT; | ||
| 157 | case IIO_CHAN_INFO_SCALE: | ||
| 158 | reg = &st->vref_reg[chan->channel]; | ||
| 159 | scale_uv = regulator_get_voltage(reg->consumer); | ||
| 160 | if (scale_uv < 0) | ||
| 161 | return scale_uv; | ||
| 162 | |||
| 163 | *val = scale_uv / 1000; | ||
| 164 | *val2 = chan->scan_type.realbits; | ||
| 165 | |||
| 166 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 167 | default: | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | |||
| 171 | return -EINVAL; | ||
| 172 | } | ||
| 173 | |||
| 174 | static int ad5449_write_raw(struct iio_dev *indio_dev, | ||
| 175 | struct iio_chan_spec const *chan, int val, int val2, long info) | ||
| 176 | { | ||
| 177 | struct ad5449 *st = iio_priv(indio_dev); | ||
| 178 | int ret; | ||
| 179 | |||
| 180 | switch (info) { | ||
| 181 | case IIO_CHAN_INFO_RAW: | ||
| 182 | if (val < 0 || val >= (1 << chan->scan_type.realbits)) | ||
| 183 | return -EINVAL; | ||
| 184 | |||
| 185 | ret = ad5449_write(indio_dev, | ||
| 186 | AD5449_CMD_LOAD_AND_UPDATE(chan->address), | ||
| 187 | val << chan->scan_type.shift); | ||
| 188 | if (ret == 0) | ||
| 189 | st->dac_cache[chan->address] = val; | ||
| 190 | break; | ||
| 191 | default: | ||
| 192 | ret = -EINVAL; | ||
| 193 | } | ||
| 194 | |||
| 195 | return ret; | ||
| 196 | } | ||
| 197 | |||
| 198 | static const struct iio_info ad5449_info = { | ||
| 199 | .read_raw = ad5449_read_raw, | ||
| 200 | .write_raw = ad5449_write_raw, | ||
| 201 | .driver_module = THIS_MODULE, | ||
| 202 | }; | ||
| 203 | |||
| 204 | #define AD5449_CHANNEL(chan, bits) { \ | ||
| 205 | .type = IIO_VOLTAGE, \ | ||
| 206 | .indexed = 1, \ | ||
| 207 | .output = 1, \ | ||
| 208 | .channel = (chan), \ | ||
| 209 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | ||
| 210 | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ | ||
| 211 | .address = (chan), \ | ||
| 212 | .scan_type = IIO_ST('u', (bits), 16, 12 - (bits)), \ | ||
| 213 | } | ||
| 214 | |||
| 215 | #define DECLARE_AD5449_CHANNELS(name, bits) \ | ||
| 216 | const struct iio_chan_spec name[] = { \ | ||
| 217 | AD5449_CHANNEL(0, bits), \ | ||
| 218 | AD5449_CHANNEL(1, bits), \ | ||
| 219 | } | ||
| 220 | |||
| 221 | static DECLARE_AD5449_CHANNELS(ad5429_channels, 8); | ||
| 222 | static DECLARE_AD5449_CHANNELS(ad5439_channels, 10); | ||
| 223 | static DECLARE_AD5449_CHANNELS(ad5449_channels, 12); | ||
| 224 | |||
| 225 | static const struct ad5449_chip_info ad5449_chip_info[] = { | ||
| 226 | [ID_AD5426] = { | ||
| 227 | .channels = ad5429_channels, | ||
| 228 | .num_channels = 1, | ||
| 229 | .has_ctrl = false, | ||
| 230 | }, | ||
| 231 | [ID_AD5429] = { | ||
| 232 | .channels = ad5429_channels, | ||
| 233 | .num_channels = 2, | ||
| 234 | .has_ctrl = true, | ||
| 235 | }, | ||
| 236 | [ID_AD5432] = { | ||
| 237 | .channels = ad5439_channels, | ||
| 238 | .num_channels = 1, | ||
| 239 | .has_ctrl = false, | ||
| 240 | }, | ||
| 241 | [ID_AD5439] = { | ||
| 242 | .channels = ad5439_channels, | ||
| 243 | .num_channels = 2, | ||
| 244 | .has_ctrl = true, | ||
| 245 | }, | ||
| 246 | [ID_AD5443] = { | ||
| 247 | .channels = ad5449_channels, | ||
| 248 | .num_channels = 1, | ||
| 249 | .has_ctrl = false, | ||
| 250 | }, | ||
| 251 | [ID_AD5449] = { | ||
| 252 | .channels = ad5449_channels, | ||
| 253 | .num_channels = 2, | ||
| 254 | .has_ctrl = true, | ||
| 255 | }, | ||
| 256 | }; | ||
| 257 | |||
| 258 | static const char *ad5449_vref_name(struct ad5449 *st, int n) | ||
| 259 | { | ||
| 260 | if (st->chip_info->num_channels == 1) | ||
| 261 | return "VREF"; | ||
| 262 | |||
| 263 | if (n == 0) | ||
| 264 | return "VREFA"; | ||
| 265 | else | ||
| 266 | return "VREFB"; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int ad5449_spi_probe(struct spi_device *spi) | ||
| 270 | { | ||
| 271 | struct ad5449_platform_data *pdata = spi->dev.platform_data; | ||
| 272 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
| 273 | struct iio_dev *indio_dev; | ||
| 274 | struct ad5449 *st; | ||
| 275 | unsigned int i; | ||
| 276 | int ret; | ||
| 277 | |||
| 278 | indio_dev = iio_device_alloc(sizeof(*st)); | ||
| 279 | if (indio_dev == NULL) | ||
| 280 | return -ENOMEM; | ||
| 281 | |||
| 282 | st = iio_priv(indio_dev); | ||
| 283 | spi_set_drvdata(spi, indio_dev); | ||
| 284 | |||
| 285 | st->chip_info = &ad5449_chip_info[id->driver_data]; | ||
| 286 | st->spi = spi; | ||
| 287 | |||
| 288 | for (i = 0; i < st->chip_info->num_channels; ++i) | ||
| 289 | st->vref_reg[i].supply = ad5449_vref_name(st, i); | ||
| 290 | |||
| 291 | ret = regulator_bulk_get(&spi->dev, st->chip_info->num_channels, | ||
| 292 | st->vref_reg); | ||
| 293 | if (ret) | ||
| 294 | goto error_free; | ||
| 295 | |||
| 296 | ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg); | ||
| 297 | if (ret) | ||
| 298 | goto error_free_reg; | ||
| 299 | |||
| 300 | indio_dev->dev.parent = &spi->dev; | ||
| 301 | indio_dev->name = id->name; | ||
| 302 | indio_dev->info = &ad5449_info; | ||
| 303 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 304 | indio_dev->channels = st->chip_info->channels; | ||
| 305 | indio_dev->num_channels = st->chip_info->num_channels; | ||
| 306 | |||
| 307 | if (st->chip_info->has_ctrl) { | ||
| 308 | unsigned int ctrl = 0x00; | ||
| 309 | if (pdata) { | ||
| 310 | if (pdata->hardware_clear_to_midscale) | ||
| 311 | ctrl |= AD5449_CTRL_HCLR_TO_MIDSCALE; | ||
| 312 | ctrl |= pdata->sdo_mode << AD5449_CTRL_SDO_OFFSET; | ||
| 313 | st->has_sdo = pdata->sdo_mode != AD5449_SDO_DISABLED; | ||
| 314 | } else { | ||
| 315 | st->has_sdo = true; | ||
| 316 | } | ||
| 317 | ad5449_write(indio_dev, AD5449_CMD_CTRL, ctrl); | ||
| 318 | } | ||
| 319 | |||
| 320 | ret = iio_device_register(indio_dev); | ||
| 321 | if (ret) | ||
| 322 | goto error_disable_reg; | ||
| 323 | |||
| 324 | return 0; | ||
| 325 | |||
| 326 | error_disable_reg: | ||
| 327 | regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); | ||
| 328 | error_free_reg: | ||
| 329 | regulator_bulk_free(st->chip_info->num_channels, st->vref_reg); | ||
| 330 | error_free: | ||
| 331 | iio_device_free(indio_dev); | ||
| 332 | |||
| 333 | return ret; | ||
| 334 | } | ||
| 335 | |||
| 336 | static int ad5449_spi_remove(struct spi_device *spi) | ||
| 337 | { | ||
| 338 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 339 | struct ad5449 *st = iio_priv(indio_dev); | ||
| 340 | |||
| 341 | iio_device_unregister(indio_dev); | ||
| 342 | |||
| 343 | regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); | ||
| 344 | regulator_bulk_free(st->chip_info->num_channels, st->vref_reg); | ||
| 345 | |||
| 346 | iio_device_free(indio_dev); | ||
| 347 | |||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | static const struct spi_device_id ad5449_spi_ids[] = { | ||
| 352 | { "ad5415", ID_AD5449 }, | ||
| 353 | { "ad5426", ID_AD5426 }, | ||
| 354 | { "ad5429", ID_AD5429 }, | ||
| 355 | { "ad5432", ID_AD5432 }, | ||
| 356 | { "ad5439", ID_AD5439 }, | ||
| 357 | { "ad5443", ID_AD5443 }, | ||
| 358 | { "ad5449", ID_AD5449 }, | ||
| 359 | {} | ||
| 360 | }; | ||
| 361 | MODULE_DEVICE_TABLE(spi, ad5449_spi_ids); | ||
| 362 | |||
| 363 | static struct spi_driver ad5449_spi_driver = { | ||
| 364 | .driver = { | ||
| 365 | .name = "ad5449", | ||
| 366 | .owner = THIS_MODULE, | ||
| 367 | }, | ||
| 368 | .probe = ad5449_spi_probe, | ||
| 369 | .remove = ad5449_spi_remove, | ||
| 370 | .id_table = ad5449_spi_ids, | ||
| 371 | }; | ||
| 372 | module_spi_driver(ad5449_spi_driver); | ||
| 373 | |||
| 374 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
| 375 | MODULE_DESCRIPTION("Analog Devices AD5449 and similar DACs"); | ||
| 376 | MODULE_LICENSE("GPL v2"); | ||
