248 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for Linear Technology LTC1665/LTC1660, 8 channels DAC4 *5 * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>6 */7#include <linux/bitops.h>8#include <linux/iio/iio.h>9#include <linux/iio/sysfs.h>10#include <linux/init.h>11#include <linux/module.h>12#include <linux/regulator/consumer.h>13#include <linux/regmap.h>14#include <linux/spi/spi.h>15 16#define LTC1660_REG_WAKE 0x017#define LTC1660_REG_DAC_A 0x118#define LTC1660_REG_DAC_B 0x219#define LTC1660_REG_DAC_C 0x320#define LTC1660_REG_DAC_D 0x421#define LTC1660_REG_DAC_E 0x522#define LTC1660_REG_DAC_F 0x623#define LTC1660_REG_DAC_G 0x724#define LTC1660_REG_DAC_H 0x825#define LTC1660_REG_SLEEP 0xe26 27#define LTC1660_NUM_CHANNELS 828 29static const struct regmap_config ltc1660_regmap_config = {30 .reg_bits = 4,31 .val_bits = 12,32};33 34enum ltc1660_supported_device_ids {35 ID_LTC1660,36 ID_LTC1665,37};38 39struct ltc1660_priv {40 struct spi_device *spi;41 struct regmap *regmap;42 struct regulator *vref_reg;43 unsigned int value[LTC1660_NUM_CHANNELS];44 unsigned int vref_mv;45};46 47static int ltc1660_read_raw(struct iio_dev *indio_dev,48 struct iio_chan_spec const *chan,49 int *val,50 int *val2,51 long mask)52{53 struct ltc1660_priv *priv = iio_priv(indio_dev);54 55 switch (mask) {56 case IIO_CHAN_INFO_RAW:57 *val = priv->value[chan->channel];58 return IIO_VAL_INT;59 case IIO_CHAN_INFO_SCALE:60 *val = regulator_get_voltage(priv->vref_reg);61 if (*val < 0) {62 dev_err(&priv->spi->dev, "failed to read vref regulator: %d\n",63 *val);64 return *val;65 }66 67 /* Convert to mV */68 *val /= 1000;69 *val2 = chan->scan_type.realbits;70 return IIO_VAL_FRACTIONAL_LOG2;71 default:72 return -EINVAL;73 }74}75 76static int ltc1660_write_raw(struct iio_dev *indio_dev,77 struct iio_chan_spec const *chan,78 int val,79 int val2,80 long mask)81{82 struct ltc1660_priv *priv = iio_priv(indio_dev);83 int ret;84 85 switch (mask) {86 case IIO_CHAN_INFO_RAW:87 if (val2 != 0)88 return -EINVAL;89 90 if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))91 return -EINVAL;92 93 ret = regmap_write(priv->regmap, chan->channel,94 (val << chan->scan_type.shift));95 if (!ret)96 priv->value[chan->channel] = val;97 98 return ret;99 default:100 return -EINVAL;101 }102}103 104#define LTC1660_CHAN(chan, bits) { \105 .type = IIO_VOLTAGE, \106 .indexed = 1, \107 .output = 1, \108 .channel = chan, \109 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \110 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \111 .scan_type = { \112 .sign = 'u', \113 .realbits = (bits), \114 .storagebits = 16, \115 .shift = 12 - (bits), \116 }, \117}118 119#define LTC1660_OCTAL_CHANNELS(bits) { \120 LTC1660_CHAN(LTC1660_REG_DAC_A, bits), \121 LTC1660_CHAN(LTC1660_REG_DAC_B, bits), \122 LTC1660_CHAN(LTC1660_REG_DAC_C, bits), \123 LTC1660_CHAN(LTC1660_REG_DAC_D, bits), \124 LTC1660_CHAN(LTC1660_REG_DAC_E, bits), \125 LTC1660_CHAN(LTC1660_REG_DAC_F, bits), \126 LTC1660_CHAN(LTC1660_REG_DAC_G, bits), \127 LTC1660_CHAN(LTC1660_REG_DAC_H, bits), \128}129 130static const struct iio_chan_spec ltc1660_channels[][LTC1660_NUM_CHANNELS] = {131 [ID_LTC1660] = LTC1660_OCTAL_CHANNELS(10),132 [ID_LTC1665] = LTC1660_OCTAL_CHANNELS(8),133};134 135static const struct iio_info ltc1660_info = {136 .read_raw = <c1660_read_raw,137 .write_raw = <c1660_write_raw,138};139 140static int ltc1660_suspend(struct device *dev)141{142 struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(143 to_spi_device(dev)));144 return regmap_write(priv->regmap, LTC1660_REG_SLEEP, 0x00);145}146 147static int ltc1660_resume(struct device *dev)148{149 struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(150 to_spi_device(dev)));151 return regmap_write(priv->regmap, LTC1660_REG_WAKE, 0x00);152}153static DEFINE_SIMPLE_DEV_PM_OPS(ltc1660_pm_ops, ltc1660_suspend,154 ltc1660_resume);155 156static int ltc1660_probe(struct spi_device *spi)157{158 struct iio_dev *indio_dev;159 struct ltc1660_priv *priv;160 const struct spi_device_id *id = spi_get_device_id(spi);161 int ret;162 163 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));164 if (indio_dev == NULL)165 return -ENOMEM;166 167 priv = iio_priv(indio_dev);168 priv->regmap = devm_regmap_init_spi(spi, <c1660_regmap_config);169 if (IS_ERR(priv->regmap)) {170 dev_err(&spi->dev, "failed to register spi regmap %ld\n",171 PTR_ERR(priv->regmap));172 return PTR_ERR(priv->regmap);173 }174 175 priv->vref_reg = devm_regulator_get(&spi->dev, "vref");176 if (IS_ERR(priv->vref_reg))177 return dev_err_probe(&spi->dev, PTR_ERR(priv->vref_reg),178 "vref regulator not specified\n");179 180 ret = regulator_enable(priv->vref_reg);181 if (ret) {182 dev_err(&spi->dev, "failed to enable vref regulator: %d\n",183 ret);184 return ret;185 }186 187 priv->spi = spi;188 spi_set_drvdata(spi, indio_dev);189 indio_dev->info = <c1660_info;190 indio_dev->modes = INDIO_DIRECT_MODE;191 indio_dev->channels = ltc1660_channels[id->driver_data];192 indio_dev->num_channels = LTC1660_NUM_CHANNELS;193 indio_dev->name = id->name;194 195 ret = iio_device_register(indio_dev);196 if (ret) {197 dev_err(&spi->dev, "failed to register iio device: %d\n",198 ret);199 goto error_disable_reg;200 }201 202 return 0;203 204error_disable_reg:205 regulator_disable(priv->vref_reg);206 207 return ret;208}209 210static void ltc1660_remove(struct spi_device *spi)211{212 struct iio_dev *indio_dev = spi_get_drvdata(spi);213 struct ltc1660_priv *priv = iio_priv(indio_dev);214 215 iio_device_unregister(indio_dev);216 regulator_disable(priv->vref_reg);217}218 219static const struct of_device_id ltc1660_dt_ids[] = {220 { .compatible = "lltc,ltc1660", .data = (void *)ID_LTC1660 },221 { .compatible = "lltc,ltc1665", .data = (void *)ID_LTC1665 },222 { /* sentinel */ }223};224MODULE_DEVICE_TABLE(of, ltc1660_dt_ids);225 226static const struct spi_device_id ltc1660_id[] = {227 {"ltc1660", ID_LTC1660},228 {"ltc1665", ID_LTC1665},229 { /* sentinel */ }230};231MODULE_DEVICE_TABLE(spi, ltc1660_id);232 233static struct spi_driver ltc1660_driver = {234 .driver = {235 .name = "ltc1660",236 .of_match_table = ltc1660_dt_ids,237 .pm = pm_sleep_ptr(<c1660_pm_ops),238 },239 .probe = ltc1660_probe,240 .remove = ltc1660_remove,241 .id_table = ltc1660_id,242};243module_spi_driver(ltc1660_driver);244 245MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");246MODULE_DESCRIPTION("Linear Technology LTC1660/LTC1665 DAC");247MODULE_LICENSE("GPL v2");248