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