aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/dac
diff options
context:
space:
mode:
authorMichael Welling <mwelling@ieee.org>2014-06-15 17:17:00 -0400
committerJonathan Cameron <jic23@kernel.org>2014-06-21 06:50:33 -0400
commit1b791fadf3a1749505b6cf04d4ef58d278ee42cd (patch)
treeaf63cad51aa634154c39d0924b1932247a73f68e /drivers/iio/dac
parent88f6da779a37a3579e580296776ba86d6c6bd980 (diff)
iio: dac: mcp4902/mcp4912/mcp4922 dac driver
This patch provides an iio device driver for the Microchip MCP49x2 series DACs. Signed-off-by: Michael Welling <mwelling@ieee.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/dac')
-rw-r--r--drivers/iio/dac/Kconfig10
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/mcp4922.c216
3 files changed, 227 insertions, 0 deletions
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index f378ca8033db..f278eff42a4c 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -163,4 +163,14 @@ config MCP4725
163 To compile this driver as a module, choose M here: the module 163 To compile this driver as a module, choose M here: the module
164 will be called mcp4725. 164 will be called mcp4725.
165 165
166config MCP4922
167 tristate "MCP4902, MCP4912, MCP4922 DAC driver"
168 depends on SPI
169 help
170 Say yes here to build the driver for the Microchip MCP4902
171 MCP4912, and MCP4922 DAC devices.
172
173 To compile this driver as a module, choose M here: the module
174 will be called mcp4922.
175
166endmenu 176endmenu
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index bb84ad64463f..10107640bb46 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_AD5686) += ad5686.o
18obj-$(CONFIG_AD7303) += ad7303.o 18obj-$(CONFIG_AD7303) += ad7303.o
19obj-$(CONFIG_MAX517) += max517.o 19obj-$(CONFIG_MAX517) += max517.o
20obj-$(CONFIG_MCP4725) += mcp4725.o 20obj-$(CONFIG_MCP4725) += mcp4725.o
21obj-$(CONFIG_MCP4922) += mcp4922.o
diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c
new file mode 100644
index 000000000000..92cf4ca6981d
--- /dev/null
+++ b/drivers/iio/dac/mcp4922.c
@@ -0,0 +1,216 @@
1/*
2 * mcp4922.c
3 *
4 * Driver for Microchip Digital to Analog Converters.
5 * Supports MCP4902, MCP4912, and MCP4922.
6 *
7 * Copyright (c) 2014 EMAC Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 */
20
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/spi/spi.h>
24#include <linux/iio/iio.h>
25#include <linux/iio/sysfs.h>
26#include <linux/regulator/consumer.h>
27#include <linux/bitops.h>
28
29#define MCP4922_NUM_CHANNELS 2
30
31enum mcp4922_supported_device_ids {
32 ID_MCP4902,
33 ID_MCP4912,
34 ID_MCP4922,
35};
36
37struct mcp4922_state {
38 struct spi_device *spi;
39 unsigned int value[MCP4922_NUM_CHANNELS];
40 unsigned int vref_mv;
41 struct regulator *vref_reg;
42 u8 mosi[2] ____cacheline_aligned;
43};
44
45#define MCP4922_CHAN(chan, bits) { \
46 .type = IIO_VOLTAGE, \
47 .output = 1, \
48 .indexed = 1, \
49 .channel = chan, \
50 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
51 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
52 .scan_type = { \
53 .sign = 'u', \
54 .realbits = (bits), \
55 .storagebits = 16, \
56 .shift = 12 - (bits), \
57 }, \
58}
59
60static int mcp4922_spi_write(struct mcp4922_state *state, u8 addr, u32 val)
61{
62 state->mosi[1] = val & 0xff;
63 state->mosi[0] = (addr == 0) ? 0x00 : 0x80;
64 state->mosi[0] |= 0x30 | ((val >> 8) & 0x0f);
65
66 return spi_write(state->spi, state->mosi, 2);
67}
68
69static int mcp4922_read_raw(struct iio_dev *indio_dev,
70 struct iio_chan_spec const *chan,
71 int *val,
72 int *val2,
73 long mask)
74{
75 struct mcp4922_state *state = iio_priv(indio_dev);
76
77 switch (mask) {
78 case IIO_CHAN_INFO_RAW:
79 *val = state->value[chan->channel];
80 return IIO_VAL_INT;
81 case IIO_CHAN_INFO_SCALE:
82 *val = state->vref_mv;
83 *val2 = chan->scan_type.realbits;
84 return IIO_VAL_FRACTIONAL_LOG2;
85 default:
86 return -EINVAL;
87 }
88}
89
90static int mcp4922_write_raw(struct iio_dev *indio_dev,
91 struct iio_chan_spec const *chan,
92 int val,
93 int val2,
94 long mask)
95{
96 struct mcp4922_state *state = iio_priv(indio_dev);
97
98 if (val2 != 0)
99 return -EINVAL;
100
101 switch (mask) {
102 case IIO_CHAN_INFO_RAW:
103 if (val > GENMASK(chan->scan_type.realbits-1, 0))
104 return -EINVAL;
105 val <<= chan->scan_type.shift;
106 state->value[chan->channel] = val;
107 return mcp4922_spi_write(state, chan->channel, val);
108 default:
109 return -EINVAL;
110 }
111}
112
113static const struct iio_chan_spec mcp4922_channels[3][MCP4922_NUM_CHANNELS] = {
114 [ID_MCP4902] = { MCP4922_CHAN(0, 8), MCP4922_CHAN(1, 8) },
115 [ID_MCP4912] = { MCP4922_CHAN(0, 10), MCP4922_CHAN(1, 10) },
116 [ID_MCP4922] = { MCP4922_CHAN(0, 12), MCP4922_CHAN(1, 12) },
117};
118
119static const struct iio_info mcp4922_info = {
120 .read_raw = &mcp4922_read_raw,
121 .write_raw = &mcp4922_write_raw,
122 .driver_module = THIS_MODULE,
123};
124
125static int mcp4922_probe(struct spi_device *spi)
126{
127 struct iio_dev *indio_dev;
128 struct mcp4922_state *state;
129 const struct spi_device_id *id;
130 int ret;
131
132 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
133 if (indio_dev == NULL)
134 return -ENOMEM;
135
136 state = iio_priv(indio_dev);
137 state->spi = spi;
138 state->vref_reg = devm_regulator_get(&spi->dev, "vref");
139 if (IS_ERR(state->vref_reg)) {
140 dev_err(&spi->dev, "Vref regulator not specified\n");
141 return PTR_ERR(state->vref_reg);
142 }
143
144 ret = regulator_enable(state->vref_reg);
145 if (ret) {
146 dev_err(&spi->dev, "Failed to enable vref regulator: %d\n",
147 ret);
148 return ret;
149 }
150
151 ret = regulator_get_voltage(state->vref_reg);
152 if (ret < 0) {
153 dev_err(&spi->dev, "Failed to read vref regulator: %d\n",
154 ret);
155 goto error_disable_reg;
156 }
157 state->vref_mv = ret / 1000;
158
159 spi_set_drvdata(spi, indio_dev);
160 id = spi_get_device_id(spi);
161 indio_dev->dev.parent = &spi->dev;
162 indio_dev->info = &mcp4922_info;
163 indio_dev->modes = INDIO_DIRECT_MODE;
164 indio_dev->channels = mcp4922_channels[id->driver_data];
165 indio_dev->num_channels = MCP4922_NUM_CHANNELS;
166 indio_dev->name = id->name;
167
168 ret = iio_device_register(indio_dev);
169 if (ret) {
170 dev_err(&spi->dev, "Failed to register iio device: %d\n",
171 ret);
172 goto error_disable_reg;
173 }
174
175 return 0;
176
177error_disable_reg:
178 regulator_disable(state->vref_reg);
179
180 return ret;
181}
182
183static int mcp4922_remove(struct spi_device *spi)
184{
185 struct iio_dev *indio_dev = spi_get_drvdata(spi);
186 struct mcp4922_state *state;
187
188 iio_device_unregister(indio_dev);
189 state = iio_priv(indio_dev);
190 regulator_disable(state->vref_reg);
191
192 return 0;
193}
194
195static const struct spi_device_id mcp4922_id[] = {
196 {"mcp4902", ID_MCP4902},
197 {"mcp4912", ID_MCP4912},
198 {"mcp4922", ID_MCP4922},
199 {}
200};
201MODULE_DEVICE_TABLE(spi, mcp4922_id);
202
203static struct spi_driver mcp4922_driver = {
204 .driver = {
205 .name = "mcp4922",
206 .owner = THIS_MODULE,
207 },
208 .probe = mcp4922_probe,
209 .remove = mcp4922_remove,
210 .id_table = mcp4922_id,
211};
212module_spi_driver(mcp4922_driver);
213
214MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>");
215MODULE_DESCRIPTION("Microchip MCP4902, MCP4912, MCP4922 DAC");
216MODULE_LICENSE("GPL v2");