linux/drivers/iio/dac/ad5761.c
<<
>>
Prefs
   1/*
   2 * AD5721, AD5721R, AD5761, AD5761R, Voltage Output Digital to Analog Converter
   3 *
   4 * Copyright 2016 Qtechnology A/S
   5 * 2016 Ricardo Ribalda <ricardo.ribalda@gmail.com>
   6 *
   7 * Licensed under the GPL-2.
   8 */
   9#include <linux/kernel.h>
  10#include <linux/module.h>
  11#include <linux/spi/spi.h>
  12#include <linux/bitops.h>
  13#include <linux/iio/iio.h>
  14#include <linux/iio/sysfs.h>
  15#include <linux/regulator/consumer.h>
  16#include <linux/platform_data/ad5761.h>
  17
  18#define AD5761_ADDR(addr)               ((addr & 0xf) << 16)
  19#define AD5761_ADDR_NOOP                0x0
  20#define AD5761_ADDR_DAC_WRITE           0x3
  21#define AD5761_ADDR_CTRL_WRITE_REG      0x4
  22#define AD5761_ADDR_SW_DATA_RESET       0x7
  23#define AD5761_ADDR_DAC_READ            0xb
  24#define AD5761_ADDR_CTRL_READ_REG       0xc
  25#define AD5761_ADDR_SW_FULL_RESET       0xf
  26
  27#define AD5761_CTRL_USE_INTVREF         BIT(5)
  28#define AD5761_CTRL_ETS                 BIT(6)
  29
  30/**
  31 * struct ad5761_chip_info - chip specific information
  32 * @int_vref:   Value of the internal reference voltage in mV - 0 if external
  33 *              reference voltage is used
  34 * @channel:    channel specification
  35*/
  36
  37struct ad5761_chip_info {
  38        unsigned long int_vref;
  39        const struct iio_chan_spec channel;
  40};
  41
  42struct ad5761_range_params {
  43        int m;
  44        int c;
  45};
  46
  47enum ad5761_supported_device_ids {
  48        ID_AD5721,
  49        ID_AD5721R,
  50        ID_AD5761,
  51        ID_AD5761R,
  52};
  53
  54/**
  55 * struct ad5761_state - driver instance specific data
  56 * @spi:                spi_device
  57 * @vref_reg:           reference voltage regulator
  58 * @use_intref:         true when the internal voltage reference is used
  59 * @vref:               actual voltage reference in mVolts
  60 * @range:              output range mode used
  61 * @data:               cache aligned spi buffer
  62 */
  63struct ad5761_state {
  64        struct spi_device               *spi;
  65        struct regulator                *vref_reg;
  66
  67        bool use_intref;
  68        int vref;
  69        enum ad5761_voltage_range range;
  70
  71        /*
  72         * DMA (thus cache coherency maintenance) requires the
  73         * transfer buffers to live in their own cache lines.
  74         */
  75        union {
  76                __be32 d32;
  77                u8 d8[4];
  78        } data[3] ____cacheline_aligned;
  79};
  80
  81static const struct ad5761_range_params ad5761_range_params[] = {
  82        [AD5761_VOLTAGE_RANGE_M10V_10V] = {
  83                .m = 80,
  84                .c = 40,
  85        },
  86        [AD5761_VOLTAGE_RANGE_0V_10V] = {
  87                .m = 40,
  88                .c = 0,
  89        },
  90        [AD5761_VOLTAGE_RANGE_M5V_5V] = {
  91                .m = 40,
  92                .c = 20,
  93        },
  94        [AD5761_VOLTAGE_RANGE_0V_5V] = {
  95                .m = 20,
  96                .c = 0,
  97        },
  98        [AD5761_VOLTAGE_RANGE_M2V5_7V5] = {
  99                .m = 40,
 100                .c = 10,
 101        },
 102        [AD5761_VOLTAGE_RANGE_M3V_3V] = {
 103                .m = 24,
 104                .c = 12,
 105        },
 106        [AD5761_VOLTAGE_RANGE_0V_16V] = {
 107                .m = 64,
 108                .c = 0,
 109        },
 110        [AD5761_VOLTAGE_RANGE_0V_20V] = {
 111                .m = 80,
 112                .c = 0,
 113        },
 114};
 115
 116static int _ad5761_spi_write(struct ad5761_state *st, u8 addr, u16 val)
 117{
 118        st->data[0].d32 = cpu_to_be32(AD5761_ADDR(addr) | val);
 119
 120        return spi_write(st->spi, &st->data[0].d8[1], 3);
 121}
 122
 123static int ad5761_spi_write(struct iio_dev *indio_dev, u8 addr, u16 val)
 124{
 125        struct ad5761_state *st = iio_priv(indio_dev);
 126        int ret;
 127
 128        mutex_lock(&indio_dev->mlock);
 129        ret = _ad5761_spi_write(st, addr, val);
 130        mutex_unlock(&indio_dev->mlock);
 131
 132        return ret;
 133}
 134
 135static int _ad5761_spi_read(struct ad5761_state *st, u8 addr, u16 *val)
 136{
 137        int ret;
 138        struct spi_transfer xfers[] = {
 139                {
 140                        .tx_buf = &st->data[0].d8[1],
 141                        .bits_per_word = 8,
 142                        .len = 3,
 143                        .cs_change = true,
 144                }, {
 145                        .tx_buf = &st->data[1].d8[1],
 146                        .rx_buf = &st->data[2].d8[1],
 147                        .bits_per_word = 8,
 148                        .len = 3,
 149                },
 150        };
 151
 152        st->data[0].d32 = cpu_to_be32(AD5761_ADDR(addr));
 153        st->data[1].d32 = cpu_to_be32(AD5761_ADDR(AD5761_ADDR_NOOP));
 154
 155        ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
 156
 157        *val = be32_to_cpu(st->data[2].d32);
 158
 159        return ret;
 160}
 161
 162static int ad5761_spi_read(struct iio_dev *indio_dev, u8 addr, u16 *val)
 163{
 164        struct ad5761_state *st = iio_priv(indio_dev);
 165        int ret;
 166
 167        mutex_lock(&indio_dev->mlock);
 168        ret = _ad5761_spi_read(st, addr, val);
 169        mutex_unlock(&indio_dev->mlock);
 170
 171        return ret;
 172}
 173
 174static int ad5761_spi_set_range(struct ad5761_state *st,
 175                                enum ad5761_voltage_range range)
 176{
 177        u16 aux;
 178        int ret;
 179
 180        aux = (range & 0x7) | AD5761_CTRL_ETS;
 181
 182        if (st->use_intref)
 183                aux |= AD5761_CTRL_USE_INTVREF;
 184
 185        ret = _ad5761_spi_write(st, AD5761_ADDR_SW_FULL_RESET, 0);
 186        if (ret)
 187                return ret;
 188
 189        ret = _ad5761_spi_write(st, AD5761_ADDR_CTRL_WRITE_REG, aux);
 190        if (ret)
 191                return ret;
 192
 193        st->range = range;
 194
 195        return 0;
 196}
 197
 198static int ad5761_read_raw(struct iio_dev *indio_dev,
 199                           struct iio_chan_spec const *chan,
 200                           int *val,
 201                           int *val2,
 202                           long mask)
 203{
 204        struct ad5761_state *st;
 205        int ret;
 206        u16 aux;
 207
 208        switch (mask) {
 209        case IIO_CHAN_INFO_RAW:
 210                ret = ad5761_spi_read(indio_dev, AD5761_ADDR_DAC_READ, &aux);
 211                if (ret)
 212                        return ret;
 213                *val = aux >> chan->scan_type.shift;
 214                return IIO_VAL_INT;
 215        case IIO_CHAN_INFO_SCALE:
 216                st = iio_priv(indio_dev);
 217                *val = st->vref * ad5761_range_params[st->range].m;
 218                *val /= 10;
 219                *val2 = chan->scan_type.realbits;
 220                return IIO_VAL_FRACTIONAL_LOG2;
 221        case IIO_CHAN_INFO_OFFSET:
 222                st = iio_priv(indio_dev);
 223                *val = -(1 << chan->scan_type.realbits);
 224                *val *= ad5761_range_params[st->range].c;
 225                *val /= ad5761_range_params[st->range].m;
 226                return IIO_VAL_INT;
 227        default:
 228                return -EINVAL;
 229        }
 230}
 231
 232static int ad5761_write_raw(struct iio_dev *indio_dev,
 233                            struct iio_chan_spec const *chan,
 234                            int val,
 235                            int val2,
 236                            long mask)
 237{
 238        u16 aux;
 239
 240        if (mask != IIO_CHAN_INFO_RAW)
 241                return -EINVAL;
 242
 243        if (val2 || (val << chan->scan_type.shift) > 0xffff || val < 0)
 244                return -EINVAL;
 245
 246        aux = val << chan->scan_type.shift;
 247
 248        return ad5761_spi_write(indio_dev, AD5761_ADDR_DAC_WRITE, aux);
 249}
 250
 251static const struct iio_info ad5761_info = {
 252        .read_raw = &ad5761_read_raw,
 253        .write_raw = &ad5761_write_raw,
 254        .driver_module = THIS_MODULE,
 255};
 256
 257#define AD5761_CHAN(_bits) {                            \
 258        .type = IIO_VOLTAGE,                            \
 259        .output = 1,                                    \
 260        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
 261        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
 262                BIT(IIO_CHAN_INFO_OFFSET),              \
 263        .scan_type = {                                  \
 264                .sign = 'u',                            \
 265                .realbits = (_bits),                    \
 266                .storagebits = 16,                      \
 267                .shift = 16 - (_bits),                  \
 268        },                                              \
 269}
 270
 271static const struct ad5761_chip_info ad5761_chip_infos[] = {
 272        [ID_AD5721] = {
 273                .int_vref = 0,
 274                .channel = AD5761_CHAN(12),
 275        },
 276        [ID_AD5721R] = {
 277                .int_vref = 2500,
 278                .channel = AD5761_CHAN(12),
 279        },
 280        [ID_AD5761] = {
 281                .int_vref = 0,
 282                .channel = AD5761_CHAN(16),
 283        },
 284        [ID_AD5761R] = {
 285                .int_vref = 2500,
 286                .channel = AD5761_CHAN(16),
 287        },
 288};
 289
 290static int ad5761_get_vref(struct ad5761_state *st,
 291                           const struct ad5761_chip_info *chip_info)
 292{
 293        int ret;
 294
 295        st->vref_reg = devm_regulator_get_optional(&st->spi->dev, "vref");
 296        if (PTR_ERR(st->vref_reg) == -ENODEV) {
 297                /* Use Internal regulator */
 298                if (!chip_info->int_vref) {
 299                        dev_err(&st->spi->dev,
 300                                "Voltage reference not found\n");
 301                        return -EIO;
 302                }
 303
 304                st->use_intref = true;
 305                st->vref = chip_info->int_vref;
 306                return 0;
 307        }
 308
 309        if (IS_ERR(st->vref_reg)) {
 310                dev_err(&st->spi->dev,
 311                        "Error getting voltage reference regulator\n");
 312                return PTR_ERR(st->vref_reg);
 313        }
 314
 315        ret = regulator_enable(st->vref_reg);
 316        if (ret) {
 317                dev_err(&st->spi->dev,
 318                         "Failed to enable voltage reference\n");
 319                return ret;
 320        }
 321
 322        ret = regulator_get_voltage(st->vref_reg);
 323        if (ret < 0) {
 324                dev_err(&st->spi->dev,
 325                         "Failed to get voltage reference value\n");
 326                goto disable_regulator_vref;
 327        }
 328
 329        if (ret < 2000000 || ret > 3000000) {
 330                dev_warn(&st->spi->dev,
 331                         "Invalid external voltage ref. value %d uV\n", ret);
 332                ret = -EIO;
 333                goto disable_regulator_vref;
 334        }
 335
 336        st->vref = ret / 1000;
 337        st->use_intref = false;
 338
 339        return 0;
 340
 341disable_regulator_vref:
 342        regulator_disable(st->vref_reg);
 343        st->vref_reg = NULL;
 344        return ret;
 345}
 346
 347static int ad5761_probe(struct spi_device *spi)
 348{
 349        struct iio_dev *iio_dev;
 350        struct ad5761_state *st;
 351        int ret;
 352        const struct ad5761_chip_info *chip_info =
 353                &ad5761_chip_infos[spi_get_device_id(spi)->driver_data];
 354        enum ad5761_voltage_range voltage_range = AD5761_VOLTAGE_RANGE_0V_5V;
 355        struct ad5761_platform_data *pdata = dev_get_platdata(&spi->dev);
 356
 357        iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 358        if (!iio_dev)
 359                return -ENOMEM;
 360
 361        st = iio_priv(iio_dev);
 362
 363        st->spi = spi;
 364        spi_set_drvdata(spi, iio_dev);
 365
 366        ret = ad5761_get_vref(st, chip_info);
 367        if (ret)
 368                return ret;
 369
 370        if (pdata)
 371                voltage_range = pdata->voltage_range;
 372
 373        ret = ad5761_spi_set_range(st, voltage_range);
 374        if (ret)
 375                goto disable_regulator_err;
 376
 377        iio_dev->dev.parent = &spi->dev;
 378        iio_dev->info = &ad5761_info;
 379        iio_dev->modes = INDIO_DIRECT_MODE;
 380        iio_dev->channels = &chip_info->channel;
 381        iio_dev->num_channels = 1;
 382        iio_dev->name = spi_get_device_id(st->spi)->name;
 383        ret = iio_device_register(iio_dev);
 384        if (ret)
 385                goto disable_regulator_err;
 386
 387        return 0;
 388
 389disable_regulator_err:
 390        if (!IS_ERR_OR_NULL(st->vref_reg))
 391                regulator_disable(st->vref_reg);
 392
 393        return ret;
 394}
 395
 396static int ad5761_remove(struct spi_device *spi)
 397{
 398        struct iio_dev *iio_dev = spi_get_drvdata(spi);
 399        struct ad5761_state *st = iio_priv(iio_dev);
 400
 401        iio_device_unregister(iio_dev);
 402
 403        if (!IS_ERR_OR_NULL(st->vref_reg))
 404                regulator_disable(st->vref_reg);
 405
 406        return 0;
 407}
 408
 409static const struct spi_device_id ad5761_id[] = {
 410        {"ad5721", ID_AD5721},
 411        {"ad5721r", ID_AD5721R},
 412        {"ad5761", ID_AD5761},
 413        {"ad5761r", ID_AD5761R},
 414        {}
 415};
 416MODULE_DEVICE_TABLE(spi, ad5761_id);
 417
 418static struct spi_driver ad5761_driver = {
 419        .driver = {
 420                   .name = "ad5761",
 421                   },
 422        .probe = ad5761_probe,
 423        .remove = ad5761_remove,
 424        .id_table = ad5761_id,
 425};
 426module_spi_driver(ad5761_driver);
 427
 428MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
 429MODULE_DESCRIPTION("Analog Devices AD5721, AD5721R, AD5761, AD5761R driver");
 430MODULE_LICENSE("GPL v2");
 431