1 // SPDX-License-Identifier: GPL-2.0
3 * DAC7612 Dual, 12-Bit Serial input Digital-to-Analog Converter
5 * Copyright 2019 Qtechnology A/S
6 * 2019 Ricardo Ribalda <ribalda@kernel.org>
8 * Licensed under the GPL-2.
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/spi/spi.h>
13 #include <linux/gpio/consumer.h>
14 #include <linux/iio/iio.h>
16 #define DAC7612_RESOLUTION 12
17 #define DAC7612_ADDRESS 4
18 #define DAC7612_START 5
21 struct spi_device
*spi
;
22 struct gpio_desc
*loaddacs
;
26 * Lock to protect the state of the device from potential concurrent
27 * write accesses from userspace. The write operation requires an
28 * SPI write, then toggling of a GPIO, so the lock aims to protect
29 * the sanity of the entire sequence of operation.
34 * DMA (thus cache coherency maintenance) requires the
35 * transfer buffers to live in their own cache lines.
37 uint8_t data
[2] ____cacheline_aligned
;
40 static int dac7612_cmd_single(struct dac7612
*priv
, int channel
, u16 val
)
44 priv
->data
[0] = BIT(DAC7612_START
) | (channel
<< DAC7612_ADDRESS
);
45 priv
->data
[0] |= val
>> 8;
46 priv
->data
[1] = val
& 0xff;
48 priv
->cache
[channel
] = val
;
50 ret
= spi_write(priv
->spi
, priv
->data
, sizeof(priv
->data
));
54 gpiod_set_value(priv
->loaddacs
, 1);
55 gpiod_set_value(priv
->loaddacs
, 0);
60 #define dac7612_CHANNEL(chan, name) { \
61 .type = IIO_VOLTAGE, \
65 .datasheet_name = name, \
66 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
67 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
70 static const struct iio_chan_spec dac7612_channels
[] = {
71 dac7612_CHANNEL(0, "OUTA"),
72 dac7612_CHANNEL(1, "OUTB"),
75 static int dac7612_read_raw(struct iio_dev
*iio_dev
,
76 const struct iio_chan_spec
*chan
,
77 int *val
, int *val2
, long mask
)
82 case IIO_CHAN_INFO_RAW
:
83 priv
= iio_priv(iio_dev
);
84 *val
= priv
->cache
[chan
->channel
];
87 case IIO_CHAN_INFO_SCALE
:
96 static int dac7612_write_raw(struct iio_dev
*iio_dev
,
97 const struct iio_chan_spec
*chan
,
98 int val
, int val2
, long mask
)
100 struct dac7612
*priv
= iio_priv(iio_dev
);
103 if (mask
!= IIO_CHAN_INFO_RAW
)
106 if ((val
>= BIT(DAC7612_RESOLUTION
)) || val
< 0 || val2
)
109 if (val
== priv
->cache
[chan
->channel
])
112 mutex_lock(&priv
->lock
);
113 ret
= dac7612_cmd_single(priv
, chan
->channel
, val
);
114 mutex_unlock(&priv
->lock
);
119 static const struct iio_info dac7612_info
= {
120 .read_raw
= dac7612_read_raw
,
121 .write_raw
= dac7612_write_raw
,
124 static int dac7612_probe(struct spi_device
*spi
)
126 struct iio_dev
*iio_dev
;
127 struct dac7612
*priv
;
131 iio_dev
= devm_iio_device_alloc(&spi
->dev
, sizeof(*priv
));
135 priv
= iio_priv(iio_dev
);
137 * LOADDACS pin can be controlled by the driver or externally.
138 * When controlled by the driver, the DAC value is updated after
140 * When the driver does not control the PIN, the user or an external
141 * event can change the value of all DACs by pulsing down the LOADDACs
144 priv
->loaddacs
= devm_gpiod_get_optional(&spi
->dev
, "ti,loaddacs",
146 if (IS_ERR(priv
->loaddacs
))
147 return PTR_ERR(priv
->loaddacs
);
149 spi_set_drvdata(spi
, iio_dev
);
150 iio_dev
->info
= &dac7612_info
;
151 iio_dev
->modes
= INDIO_DIRECT_MODE
;
152 iio_dev
->channels
= dac7612_channels
;
153 iio_dev
->num_channels
= ARRAY_SIZE(priv
->cache
);
154 iio_dev
->name
= spi_get_device_id(spi
)->name
;
156 mutex_init(&priv
->lock
);
158 for (i
= 0; i
< ARRAY_SIZE(priv
->cache
); i
++) {
159 ret
= dac7612_cmd_single(priv
, i
, 0);
164 return devm_iio_device_register(&spi
->dev
, iio_dev
);
167 static const struct spi_device_id dac7612_id
[] = {
171 MODULE_DEVICE_TABLE(spi
, dac7612_id
);
173 static const struct of_device_id dac7612_of_match
[] = {
174 { .compatible
= "ti,dac7612" },
175 { .compatible
= "ti,dac7612u" },
176 { .compatible
= "ti,dac7612ub" },
179 MODULE_DEVICE_TABLE(of
, dac7612_of_match
);
181 static struct spi_driver dac7612_driver
= {
183 .name
= "ti-dac7612",
184 .of_match_table
= dac7612_of_match
,
186 .probe
= dac7612_probe
,
187 .id_table
= dac7612_id
,
189 module_spi_driver(dac7612_driver
);
191 MODULE_AUTHOR("Ricardo Ribalda <ribalda@kernel.org>");
192 MODULE_DESCRIPTION("Texas Instruments DAC7612 DAC driver");
193 MODULE_LICENSE("GPL v2");