]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/iio/adc/mcp320x.c
Merge branch 'x86-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / iio / adc / mcp320x.c
1 /*
2  * Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com>
3  *
4  * Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips.
5  * Datasheet can be found here:
6  * http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/err.h>
14 #include <linux/spi/spi.h>
15 #include <linux/module.h>
16 #include <linux/iio/iio.h>
17 #include <linux/regulator/consumer.h>
18
19 #define MCP_SINGLE_ENDED        (1 << 3)
20 #define MCP_START_BIT           (1 << 4)
21
22 enum {
23         mcp3204,
24         mcp3208,
25 };
26
27 struct mcp320x {
28         struct spi_device *spi;
29         struct spi_message msg;
30         struct spi_transfer transfer[2];
31
32         u8 tx_buf;
33         u8 rx_buf[2];
34
35         struct regulator *reg;
36         struct mutex lock;
37 };
38
39 static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg)
40 {
41         int ret;
42
43         adc->tx_buf = msg;
44         ret = spi_sync(adc->spi, &adc->msg);
45         if (ret < 0)
46                 return ret;
47
48         return ((adc->rx_buf[0] & 0x3f) << 6)  |
49                 (adc->rx_buf[1] >> 2);
50 }
51
52 static int mcp320x_read_raw(struct iio_dev *indio_dev,
53                             struct iio_chan_spec const *channel, int *val,
54                             int *val2, long mask)
55 {
56         struct mcp320x *adc = iio_priv(indio_dev);
57         int ret = -EINVAL;
58
59         mutex_lock(&adc->lock);
60
61         switch (mask) {
62         case IIO_CHAN_INFO_RAW:
63                 if (channel->differential)
64                         ret = mcp320x_adc_conversion(adc,
65                                 MCP_START_BIT | channel->address);
66                 else
67                         ret = mcp320x_adc_conversion(adc,
68                                 MCP_START_BIT | MCP_SINGLE_ENDED |
69                                 channel->address);
70                 if (ret < 0)
71                         goto out;
72
73                 *val = ret;
74                 ret = IIO_VAL_INT;
75                 break;
76
77         case IIO_CHAN_INFO_SCALE:
78                 /* Digital output code = (4096 * Vin) / Vref */
79                 ret = regulator_get_voltage(adc->reg);
80                 if (ret < 0)
81                         goto out;
82
83                 *val = ret / 1000;
84                 *val2 = 12;
85                 ret = IIO_VAL_FRACTIONAL_LOG2;
86                 break;
87
88         default:
89                 break;
90         }
91
92 out:
93         mutex_unlock(&adc->lock);
94
95         return ret;
96 }
97
98 #define MCP320X_VOLTAGE_CHANNEL(num)                            \
99         {                                                       \
100                 .type = IIO_VOLTAGE,                            \
101                 .indexed = 1,                                   \
102                 .channel = (num),                               \
103                 .address = (num),                               \
104                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
105                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
106         }
107
108 #define MCP320X_VOLTAGE_CHANNEL_DIFF(num)                       \
109         {                                                       \
110                 .type = IIO_VOLTAGE,                            \
111                 .indexed = 1,                                   \
112                 .channel = (num * 2),                           \
113                 .channel2 = (num * 2 + 1),                      \
114                 .address = (num * 2),                           \
115                 .differential = 1,                              \
116                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
117                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
118         }
119
120 static const struct iio_chan_spec mcp3204_channels[] = {
121         MCP320X_VOLTAGE_CHANNEL(0),
122         MCP320X_VOLTAGE_CHANNEL(1),
123         MCP320X_VOLTAGE_CHANNEL(2),
124         MCP320X_VOLTAGE_CHANNEL(3),
125         MCP320X_VOLTAGE_CHANNEL_DIFF(0),
126         MCP320X_VOLTAGE_CHANNEL_DIFF(1),
127 };
128
129 static const struct iio_chan_spec mcp3208_channels[] = {
130         MCP320X_VOLTAGE_CHANNEL(0),
131         MCP320X_VOLTAGE_CHANNEL(1),
132         MCP320X_VOLTAGE_CHANNEL(2),
133         MCP320X_VOLTAGE_CHANNEL(3),
134         MCP320X_VOLTAGE_CHANNEL(4),
135         MCP320X_VOLTAGE_CHANNEL(5),
136         MCP320X_VOLTAGE_CHANNEL(6),
137         MCP320X_VOLTAGE_CHANNEL(7),
138         MCP320X_VOLTAGE_CHANNEL_DIFF(0),
139         MCP320X_VOLTAGE_CHANNEL_DIFF(1),
140         MCP320X_VOLTAGE_CHANNEL_DIFF(2),
141         MCP320X_VOLTAGE_CHANNEL_DIFF(3),
142 };
143
144 static const struct iio_info mcp320x_info = {
145         .read_raw = mcp320x_read_raw,
146         .driver_module = THIS_MODULE,
147 };
148
149 struct mcp3208_chip_info {
150         const struct iio_chan_spec *channels;
151         unsigned int num_channels;
152 };
153
154 static const struct mcp3208_chip_info mcp3208_chip_infos[] = {
155         [mcp3204] = {
156                 .channels = mcp3204_channels,
157                 .num_channels = ARRAY_SIZE(mcp3204_channels)
158         },
159         [mcp3208] = {
160                 .channels = mcp3208_channels,
161                 .num_channels = ARRAY_SIZE(mcp3208_channels)
162         },
163 };
164
165 static int mcp320x_probe(struct spi_device *spi)
166 {
167         struct iio_dev *indio_dev;
168         struct mcp320x *adc;
169         const struct mcp3208_chip_info *chip_info;
170         int ret;
171
172         indio_dev = iio_device_alloc(sizeof(*adc));
173         if (!indio_dev)
174                 return -ENOMEM;
175
176         adc = iio_priv(indio_dev);
177         adc->spi = spi;
178
179         indio_dev->dev.parent = &spi->dev;
180         indio_dev->name = spi_get_device_id(spi)->name;
181         indio_dev->modes = INDIO_DIRECT_MODE;
182         indio_dev->info = &mcp320x_info;
183
184         chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data];
185         indio_dev->channels = chip_info->channels;
186         indio_dev->num_channels = chip_info->num_channels;
187
188         adc->transfer[0].tx_buf = &adc->tx_buf;
189         adc->transfer[0].len = sizeof(adc->tx_buf);
190         adc->transfer[1].rx_buf = adc->rx_buf;
191         adc->transfer[1].len = sizeof(adc->rx_buf);
192
193         spi_message_init_with_transfers(&adc->msg, adc->transfer,
194                                         ARRAY_SIZE(adc->transfer));
195
196         adc->reg = regulator_get(&spi->dev, "vref");
197         if (IS_ERR(adc->reg)) {
198                 ret = PTR_ERR(adc->reg);
199                 goto iio_free;
200         }
201
202         ret = regulator_enable(adc->reg);
203         if (ret < 0)
204                 goto reg_free;
205
206         mutex_init(&adc->lock);
207
208         ret = iio_device_register(indio_dev);
209         if (ret < 0)
210                 goto reg_disable;
211
212         return 0;
213
214 reg_disable:
215         regulator_disable(adc->reg);
216 reg_free:
217         regulator_put(adc->reg);
218 iio_free:
219         iio_device_free(indio_dev);
220
221         return ret;
222 }
223
224 static int mcp320x_remove(struct spi_device *spi)
225 {
226         struct iio_dev *indio_dev = spi_get_drvdata(spi);
227         struct mcp320x *adc = iio_priv(indio_dev);
228
229         iio_device_unregister(indio_dev);
230         regulator_disable(adc->reg);
231         regulator_put(adc->reg);
232         iio_device_free(indio_dev);
233
234         return 0;
235 }
236
237 static const struct spi_device_id mcp320x_id[] = {
238         { "mcp3204", mcp3204 },
239         { "mcp3208", mcp3208 },
240         { }
241 };
242 MODULE_DEVICE_TABLE(spi, mcp320x_id);
243
244 static struct spi_driver mcp320x_driver = {
245         .driver = {
246                 .name = "mcp320x",
247                 .owner = THIS_MODULE,
248         },
249         .probe = mcp320x_probe,
250         .remove = mcp320x_remove,
251         .id_table = mcp320x_id,
252 };
253 module_spi_driver(mcp320x_driver);
254
255 MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>");
256 MODULE_DESCRIPTION("Microchip Technology MCP3204/08");
257 MODULE_LICENSE("GPL v2");