18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AD5672R, AD5674R, AD5676, AD5676R, AD5679R,
48c2ecf20Sopenharmony_ci * AD5681R, AD5682R, AD5683, AD5683R, AD5684,
58c2ecf20Sopenharmony_ci * AD5684R, AD5685R, AD5686, AD5686R
68c2ecf20Sopenharmony_ci * Digital to analog converters driver
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright 2018 Analog Devices Inc.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "ad5686.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int ad5686_spi_write(struct ad5686_state *st,
178c2ecf20Sopenharmony_ci			    u8 cmd, u8 addr, u16 val)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	struct spi_device *spi = to_spi_device(st->dev);
208c2ecf20Sopenharmony_ci	u8 tx_len, *buf;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	switch (st->chip_info->regmap_type) {
238c2ecf20Sopenharmony_ci	case AD5310_REGMAP:
248c2ecf20Sopenharmony_ci		st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) |
258c2ecf20Sopenharmony_ci					      val);
268c2ecf20Sopenharmony_ci		buf = &st->data[0].d8[0];
278c2ecf20Sopenharmony_ci		tx_len = 2;
288c2ecf20Sopenharmony_ci		break;
298c2ecf20Sopenharmony_ci	case AD5683_REGMAP:
308c2ecf20Sopenharmony_ci		st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
318c2ecf20Sopenharmony_ci					      AD5683_DATA(val));
328c2ecf20Sopenharmony_ci		buf = &st->data[0].d8[1];
338c2ecf20Sopenharmony_ci		tx_len = 3;
348c2ecf20Sopenharmony_ci		break;
358c2ecf20Sopenharmony_ci	case AD5686_REGMAP:
368c2ecf20Sopenharmony_ci		st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
378c2ecf20Sopenharmony_ci					      AD5686_ADDR(addr) |
388c2ecf20Sopenharmony_ci					      val);
398c2ecf20Sopenharmony_ci		buf = &st->data[0].d8[1];
408c2ecf20Sopenharmony_ci		tx_len = 3;
418c2ecf20Sopenharmony_ci		break;
428c2ecf20Sopenharmony_ci	default:
438c2ecf20Sopenharmony_ci		return -EINVAL;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	return spi_write(spi, buf, tx_len);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic int ad5686_spi_read(struct ad5686_state *st, u8 addr)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct spi_transfer t[] = {
528c2ecf20Sopenharmony_ci		{
538c2ecf20Sopenharmony_ci			.tx_buf = &st->data[0].d8[1],
548c2ecf20Sopenharmony_ci			.len = 3,
558c2ecf20Sopenharmony_ci			.cs_change = 1,
568c2ecf20Sopenharmony_ci		}, {
578c2ecf20Sopenharmony_ci			.tx_buf = &st->data[1].d8[1],
588c2ecf20Sopenharmony_ci			.rx_buf = &st->data[2].d8[1],
598c2ecf20Sopenharmony_ci			.len = 3,
608c2ecf20Sopenharmony_ci		},
618c2ecf20Sopenharmony_ci	};
628c2ecf20Sopenharmony_ci	struct spi_device *spi = to_spi_device(st->dev);
638c2ecf20Sopenharmony_ci	u8 cmd = 0;
648c2ecf20Sopenharmony_ci	int ret;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	switch (st->chip_info->regmap_type) {
678c2ecf20Sopenharmony_ci	case AD5310_REGMAP:
688c2ecf20Sopenharmony_ci		return -ENOTSUPP;
698c2ecf20Sopenharmony_ci	case AD5683_REGMAP:
708c2ecf20Sopenharmony_ci		cmd = AD5686_CMD_READBACK_ENABLE_V2;
718c2ecf20Sopenharmony_ci		break;
728c2ecf20Sopenharmony_ci	case AD5686_REGMAP:
738c2ecf20Sopenharmony_ci		cmd = AD5686_CMD_READBACK_ENABLE;
748c2ecf20Sopenharmony_ci		break;
758c2ecf20Sopenharmony_ci	default:
768c2ecf20Sopenharmony_ci		return -EINVAL;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
808c2ecf20Sopenharmony_ci				      AD5686_ADDR(addr));
818c2ecf20Sopenharmony_ci	st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
848c2ecf20Sopenharmony_ci	if (ret < 0)
858c2ecf20Sopenharmony_ci		return ret;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return be32_to_cpu(st->data[2].d32);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int ad5686_spi_probe(struct spi_device *spi)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	const struct spi_device_id *id = spi_get_device_id(spi);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return ad5686_probe(&spi->dev, id->driver_data, id->name,
958c2ecf20Sopenharmony_ci			    ad5686_spi_write, ad5686_spi_read);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int ad5686_spi_remove(struct spi_device *spi)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	return ad5686_remove(&spi->dev);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5686_spi_id[] = {
1048c2ecf20Sopenharmony_ci	{"ad5310r", ID_AD5310R},
1058c2ecf20Sopenharmony_ci	{"ad5672r", ID_AD5672R},
1068c2ecf20Sopenharmony_ci	{"ad5674r", ID_AD5674R},
1078c2ecf20Sopenharmony_ci	{"ad5676", ID_AD5676},
1088c2ecf20Sopenharmony_ci	{"ad5676r", ID_AD5676R},
1098c2ecf20Sopenharmony_ci	{"ad5679r", ID_AD5679R},
1108c2ecf20Sopenharmony_ci	{"ad5681r", ID_AD5681R},
1118c2ecf20Sopenharmony_ci	{"ad5682r", ID_AD5682R},
1128c2ecf20Sopenharmony_ci	{"ad5683", ID_AD5683},
1138c2ecf20Sopenharmony_ci	{"ad5683r", ID_AD5683R},
1148c2ecf20Sopenharmony_ci	{"ad5684", ID_AD5684},
1158c2ecf20Sopenharmony_ci	{"ad5684r", ID_AD5684R},
1168c2ecf20Sopenharmony_ci	{"ad5685", ID_AD5685R}, /* Does not exist */
1178c2ecf20Sopenharmony_ci	{"ad5685r", ID_AD5685R},
1188c2ecf20Sopenharmony_ci	{"ad5686", ID_AD5686},
1198c2ecf20Sopenharmony_ci	{"ad5686r", ID_AD5686R},
1208c2ecf20Sopenharmony_ci	{}
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5686_spi_id);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic struct spi_driver ad5686_spi_driver = {
1258c2ecf20Sopenharmony_ci	.driver = {
1268c2ecf20Sopenharmony_ci		.name = "ad5686",
1278c2ecf20Sopenharmony_ci	},
1288c2ecf20Sopenharmony_ci	.probe = ad5686_spi_probe,
1298c2ecf20Sopenharmony_ci	.remove = ad5686_spi_remove,
1308c2ecf20Sopenharmony_ci	.id_table = ad5686_spi_id,
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cimodule_spi_driver(ad5686_spi_driver);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
1368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
1378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
138