linux/drivers/iio/dac/ad5504.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * AD5504, AD5501 High Voltage Digital to Analog Converter
   4 *
   5 * Copyright 2011 Analog Devices Inc.
   6 */
   7
   8#include <linux/interrupt.h>
   9#include <linux/fs.h>
  10#include <linux/device.h>
  11#include <linux/kernel.h>
  12#include <linux/spi/spi.h>
  13#include <linux/slab.h>
  14#include <linux/sysfs.h>
  15#include <linux/regulator/consumer.h>
  16#include <linux/module.h>
  17#include <linux/bitops.h>
  18
  19#include <linux/iio/iio.h>
  20#include <linux/iio/sysfs.h>
  21#include <linux/iio/events.h>
  22#include <linux/iio/dac/ad5504.h>
  23
  24#define AD5504_RES_MASK                 GENMASK(11, 0)
  25#define AD5504_CMD_READ                 BIT(15)
  26#define AD5504_CMD_WRITE                0
  27#define AD5504_ADDR(addr)               ((addr) << 12)
  28
  29/* Registers */
  30#define AD5504_ADDR_NOOP                0
  31#define AD5504_ADDR_DAC(x)              ((x) + 1)
  32#define AD5504_ADDR_ALL_DAC             5
  33#define AD5504_ADDR_CTRL                7
  34
  35/* Control Register */
  36#define AD5504_DAC_PWR(ch)              ((ch) << 2)
  37#define AD5504_DAC_PWRDWN_MODE(mode)    ((mode) << 6)
  38#define AD5504_DAC_PWRDN_20K            0
  39#define AD5504_DAC_PWRDN_3STATE         1
  40
  41/**
  42 * struct ad5504_state - driver instance specific data
  43 * @spi:                        spi_device
  44 * @reg:                supply regulator
  45 * @vref_mv:            actual reference voltage used
  46 * @pwr_down_mask:      power down mask
  47 * @pwr_down_mode:      current power down mode
  48 * @data:               transfer buffer
  49 */
  50struct ad5504_state {
  51        struct spi_device               *spi;
  52        struct regulator                *reg;
  53        unsigned short                  vref_mv;
  54        unsigned                        pwr_down_mask;
  55        unsigned                        pwr_down_mode;
  56
  57        __be16                          data[2] ____cacheline_aligned;
  58};
  59
  60/*
  61 * ad5504_supported_device_ids:
  62 */
  63enum ad5504_supported_device_ids {
  64        ID_AD5504,
  65        ID_AD5501,
  66};
  67
  68static int ad5504_spi_write(struct ad5504_state *st, u8 addr, u16 val)
  69{
  70        st->data[0] = cpu_to_be16(AD5504_CMD_WRITE | AD5504_ADDR(addr) |
  71                              (val & AD5504_RES_MASK));
  72
  73        return spi_write(st->spi, &st->data[0], 2);
  74}
  75
  76static int ad5504_spi_read(struct ad5504_state *st, u8 addr)
  77{
  78        int ret;
  79        struct spi_transfer t = {
  80            .tx_buf = &st->data[0],
  81            .rx_buf = &st->data[1],
  82            .len = 2,
  83        };
  84
  85        st->data[0] = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr));
  86        ret = spi_sync_transfer(st->spi, &t, 1);
  87        if (ret < 0)
  88                return ret;
  89
  90        return be16_to_cpu(st->data[1]) & AD5504_RES_MASK;
  91}
  92
  93static int ad5504_read_raw(struct iio_dev *indio_dev,
  94                           struct iio_chan_spec const *chan,
  95                           int *val,
  96                           int *val2,
  97                           long m)
  98{
  99        struct ad5504_state *st = iio_priv(indio_dev);
 100        int ret;
 101
 102        switch (m) {
 103        case IIO_CHAN_INFO_RAW:
 104                ret = ad5504_spi_read(st, chan->address);
 105                if (ret < 0)
 106                        return ret;
 107
 108                *val = ret;
 109
 110                return IIO_VAL_INT;
 111        case IIO_CHAN_INFO_SCALE:
 112                *val = st->vref_mv;
 113                *val2 = chan->scan_type.realbits;
 114                return IIO_VAL_FRACTIONAL_LOG2;
 115        }
 116        return -EINVAL;
 117}
 118
 119static int ad5504_write_raw(struct iio_dev *indio_dev,
 120                               struct iio_chan_spec const *chan,
 121                               int val,
 122                               int val2,
 123                               long mask)
 124{
 125        struct ad5504_state *st = iio_priv(indio_dev);
 126
 127        switch (mask) {
 128        case IIO_CHAN_INFO_RAW:
 129                if (val >= (1 << chan->scan_type.realbits) || val < 0)
 130                        return -EINVAL;
 131
 132                return ad5504_spi_write(st, chan->address, val);
 133        default:
 134                return -EINVAL;
 135        }
 136}
 137
 138static const char * const ad5504_powerdown_modes[] = {
 139        "20kohm_to_gnd",
 140        "three_state",
 141};
 142
 143static int ad5504_get_powerdown_mode(struct iio_dev *indio_dev,
 144        const struct iio_chan_spec *chan)
 145{
 146        struct ad5504_state *st = iio_priv(indio_dev);
 147
 148        return st->pwr_down_mode;
 149}
 150
 151static int ad5504_set_powerdown_mode(struct iio_dev *indio_dev,
 152        const struct iio_chan_spec *chan, unsigned int mode)
 153{
 154        struct ad5504_state *st = iio_priv(indio_dev);
 155
 156        st->pwr_down_mode = mode;
 157
 158        return 0;
 159}
 160
 161static const struct iio_enum ad5504_powerdown_mode_enum = {
 162        .items = ad5504_powerdown_modes,
 163        .num_items = ARRAY_SIZE(ad5504_powerdown_modes),
 164        .get = ad5504_get_powerdown_mode,
 165        .set = ad5504_set_powerdown_mode,
 166};
 167
 168static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev,
 169        uintptr_t private, const struct iio_chan_spec *chan, char *buf)
 170{
 171        struct ad5504_state *st = iio_priv(indio_dev);
 172
 173        return sysfs_emit(buf, "%d\n",
 174                          !(st->pwr_down_mask & (1 << chan->channel)));
 175}
 176
 177static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev,
 178        uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
 179        size_t len)
 180{
 181        bool pwr_down;
 182        int ret;
 183        struct ad5504_state *st = iio_priv(indio_dev);
 184
 185        ret = strtobool(buf, &pwr_down);
 186        if (ret)
 187                return ret;
 188
 189        if (pwr_down)
 190                st->pwr_down_mask &= ~(1 << chan->channel);
 191        else
 192                st->pwr_down_mask |= (1 << chan->channel);
 193
 194        ret = ad5504_spi_write(st, AD5504_ADDR_CTRL,
 195                                AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
 196                                AD5504_DAC_PWR(st->pwr_down_mask));
 197
 198        /* writes to the CTRL register must be followed by a NOOP */
 199        ad5504_spi_write(st, AD5504_ADDR_NOOP, 0);
 200
 201        return ret ? ret : len;
 202}
 203
 204static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000");
 205static IIO_CONST_ATTR(temp0_thresh_rising_en, "1");
 206
 207static struct attribute *ad5504_ev_attributes[] = {
 208        &iio_const_attr_temp0_thresh_rising_value.dev_attr.attr,
 209        &iio_const_attr_temp0_thresh_rising_en.dev_attr.attr,
 210        NULL,
 211};
 212
 213static const struct attribute_group ad5504_ev_attribute_group = {
 214        .attrs = ad5504_ev_attributes,
 215};
 216
 217static irqreturn_t ad5504_event_handler(int irq, void *private)
 218{
 219        iio_push_event(private,
 220                       IIO_UNMOD_EVENT_CODE(IIO_TEMP,
 221                                            0,
 222                                            IIO_EV_TYPE_THRESH,
 223                                            IIO_EV_DIR_RISING),
 224                       iio_get_time_ns(private));
 225
 226        return IRQ_HANDLED;
 227}
 228
 229static const struct iio_info ad5504_info = {
 230        .write_raw = ad5504_write_raw,
 231        .read_raw = ad5504_read_raw,
 232        .event_attrs = &ad5504_ev_attribute_group,
 233};
 234
 235static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
 236        {
 237                .name = "powerdown",
 238                .read = ad5504_read_dac_powerdown,
 239                .write = ad5504_write_dac_powerdown,
 240                .shared = IIO_SEPARATE,
 241        },
 242        IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
 243                 &ad5504_powerdown_mode_enum),
 244        IIO_ENUM_AVAILABLE("powerdown_mode", &ad5504_powerdown_mode_enum),
 245        { },
 246};
 247
 248#define AD5504_CHANNEL(_chan) { \
 249        .type = IIO_VOLTAGE, \
 250        .indexed = 1, \
 251        .output = 1, \
 252        .channel = (_chan), \
 253        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
 254        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
 255        .address = AD5504_ADDR_DAC(_chan), \
 256        .scan_type = { \
 257                .sign = 'u', \
 258                .realbits = 12, \
 259                .storagebits = 16, \
 260        }, \
 261        .ext_info = ad5504_ext_info, \
 262}
 263
 264static const struct iio_chan_spec ad5504_channels[] = {
 265        AD5504_CHANNEL(0),
 266        AD5504_CHANNEL(1),
 267        AD5504_CHANNEL(2),
 268        AD5504_CHANNEL(3),
 269};
 270
 271static int ad5504_probe(struct spi_device *spi)
 272{
 273        struct ad5504_platform_data *pdata = spi->dev.platform_data;
 274        struct iio_dev *indio_dev;
 275        struct ad5504_state *st;
 276        struct regulator *reg;
 277        int ret, voltage_uv = 0;
 278
 279        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 280        if (!indio_dev)
 281                return -ENOMEM;
 282        reg = devm_regulator_get(&spi->dev, "vcc");
 283        if (!IS_ERR(reg)) {
 284                ret = regulator_enable(reg);
 285                if (ret)
 286                        return ret;
 287
 288                ret = regulator_get_voltage(reg);
 289                if (ret < 0)
 290                        goto error_disable_reg;
 291
 292                voltage_uv = ret;
 293        }
 294
 295        spi_set_drvdata(spi, indio_dev);
 296        st = iio_priv(indio_dev);
 297        if (voltage_uv)
 298                st->vref_mv = voltage_uv / 1000;
 299        else if (pdata)
 300                st->vref_mv = pdata->vref_mv;
 301        else
 302                dev_warn(&spi->dev, "reference voltage unspecified\n");
 303
 304        st->reg = reg;
 305        st->spi = spi;
 306        indio_dev->name = spi_get_device_id(st->spi)->name;
 307        indio_dev->info = &ad5504_info;
 308        if (spi_get_device_id(st->spi)->driver_data == ID_AD5501)
 309                indio_dev->num_channels = 1;
 310        else
 311                indio_dev->num_channels = 4;
 312        indio_dev->channels = ad5504_channels;
 313        indio_dev->modes = INDIO_DIRECT_MODE;
 314
 315        if (spi->irq) {
 316                ret = devm_request_threaded_irq(&spi->dev, spi->irq,
 317                                           NULL,
 318                                           &ad5504_event_handler,
 319                                           IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 320                                           spi_get_device_id(st->spi)->name,
 321                                           indio_dev);
 322                if (ret)
 323                        goto error_disable_reg;
 324        }
 325
 326        ret = iio_device_register(indio_dev);
 327        if (ret)
 328                goto error_disable_reg;
 329
 330        return 0;
 331
 332error_disable_reg:
 333        if (!IS_ERR(reg))
 334                regulator_disable(reg);
 335
 336        return ret;
 337}
 338
 339static int ad5504_remove(struct spi_device *spi)
 340{
 341        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 342        struct ad5504_state *st = iio_priv(indio_dev);
 343
 344        iio_device_unregister(indio_dev);
 345
 346        if (!IS_ERR(st->reg))
 347                regulator_disable(st->reg);
 348
 349        return 0;
 350}
 351
 352static const struct spi_device_id ad5504_id[] = {
 353        {"ad5504", ID_AD5504},
 354        {"ad5501", ID_AD5501},
 355        {}
 356};
 357MODULE_DEVICE_TABLE(spi, ad5504_id);
 358
 359static struct spi_driver ad5504_driver = {
 360        .driver = {
 361                   .name = "ad5504",
 362                   },
 363        .probe = ad5504_probe,
 364        .remove = ad5504_remove,
 365        .id_table = ad5504_id,
 366};
 367module_spi_driver(ad5504_driver);
 368
 369MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 370MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
 371MODULE_LICENSE("GPL v2");
 372