18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ti-dac5571.c - Texas Instruments 8/10/12-bit 1/4-channel DAC driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Prevas A/S 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac5571.pdf 88c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac6571.pdf 98c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac7571.pdf 108c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac5574.pdf 118c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac6574.pdf 128c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac7574.pdf 138c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac5573.pdf 148c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac6573.pdf 158c2ecf20Sopenharmony_ci * https://www.ti.com/lit/ds/symlink/dac7573.pdf 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 198c2ecf20Sopenharmony_ci#include <linux/i2c.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 228c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cienum chip_id { 258c2ecf20Sopenharmony_ci single_8bit, single_10bit, single_12bit, 268c2ecf20Sopenharmony_ci quad_8bit, quad_10bit, quad_12bit 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct dac5571_spec { 308c2ecf20Sopenharmony_ci u8 num_channels; 318c2ecf20Sopenharmony_ci u8 resolution; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const struct dac5571_spec dac5571_spec[] = { 358c2ecf20Sopenharmony_ci [single_8bit] = {.num_channels = 1, .resolution = 8}, 368c2ecf20Sopenharmony_ci [single_10bit] = {.num_channels = 1, .resolution = 10}, 378c2ecf20Sopenharmony_ci [single_12bit] = {.num_channels = 1, .resolution = 12}, 388c2ecf20Sopenharmony_ci [quad_8bit] = {.num_channels = 4, .resolution = 8}, 398c2ecf20Sopenharmony_ci [quad_10bit] = {.num_channels = 4, .resolution = 10}, 408c2ecf20Sopenharmony_ci [quad_12bit] = {.num_channels = 4, .resolution = 12}, 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct dac5571_data { 448c2ecf20Sopenharmony_ci struct i2c_client *client; 458c2ecf20Sopenharmony_ci int id; 468c2ecf20Sopenharmony_ci struct mutex lock; 478c2ecf20Sopenharmony_ci struct regulator *vref; 488c2ecf20Sopenharmony_ci u16 val[4]; 498c2ecf20Sopenharmony_ci bool powerdown[4]; 508c2ecf20Sopenharmony_ci u8 powerdown_mode[4]; 518c2ecf20Sopenharmony_ci struct dac5571_spec const *spec; 528c2ecf20Sopenharmony_ci int (*dac5571_cmd)(struct dac5571_data *data, int channel, u16 val); 538c2ecf20Sopenharmony_ci int (*dac5571_pwrdwn)(struct dac5571_data *data, int channel, u8 pwrdwn); 548c2ecf20Sopenharmony_ci u8 buf[3] ____cacheline_aligned; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define DAC5571_POWERDOWN(mode) ((mode) + 1) 588c2ecf20Sopenharmony_ci#define DAC5571_POWERDOWN_FLAG BIT(0) 598c2ecf20Sopenharmony_ci#define DAC5571_CHANNEL_SELECT 1 608c2ecf20Sopenharmony_ci#define DAC5571_LOADMODE_DIRECT BIT(4) 618c2ecf20Sopenharmony_ci#define DAC5571_SINGLE_PWRDWN_BITS 4 628c2ecf20Sopenharmony_ci#define DAC5571_QUAD_PWRDWN_BITS 6 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int dac5571_cmd_single(struct dac5571_data *data, int channel, u16 val) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci unsigned int shift; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci shift = 12 - data->spec->resolution; 698c2ecf20Sopenharmony_ci data->buf[1] = val << shift; 708c2ecf20Sopenharmony_ci data->buf[0] = val >> (8 - shift); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (i2c_master_send(data->client, data->buf, 2) != 2) 738c2ecf20Sopenharmony_ci return -EIO; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int dac5571_cmd_quad(struct dac5571_data *data, int channel, u16 val) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci unsigned int shift; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci shift = 16 - data->spec->resolution; 838c2ecf20Sopenharmony_ci data->buf[2] = val << shift; 848c2ecf20Sopenharmony_ci data->buf[1] = (val >> (8 - shift)); 858c2ecf20Sopenharmony_ci data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | 868c2ecf20Sopenharmony_ci DAC5571_LOADMODE_DIRECT; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (i2c_master_send(data->client, data->buf, 3) != 3) 898c2ecf20Sopenharmony_ci return -EIO; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci data->buf[1] = 0; 978c2ecf20Sopenharmony_ci data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (i2c_master_send(data->client, data->buf, 2) != 2) 1008c2ecf20Sopenharmony_ci return -EIO; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci data->buf[2] = 0; 1088c2ecf20Sopenharmony_ci data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS; 1098c2ecf20Sopenharmony_ci data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | 1108c2ecf20Sopenharmony_ci DAC5571_LOADMODE_DIRECT | DAC5571_POWERDOWN_FLAG; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (i2c_master_send(data->client, data->buf, 3) != 3) 1138c2ecf20Sopenharmony_ci return -EIO; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic const char *const dac5571_powerdown_modes[] = { 1198c2ecf20Sopenharmony_ci "1kohm_to_gnd", "100kohm_to_gnd", "three_state", 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int dac5571_get_powerdown_mode(struct iio_dev *indio_dev, 1238c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct dac5571_data *data = iio_priv(indio_dev); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return data->powerdown_mode[chan->channel]; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int dac5571_set_powerdown_mode(struct iio_dev *indio_dev, 1318c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 1328c2ecf20Sopenharmony_ci unsigned int mode) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct dac5571_data *data = iio_priv(indio_dev); 1358c2ecf20Sopenharmony_ci int ret = 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (data->powerdown_mode[chan->channel] == mode) 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 1418c2ecf20Sopenharmony_ci if (data->powerdown[chan->channel]) { 1428c2ecf20Sopenharmony_ci ret = data->dac5571_pwrdwn(data, chan->channel, 1438c2ecf20Sopenharmony_ci DAC5571_POWERDOWN(mode)); 1448c2ecf20Sopenharmony_ci if (ret) 1458c2ecf20Sopenharmony_ci goto out; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci data->powerdown_mode[chan->channel] = mode; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci out: 1508c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return ret; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const struct iio_enum dac5571_powerdown_mode = { 1568c2ecf20Sopenharmony_ci .items = dac5571_powerdown_modes, 1578c2ecf20Sopenharmony_ci .num_items = ARRAY_SIZE(dac5571_powerdown_modes), 1588c2ecf20Sopenharmony_ci .get = dac5571_get_powerdown_mode, 1598c2ecf20Sopenharmony_ci .set = dac5571_set_powerdown_mode, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic ssize_t dac5571_read_powerdown(struct iio_dev *indio_dev, 1638c2ecf20Sopenharmony_ci uintptr_t private, 1648c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 1658c2ecf20Sopenharmony_ci char *buf) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct dac5571_data *data = iio_priv(indio_dev); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->powerdown[chan->channel]); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev, 1738c2ecf20Sopenharmony_ci uintptr_t private, 1748c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 1758c2ecf20Sopenharmony_ci const char *buf, size_t len) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct dac5571_data *data = iio_priv(indio_dev); 1788c2ecf20Sopenharmony_ci bool powerdown; 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = strtobool(buf, &powerdown); 1828c2ecf20Sopenharmony_ci if (ret) 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (data->powerdown[chan->channel] == powerdown) 1868c2ecf20Sopenharmony_ci return len; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 1898c2ecf20Sopenharmony_ci if (powerdown) 1908c2ecf20Sopenharmony_ci ret = data->dac5571_pwrdwn(data, chan->channel, 1918c2ecf20Sopenharmony_ci DAC5571_POWERDOWN(data->powerdown_mode[chan->channel])); 1928c2ecf20Sopenharmony_ci else 1938c2ecf20Sopenharmony_ci ret = data->dac5571_cmd(data, chan->channel, 1948c2ecf20Sopenharmony_ci data->val[chan->channel]); 1958c2ecf20Sopenharmony_ci if (ret) 1968c2ecf20Sopenharmony_ci goto out; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci data->powerdown[chan->channel] = powerdown; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci out: 2018c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return ret ? ret : len; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info dac5571_ext_info[] = { 2088c2ecf20Sopenharmony_ci { 2098c2ecf20Sopenharmony_ci .name = "powerdown", 2108c2ecf20Sopenharmony_ci .read = dac5571_read_powerdown, 2118c2ecf20Sopenharmony_ci .write = dac5571_write_powerdown, 2128c2ecf20Sopenharmony_ci .shared = IIO_SEPARATE, 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci IIO_ENUM("powerdown_mode", IIO_SEPARATE, &dac5571_powerdown_mode), 2158c2ecf20Sopenharmony_ci IIO_ENUM_AVAILABLE("powerdown_mode", &dac5571_powerdown_mode), 2168c2ecf20Sopenharmony_ci {}, 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci#define dac5571_CHANNEL(chan, name) { \ 2208c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 2218c2ecf20Sopenharmony_ci .channel = (chan), \ 2228c2ecf20Sopenharmony_ci .address = (chan), \ 2238c2ecf20Sopenharmony_ci .indexed = true, \ 2248c2ecf20Sopenharmony_ci .output = true, \ 2258c2ecf20Sopenharmony_ci .datasheet_name = name, \ 2268c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 2278c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 2288c2ecf20Sopenharmony_ci .ext_info = dac5571_ext_info, \ 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic const struct iio_chan_spec dac5571_channels[] = { 2328c2ecf20Sopenharmony_ci dac5571_CHANNEL(0, "A"), 2338c2ecf20Sopenharmony_ci dac5571_CHANNEL(1, "B"), 2348c2ecf20Sopenharmony_ci dac5571_CHANNEL(2, "C"), 2358c2ecf20Sopenharmony_ci dac5571_CHANNEL(3, "D"), 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int dac5571_read_raw(struct iio_dev *indio_dev, 2398c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2408c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct dac5571_data *data = iio_priv(indio_dev); 2438c2ecf20Sopenharmony_ci int ret; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci switch (mask) { 2468c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 2478c2ecf20Sopenharmony_ci *val = data->val[chan->channel]; 2488c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 2518c2ecf20Sopenharmony_ci ret = regulator_get_voltage(data->vref); 2528c2ecf20Sopenharmony_ci if (ret < 0) 2538c2ecf20Sopenharmony_ci return ret; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci *val = ret / 1000; 2568c2ecf20Sopenharmony_ci *val2 = data->spec->resolution; 2578c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci default: 2608c2ecf20Sopenharmony_ci return -EINVAL; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int dac5571_write_raw(struct iio_dev *indio_dev, 2658c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2668c2ecf20Sopenharmony_ci int val, int val2, long mask) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct dac5571_data *data = iio_priv(indio_dev); 2698c2ecf20Sopenharmony_ci int ret; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci switch (mask) { 2728c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 2738c2ecf20Sopenharmony_ci if (data->val[chan->channel] == val) 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (val >= (1 << data->spec->resolution) || val < 0) 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (data->powerdown[chan->channel]) 2808c2ecf20Sopenharmony_ci return -EBUSY; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 2838c2ecf20Sopenharmony_ci ret = data->dac5571_cmd(data, chan->channel, val); 2848c2ecf20Sopenharmony_ci if (ret == 0) 2858c2ecf20Sopenharmony_ci data->val[chan->channel] = val; 2868c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 2878c2ecf20Sopenharmony_ci return ret; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci default: 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int dac5571_write_raw_get_fmt(struct iio_dev *indio_dev, 2958c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2968c2ecf20Sopenharmony_ci long mask) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic const struct iio_info dac5571_info = { 3028c2ecf20Sopenharmony_ci .read_raw = dac5571_read_raw, 3038c2ecf20Sopenharmony_ci .write_raw = dac5571_write_raw, 3048c2ecf20Sopenharmony_ci .write_raw_get_fmt = dac5571_write_raw_get_fmt, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int dac5571_probe(struct i2c_client *client, 3088c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 3118c2ecf20Sopenharmony_ci const struct dac5571_spec *spec; 3128c2ecf20Sopenharmony_ci struct dac5571_data *data; 3138c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 3148c2ecf20Sopenharmony_ci int ret, i; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 3178c2ecf20Sopenharmony_ci if (!indio_dev) 3188c2ecf20Sopenharmony_ci return -ENOMEM; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci data = iio_priv(indio_dev); 3218c2ecf20Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 3228c2ecf20Sopenharmony_ci data->client = client; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci indio_dev->info = &dac5571_info; 3258c2ecf20Sopenharmony_ci indio_dev->name = id->name; 3268c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 3278c2ecf20Sopenharmony_ci indio_dev->channels = dac5571_channels; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci spec = &dac5571_spec[id->driver_data]; 3308c2ecf20Sopenharmony_ci indio_dev->num_channels = spec->num_channels; 3318c2ecf20Sopenharmony_ci data->spec = spec; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci data->vref = devm_regulator_get(dev, "vref"); 3348c2ecf20Sopenharmony_ci if (IS_ERR(data->vref)) 3358c2ecf20Sopenharmony_ci return PTR_ERR(data->vref); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ret = regulator_enable(data->vref); 3388c2ecf20Sopenharmony_ci if (ret < 0) 3398c2ecf20Sopenharmony_ci return ret; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci mutex_init(&data->lock); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci switch (spec->num_channels) { 3448c2ecf20Sopenharmony_ci case 1: 3458c2ecf20Sopenharmony_ci data->dac5571_cmd = dac5571_cmd_single; 3468c2ecf20Sopenharmony_ci data->dac5571_pwrdwn = dac5571_pwrdwn_single; 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci case 4: 3498c2ecf20Sopenharmony_ci data->dac5571_cmd = dac5571_cmd_quad; 3508c2ecf20Sopenharmony_ci data->dac5571_pwrdwn = dac5571_pwrdwn_quad; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci default: 3538c2ecf20Sopenharmony_ci ret = -EINVAL; 3548c2ecf20Sopenharmony_ci goto err; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (i = 0; i < spec->num_channels; i++) { 3588c2ecf20Sopenharmony_ci ret = data->dac5571_cmd(data, i, 0); 3598c2ecf20Sopenharmony_ci if (ret) { 3608c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize channel %d to 0\n", i); 3618c2ecf20Sopenharmony_ci goto err; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 3668c2ecf20Sopenharmony_ci if (ret) 3678c2ecf20Sopenharmony_ci goto err; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci err: 3728c2ecf20Sopenharmony_ci regulator_disable(data->vref); 3738c2ecf20Sopenharmony_ci return ret; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int dac5571_remove(struct i2c_client *i2c) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(i2c); 3798c2ecf20Sopenharmony_ci struct dac5571_data *data = iio_priv(indio_dev); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 3828c2ecf20Sopenharmony_ci regulator_disable(data->vref); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic const struct of_device_id dac5571_of_id[] = { 3888c2ecf20Sopenharmony_ci {.compatible = "ti,dac5571"}, 3898c2ecf20Sopenharmony_ci {.compatible = "ti,dac6571"}, 3908c2ecf20Sopenharmony_ci {.compatible = "ti,dac7571"}, 3918c2ecf20Sopenharmony_ci {.compatible = "ti,dac5574"}, 3928c2ecf20Sopenharmony_ci {.compatible = "ti,dac6574"}, 3938c2ecf20Sopenharmony_ci {.compatible = "ti,dac7574"}, 3948c2ecf20Sopenharmony_ci {.compatible = "ti,dac5573"}, 3958c2ecf20Sopenharmony_ci {.compatible = "ti,dac6573"}, 3968c2ecf20Sopenharmony_ci {.compatible = "ti,dac7573"}, 3978c2ecf20Sopenharmony_ci {} 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, dac5571_of_id); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic const struct i2c_device_id dac5571_id[] = { 4028c2ecf20Sopenharmony_ci {"dac5571", single_8bit}, 4038c2ecf20Sopenharmony_ci {"dac6571", single_10bit}, 4048c2ecf20Sopenharmony_ci {"dac7571", single_12bit}, 4058c2ecf20Sopenharmony_ci {"dac5574", quad_8bit}, 4068c2ecf20Sopenharmony_ci {"dac6574", quad_10bit}, 4078c2ecf20Sopenharmony_ci {"dac7574", quad_12bit}, 4088c2ecf20Sopenharmony_ci {"dac5573", quad_8bit}, 4098c2ecf20Sopenharmony_ci {"dac6573", quad_10bit}, 4108c2ecf20Sopenharmony_ci {"dac7573", quad_12bit}, 4118c2ecf20Sopenharmony_ci {} 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, dac5571_id); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic struct i2c_driver dac5571_driver = { 4168c2ecf20Sopenharmony_ci .driver = { 4178c2ecf20Sopenharmony_ci .name = "ti-dac5571", 4188c2ecf20Sopenharmony_ci .of_match_table = dac5571_of_id, 4198c2ecf20Sopenharmony_ci }, 4208c2ecf20Sopenharmony_ci .probe = dac5571_probe, 4218c2ecf20Sopenharmony_ci .remove = dac5571_remove, 4228c2ecf20Sopenharmony_ci .id_table = dac5571_id, 4238c2ecf20Sopenharmony_ci}; 4248c2ecf20Sopenharmony_cimodule_i2c_driver(dac5571_driver); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>"); 4278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver"); 4288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 429