18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IIO DAC driver for Analog Devices AD8801 DAC 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Gwenhael Goavec-Merou 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 128c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define AD8801_CFG_ADDR_OFFSET 8 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cienum ad8801_device_ids { 178c2ecf20Sopenharmony_ci ID_AD8801, 188c2ecf20Sopenharmony_ci ID_AD8803, 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct ad8801_state { 228c2ecf20Sopenharmony_ci struct spi_device *spi; 238c2ecf20Sopenharmony_ci unsigned char dac_cache[8]; /* Value write on each channel */ 248c2ecf20Sopenharmony_ci unsigned int vrefh_mv; 258c2ecf20Sopenharmony_ci unsigned int vrefl_mv; 268c2ecf20Sopenharmony_ci struct regulator *vrefh_reg; 278c2ecf20Sopenharmony_ci struct regulator *vrefl_reg; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci __be16 data ____cacheline_aligned; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int ad8801_spi_write(struct ad8801_state *state, 338c2ecf20Sopenharmony_ci u8 channel, unsigned char value) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci state->data = cpu_to_be16((channel << AD8801_CFG_ADDR_OFFSET) | value); 368c2ecf20Sopenharmony_ci return spi_write(state->spi, &state->data, sizeof(state->data)); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int ad8801_write_raw(struct iio_dev *indio_dev, 408c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, int val, int val2, long mask) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct ad8801_state *state = iio_priv(indio_dev); 438c2ecf20Sopenharmony_ci int ret; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci switch (mask) { 468c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 478c2ecf20Sopenharmony_ci if (val >= 256 || val < 0) 488c2ecf20Sopenharmony_ci return -EINVAL; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci ret = ad8801_spi_write(state, chan->channel, val); 518c2ecf20Sopenharmony_ci if (ret == 0) 528c2ecf20Sopenharmony_ci state->dac_cache[chan->channel] = val; 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci default: 558c2ecf20Sopenharmony_ci ret = -EINVAL; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int ad8801_read_raw(struct iio_dev *indio_dev, 628c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, int *val, int *val2, long info) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct ad8801_state *state = iio_priv(indio_dev); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci switch (info) { 678c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 688c2ecf20Sopenharmony_ci *val = state->dac_cache[chan->channel]; 698c2ecf20Sopenharmony_ci return IIO_VAL_INT; 708c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 718c2ecf20Sopenharmony_ci *val = state->vrefh_mv - state->vrefl_mv; 728c2ecf20Sopenharmony_ci *val2 = 8; 738c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 748c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 758c2ecf20Sopenharmony_ci *val = state->vrefl_mv; 768c2ecf20Sopenharmony_ci return IIO_VAL_INT; 778c2ecf20Sopenharmony_ci default: 788c2ecf20Sopenharmony_ci return -EINVAL; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return -EINVAL; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const struct iio_info ad8801_info = { 858c2ecf20Sopenharmony_ci .read_raw = ad8801_read_raw, 868c2ecf20Sopenharmony_ci .write_raw = ad8801_write_raw, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define AD8801_CHANNEL(chan) { \ 908c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 918c2ecf20Sopenharmony_ci .indexed = 1, \ 928c2ecf20Sopenharmony_ci .output = 1, \ 938c2ecf20Sopenharmony_ci .channel = chan, \ 948c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 958c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 968c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), \ 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic const struct iio_chan_spec ad8801_channels[] = { 1008c2ecf20Sopenharmony_ci AD8801_CHANNEL(0), 1018c2ecf20Sopenharmony_ci AD8801_CHANNEL(1), 1028c2ecf20Sopenharmony_ci AD8801_CHANNEL(2), 1038c2ecf20Sopenharmony_ci AD8801_CHANNEL(3), 1048c2ecf20Sopenharmony_ci AD8801_CHANNEL(4), 1058c2ecf20Sopenharmony_ci AD8801_CHANNEL(5), 1068c2ecf20Sopenharmony_ci AD8801_CHANNEL(6), 1078c2ecf20Sopenharmony_ci AD8801_CHANNEL(7), 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int ad8801_probe(struct spi_device *spi) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 1138c2ecf20Sopenharmony_ci struct ad8801_state *state; 1148c2ecf20Sopenharmony_ci const struct spi_device_id *id; 1158c2ecf20Sopenharmony_ci int ret; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state)); 1188c2ecf20Sopenharmony_ci if (indio_dev == NULL) 1198c2ecf20Sopenharmony_ci return -ENOMEM; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci state = iio_priv(indio_dev); 1228c2ecf20Sopenharmony_ci state->spi = spi; 1238c2ecf20Sopenharmony_ci id = spi_get_device_id(spi); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh"); 1268c2ecf20Sopenharmony_ci if (IS_ERR(state->vrefh_reg)) { 1278c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Vrefh regulator not specified\n"); 1288c2ecf20Sopenharmony_ci return PTR_ERR(state->vrefh_reg); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ret = regulator_enable(state->vrefh_reg); 1328c2ecf20Sopenharmony_ci if (ret) { 1338c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n", 1348c2ecf20Sopenharmony_ci ret); 1358c2ecf20Sopenharmony_ci return ret; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ret = regulator_get_voltage(state->vrefh_reg); 1398c2ecf20Sopenharmony_ci if (ret < 0) { 1408c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n", 1418c2ecf20Sopenharmony_ci ret); 1428c2ecf20Sopenharmony_ci goto error_disable_vrefh_reg; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci state->vrefh_mv = ret / 1000; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (id->driver_data == ID_AD8803) { 1478c2ecf20Sopenharmony_ci state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl"); 1488c2ecf20Sopenharmony_ci if (IS_ERR(state->vrefl_reg)) { 1498c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Vrefl regulator not specified\n"); 1508c2ecf20Sopenharmony_ci ret = PTR_ERR(state->vrefl_reg); 1518c2ecf20Sopenharmony_ci goto error_disable_vrefh_reg; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ret = regulator_enable(state->vrefl_reg); 1558c2ecf20Sopenharmony_ci if (ret) { 1568c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n", 1578c2ecf20Sopenharmony_ci ret); 1588c2ecf20Sopenharmony_ci goto error_disable_vrefh_reg; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci ret = regulator_get_voltage(state->vrefl_reg); 1628c2ecf20Sopenharmony_ci if (ret < 0) { 1638c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n", 1648c2ecf20Sopenharmony_ci ret); 1658c2ecf20Sopenharmony_ci goto error_disable_vrefl_reg; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci state->vrefl_mv = ret / 1000; 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci state->vrefl_mv = 0; 1708c2ecf20Sopenharmony_ci state->vrefl_reg = NULL; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 1748c2ecf20Sopenharmony_ci indio_dev->info = &ad8801_info; 1758c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 1768c2ecf20Sopenharmony_ci indio_dev->channels = ad8801_channels; 1778c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(ad8801_channels); 1788c2ecf20Sopenharmony_ci indio_dev->name = id->name; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 1818c2ecf20Sopenharmony_ci if (ret) { 1828c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to register iio device: %d\n", 1838c2ecf20Sopenharmony_ci ret); 1848c2ecf20Sopenharmony_ci goto error_disable_vrefl_reg; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cierror_disable_vrefl_reg: 1908c2ecf20Sopenharmony_ci if (state->vrefl_reg) 1918c2ecf20Sopenharmony_ci regulator_disable(state->vrefl_reg); 1928c2ecf20Sopenharmony_cierror_disable_vrefh_reg: 1938c2ecf20Sopenharmony_ci regulator_disable(state->vrefh_reg); 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int ad8801_remove(struct spi_device *spi) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = spi_get_drvdata(spi); 2008c2ecf20Sopenharmony_ci struct ad8801_state *state = iio_priv(indio_dev); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 2038c2ecf20Sopenharmony_ci if (state->vrefl_reg) 2048c2ecf20Sopenharmony_ci regulator_disable(state->vrefl_reg); 2058c2ecf20Sopenharmony_ci regulator_disable(state->vrefh_reg); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic const struct spi_device_id ad8801_ids[] = { 2118c2ecf20Sopenharmony_ci {"ad8801", ID_AD8801}, 2128c2ecf20Sopenharmony_ci {"ad8803", ID_AD8803}, 2138c2ecf20Sopenharmony_ci {} 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad8801_ids); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic struct spi_driver ad8801_driver = { 2188c2ecf20Sopenharmony_ci .driver = { 2198c2ecf20Sopenharmony_ci .name = "ad8801", 2208c2ecf20Sopenharmony_ci }, 2218c2ecf20Sopenharmony_ci .probe = ad8801_probe, 2228c2ecf20Sopenharmony_ci .remove = ad8801_remove, 2238c2ecf20Sopenharmony_ci .id_table = ad8801_ids, 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_cimodule_spi_driver(ad8801_driver); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>"); 2288c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD8801/AD8803 DAC"); 2298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 230