Commit | Line | Data |
---|---|---|
913b8646 AC |
1 | /* |
2 | * Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com> | |
3 | * | |
b41fa86b | 4 | * Driver for Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip. |
2a67dfba | 5 | * Datasheets can be found here: |
913b8646 | 6 | * http://www.ti.com/lit/ds/symlink/adc128s052.pdf |
2a67dfba | 7 | * http://www.ti.com/lit/ds/symlink/adc122s021.pdf |
b41fa86b | 8 | * http://www.ti.com/lit/ds/symlink/adc124s021.pdf |
913b8646 AC |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
14 | ||
15 | #include <linux/err.h> | |
16 | #include <linux/spi/spi.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/iio/iio.h> | |
19 | #include <linux/regulator/consumer.h> | |
20 | ||
2a67dfba UF |
21 | struct adc128_configuration { |
22 | const struct iio_chan_spec *channels; | |
23 | u8 num_channels; | |
24 | }; | |
25 | ||
913b8646 AC |
26 | struct adc128 { |
27 | struct spi_device *spi; | |
28 | ||
29 | struct regulator *reg; | |
30 | struct mutex lock; | |
31 | ||
32 | u8 buffer[2] ____cacheline_aligned; | |
33 | }; | |
34 | ||
35 | static int adc128_adc_conversion(struct adc128 *adc, u8 channel) | |
36 | { | |
37 | int ret; | |
38 | ||
39 | mutex_lock(&adc->lock); | |
40 | ||
41 | adc->buffer[0] = channel << 3; | |
42 | adc->buffer[1] = 0; | |
43 | ||
44 | ret = spi_write(adc->spi, &adc->buffer, 2); | |
45 | if (ret < 0) { | |
46 | mutex_unlock(&adc->lock); | |
47 | return ret; | |
48 | } | |
49 | ||
50 | ret = spi_read(adc->spi, &adc->buffer, 2); | |
51 | ||
52 | mutex_unlock(&adc->lock); | |
53 | ||
54 | if (ret < 0) | |
55 | return ret; | |
56 | ||
57 | return ((adc->buffer[0] << 8 | adc->buffer[1]) & 0xFFF); | |
58 | } | |
59 | ||
60 | static int adc128_read_raw(struct iio_dev *indio_dev, | |
61 | struct iio_chan_spec const *channel, int *val, | |
62 | int *val2, long mask) | |
63 | { | |
64 | struct adc128 *adc = iio_priv(indio_dev); | |
65 | int ret; | |
66 | ||
67 | switch (mask) { | |
68 | case IIO_CHAN_INFO_RAW: | |
69 | ||
70 | ret = adc128_adc_conversion(adc, channel->channel); | |
71 | if (ret < 0) | |
72 | return ret; | |
73 | ||
74 | *val = ret; | |
75 | return IIO_VAL_INT; | |
76 | ||
77 | case IIO_CHAN_INFO_SCALE: | |
78 | ||
79 | ret = regulator_get_voltage(adc->reg); | |
80 | if (ret < 0) | |
81 | return ret; | |
82 | ||
83 | *val = ret / 1000; | |
84 | *val2 = 12; | |
85 | return IIO_VAL_FRACTIONAL_LOG2; | |
86 | ||
87 | default: | |
88 | return -EINVAL; | |
89 | } | |
90 | ||
91 | } | |
92 | ||
93 | #define ADC128_VOLTAGE_CHANNEL(num) \ | |
94 | { \ | |
95 | .type = IIO_VOLTAGE, \ | |
96 | .indexed = 1, \ | |
97 | .channel = (num), \ | |
98 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
99 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ | |
100 | } | |
101 | ||
2a67dfba | 102 | static const struct iio_chan_spec adc128s052_channels[] = { |
913b8646 AC |
103 | ADC128_VOLTAGE_CHANNEL(0), |
104 | ADC128_VOLTAGE_CHANNEL(1), | |
105 | ADC128_VOLTAGE_CHANNEL(2), | |
106 | ADC128_VOLTAGE_CHANNEL(3), | |
107 | ADC128_VOLTAGE_CHANNEL(4), | |
108 | ADC128_VOLTAGE_CHANNEL(5), | |
109 | ADC128_VOLTAGE_CHANNEL(6), | |
110 | ADC128_VOLTAGE_CHANNEL(7), | |
111 | }; | |
112 | ||
2a67dfba UF |
113 | static const struct iio_chan_spec adc122s021_channels[] = { |
114 | ADC128_VOLTAGE_CHANNEL(0), | |
115 | ADC128_VOLTAGE_CHANNEL(1), | |
116 | }; | |
117 | ||
b41fa86b OS |
118 | static const struct iio_chan_spec adc124s021_channels[] = { |
119 | ADC128_VOLTAGE_CHANNEL(0), | |
120 | ADC128_VOLTAGE_CHANNEL(1), | |
121 | ADC128_VOLTAGE_CHANNEL(2), | |
122 | ADC128_VOLTAGE_CHANNEL(3), | |
123 | }; | |
124 | ||
2a67dfba UF |
125 | static const struct adc128_configuration adc128_config[] = { |
126 | { adc128s052_channels, ARRAY_SIZE(adc128s052_channels) }, | |
127 | { adc122s021_channels, ARRAY_SIZE(adc122s021_channels) }, | |
b41fa86b | 128 | { adc124s021_channels, ARRAY_SIZE(adc124s021_channels) }, |
2a67dfba UF |
129 | }; |
130 | ||
913b8646 AC |
131 | static const struct iio_info adc128_info = { |
132 | .read_raw = adc128_read_raw, | |
133 | .driver_module = THIS_MODULE, | |
134 | }; | |
135 | ||
136 | static int adc128_probe(struct spi_device *spi) | |
137 | { | |
138 | struct iio_dev *indio_dev; | |
139 | struct adc128 *adc; | |
2a67dfba | 140 | int config = spi_get_device_id(spi)->driver_data; |
913b8646 AC |
141 | int ret; |
142 | ||
143 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); | |
144 | if (!indio_dev) | |
145 | return -ENOMEM; | |
146 | ||
147 | adc = iio_priv(indio_dev); | |
148 | adc->spi = spi; | |
149 | ||
150 | spi_set_drvdata(spi, indio_dev); | |
151 | ||
152 | indio_dev->dev.parent = &spi->dev; | |
153 | indio_dev->name = spi_get_device_id(spi)->name; | |
154 | indio_dev->modes = INDIO_DIRECT_MODE; | |
155 | indio_dev->info = &adc128_info; | |
156 | ||
2a67dfba UF |
157 | indio_dev->channels = adc128_config[config].channels; |
158 | indio_dev->num_channels = adc128_config[config].num_channels; | |
913b8646 AC |
159 | |
160 | adc->reg = devm_regulator_get(&spi->dev, "vref"); | |
161 | if (IS_ERR(adc->reg)) | |
162 | return PTR_ERR(adc->reg); | |
163 | ||
164 | ret = regulator_enable(adc->reg); | |
165 | if (ret < 0) | |
166 | return ret; | |
167 | ||
168 | mutex_init(&adc->lock); | |
169 | ||
170 | ret = iio_device_register(indio_dev); | |
171 | ||
172 | return ret; | |
173 | } | |
174 | ||
175 | static int adc128_remove(struct spi_device *spi) | |
176 | { | |
177 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | |
178 | struct adc128 *adc = iio_priv(indio_dev); | |
179 | ||
180 | iio_device_unregister(indio_dev); | |
181 | regulator_disable(adc->reg); | |
182 | ||
183 | return 0; | |
184 | } | |
185 | ||
9e611c9e JMC |
186 | static const struct of_device_id adc128_of_match[] = { |
187 | { .compatible = "ti,adc128s052", }, | |
188 | { .compatible = "ti,adc122s021", }, | |
b41fa86b | 189 | { .compatible = "ti,adc124s021", }, |
9e611c9e JMC |
190 | { /* sentinel */ }, |
191 | }; | |
192 | MODULE_DEVICE_TABLE(of, adc128_of_match); | |
193 | ||
913b8646 | 194 | static const struct spi_device_id adc128_id[] = { |
2a67dfba UF |
195 | { "adc128s052", 0}, /* index into adc128_config */ |
196 | { "adc122s021", 1}, | |
b41fa86b | 197 | { "adc124s021", 2}, |
913b8646 AC |
198 | { } |
199 | }; | |
200 | MODULE_DEVICE_TABLE(spi, adc128_id); | |
201 | ||
202 | static struct spi_driver adc128_driver = { | |
203 | .driver = { | |
204 | .name = "adc128s052", | |
9e611c9e | 205 | .of_match_table = of_match_ptr(adc128_of_match), |
913b8646 AC |
206 | }, |
207 | .probe = adc128_probe, | |
208 | .remove = adc128_remove, | |
209 | .id_table = adc128_id, | |
210 | }; | |
211 | module_spi_driver(adc128_driver); | |
212 | ||
213 | MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>"); | |
214 | MODULE_DESCRIPTION("Texas Instruments ADC128S052"); | |
215 | MODULE_LICENSE("GPL v2"); |