18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Maxim Integrated 48c2ecf20Sopenharmony_ci * 7-bit, Multi-Channel Sink/Source Current DAC Driver 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Maxim Integrated 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 158c2ecf20Sopenharmony_ci#include <linux/iio/driver.h> 168c2ecf20Sopenharmony_ci#include <linux/iio/machine.h> 178c2ecf20Sopenharmony_ci#include <linux/iio/consumer.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define DS4422_MAX_DAC_CHANNELS 2 208c2ecf20Sopenharmony_ci#define DS4424_MAX_DAC_CHANNELS 4 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define DS4424_DAC_ADDR(chan) ((chan) + 0xf8) 238c2ecf20Sopenharmony_ci#define DS4424_SOURCE_I 1 248c2ecf20Sopenharmony_ci#define DS4424_SINK_I 0 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DS4424_CHANNEL(chan) { \ 278c2ecf20Sopenharmony_ci .type = IIO_CURRENT, \ 288c2ecf20Sopenharmony_ci .indexed = 1, \ 298c2ecf20Sopenharmony_ci .output = 1, \ 308c2ecf20Sopenharmony_ci .channel = chan, \ 318c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * DS4424 DAC control register 8 bits 368c2ecf20Sopenharmony_ci * [7] 0: to sink; 1: to source 378c2ecf20Sopenharmony_ci * [6:0] steps to sink/source 388c2ecf20Sopenharmony_ci * bit[7] looks like a sign bit, but the value of the register is 398c2ecf20Sopenharmony_ci * not a two's complement code considering the bit[6:0] is a absolute 408c2ecf20Sopenharmony_ci * distance from the zero point. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ciunion ds4424_raw_data { 438c2ecf20Sopenharmony_ci struct { 448c2ecf20Sopenharmony_ci u8 dx:7; 458c2ecf20Sopenharmony_ci u8 source_bit:1; 468c2ecf20Sopenharmony_ci }; 478c2ecf20Sopenharmony_ci u8 bits; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cienum ds4424_device_ids { 518c2ecf20Sopenharmony_ci ID_DS4422, 528c2ecf20Sopenharmony_ci ID_DS4424, 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct ds4424_data { 568c2ecf20Sopenharmony_ci struct i2c_client *client; 578c2ecf20Sopenharmony_ci struct mutex lock; 588c2ecf20Sopenharmony_ci uint8_t save[DS4424_MAX_DAC_CHANNELS]; 598c2ecf20Sopenharmony_ci struct regulator *vcc_reg; 608c2ecf20Sopenharmony_ci uint8_t raw[DS4424_MAX_DAC_CHANNELS]; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic const struct iio_chan_spec ds4424_channels[] = { 648c2ecf20Sopenharmony_ci DS4424_CHANNEL(0), 658c2ecf20Sopenharmony_ci DS4424_CHANNEL(1), 668c2ecf20Sopenharmony_ci DS4424_CHANNEL(2), 678c2ecf20Sopenharmony_ci DS4424_CHANNEL(3), 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int ds4424_get_value(struct iio_dev *indio_dev, 718c2ecf20Sopenharmony_ci int *val, int channel) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct ds4424_data *data = iio_priv(indio_dev); 748c2ecf20Sopenharmony_ci int ret; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 778c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel)); 788c2ecf20Sopenharmony_ci if (ret < 0) 798c2ecf20Sopenharmony_ci goto fail; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci *val = ret; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cifail: 848c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 858c2ecf20Sopenharmony_ci return ret; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int ds4424_set_value(struct iio_dev *indio_dev, 898c2ecf20Sopenharmony_ci int val, struct iio_chan_spec const *chan) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct ds4424_data *data = iio_priv(indio_dev); 928c2ecf20Sopenharmony_ci int ret; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 958c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(data->client, 968c2ecf20Sopenharmony_ci DS4424_DAC_ADDR(chan->channel), val); 978c2ecf20Sopenharmony_ci if (ret < 0) 988c2ecf20Sopenharmony_ci goto fail; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci data->raw[chan->channel] = val; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cifail: 1038c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int ds4424_read_raw(struct iio_dev *indio_dev, 1088c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1098c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci union ds4424_raw_data raw; 1128c2ecf20Sopenharmony_ci int ret; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci switch (mask) { 1158c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1168c2ecf20Sopenharmony_ci ret = ds4424_get_value(indio_dev, val, chan->channel); 1178c2ecf20Sopenharmony_ci if (ret < 0) { 1188c2ecf20Sopenharmony_ci pr_err("%s : ds4424_get_value returned %d\n", 1198c2ecf20Sopenharmony_ci __func__, ret); 1208c2ecf20Sopenharmony_ci return ret; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci raw.bits = *val; 1238c2ecf20Sopenharmony_ci *val = raw.dx; 1248c2ecf20Sopenharmony_ci if (raw.source_bit == DS4424_SINK_I) 1258c2ecf20Sopenharmony_ci *val = -*val; 1268c2ecf20Sopenharmony_ci return IIO_VAL_INT; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci default: 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int ds4424_write_raw(struct iio_dev *indio_dev, 1348c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1358c2ecf20Sopenharmony_ci int val, int val2, long mask) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci union ds4424_raw_data raw; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (val2 != 0) 1408c2ecf20Sopenharmony_ci return -EINVAL; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci switch (mask) { 1438c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1448c2ecf20Sopenharmony_ci if (val < S8_MIN || val > S8_MAX) 1458c2ecf20Sopenharmony_ci return -EINVAL; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (val > 0) { 1488c2ecf20Sopenharmony_ci raw.source_bit = DS4424_SOURCE_I; 1498c2ecf20Sopenharmony_ci raw.dx = val; 1508c2ecf20Sopenharmony_ci } else { 1518c2ecf20Sopenharmony_ci raw.source_bit = DS4424_SINK_I; 1528c2ecf20Sopenharmony_ci raw.dx = -val; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return ds4424_set_value(indio_dev, raw.bits, chan); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int ds4424_verify_chip(struct iio_dev *indio_dev) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci int ret, val; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ret = ds4424_get_value(indio_dev, &val, 0); 1678c2ecf20Sopenharmony_ci if (ret < 0) 1688c2ecf20Sopenharmony_ci dev_err(&indio_dev->dev, 1698c2ecf20Sopenharmony_ci "%s failed. ret: %d\n", __func__, ret); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return ret; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int __maybe_unused ds4424_suspend(struct device *dev) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 1778c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(client); 1788c2ecf20Sopenharmony_ci struct ds4424_data *data = iio_priv(indio_dev); 1798c2ecf20Sopenharmony_ci int ret = 0; 1808c2ecf20Sopenharmony_ci int i; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci for (i = 0; i < indio_dev->num_channels; i++) { 1838c2ecf20Sopenharmony_ci data->save[i] = data->raw[i]; 1848c2ecf20Sopenharmony_ci ret = ds4424_set_value(indio_dev, 0, 1858c2ecf20Sopenharmony_ci &indio_dev->channels[i]); 1868c2ecf20Sopenharmony_ci if (ret < 0) 1878c2ecf20Sopenharmony_ci return ret; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci return ret; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int __maybe_unused ds4424_resume(struct device *dev) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 1958c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(client); 1968c2ecf20Sopenharmony_ci struct ds4424_data *data = iio_priv(indio_dev); 1978c2ecf20Sopenharmony_ci int ret = 0; 1988c2ecf20Sopenharmony_ci int i; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci for (i = 0; i < indio_dev->num_channels; i++) { 2018c2ecf20Sopenharmony_ci ret = ds4424_set_value(indio_dev, data->save[i], 2028c2ecf20Sopenharmony_ci &indio_dev->channels[i]); 2038c2ecf20Sopenharmony_ci if (ret < 0) 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci return ret; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic const struct iio_info ds4424_info = { 2128c2ecf20Sopenharmony_ci .read_raw = ds4424_read_raw, 2138c2ecf20Sopenharmony_ci .write_raw = ds4424_write_raw, 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int ds4424_probe(struct i2c_client *client, 2178c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct ds4424_data *data; 2208c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 2218c2ecf20Sopenharmony_ci int ret; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 2248c2ecf20Sopenharmony_ci if (!indio_dev) { 2258c2ecf20Sopenharmony_ci dev_err(&client->dev, "iio dev alloc failed.\n"); 2268c2ecf20Sopenharmony_ci return -ENOMEM; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci data = iio_priv(indio_dev); 2308c2ecf20Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 2318c2ecf20Sopenharmony_ci data->client = client; 2328c2ecf20Sopenharmony_ci indio_dev->name = id->name; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci data->vcc_reg = devm_regulator_get(&client->dev, "vcc"); 2358c2ecf20Sopenharmony_ci if (IS_ERR(data->vcc_reg)) { 2368c2ecf20Sopenharmony_ci dev_err(&client->dev, 2378c2ecf20Sopenharmony_ci "Failed to get vcc-supply regulator. err: %ld\n", 2388c2ecf20Sopenharmony_ci PTR_ERR(data->vcc_reg)); 2398c2ecf20Sopenharmony_ci return PTR_ERR(data->vcc_reg); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci mutex_init(&data->lock); 2438c2ecf20Sopenharmony_ci ret = regulator_enable(data->vcc_reg); 2448c2ecf20Sopenharmony_ci if (ret < 0) { 2458c2ecf20Sopenharmony_ci dev_err(&client->dev, 2468c2ecf20Sopenharmony_ci "Unable to enable the regulator.\n"); 2478c2ecf20Sopenharmony_ci return ret; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci usleep_range(1000, 1200); 2518c2ecf20Sopenharmony_ci ret = ds4424_verify_chip(indio_dev); 2528c2ecf20Sopenharmony_ci if (ret < 0) 2538c2ecf20Sopenharmony_ci goto fail; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci switch (id->driver_data) { 2568c2ecf20Sopenharmony_ci case ID_DS4422: 2578c2ecf20Sopenharmony_ci indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case ID_DS4424: 2608c2ecf20Sopenharmony_ci indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci default: 2638c2ecf20Sopenharmony_ci dev_err(&client->dev, 2648c2ecf20Sopenharmony_ci "ds4424: Invalid chip id.\n"); 2658c2ecf20Sopenharmony_ci ret = -ENXIO; 2668c2ecf20Sopenharmony_ci goto fail; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci indio_dev->channels = ds4424_channels; 2708c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 2718c2ecf20Sopenharmony_ci indio_dev->info = &ds4424_info; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 2748c2ecf20Sopenharmony_ci if (ret < 0) { 2758c2ecf20Sopenharmony_ci dev_err(&client->dev, 2768c2ecf20Sopenharmony_ci "iio_device_register failed. ret: %d\n", ret); 2778c2ecf20Sopenharmony_ci goto fail; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cifail: 2838c2ecf20Sopenharmony_ci regulator_disable(data->vcc_reg); 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int ds4424_remove(struct i2c_client *client) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = i2c_get_clientdata(client); 2908c2ecf20Sopenharmony_ci struct ds4424_data *data = iio_priv(indio_dev); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 2938c2ecf20Sopenharmony_ci regulator_disable(data->vcc_reg); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic const struct i2c_device_id ds4424_id[] = { 2998c2ecf20Sopenharmony_ci { "ds4422", ID_DS4422 }, 3008c2ecf20Sopenharmony_ci { "ds4424", ID_DS4424 }, 3018c2ecf20Sopenharmony_ci { } 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ds4424_id); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic const struct of_device_id ds4424_of_match[] = { 3078c2ecf20Sopenharmony_ci { .compatible = "maxim,ds4422" }, 3088c2ecf20Sopenharmony_ci { .compatible = "maxim,ds4424" }, 3098c2ecf20Sopenharmony_ci { }, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ds4424_of_match); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic struct i2c_driver ds4424_driver = { 3158c2ecf20Sopenharmony_ci .driver = { 3168c2ecf20Sopenharmony_ci .name = "ds4424", 3178c2ecf20Sopenharmony_ci .of_match_table = ds4424_of_match, 3188c2ecf20Sopenharmony_ci .pm = &ds4424_pm_ops, 3198c2ecf20Sopenharmony_ci }, 3208c2ecf20Sopenharmony_ci .probe = ds4424_probe, 3218c2ecf20Sopenharmony_ci .remove = ds4424_remove, 3228c2ecf20Sopenharmony_ci .id_table = ds4424_id, 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_cimodule_i2c_driver(ds4424_driver); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Maxim DS4424 DAC Driver"); 3278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ismail H. Kose <ismail.kose@maximintegrated.com>"); 3288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vishal Sood <vishal.sood@maximintegrated.com>"); 3298c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Jung <david.jung@maximintegrated.com>"); 3308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 331