xref: /kernel/linux/linux-5.10/drivers/iio/dac/ds4424.c (revision 8c2ecf20)
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