xref: /openbmc/linux/drivers/iio/adc/mcp320x.c (revision f5ce4a7a)
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");
258