blob: 7e0b036536eb2060c5825aadf865f15a85f98717 [file] [log] [blame]
Kyle Swensoncc33c242022-05-16 10:38:04 -06001/*
2 * ./kernel_modules/qcom-adc/ads7924-driver.c
3 *
4 * ads7924-driver.c - driver for TI ADS7924 4-channel A/D converter
5 *
6 * Author: Cradlepoint Technology, Inc. <source@cradlepoint.com>
7 * Kyle Swenson <kswenson@cradlepoint.com>
8 * Derived heavily from similar hwmon-based drivers in the linux source tree.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 */
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/hwmon.h>
26#include <linux/hwmon-sysfs.h>
27#include <linux/i2c.h>
28#include <linux/init.h>
29#include <linux/device.h>
30#include <linux/workqueue.h>
31#include <linux/jiffies.h>
32#include <linux/module.h>
33#include <linux/delay.h>
34#include <linux/mutex.h>
35#include <linux/gpio.h>
36#include <linux/timer.h>
37#include <linux/slab.h>
38
39#include "ads7924-regdefs.h"
40#include "adc-averaging.h"
41
42#define ADS7924_NCH 4 /* Number of ADC Channels for the ADS7924 */
43#define ADS7924_SAMPLE_INTERVAL 10 /*In ms -> 100 Hz default */
44#define ADS7924_ENABLE_DEFAULT 0 /*Automatic sampling disabled by default */
45#define ADS7924_DEFAULT_BUFFER_SIZE 16 /*Default length for each channel's buffer */
46#define ADS7924_VMAX 5000 /* Reference voltage, maximum */
47
48/* ADS7924-specific data */
49struct ads7924_data {
50 struct mutex update_lock; /* Mutex protecting updates */
51 struct timer_list sample_timer;
52 struct work_struct workq;
53
54 struct device *hwmon_dev; /* result of register the struct i2c_client->dev with hwmon */
55 struct i2c_client * client;
56 struct gpio_desc * reset;
57 unsigned long last_updated; /* Last updated time (in jiffies) */
58 unsigned enabled; /* */
59 unsigned update_interval; /* in ms */
60 bool valid; /* Validity flag, for first data resquest */
61 unsigned sample_length; /*Number of samples stored for the average */
62 struct adc_channel *channel[ADS7924_NCH];
63};
64
65
Ravineet Singhf4d52842023-02-16 10:59:33 +010066void ads7924_timer_irq(struct timer_list *timer)
Kyle Swenson89648b22022-05-16 10:56:50 -060067{
Ravineet Singhf4d52842023-02-16 10:59:33 +010068 struct ads7924_data *data = from_timer(data, timer, sample_timer);
Kyle Swenson89648b22022-05-16 10:56:50 -060069
Kyle Swensoncc33c242022-05-16 10:38:04 -060070 if (data->enabled) {
71 mod_timer(&data->sample_timer, jiffies + msecs_to_jiffies(data->update_interval));
72 schedule_work(&data->workq);
73 }
74}
75
Kyle Swensoncc33c242022-05-16 10:38:04 -060076static uint16_t ads7924_sample_channel(struct i2c_client *client, uint8_t channel)
77{
78 int err;
79 int lb, hb, hb2;
80 uint16_t adc_count = 0;
81 err = i2c_smbus_write_byte_data(client, ADS7924_REG_MODECNTRL, (ADS7924_MODE_MANUAL_SINGLE << 2) | (channel & 0x03));
82 if (err < 0) {
83 dev_warn(&client->dev, "Failed to i2c write");
84 }
85 hb = i2c_smbus_read_byte_data(client, ADS7924_REG_DATA0_U + (channel << 1));
86 lb = i2c_smbus_read_byte_data(client, ADS7924_REG_DATA0_L + (channel << 1));
87 hb2 = i2c_smbus_read_byte_data(client, ADS7924_REG_DATA0_U + (channel << 1));
88 if (hb != hb2)
89 dev_warn(&client->dev, "Warning hb reading inconsistent!\n");
90 if (hb < 0 || lb < 0) {
91 dev_warn(&client->dev, "Failed to i2c read");
92 return (uint16_t) 0xFFFF; /* return a value > 4096, upper layers should check */
93 }
94 adc_count = (uint16_t)((((hb & 0x00FF) << 8) | (lb & 0x00FF)) >> 4);
95
96 return adc_count;
97}
98
99static struct ads7924_data *ads7924_update_device(struct i2c_client *client)
100{
101 struct ads7924_data *data = i2c_get_clientdata(client);
102 uint16_t sample;
103 int i = 0;
104
105 mutex_lock(&data->update_lock);
106
107 for(i=0; i<ADS7924_NCH; i++) {
108 sample = ads7924_sample_channel(client, i);
109 if (!(sample & 0xF000))
110 add_sample(data->channel[i], sample);
111 else
112 dev_info(&client->dev, "Ch%d sample 0x%04x out of range\n", i, sample);
113
114 }
115 data->last_updated = jiffies;
116 data->valid = 1;
117 mutex_unlock(&data->update_lock);
118 return data;
119}
120
121void ads7924_work(struct work_struct *work)
122{
123 struct ads7924_data *data = container_of(work, struct ads7924_data, workq);
124 ads7924_update_device(data->client);
125}
126
127/*
128 Number of samples used to compute the average
129*/
130static ssize_t sample_length_store(struct device *dev, struct device_attribute *da, const char *buf, size_t len)
131{
132 struct i2c_client *client = to_i2c_client(dev);
133 struct ads7924_data *data = i2c_get_clientdata(client);
134 int i;
135 unsigned long length;
136 int err = kstrtoul(buf, 10, &length);
137 if (err)
138 return err;
139
140 if (length >= MAX_SAMPLE_LENGTH) {
141 return -EINVAL;
142 }
143 mutex_lock(&data->update_lock);
144 data->sample_length = length;
145 for (i = 0; i < ADS7924_NCH; i++) {
146 free_adc_channel(data->channel[i]);
Kyle Swenson89648b22022-05-16 10:56:50 -0600147 data->channel[i] = create_adc_channel(dev, data->sample_length);
Kyle Swensoncc33c242022-05-16 10:38:04 -0600148 if (!data->channel[i]) {
149 dev_warn(&client->dev, "Failed to resize the channel buffer\n");
150 /*TODO: If this happens, we're pretty screwed. Like, we should unload ourselves. */
151 }
152 }
153 mutex_unlock(&data->update_lock);
154 return len;
155}
156static ssize_t sample_length_show(struct device *dev, struct device_attribute *da, char *buf)
157{
158 struct i2c_client *client = to_i2c_client(dev);
159 struct ads7924_data *data = i2c_get_clientdata(client);
160 return sprintf(buf, "%u", data->sample_length);
161}
162static SENSOR_DEVICE_ATTR(sample_length, S_IRUGO|S_IWUSR|S_IWGRP, sample_length_show, sample_length_store, 0);
163
164
165/*
166 Enable/disable the automatic sample & average functionality. Disabled by default
167*/
168static ssize_t enable_store(struct device *dev, struct device_attribute *da, const char *buf, size_t length)
169{
170 struct i2c_client *client = to_i2c_client(dev);
171 struct ads7924_data *data = i2c_get_clientdata(client);
172 unsigned long enabled;
173 int err = kstrtoul(buf, 10, &enabled);
174 if (err)
175 return err;
176
177 mutex_lock(&data->update_lock);
Kyle Swenson89648b22022-05-16 10:56:50 -0600178 if (enabled != data->enabled) {
179 data->enabled = enabled;
180 if (enabled)
181 mod_timer(&data->sample_timer, 0);
182 }
Kyle Swensoncc33c242022-05-16 10:38:04 -0600183 mutex_unlock(&data->update_lock);
Kyle Swenson89648b22022-05-16 10:56:50 -0600184
Kyle Swensoncc33c242022-05-16 10:38:04 -0600185 return length;
186}
187static ssize_t enable_show(struct device *dev, struct device_attribute *da, char *buf)
188{
189 struct i2c_client *client = to_i2c_client(dev);
190 struct ads7924_data *data = i2c_get_clientdata(client);
191 return sprintf(buf, "%u", data->enabled);
192}
193static SENSOR_DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, enable_show, enable_store, 0);
194
195/*
196 update interval : minimium time between sample requests
197*/
198static ssize_t update_interval_store(struct device *dev, struct device_attribute *da, const char *buf, size_t length)
199{
200 struct i2c_client *client = to_i2c_client(dev);
201 struct ads7924_data *data = i2c_get_clientdata(client);
202 unsigned long update_interval;
203 int err = kstrtoul(buf, 10, &update_interval);
204 if (err)
205 return err;
206 mutex_lock(&data->update_lock);
207 data->update_interval = update_interval;
208 mutex_unlock(&data->update_lock);
209 return length;
210}
211static ssize_t update_interval_show(struct device *dev, struct device_attribute *da, char *buf)
212{
213 struct i2c_client *client = to_i2c_client(dev);
214 struct ads7924_data *data = i2c_get_clientdata(client);
215 return sprintf(buf, "%u", data->update_interval);
216}
217static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO|S_IWUSR|S_IWGRP, update_interval_show, update_interval_store, 0);
218
219/*
220 Show the voltage on the specified channel.
221
222 Note that this causes the ADC to sample the specified channel,
223 independently of any averaging that might be going on. Also note that if there
224 is averaging going on, this particular average will not be included in the
225 sample
226
227*/
228static ssize_t ads7924_show_in(struct device *dev, struct device_attribute *da, char *buf)
229{
230 struct i2c_client *client = to_i2c_client(dev);
231 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
232 struct ads7924_data *data = i2c_get_clientdata(client);
233 uint16_t value;
234 mutex_lock(&data->update_lock);
235 /* TODO RATE LIMITE THIS*/
236 value = ads7924_sample_channel(client, attr->index);
237 mutex_unlock(&data->update_lock);
238 return sprintf(buf, "%d", value);
239}
240
241static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7924_show_in, NULL, 0);
242static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7924_show_in, NULL, 1);
243static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7924_show_in, NULL, 2);
244static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7924_show_in, NULL, 3);
245
246static ssize_t ads7924_show_average(struct device *dev, struct device_attribute *da, char *buf)
247{
248 struct i2c_client *client = to_i2c_client(dev);
249 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
250 struct ads7924_data *data = ads7924_update_device(client);
251 uint16_t value;
252 if (data) {
253 value = compute_average(data->channel[attr->index]);
254 return sprintf(buf, "%d", value);
255 }
256 return -EAGAIN;
257}
258static SENSOR_DEVICE_ATTR(in0_average, S_IRUGO, ads7924_show_average, NULL, 0);
259static SENSOR_DEVICE_ATTR(in1_average, S_IRUGO, ads7924_show_average, NULL, 1);
260static SENSOR_DEVICE_ATTR(in2_average, S_IRUGO, ads7924_show_average, NULL, 2);
261static SENSOR_DEVICE_ATTR(in3_average, S_IRUGO, ads7924_show_average, NULL, 3);
262
263static struct attribute *ads7924_attrs[] = {
264 &sensor_dev_attr_update_interval.dev_attr.attr, /* Interval between device updates*/
265 &sensor_dev_attr_sample_length.dev_attr.attr, /* Number of samples used to average*/
266 &sensor_dev_attr_enable.dev_attr.attr, /* Enable/disable the timer-based sampleing*/
267 &sensor_dev_attr_in0_average.dev_attr.attr,
268 &sensor_dev_attr_in1_average.dev_attr.attr,
269 &sensor_dev_attr_in2_average.dev_attr.attr,
270 &sensor_dev_attr_in3_average.dev_attr.attr,
271 &sensor_dev_attr_in0_input.dev_attr.attr,
272 &sensor_dev_attr_in1_input.dev_attr.attr,
273 &sensor_dev_attr_in2_input.dev_attr.attr,
274 &sensor_dev_attr_in3_input.dev_attr.attr,
275 NULL
276};
277
278static const struct attribute_group ads7924_group = {
279 .attrs = ads7924_attrs,
280};
281
282static int ads7924_remove(struct i2c_client *client)
283{
284 struct ads7924_data *data = i2c_get_clientdata(client);
285 int i;
286
Kyle Swensoncc33c242022-05-16 10:38:04 -0600287 hwmon_device_unregister(data->hwmon_dev);
Kyle Swenson89648b22022-05-16 10:56:50 -0600288
Kyle Swensoncc33c242022-05-16 10:38:04 -0600289 sysfs_remove_group(&client->dev.kobj, &ads7924_group);
Kyle Swenson89648b22022-05-16 10:56:50 -0600290
291 mutex_lock(&data->update_lock);
292 data->enabled = 0;
293 for (i = 0; i < ADS7924_NCH; i++)
294 free_adc_channel(data->channel[i]);
295
Kyle Swensoncc33c242022-05-16 10:38:04 -0600296 mutex_unlock(&data->update_lock);
Kyle Swenson89648b22022-05-16 10:56:50 -0600297 del_timer_sync(&data->sample_timer);
298 cancel_work_sync(&data->workq);
299
300 mutex_destroy(&data->update_lock);
301
Kyle Swensoncc33c242022-05-16 10:38:04 -0600302 return 0;
303}
304
305static int ads7924_probe(struct i2c_client *client, const struct i2c_device_id *id)
306{
307 struct ads7924_data *data;
308 int i;
309 uint8_t dev_id;
310 int err;
311 int smbus_err;
312 dev_info(&client->dev, "ads7924 probe begin\n");
313 data = devm_kzalloc(&client->dev, sizeof(struct ads7924_data), GFP_KERNEL);
314 if (!data)
315 return -ENOMEM;
316
317 data->valid = 0;
318 data->update_interval = ADS7924_SAMPLE_INTERVAL;
319 data->sample_length = ADS7924_DEFAULT_BUFFER_SIZE;
320 data->enabled = ADS7924_ENABLE_DEFAULT;
321 data->client = client;
Kyle Swenson89648b22022-05-16 10:56:50 -0600322 data->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); /* Grab reset GPIO if available and assert reset */
323 if (IS_ERR(data->reset)) {
Kyle Swensoncc33c242022-05-16 10:38:04 -0600324 dev_warn(&client->dev, "Failed to request the reset gpio, error=%ld\n", PTR_ERR(data->reset));
325 data->reset = NULL;
326 } else {
Kyle Swenson89648b22022-05-16 10:56:50 -0600327 dev_info(&client->dev, "Successfully claimed the reset gpio (gpio %d), value is %d\n", desc_to_gpio(data->reset), gpiod_get_value_cansleep(data->reset));
328 mdelay(5);
329 gpiod_set_value_cansleep(data->reset, 0); /* Deassert reset */
330 mdelay(10);
Kyle Swensoncc33c242022-05-16 10:38:04 -0600331 }
332
Kyle Swensoncc33c242022-05-16 10:38:04 -0600333 smbus_err = i2c_smbus_read_byte_data(client, ADS7924_REG_RESET);
Kyle Swenson89648b22022-05-16 10:56:50 -0600334 if (smbus_err < 0) {
Kyle Swensoncc33c242022-05-16 10:38:04 -0600335 dev_warn(&client->dev, "failed to read device id register 0x%02X, err=%d\n", ADS7924_REG_RESET, smbus_err);
Kyle Swenson89648b22022-05-16 10:56:50 -0600336 return smbus_err;
337 }
338
339 dev_id = (uint8_t) smbus_err;
Kyle Swensoncc33c242022-05-16 10:38:04 -0600340 if (dev_id != 0x19) { /* This is my device's ID, at least. */
341 dev_warn(&client->dev, "Device id of 0x%02x doesn't match the expected 0x19\n", dev_id);
Kyle Swenson89648b22022-05-16 10:56:50 -0600342 return -ENODEV;
Kyle Swensoncc33c242022-05-16 10:38:04 -0600343 }
344
345 for (i = 0; i < ADS7924_NCH; i++) {
Kyle Swenson89648b22022-05-16 10:56:50 -0600346 data->channel[i] = create_adc_channel(&client->dev, data->sample_length);
Kyle Swensoncc33c242022-05-16 10:38:04 -0600347 if (!data->channel[i]) {
348 dev_warn(&client->dev, "Failed to allocate memeory for adc_channel %d\n", i);
349 return -ENOMEM;
350 }
351 }
352
353 INIT_WORK(&data->workq, ads7924_work);
354 mutex_init(&data->update_lock);
355
356 err = sysfs_create_group(&client->dev.kobj, &ads7924_group);
357 if (err < 0)
358 return err;
359
360 i2c_set_clientdata(client, data);
361
362 data->hwmon_dev = hwmon_device_register(&client->dev);
363
364 if (IS_ERR(data->hwmon_dev)) {
365 err = PTR_ERR(data->hwmon_dev);
366 dev_err(&client->dev, "Failed to register with hwmon, error=%d\n", err);
367 goto err_remove;
368 }
Ravineet Singhf4d52842023-02-16 10:59:33 +0100369 timer_setup(&data->sample_timer, ads7924_timer_irq, 0);
Kyle Swensoncc33c242022-05-16 10:38:04 -0600370 return 0;
371
372
373err_remove:
Kyle Swenson89648b22022-05-16 10:56:50 -0600374 mutex_destroy(&data->update_lock);
Kyle Swensoncc33c242022-05-16 10:38:04 -0600375 sysfs_remove_group(&client->dev.kobj, &ads7924_group);
Kyle Swensoncc33c242022-05-16 10:38:04 -0600376 return err;
377
378}
379
380static const struct i2c_device_id ads7924_device_ids[] = {
381 { "ads7924", 0},
382 { },
383};
384MODULE_DEVICE_TABLE(i2c, ads7924_device_ids);
385
386static struct i2c_driver ads7924_driver = {
387 .class = I2C_CLASS_HWMON,
388 .driver = {
389 .name = "ads7924",
390 },
391 .id_table = ads7924_device_ids,
392 .probe = ads7924_probe,
393 .remove = ads7924_remove,
394};
395
396module_i2c_driver(ads7924_driver);
397
398MODULE_LICENSE("GPL");
399MODULE_AUTHOR("Kyle Swenson <kswenson@cradlepoint.com>");
400MODULE_DESCRIPTION("Driver for TI ADS7924 A/D converter and compatibles");