diff options
author | Søren Andersen <san@rosetechnology.dk> | 2014-10-08 14:42:00 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2014-10-09 15:14:03 -0400 |
commit | b12206e917ac34bec41b9ff93d37d8bd53a2b3bc (patch) | |
tree | 5759fccf881e10ca6a7a59c1bd09f73421027ba4 /drivers/iio | |
parent | 064a74637ccdee608eb898ea3e3847b142b261c6 (diff) |
iio: adc: mcp320x. Add support for more ADCs
Signed-off-by: Soeren Andersen <san at rosetechnology.dk>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/adc/mcp320x.c | 222 |
1 files changed, 187 insertions, 35 deletions
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 28a086e48776..efbfd12a4bfd 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c | |||
@@ -1,9 +1,30 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com> | 2 | * Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com> |
3 | * Copyright (C) 2014 Rose Technology | ||
4 | * Allan Bendorff Jensen <abj@rosetechnology.dk> | ||
5 | * Soren Andersen <san@rosetechnology.dk> | ||
6 | * | ||
7 | * Driver for following ADC chips from Microchip Technology's: | ||
8 | * 10 Bit converter | ||
9 | * MCP3001 | ||
10 | * MCP3002 | ||
11 | * MCP3004 | ||
12 | * MCP3008 | ||
13 | * ------------ | ||
14 | * 12 bit converter | ||
15 | * MCP3201 | ||
16 | * MCP3202 | ||
17 | * MCP3204 | ||
18 | * MCP3208 | ||
19 | * ------------ | ||
3 | * | 20 | * |
4 | * Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips. | ||
5 | * Datasheet can be found here: | 21 | * Datasheet can be found here: |
6 | * http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf | 22 | * http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf mcp3001 |
23 | * http://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf mcp3002 | ||
24 | * http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf mcp3004/08 | ||
25 | * http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201 | ||
26 | * http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202 | ||
27 | * http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08 | ||
7 | * | 28 | * |
8 | * This program is free software; you can redistribute it and/or modify | 29 | * 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 | 30 | * it under the terms of the GNU General Public License version 2 as |
@@ -11,19 +32,29 @@ | |||
11 | */ | 32 | */ |
12 | 33 | ||
13 | #include <linux/err.h> | 34 | #include <linux/err.h> |
35 | #include <linux/delay.h> | ||
14 | #include <linux/spi/spi.h> | 36 | #include <linux/spi/spi.h> |
15 | #include <linux/module.h> | 37 | #include <linux/module.h> |
16 | #include <linux/iio/iio.h> | 38 | #include <linux/iio/iio.h> |
17 | #include <linux/regulator/consumer.h> | 39 | #include <linux/regulator/consumer.h> |
18 | 40 | ||
19 | #define MCP_SINGLE_ENDED (1 << 3) | ||
20 | #define MCP_START_BIT (1 << 4) | ||
21 | |||
22 | enum { | 41 | enum { |
42 | mcp3001, | ||
43 | mcp3002, | ||
44 | mcp3004, | ||
45 | mcp3008, | ||
46 | mcp3201, | ||
47 | mcp3202, | ||
23 | mcp3204, | 48 | mcp3204, |
24 | mcp3208, | 49 | mcp3208, |
25 | }; | 50 | }; |
26 | 51 | ||
52 | struct mcp320x_chip_info { | ||
53 | const struct iio_chan_spec *channels; | ||
54 | unsigned int num_channels; | ||
55 | unsigned int resolution; | ||
56 | }; | ||
57 | |||
27 | struct mcp320x { | 58 | struct mcp320x { |
28 | struct spi_device *spi; | 59 | struct spi_device *spi; |
29 | struct spi_message msg; | 60 | struct spi_message msg; |
@@ -34,19 +65,69 @@ struct mcp320x { | |||
34 | 65 | ||
35 | struct regulator *reg; | 66 | struct regulator *reg; |
36 | struct mutex lock; | 67 | struct mutex lock; |
68 | const struct mcp320x_chip_info *chip_info; | ||
37 | }; | 69 | }; |
38 | 70 | ||
39 | static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg) | 71 | static int mcp320x_channel_to_tx_data(int device_index, |
72 | const unsigned int channel, bool differential) | ||
73 | { | ||
74 | int start_bit = 1; | ||
75 | |||
76 | switch (device_index) { | ||
77 | case mcp3001: | ||
78 | case mcp3201: | ||
79 | return 0; | ||
80 | case mcp3002: | ||
81 | case mcp3202: | ||
82 | return ((start_bit << 4) | (!differential << 3) | | ||
83 | (channel << 2)); | ||
84 | case mcp3004: | ||
85 | case mcp3204: | ||
86 | case mcp3008: | ||
87 | case mcp3208: | ||
88 | return ((start_bit << 6) | (!differential << 5) | | ||
89 | (channel << 2)); | ||
90 | default: | ||
91 | return -EINVAL; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, | ||
96 | bool differential, int device_index) | ||
40 | { | 97 | { |
41 | int ret; | 98 | int ret; |
42 | 99 | ||
43 | adc->tx_buf = msg; | 100 | adc->rx_buf[0] = 0; |
44 | ret = spi_sync(adc->spi, &adc->msg); | 101 | adc->rx_buf[1] = 0; |
45 | if (ret < 0) | 102 | adc->tx_buf = mcp320x_channel_to_tx_data(device_index, |
46 | return ret; | 103 | channel, differential); |
104 | |||
105 | if (device_index != mcp3001 && device_index != mcp3201) { | ||
106 | ret = spi_sync(adc->spi, &adc->msg); | ||
107 | if (ret < 0) | ||
108 | return ret; | ||
109 | } else { | ||
110 | ret = spi_read(adc->spi, &adc->rx_buf, sizeof(adc->rx_buf)); | ||
111 | if (ret < 0) | ||
112 | return ret; | ||
113 | } | ||
47 | 114 | ||
48 | return ((adc->rx_buf[0] & 0x3f) << 6) | | 115 | switch (device_index) { |
49 | (adc->rx_buf[1] >> 2); | 116 | case mcp3001: |
117 | return (adc->rx_buf[0] << 5 | adc->rx_buf[1] >> 3); | ||
118 | case mcp3002: | ||
119 | case mcp3004: | ||
120 | case mcp3008: | ||
121 | return (adc->rx_buf[0] << 2 | adc->rx_buf[1] >> 6); | ||
122 | case mcp3201: | ||
123 | return (adc->rx_buf[0] << 7 | adc->rx_buf[1] >> 1); | ||
124 | case mcp3202: | ||
125 | case mcp3204: | ||
126 | case mcp3208: | ||
127 | return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4); | ||
128 | default: | ||
129 | return -EINVAL; | ||
130 | } | ||
50 | } | 131 | } |
51 | 132 | ||
52 | static int mcp320x_read_raw(struct iio_dev *indio_dev, | 133 | static int mcp320x_read_raw(struct iio_dev *indio_dev, |
@@ -55,18 +136,17 @@ static int mcp320x_read_raw(struct iio_dev *indio_dev, | |||
55 | { | 136 | { |
56 | struct mcp320x *adc = iio_priv(indio_dev); | 137 | struct mcp320x *adc = iio_priv(indio_dev); |
57 | int ret = -EINVAL; | 138 | int ret = -EINVAL; |
139 | int device_index = 0; | ||
58 | 140 | ||
59 | mutex_lock(&adc->lock); | 141 | mutex_lock(&adc->lock); |
60 | 142 | ||
143 | device_index = spi_get_device_id(adc->spi)->driver_data; | ||
144 | |||
61 | switch (mask) { | 145 | switch (mask) { |
62 | case IIO_CHAN_INFO_RAW: | 146 | case IIO_CHAN_INFO_RAW: |
63 | if (channel->differential) | 147 | ret = mcp320x_adc_conversion(adc, channel->address, |
64 | ret = mcp320x_adc_conversion(adc, | 148 | channel->differential, device_index); |
65 | MCP_START_BIT | channel->address); | 149 | |
66 | else | ||
67 | ret = mcp320x_adc_conversion(adc, | ||
68 | MCP_START_BIT | MCP_SINGLE_ENDED | | ||
69 | channel->address); | ||
70 | if (ret < 0) | 150 | if (ret < 0) |
71 | goto out; | 151 | goto out; |
72 | 152 | ||
@@ -75,18 +155,15 @@ static int mcp320x_read_raw(struct iio_dev *indio_dev, | |||
75 | break; | 155 | break; |
76 | 156 | ||
77 | case IIO_CHAN_INFO_SCALE: | 157 | case IIO_CHAN_INFO_SCALE: |
78 | /* Digital output code = (4096 * Vin) / Vref */ | ||
79 | ret = regulator_get_voltage(adc->reg); | 158 | ret = regulator_get_voltage(adc->reg); |
80 | if (ret < 0) | 159 | if (ret < 0) |
81 | goto out; | 160 | goto out; |
82 | 161 | ||
162 | /* convert regulator output voltage to mV */ | ||
83 | *val = ret / 1000; | 163 | *val = ret / 1000; |
84 | *val2 = 12; | 164 | *val2 = adc->chip_info->resolution; |
85 | ret = IIO_VAL_FRACTIONAL_LOG2; | 165 | ret = IIO_VAL_FRACTIONAL_LOG2; |
86 | break; | 166 | break; |
87 | |||
88 | default: | ||
89 | break; | ||
90 | } | 167 | } |
91 | 168 | ||
92 | out: | 169 | out: |
@@ -117,6 +194,16 @@ out: | |||
117 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ | 194 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ |
118 | } | 195 | } |
119 | 196 | ||
197 | static const struct iio_chan_spec mcp3201_channels[] = { | ||
198 | MCP320X_VOLTAGE_CHANNEL_DIFF(0), | ||
199 | }; | ||
200 | |||
201 | static const struct iio_chan_spec mcp3202_channels[] = { | ||
202 | MCP320X_VOLTAGE_CHANNEL(0), | ||
203 | MCP320X_VOLTAGE_CHANNEL(1), | ||
204 | MCP320X_VOLTAGE_CHANNEL_DIFF(0), | ||
205 | }; | ||
206 | |||
120 | static const struct iio_chan_spec mcp3204_channels[] = { | 207 | static const struct iio_chan_spec mcp3204_channels[] = { |
121 | MCP320X_VOLTAGE_CHANNEL(0), | 208 | MCP320X_VOLTAGE_CHANNEL(0), |
122 | MCP320X_VOLTAGE_CHANNEL(1), | 209 | MCP320X_VOLTAGE_CHANNEL(1), |
@@ -146,19 +233,46 @@ static const struct iio_info mcp320x_info = { | |||
146 | .driver_module = THIS_MODULE, | 233 | .driver_module = THIS_MODULE, |
147 | }; | 234 | }; |
148 | 235 | ||
149 | struct mcp3208_chip_info { | 236 | static const struct mcp320x_chip_info mcp320x_chip_infos[] = { |
150 | const struct iio_chan_spec *channels; | 237 | [mcp3001] = { |
151 | unsigned int num_channels; | 238 | .channels = mcp3201_channels, |
152 | }; | 239 | .num_channels = ARRAY_SIZE(mcp3201_channels), |
153 | 240 | .resolution = 10 | |
154 | static const struct mcp3208_chip_info mcp3208_chip_infos[] = { | 241 | }, |
242 | [mcp3002] = { | ||
243 | .channels = mcp3202_channels, | ||
244 | .num_channels = ARRAY_SIZE(mcp3202_channels), | ||
245 | .resolution = 10 | ||
246 | }, | ||
247 | [mcp3004] = { | ||
248 | .channels = mcp3204_channels, | ||
249 | .num_channels = ARRAY_SIZE(mcp3204_channels), | ||
250 | .resolution = 10 | ||
251 | }, | ||
252 | [mcp3008] = { | ||
253 | .channels = mcp3208_channels, | ||
254 | .num_channels = ARRAY_SIZE(mcp3208_channels), | ||
255 | .resolution = 10 | ||
256 | }, | ||
257 | [mcp3201] = { | ||
258 | .channels = mcp3201_channels, | ||
259 | .num_channels = ARRAY_SIZE(mcp3201_channels), | ||
260 | .resolution = 12 | ||
261 | }, | ||
262 | [mcp3202] = { | ||
263 | .channels = mcp3202_channels, | ||
264 | .num_channels = ARRAY_SIZE(mcp3202_channels), | ||
265 | .resolution = 12 | ||
266 | }, | ||
155 | [mcp3204] = { | 267 | [mcp3204] = { |
156 | .channels = mcp3204_channels, | 268 | .channels = mcp3204_channels, |
157 | .num_channels = ARRAY_SIZE(mcp3204_channels) | 269 | .num_channels = ARRAY_SIZE(mcp3204_channels), |
270 | .resolution = 12 | ||
158 | }, | 271 | }, |
159 | [mcp3208] = { | 272 | [mcp3208] = { |
160 | .channels = mcp3208_channels, | 273 | .channels = mcp3208_channels, |
161 | .num_channels = ARRAY_SIZE(mcp3208_channels) | 274 | .num_channels = ARRAY_SIZE(mcp3208_channels), |
275 | .resolution = 12 | ||
162 | }, | 276 | }, |
163 | }; | 277 | }; |
164 | 278 | ||
@@ -166,7 +280,7 @@ static int mcp320x_probe(struct spi_device *spi) | |||
166 | { | 280 | { |
167 | struct iio_dev *indio_dev; | 281 | struct iio_dev *indio_dev; |
168 | struct mcp320x *adc; | 282 | struct mcp320x *adc; |
169 | const struct mcp3208_chip_info *chip_info; | 283 | const struct mcp320x_chip_info *chip_info; |
170 | int ret; | 284 | int ret; |
171 | 285 | ||
172 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); | 286 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); |
@@ -181,7 +295,7 @@ static int mcp320x_probe(struct spi_device *spi) | |||
181 | indio_dev->modes = INDIO_DIRECT_MODE; | 295 | indio_dev->modes = INDIO_DIRECT_MODE; |
182 | indio_dev->info = &mcp320x_info; | 296 | indio_dev->info = &mcp320x_info; |
183 | 297 | ||
184 | chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data]; | 298 | chip_info = &mcp320x_chip_infos[spi_get_device_id(spi)->driver_data]; |
185 | indio_dev->channels = chip_info->channels; | 299 | indio_dev->channels = chip_info->channels; |
186 | indio_dev->num_channels = chip_info->num_channels; | 300 | indio_dev->num_channels = chip_info->num_channels; |
187 | 301 | ||
@@ -226,7 +340,45 @@ static int mcp320x_remove(struct spi_device *spi) | |||
226 | return 0; | 340 | return 0; |
227 | } | 341 | } |
228 | 342 | ||
343 | #if defined(CONFIG_OF) | ||
344 | static const struct of_device_id mcp320x_dt_ids[] = { | ||
345 | { | ||
346 | .compatible = "mcp3001", | ||
347 | .data = &mcp320x_chip_infos[mcp3001], | ||
348 | }, { | ||
349 | .compatible = "mcp3002", | ||
350 | .data = &mcp320x_chip_infos[mcp3002], | ||
351 | }, { | ||
352 | .compatible = "mcp3004", | ||
353 | .data = &mcp320x_chip_infos[mcp3004], | ||
354 | }, { | ||
355 | .compatible = "mcp3008", | ||
356 | .data = &mcp320x_chip_infos[mcp3008], | ||
357 | }, { | ||
358 | .compatible = "mcp3201", | ||
359 | .data = &mcp320x_chip_infos[mcp3201], | ||
360 | }, { | ||
361 | .compatible = "mcp3202", | ||
362 | .data = &mcp320x_chip_infos[mcp3202], | ||
363 | }, { | ||
364 | .compatible = "mcp3204", | ||
365 | .data = &mcp320x_chip_infos[mcp3204], | ||
366 | }, { | ||
367 | .compatible = "mcp3208", | ||
368 | .data = &mcp320x_chip_infos[mcp3208], | ||
369 | }, { | ||
370 | } | ||
371 | }; | ||
372 | MODULE_DEVICE_TABLE(of, mcp320x_dt_ids); | ||
373 | #endif | ||
374 | |||
229 | static const struct spi_device_id mcp320x_id[] = { | 375 | static const struct spi_device_id mcp320x_id[] = { |
376 | { "mcp3001", mcp3001 }, | ||
377 | { "mcp3002", mcp3002 }, | ||
378 | { "mcp3004", mcp3004 }, | ||
379 | { "mcp3008", mcp3008 }, | ||
380 | { "mcp3201", mcp3201 }, | ||
381 | { "mcp3202", mcp3202 }, | ||
230 | { "mcp3204", mcp3204 }, | 382 | { "mcp3204", mcp3204 }, |
231 | { "mcp3208", mcp3208 }, | 383 | { "mcp3208", mcp3208 }, |
232 | { } | 384 | { } |
@@ -245,5 +397,5 @@ static struct spi_driver mcp320x_driver = { | |||
245 | module_spi_driver(mcp320x_driver); | 397 | module_spi_driver(mcp320x_driver); |
246 | 398 | ||
247 | MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>"); | 399 | MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>"); |
248 | MODULE_DESCRIPTION("Microchip Technology MCP3204/08"); | 400 | MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08"); |
249 | MODULE_LICENSE("GPL v2"); | 401 | MODULE_LICENSE("GPL v2"); |