1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * adcxx.c |
4 | * |
5 | * The adcxx4s is an AD converter family from National Semiconductor (NS). |
6 | * |
7 | * Copyright (c) 2008 Marc Pignat <marc.pignat@hevs.ch> |
8 | * |
9 | * The adcxx4s communicates with a host processor via an SPI/Microwire Bus |
10 | * interface. This driver supports the whole family of devices with name |
11 | * ADC<bb><c>S<sss>, where |
12 | * * bb is the resolution in number of bits (8, 10, 12) |
13 | * * c is the number of channels (1, 2, 4, 8) |
14 | * * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500 kSPS |
15 | * and 101 for 1 MSPS) |
16 | * |
17 | * Complete datasheets are available at National's website here: |
18 | * http://www.national.com/ds/DC/ADC<bb><c>S<sss>.pdf |
19 | * |
20 | * Handling of 8, 10 and 12 bits converters are the same, the |
21 | * unavailable bits are 0 :) |
22 | */ |
23 | |
24 | #include <linux/init.h> |
25 | #include <linux/module.h> |
26 | #include <linux/kernel.h> |
27 | #include <linux/slab.h> |
28 | #include <linux/device.h> |
29 | #include <linux/err.h> |
30 | #include <linux/sysfs.h> |
31 | #include <linux/hwmon.h> |
32 | #include <linux/hwmon-sysfs.h> |
33 | #include <linux/mutex.h> |
34 | #include <linux/mod_devicetable.h> |
35 | #include <linux/spi/spi.h> |
36 | |
37 | #define DRVNAME "adcxx" |
38 | |
39 | struct adcxx { |
40 | struct device *hwmon_dev; |
41 | struct mutex lock; |
42 | u32 channels; |
43 | u32 reference; /* in millivolts */ |
44 | }; |
45 | |
46 | /* sysfs hook function */ |
47 | static ssize_t adcxx_show(struct device *dev, |
48 | struct device_attribute *devattr, char *buf) |
49 | { |
50 | struct spi_device *spi = to_spi_device(dev); |
51 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
52 | struct adcxx *adc = spi_get_drvdata(spi); |
53 | u8 tx_buf[2]; |
54 | u8 rx_buf[2]; |
55 | int status; |
56 | u32 value; |
57 | |
58 | if (mutex_lock_interruptible(&adc->lock)) |
59 | return -ERESTARTSYS; |
60 | |
61 | if (adc->channels == 1) { |
62 | status = spi_read(spi, buf: rx_buf, len: sizeof(rx_buf)); |
63 | } else { |
64 | tx_buf[0] = attr->index << 3; /* other bits are don't care */ |
65 | status = spi_write_then_read(spi, txbuf: tx_buf, n_tx: sizeof(tx_buf), |
66 | rxbuf: rx_buf, n_rx: sizeof(rx_buf)); |
67 | } |
68 | if (status < 0) { |
69 | dev_warn(dev, "SPI synch. transfer failed with status %d\n" , |
70 | status); |
71 | goto out; |
72 | } |
73 | |
74 | value = (rx_buf[0] << 8) + rx_buf[1]; |
75 | dev_dbg(dev, "raw value = 0x%x\n" , value); |
76 | |
77 | value = value * adc->reference >> 12; |
78 | status = sprintf(buf, fmt: "%d\n" , value); |
79 | out: |
80 | mutex_unlock(lock: &adc->lock); |
81 | return status; |
82 | } |
83 | |
84 | static ssize_t adcxx_min_show(struct device *dev, |
85 | struct device_attribute *devattr, char *buf) |
86 | { |
87 | /* The minimum reference is 0 for this chip family */ |
88 | return sprintf(buf, fmt: "0\n" ); |
89 | } |
90 | |
91 | static ssize_t adcxx_max_show(struct device *dev, |
92 | struct device_attribute *devattr, char *buf) |
93 | { |
94 | struct spi_device *spi = to_spi_device(dev); |
95 | struct adcxx *adc = spi_get_drvdata(spi); |
96 | u32 reference; |
97 | |
98 | if (mutex_lock_interruptible(&adc->lock)) |
99 | return -ERESTARTSYS; |
100 | |
101 | reference = adc->reference; |
102 | |
103 | mutex_unlock(lock: &adc->lock); |
104 | |
105 | return sprintf(buf, fmt: "%d\n" , reference); |
106 | } |
107 | |
108 | static ssize_t adcxx_max_store(struct device *dev, |
109 | struct device_attribute *devattr, |
110 | const char *buf, size_t count) |
111 | { |
112 | struct spi_device *spi = to_spi_device(dev); |
113 | struct adcxx *adc = spi_get_drvdata(spi); |
114 | unsigned long value; |
115 | |
116 | if (kstrtoul(s: buf, base: 10, res: &value)) |
117 | return -EINVAL; |
118 | |
119 | if (mutex_lock_interruptible(&adc->lock)) |
120 | return -ERESTARTSYS; |
121 | |
122 | adc->reference = value; |
123 | |
124 | mutex_unlock(lock: &adc->lock); |
125 | |
126 | return count; |
127 | } |
128 | |
129 | static ssize_t adcxx_name_show(struct device *dev, |
130 | struct device_attribute *devattr, char *buf) |
131 | { |
132 | return sprintf(buf, fmt: "%s\n" , to_spi_device(dev)->modalias); |
133 | } |
134 | |
135 | static struct sensor_device_attribute ad_input[] = { |
136 | SENSOR_ATTR_RO(name, adcxx_name, 0), |
137 | SENSOR_ATTR_RO(in_min, adcxx_min, 0), |
138 | SENSOR_ATTR_RW(in_max, adcxx_max, 0), |
139 | SENSOR_ATTR_RO(in0_input, adcxx, 0), |
140 | SENSOR_ATTR_RO(in1_input, adcxx, 1), |
141 | SENSOR_ATTR_RO(in2_input, adcxx, 2), |
142 | SENSOR_ATTR_RO(in3_input, adcxx, 3), |
143 | SENSOR_ATTR_RO(in4_input, adcxx, 4), |
144 | SENSOR_ATTR_RO(in5_input, adcxx, 5), |
145 | SENSOR_ATTR_RO(in6_input, adcxx, 6), |
146 | SENSOR_ATTR_RO(in7_input, adcxx, 7), |
147 | }; |
148 | |
149 | /*----------------------------------------------------------------------*/ |
150 | |
151 | static int adcxx_probe(struct spi_device *spi) |
152 | { |
153 | int channels = spi_get_device_id(sdev: spi)->driver_data; |
154 | struct adcxx *adc; |
155 | int status; |
156 | int i; |
157 | |
158 | adc = devm_kzalloc(dev: &spi->dev, size: sizeof(*adc), GFP_KERNEL); |
159 | if (!adc) |
160 | return -ENOMEM; |
161 | |
162 | /* set a default value for the reference */ |
163 | adc->reference = 3300; |
164 | adc->channels = channels; |
165 | mutex_init(&adc->lock); |
166 | |
167 | mutex_lock(&adc->lock); |
168 | |
169 | spi_set_drvdata(spi, data: adc); |
170 | |
171 | for (i = 0; i < 3 + adc->channels; i++) { |
172 | status = device_create_file(device: &spi->dev, entry: &ad_input[i].dev_attr); |
173 | if (status) { |
174 | dev_err(&spi->dev, "device_create_file failed.\n" ); |
175 | goto out_err; |
176 | } |
177 | } |
178 | |
179 | adc->hwmon_dev = hwmon_device_register(dev: &spi->dev); |
180 | if (IS_ERR(ptr: adc->hwmon_dev)) { |
181 | dev_err(&spi->dev, "hwmon_device_register failed.\n" ); |
182 | status = PTR_ERR(ptr: adc->hwmon_dev); |
183 | goto out_err; |
184 | } |
185 | |
186 | mutex_unlock(lock: &adc->lock); |
187 | return 0; |
188 | |
189 | out_err: |
190 | for (i--; i >= 0; i--) |
191 | device_remove_file(dev: &spi->dev, attr: &ad_input[i].dev_attr); |
192 | |
193 | mutex_unlock(lock: &adc->lock); |
194 | return status; |
195 | } |
196 | |
197 | static void adcxx_remove(struct spi_device *spi) |
198 | { |
199 | struct adcxx *adc = spi_get_drvdata(spi); |
200 | int i; |
201 | |
202 | mutex_lock(&adc->lock); |
203 | hwmon_device_unregister(dev: adc->hwmon_dev); |
204 | for (i = 0; i < 3 + adc->channels; i++) |
205 | device_remove_file(dev: &spi->dev, attr: &ad_input[i].dev_attr); |
206 | |
207 | mutex_unlock(lock: &adc->lock); |
208 | } |
209 | |
210 | static const struct spi_device_id adcxx_ids[] = { |
211 | { "adcxx1s" , 1 }, |
212 | { "adcxx2s" , 2 }, |
213 | { "adcxx4s" , 4 }, |
214 | { "adcxx8s" , 8 }, |
215 | { }, |
216 | }; |
217 | MODULE_DEVICE_TABLE(spi, adcxx_ids); |
218 | |
219 | static struct spi_driver adcxx_driver = { |
220 | .driver = { |
221 | .name = "adcxx" , |
222 | }, |
223 | .id_table = adcxx_ids, |
224 | .probe = adcxx_probe, |
225 | .remove = adcxx_remove, |
226 | }; |
227 | |
228 | module_spi_driver(adcxx_driver); |
229 | |
230 | MODULE_AUTHOR("Marc Pignat" ); |
231 | MODULE_DESCRIPTION("National Semiconductor adcxx8sxxx Linux driver" ); |
232 | MODULE_LICENSE("GPL" ); |
233 | |