linux/drivers/iio/dac/ltc2632.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * LTC2632 Digital to analog convertors spi driver
   4 *
   5 * Copyright 2017 Maxime Roussin-B\xC3\xA9langer
   6 * expanded by Silvan Murer <silvan.murer@gmail.com>
   7 */
   8
   9#include <linux/device.h>
  10#include <linux/spi/spi.h>
  11#include <linux/module.h>
  12#include <linux/iio/iio.h>
  13#include <linux/regulator/consumer.h>
  14
  15#include <asm/unaligned.h>
  16
  17#define LTC2632_CMD_WRITE_INPUT_N               0x0
  18#define LTC2632_CMD_UPDATE_DAC_N                0x1
  19#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL    0x2
  20#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_N      0x3
  21#define LTC2632_CMD_POWERDOWN_DAC_N             0x4
  22#define LTC2632_CMD_POWERDOWN_CHIP              0x5
  23#define LTC2632_CMD_INTERNAL_REFER              0x6
  24#define LTC2632_CMD_EXTERNAL_REFER              0x7
  25
  26/**
  27 * struct ltc2632_chip_info - chip specific information
  28 * @channels:           channel spec for the DAC
  29 * @num_channels:       DAC channel count of the chip
  30 * @vref_mv:            internal reference voltage
  31 */
  32struct ltc2632_chip_info {
  33        const struct iio_chan_spec *channels;
  34        const size_t num_channels;
  35        const int vref_mv;
  36};
  37
  38/**
  39 * struct ltc2632_state - driver instance specific data
  40 * @spi_dev:                    pointer to the spi_device struct
  41 * @powerdown_cache_mask:       used to show current channel powerdown state
  42 * @vref_mv:                    used reference voltage (internal or external)
  43 * @vref_reg:           regulator for the reference voltage
  44 */
  45struct ltc2632_state {
  46        struct spi_device *spi_dev;
  47        unsigned int powerdown_cache_mask;
  48        int vref_mv;
  49        struct regulator *vref_reg;
  50};
  51
  52enum ltc2632_supported_device_ids {
  53        ID_LTC2632L12,
  54        ID_LTC2632L10,
  55        ID_LTC2632L8,
  56        ID_LTC2632H12,
  57        ID_LTC2632H10,
  58        ID_LTC2632H8,
  59        ID_LTC2634L12,
  60        ID_LTC2634L10,
  61        ID_LTC2634L8,
  62        ID_LTC2634H12,
  63        ID_LTC2634H10,
  64        ID_LTC2634H8,
  65        ID_LTC2636L12,
  66        ID_LTC2636L10,
  67        ID_LTC2636L8,
  68        ID_LTC2636H12,
  69        ID_LTC2636H10,
  70        ID_LTC2636H8,
  71};
  72
  73static int ltc2632_spi_write(struct spi_device *spi,
  74                             u8 cmd, u8 addr, u16 val, u8 shift)
  75{
  76        u32 data;
  77        u8 msg[3];
  78
  79        /*
  80         * The input shift register is 24 bits wide.
  81         * The next four are the command bits, C3 to C0,
  82         * followed by the 4-bit DAC address, A3 to A0, and then the
  83         * 12-, 10-, 8-bit data-word. The data-word comprises the 12-,
  84         * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits.
  85         */
  86        data = (cmd << 20) | (addr << 16) | (val << shift);
  87        put_unaligned_be24(data, &msg[0]);
  88
  89        return spi_write(spi, msg, sizeof(msg));
  90}
  91
  92static int ltc2632_read_raw(struct iio_dev *indio_dev,
  93                            struct iio_chan_spec const *chan,
  94                            int *val,
  95                            int *val2,
  96                            long m)
  97{
  98        const struct ltc2632_state *st = iio_priv(indio_dev);
  99
 100        switch (m) {
 101        case IIO_CHAN_INFO_SCALE:
 102                *val = st->vref_mv;
 103                *val2 = chan->scan_type.realbits;
 104                return IIO_VAL_FRACTIONAL_LOG2;
 105        }
 106        return -EINVAL;
 107}
 108
 109static int ltc2632_write_raw(struct iio_dev *indio_dev,
 110                             struct iio_chan_spec const *chan,
 111                             int val,
 112                             int val2,
 113                             long mask)
 114{
 115        struct ltc2632_state *st = iio_priv(indio_dev);
 116
 117        switch (mask) {
 118        case IIO_CHAN_INFO_RAW:
 119                if (val >= (1 << chan->scan_type.realbits) || val < 0)
 120                        return -EINVAL;
 121
 122                return ltc2632_spi_write(st->spi_dev,
 123                                         LTC2632_CMD_WRITE_INPUT_N_UPDATE_N,
 124                                         chan->address, val,
 125                                         chan->scan_type.shift);
 126        default:
 127                return -EINVAL;
 128        }
 129}
 130
 131static ssize_t ltc2632_read_dac_powerdown(struct iio_dev *indio_dev,
 132                                          uintptr_t private,
 133                                          const struct iio_chan_spec *chan,
 134                                          char *buf)
 135{
 136        struct ltc2632_state *st = iio_priv(indio_dev);
 137
 138        return sysfs_emit(buf, "%d\n",
 139                          !!(st->powerdown_cache_mask & (1 << chan->channel)));
 140}
 141
 142static ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev,
 143                                           uintptr_t private,
 144                                           const struct iio_chan_spec *chan,
 145                                           const char *buf,
 146                                           size_t len)
 147{
 148        bool pwr_down;
 149        int ret;
 150        struct ltc2632_state *st = iio_priv(indio_dev);
 151
 152        ret = strtobool(buf, &pwr_down);
 153        if (ret)
 154                return ret;
 155
 156        if (pwr_down)
 157                st->powerdown_cache_mask |= (1 << chan->channel);
 158        else
 159                st->powerdown_cache_mask &= ~(1 << chan->channel);
 160
 161        ret = ltc2632_spi_write(st->spi_dev,
 162                                LTC2632_CMD_POWERDOWN_DAC_N,
 163                                chan->channel, 0, 0);
 164
 165        return ret ? ret : len;
 166}
 167
 168static const struct iio_info ltc2632_info = {
 169        .write_raw      = ltc2632_write_raw,
 170        .read_raw       = ltc2632_read_raw,
 171};
 172
 173static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = {
 174        {
 175                .name = "powerdown",
 176                .read = ltc2632_read_dac_powerdown,
 177                .write = ltc2632_write_dac_powerdown,
 178                .shared = IIO_SEPARATE,
 179        },
 180        { },
 181};
 182
 183#define LTC2632_CHANNEL(_chan, _bits) { \
 184                .type = IIO_VOLTAGE, \
 185                .indexed = 1, \
 186                .output = 1, \
 187                .channel = (_chan), \
 188                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
 189                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
 190                .address = (_chan), \
 191                .scan_type = { \
 192                        .realbits       = (_bits), \
 193                        .shift          = 16 - (_bits), \
 194                }, \
 195                .ext_info = ltc2632_ext_info, \
 196}
 197
 198#define DECLARE_LTC2632_CHANNELS(_name, _bits) \
 199        const struct iio_chan_spec _name ## _channels[] = { \
 200                LTC2632_CHANNEL(0, _bits), \
 201                LTC2632_CHANNEL(1, _bits), \
 202                LTC2632_CHANNEL(2, _bits), \
 203                LTC2632_CHANNEL(3, _bits), \
 204                LTC2632_CHANNEL(4, _bits), \
 205                LTC2632_CHANNEL(5, _bits), \
 206                LTC2632_CHANNEL(6, _bits), \
 207                LTC2632_CHANNEL(7, _bits), \
 208        }
 209
 210static DECLARE_LTC2632_CHANNELS(ltc2632x12, 12);
 211static DECLARE_LTC2632_CHANNELS(ltc2632x10, 10);
 212static DECLARE_LTC2632_CHANNELS(ltc2632x8, 8);
 213
 214static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = {
 215        [ID_LTC2632L12] = {
 216                .channels       = ltc2632x12_channels,
 217                .num_channels   = 2,
 218                .vref_mv        = 2500,
 219        },
 220        [ID_LTC2632L10] = {
 221                .channels       = ltc2632x10_channels,
 222                .num_channels   = 2,
 223                .vref_mv        = 2500,
 224        },
 225        [ID_LTC2632L8] =  {
 226                .channels       = ltc2632x8_channels,
 227                .num_channels   = 2,
 228                .vref_mv        = 2500,
 229        },
 230        [ID_LTC2632H12] = {
 231                .channels       = ltc2632x12_channels,
 232                .num_channels   = 2,
 233                .vref_mv        = 4096,
 234        },
 235        [ID_LTC2632H10] = {
 236                .channels       = ltc2632x10_channels,
 237                .num_channels   = 2,
 238                .vref_mv        = 4096,
 239        },
 240        [ID_LTC2632H8] =  {
 241                .channels       = ltc2632x8_channels,
 242                .num_channels   = 2,
 243                .vref_mv        = 4096,
 244        },
 245        [ID_LTC2634L12] = {
 246                .channels       = ltc2632x12_channels,
 247                .num_channels   = 4,
 248                .vref_mv        = 2500,
 249        },
 250        [ID_LTC2634L10] = {
 251                .channels       = ltc2632x10_channels,
 252                .num_channels   = 4,
 253                .vref_mv        = 2500,
 254        },
 255        [ID_LTC2634L8] =  {
 256                .channels       = ltc2632x8_channels,
 257                .num_channels   = 4,
 258                .vref_mv        = 2500,
 259        },
 260        [ID_LTC2634H12] = {
 261                .channels       = ltc2632x12_channels,
 262                .num_channels   = 4,
 263                .vref_mv        = 4096,
 264        },
 265        [ID_LTC2634H10] = {
 266                .channels       = ltc2632x10_channels,
 267                .num_channels   = 4,
 268                .vref_mv        = 4096,
 269        },
 270        [ID_LTC2634H8] =  {
 271                .channels       = ltc2632x8_channels,
 272                .num_channels   = 4,
 273                .vref_mv        = 4096,
 274        },
 275        [ID_LTC2636L12] = {
 276                .channels       = ltc2632x12_channels,
 277                .num_channels   = 8,
 278                .vref_mv        = 2500,
 279        },
 280        [ID_LTC2636L10] = {
 281                .channels       = ltc2632x10_channels,
 282                .num_channels   = 8,
 283                .vref_mv        = 2500,
 284        },
 285        [ID_LTC2636L8] =  {
 286                .channels       = ltc2632x8_channels,
 287                .num_channels   = 8,
 288                .vref_mv        = 2500,
 289        },
 290        [ID_LTC2636H12] = {
 291                .channels       = ltc2632x12_channels,
 292                .num_channels   = 8,
 293                .vref_mv        = 4096,
 294        },
 295        [ID_LTC2636H10] = {
 296                .channels       = ltc2632x10_channels,
 297                .num_channels   = 8,
 298                .vref_mv        = 4096,
 299        },
 300        [ID_LTC2636H8] =  {
 301                .channels       = ltc2632x8_channels,
 302                .num_channels   = 8,
 303                .vref_mv        = 4096,
 304        },
 305};
 306
 307static int ltc2632_probe(struct spi_device *spi)
 308{
 309        struct ltc2632_state *st;
 310        struct iio_dev *indio_dev;
 311        struct ltc2632_chip_info *chip_info;
 312        int ret;
 313
 314        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 315        if (!indio_dev)
 316                return -ENOMEM;
 317
 318        st = iio_priv(indio_dev);
 319
 320        spi_set_drvdata(spi, indio_dev);
 321        st->spi_dev = spi;
 322
 323        chip_info = (struct ltc2632_chip_info *)
 324                        spi_get_device_id(spi)->driver_data;
 325
 326        st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
 327        if (PTR_ERR(st->vref_reg) == -ENODEV) {
 328                /* use internal reference voltage */
 329                st->vref_reg = NULL;
 330                st->vref_mv = chip_info->vref_mv;
 331
 332                ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
 333                                0, 0, 0);
 334                if (ret) {
 335                        dev_err(&spi->dev,
 336                                "Set internal reference command failed, %d\n",
 337                                ret);
 338                        return ret;
 339                }
 340        } else if (IS_ERR(st->vref_reg)) {
 341                dev_err(&spi->dev,
 342                                "Error getting voltage reference regulator\n");
 343                return PTR_ERR(st->vref_reg);
 344        } else {
 345                /* use external reference voltage */
 346                ret = regulator_enable(st->vref_reg);
 347                if (ret) {
 348                        dev_err(&spi->dev,
 349                                "enable reference regulator failed, %d\n",
 350                                ret);
 351                        return ret;
 352                }
 353                st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000;
 354
 355                ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER,
 356                                0, 0, 0);
 357                if (ret) {
 358                        dev_err(&spi->dev,
 359                                "Set external reference command failed, %d\n",
 360                                ret);
 361                        return ret;
 362                }
 363        }
 364
 365        indio_dev->name = dev_of_node(&spi->dev) ? dev_of_node(&spi->dev)->name
 366                                                 : spi_get_device_id(spi)->name;
 367        indio_dev->info = &ltc2632_info;
 368        indio_dev->modes = INDIO_DIRECT_MODE;
 369        indio_dev->channels = chip_info->channels;
 370        indio_dev->num_channels = chip_info->num_channels;
 371
 372        return iio_device_register(indio_dev);
 373}
 374
 375static int ltc2632_remove(struct spi_device *spi)
 376{
 377        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 378        struct ltc2632_state *st = iio_priv(indio_dev);
 379
 380        iio_device_unregister(indio_dev);
 381
 382        if (st->vref_reg)
 383                regulator_disable(st->vref_reg);
 384
 385        return 0;
 386}
 387
 388static const struct spi_device_id ltc2632_id[] = {
 389        { "ltc2632-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L12] },
 390        { "ltc2632-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L10] },
 391        { "ltc2632-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L8] },
 392        { "ltc2632-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H12] },
 393        { "ltc2632-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H10] },
 394        { "ltc2632-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H8] },
 395        { "ltc2634-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L12] },
 396        { "ltc2634-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L10] },
 397        { "ltc2634-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L8] },
 398        { "ltc2634-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H12] },
 399        { "ltc2634-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H10] },
 400        { "ltc2634-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H8] },
 401        { "ltc2636-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L12] },
 402        { "ltc2636-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L10] },
 403        { "ltc2636-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L8] },
 404        { "ltc2636-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H12] },
 405        { "ltc2636-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H10] },
 406        { "ltc2636-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H8] },
 407        {}
 408};
 409MODULE_DEVICE_TABLE(spi, ltc2632_id);
 410
 411static const struct of_device_id ltc2632_of_match[] = {
 412        {
 413                .compatible = "lltc,ltc2632-l12",
 414                .data = &ltc2632_chip_info_tbl[ID_LTC2632L12]
 415        }, {
 416                .compatible = "lltc,ltc2632-l10",
 417                .data = &ltc2632_chip_info_tbl[ID_LTC2632L10]
 418        }, {
 419                .compatible = "lltc,ltc2632-l8",
 420                .data = &ltc2632_chip_info_tbl[ID_LTC2632L8]
 421        }, {
 422                .compatible = "lltc,ltc2632-h12",
 423                .data = &ltc2632_chip_info_tbl[ID_LTC2632H12]
 424        }, {
 425                .compatible = "lltc,ltc2632-h10",
 426                .data = &ltc2632_chip_info_tbl[ID_LTC2632H10]
 427        }, {
 428                .compatible = "lltc,ltc2632-h8",
 429                .data = &ltc2632_chip_info_tbl[ID_LTC2632H8]
 430        }, {
 431                .compatible = "lltc,ltc2634-l12",
 432                .data = &ltc2632_chip_info_tbl[ID_LTC2634L12]
 433        }, {
 434                .compatible = "lltc,ltc2634-l10",
 435                .data = &ltc2632_chip_info_tbl[ID_LTC2634L10]
 436        }, {
 437                .compatible = "lltc,ltc2634-l8",
 438                .data = &ltc2632_chip_info_tbl[ID_LTC2634L8]
 439        }, {
 440                .compatible = "lltc,ltc2634-h12",
 441                .data = &ltc2632_chip_info_tbl[ID_LTC2634H12]
 442        }, {
 443                .compatible = "lltc,ltc2634-h10",
 444                .data = &ltc2632_chip_info_tbl[ID_LTC2634H10]
 445        }, {
 446                .compatible = "lltc,ltc2634-h8",
 447                .data = &ltc2632_chip_info_tbl[ID_LTC2634H8]
 448        }, {
 449                .compatible = "lltc,ltc2636-l12",
 450                .data = &ltc2632_chip_info_tbl[ID_LTC2636L12]
 451        }, {
 452                .compatible = "lltc,ltc2636-l10",
 453                .data = &ltc2632_chip_info_tbl[ID_LTC2636L10]
 454        }, {
 455                .compatible = "lltc,ltc2636-l8",
 456                .data = &ltc2632_chip_info_tbl[ID_LTC2636L8]
 457        }, {
 458                .compatible = "lltc,ltc2636-h12",
 459                .data = &ltc2632_chip_info_tbl[ID_LTC2636H12]
 460        }, {
 461                .compatible = "lltc,ltc2636-h10",
 462                .data = &ltc2632_chip_info_tbl[ID_LTC2636H10]
 463        }, {
 464                .compatible = "lltc,ltc2636-h8",
 465                .data = &ltc2632_chip_info_tbl[ID_LTC2636H8]
 466        },
 467        {}
 468};
 469MODULE_DEVICE_TABLE(of, ltc2632_of_match);
 470
 471static struct spi_driver ltc2632_driver = {
 472        .driver         = {
 473                .name   = "ltc2632",
 474                .of_match_table = of_match_ptr(ltc2632_of_match),
 475        },
 476        .probe          = ltc2632_probe,
 477        .remove         = ltc2632_remove,
 478        .id_table       = ltc2632_id,
 479};
 480module_spi_driver(ltc2632_driver);
 481
 482MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");
 483MODULE_DESCRIPTION("LTC2632 DAC SPI driver");
 484MODULE_LICENSE("GPL v2");
 485