xref: /openbmc/linux/drivers/iio/dac/ad5592r.c (revision 56ca9db862bf3d78e279d424b3434d66617c27ae)
1*56ca9db8SPaul Cercueil /*
2*56ca9db8SPaul Cercueil  * AD5592R Digital <-> Analog converters driver
3*56ca9db8SPaul Cercueil  *
4*56ca9db8SPaul Cercueil  * Copyright 2015-2016 Analog Devices Inc.
5*56ca9db8SPaul Cercueil  * Author: Paul Cercueil <paul.cercueil@analog.com>
6*56ca9db8SPaul Cercueil  *
7*56ca9db8SPaul Cercueil  * Licensed under the GPL-2.
8*56ca9db8SPaul Cercueil  */
9*56ca9db8SPaul Cercueil 
10*56ca9db8SPaul Cercueil #include "ad5592r-base.h"
11*56ca9db8SPaul Cercueil 
12*56ca9db8SPaul Cercueil #include <linux/bitops.h>
13*56ca9db8SPaul Cercueil #include <linux/module.h>
14*56ca9db8SPaul Cercueil #include <linux/of.h>
15*56ca9db8SPaul Cercueil #include <linux/spi/spi.h>
16*56ca9db8SPaul Cercueil 
17*56ca9db8SPaul Cercueil #define AD5592R_GPIO_READBACK_EN	BIT(10)
18*56ca9db8SPaul Cercueil #define AD5592R_LDAC_READBACK_EN	BIT(6)
19*56ca9db8SPaul Cercueil 
20*56ca9db8SPaul Cercueil static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, u16 *buf)
21*56ca9db8SPaul Cercueil {
22*56ca9db8SPaul Cercueil 	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
23*56ca9db8SPaul Cercueil 	struct spi_transfer t = {
24*56ca9db8SPaul Cercueil 			.tx_buf	= &st->spi_msg_nop,
25*56ca9db8SPaul Cercueil 			.rx_buf	= buf,
26*56ca9db8SPaul Cercueil 			.len = 2
27*56ca9db8SPaul Cercueil 		};
28*56ca9db8SPaul Cercueil 
29*56ca9db8SPaul Cercueil 	st->spi_msg_nop = 0; /* NOP */
30*56ca9db8SPaul Cercueil 
31*56ca9db8SPaul Cercueil 	return spi_sync_transfer(spi, &t, 1);
32*56ca9db8SPaul Cercueil }
33*56ca9db8SPaul Cercueil 
34*56ca9db8SPaul Cercueil static int ad5592r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
35*56ca9db8SPaul Cercueil {
36*56ca9db8SPaul Cercueil 	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
37*56ca9db8SPaul Cercueil 
38*56ca9db8SPaul Cercueil 	st->spi_msg = cpu_to_be16(BIT(15) | (chan << 12) | value);
39*56ca9db8SPaul Cercueil 
40*56ca9db8SPaul Cercueil 	return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
41*56ca9db8SPaul Cercueil }
42*56ca9db8SPaul Cercueil 
43*56ca9db8SPaul Cercueil static int ad5592r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
44*56ca9db8SPaul Cercueil {
45*56ca9db8SPaul Cercueil 	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
46*56ca9db8SPaul Cercueil 	int ret;
47*56ca9db8SPaul Cercueil 
48*56ca9db8SPaul Cercueil 	st->spi_msg = cpu_to_be16((AD5592R_REG_ADC_SEQ << 11) | BIT(chan));
49*56ca9db8SPaul Cercueil 
50*56ca9db8SPaul Cercueil 	ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
51*56ca9db8SPaul Cercueil 	if (ret)
52*56ca9db8SPaul Cercueil 		return ret;
53*56ca9db8SPaul Cercueil 
54*56ca9db8SPaul Cercueil 	/*
55*56ca9db8SPaul Cercueil 	 * Invalid data:
56*56ca9db8SPaul Cercueil 	 * See Figure 40. Single-Channel ADC Conversion Sequence
57*56ca9db8SPaul Cercueil 	 */
58*56ca9db8SPaul Cercueil 	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
59*56ca9db8SPaul Cercueil 	if (ret)
60*56ca9db8SPaul Cercueil 		return ret;
61*56ca9db8SPaul Cercueil 
62*56ca9db8SPaul Cercueil 	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
63*56ca9db8SPaul Cercueil 	if (ret)
64*56ca9db8SPaul Cercueil 		return ret;
65*56ca9db8SPaul Cercueil 
66*56ca9db8SPaul Cercueil 	*value = be16_to_cpu(st->spi_msg);
67*56ca9db8SPaul Cercueil 
68*56ca9db8SPaul Cercueil 	return 0;
69*56ca9db8SPaul Cercueil }
70*56ca9db8SPaul Cercueil 
71*56ca9db8SPaul Cercueil static int ad5592r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
72*56ca9db8SPaul Cercueil {
73*56ca9db8SPaul Cercueil 	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
74*56ca9db8SPaul Cercueil 
75*56ca9db8SPaul Cercueil 	st->spi_msg = cpu_to_be16((reg << 11) | value);
76*56ca9db8SPaul Cercueil 
77*56ca9db8SPaul Cercueil 	return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
78*56ca9db8SPaul Cercueil }
79*56ca9db8SPaul Cercueil 
80*56ca9db8SPaul Cercueil static int ad5592r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
81*56ca9db8SPaul Cercueil {
82*56ca9db8SPaul Cercueil 	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
83*56ca9db8SPaul Cercueil 	int ret;
84*56ca9db8SPaul Cercueil 
85*56ca9db8SPaul Cercueil 	st->spi_msg = cpu_to_be16((AD5592R_REG_LDAC << 11) |
86*56ca9db8SPaul Cercueil 				   AD5592R_LDAC_READBACK_EN | (reg << 2));
87*56ca9db8SPaul Cercueil 
88*56ca9db8SPaul Cercueil 	ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
89*56ca9db8SPaul Cercueil 	if (ret)
90*56ca9db8SPaul Cercueil 		return ret;
91*56ca9db8SPaul Cercueil 
92*56ca9db8SPaul Cercueil 	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
93*56ca9db8SPaul Cercueil 	if (ret)
94*56ca9db8SPaul Cercueil 		return ret;
95*56ca9db8SPaul Cercueil 
96*56ca9db8SPaul Cercueil 	*value = be16_to_cpu(st->spi_msg);
97*56ca9db8SPaul Cercueil 
98*56ca9db8SPaul Cercueil 	return 0;
99*56ca9db8SPaul Cercueil }
100*56ca9db8SPaul Cercueil 
101*56ca9db8SPaul Cercueil static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
102*56ca9db8SPaul Cercueil {
103*56ca9db8SPaul Cercueil 	int ret;
104*56ca9db8SPaul Cercueil 
105*56ca9db8SPaul Cercueil 	ret = ad5592r_reg_write(st, AD5592R_REG_GPIO_IN_EN,
106*56ca9db8SPaul Cercueil 				AD5592R_GPIO_READBACK_EN | st->gpio_in);
107*56ca9db8SPaul Cercueil 	if (ret)
108*56ca9db8SPaul Cercueil 		return ret;
109*56ca9db8SPaul Cercueil 
110*56ca9db8SPaul Cercueil 	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
111*56ca9db8SPaul Cercueil 	if (ret)
112*56ca9db8SPaul Cercueil 		return ret;
113*56ca9db8SPaul Cercueil 
114*56ca9db8SPaul Cercueil 	*value = (u8) be16_to_cpu(st->spi_msg);
115*56ca9db8SPaul Cercueil 
116*56ca9db8SPaul Cercueil 	return 0;
117*56ca9db8SPaul Cercueil }
118*56ca9db8SPaul Cercueil 
119*56ca9db8SPaul Cercueil static const struct ad5592r_rw_ops ad5592r_rw_ops = {
120*56ca9db8SPaul Cercueil 	.write_dac = ad5592r_write_dac,
121*56ca9db8SPaul Cercueil 	.read_adc = ad5592r_read_adc,
122*56ca9db8SPaul Cercueil 	.reg_write = ad5592r_reg_write,
123*56ca9db8SPaul Cercueil 	.reg_read = ad5592r_reg_read,
124*56ca9db8SPaul Cercueil 	.gpio_read = ad5593r_gpio_read,
125*56ca9db8SPaul Cercueil };
126*56ca9db8SPaul Cercueil 
127*56ca9db8SPaul Cercueil static int ad5592r_spi_probe(struct spi_device *spi)
128*56ca9db8SPaul Cercueil {
129*56ca9db8SPaul Cercueil 	const struct spi_device_id *id = spi_get_device_id(spi);
130*56ca9db8SPaul Cercueil 
131*56ca9db8SPaul Cercueil 	return ad5592r_probe(&spi->dev, id->name, &ad5592r_rw_ops);
132*56ca9db8SPaul Cercueil }
133*56ca9db8SPaul Cercueil 
134*56ca9db8SPaul Cercueil static int ad5592r_spi_remove(struct spi_device *spi)
135*56ca9db8SPaul Cercueil {
136*56ca9db8SPaul Cercueil 	return ad5592r_remove(&spi->dev);
137*56ca9db8SPaul Cercueil }
138*56ca9db8SPaul Cercueil 
139*56ca9db8SPaul Cercueil static const struct spi_device_id ad5592r_spi_ids[] = {
140*56ca9db8SPaul Cercueil 	{ .name = "ad5592r", },
141*56ca9db8SPaul Cercueil 	{}
142*56ca9db8SPaul Cercueil };
143*56ca9db8SPaul Cercueil MODULE_DEVICE_TABLE(spi, ad5592r_spi_ids);
144*56ca9db8SPaul Cercueil 
145*56ca9db8SPaul Cercueil static const struct of_device_id ad5592r_of_match[] = {
146*56ca9db8SPaul Cercueil 	{ .compatible = "adi,ad5592r", },
147*56ca9db8SPaul Cercueil 	{},
148*56ca9db8SPaul Cercueil };
149*56ca9db8SPaul Cercueil MODULE_DEVICE_TABLE(of, ad5592r_of_match);
150*56ca9db8SPaul Cercueil 
151*56ca9db8SPaul Cercueil static struct spi_driver ad5592r_spi_driver = {
152*56ca9db8SPaul Cercueil 	.driver = {
153*56ca9db8SPaul Cercueil 		.name = "ad5592r",
154*56ca9db8SPaul Cercueil 		.of_match_table = of_match_ptr(ad5592r_of_match),
155*56ca9db8SPaul Cercueil 	},
156*56ca9db8SPaul Cercueil 	.probe = ad5592r_spi_probe,
157*56ca9db8SPaul Cercueil 	.remove = ad5592r_spi_remove,
158*56ca9db8SPaul Cercueil 	.id_table = ad5592r_spi_ids,
159*56ca9db8SPaul Cercueil };
160*56ca9db8SPaul Cercueil module_spi_driver(ad5592r_spi_driver);
161*56ca9db8SPaul Cercueil 
162*56ca9db8SPaul Cercueil MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
163*56ca9db8SPaul Cercueil MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
164*56ca9db8SPaul Cercueil MODULE_LICENSE("GPL v2");
165