aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc/hx711.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/hx711.c')
-rw-r--r--drivers/iio/adc/hx711.c134
1 files changed, 104 insertions, 30 deletions
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index d10b9f13d557..9430b54121e0 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -24,6 +24,9 @@
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
@@ -89,6 +92,11 @@ struct hx711_data {
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
struct mutex lock;
+ /*
+ * triggered buffer
+ * 2x32-bit channel + 64-bit timestamp
+ */
+ u32 buffer[4];
};
static int hx711_cycle(struct hx711_data *hx711_data)
@@ -145,15 +153,16 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data)
int i, val;
/*
- * a maximum reset cycle time of 56 ms was measured.
- * we round it up to 100 ms
+ * in some rare cases the reset takes quite a long time
+ * especially when the channel is changed.
+ * Allow up to one second for it
*/
for (i = 0; i < 100; i++) {
val = gpiod_get_value(hx711_data->gpiod_dout);
if (!val)
break;
- /* sleep at least 1 ms */
- msleep(1);
+ /* sleep at least 10 ms */
+ msleep(10);
}
if (val)
return -EIO;
@@ -195,9 +204,7 @@ static int hx711_reset(struct hx711_data *hx711_data)
* after a dummy read we need to wait vor readiness
* for not mixing gain pulses with the clock
*/
- ret = hx711_wait_for_ready(hx711_data);
- if (ret)
- return ret;
+ val = hx711_wait_for_ready(hx711_data);
}
return val;
@@ -236,34 +243,40 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
return 0;
}
+static int hx711_reset_read(struct hx711_data *hx711_data, int chan)
+{
+ int ret;
+ int val;
+
+ /*
+ * hx711_reset() must be called from here
+ * because it could be calling hx711_read() by itself
+ */
+ if (hx711_reset(hx711_data)) {
+ dev_err(hx711_data->dev, "reset failed!");
+ return -EIO;
+ }
+
+ ret = hx711_set_gain_for_channel(hx711_data, chan);
+ if (ret < 0)
+ return ret;
+
+ val = hx711_read(hx711_data);
+
+ return val;
+}
+
static int hx711_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct hx711_data *hx711_data = iio_priv(indio_dev);
- int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&hx711_data->lock);
- /*
- * hx711_reset() must be called from here
- * because it could be calling hx711_read() by itself
- */
- if (hx711_reset(hx711_data)) {
- mutex_unlock(&hx711_data->lock);
- dev_err(hx711_data->dev, "reset failed!");
- return -EIO;
- }
-
- ret = hx711_set_gain_for_channel(hx711_data, chan->channel);
- if (ret < 0) {
- mutex_unlock(&hx711_data->lock);
- return ret;
- }
-
- *val = hx711_read(hx711_data);
+ *val = hx711_reset_read(hx711_data, chan->channel);
mutex_unlock(&hx711_data->lock);
@@ -339,6 +352,36 @@ static int hx711_write_raw_get_fmt(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
}
+static irqreturn_t hx711_trigger(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct hx711_data *hx711_data = iio_priv(indio_dev);
+ int i, j = 0;
+
+ mutex_lock(&hx711_data->lock);
+
+ memset(hx711_data->buffer, 0, sizeof(hx711_data->buffer));
+
+ for (i = 0; i < indio_dev->masklength; i++) {
+ if (!test_bit(i, indio_dev->active_scan_mask))
+ continue;
+
+ hx711_data->buffer[j] = hx711_reset_read(hx711_data,
+ indio_dev->channels[i].channel);
+ j++;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, hx711_data->buffer,
+ pf->timestamp);
+
+ mutex_unlock(&hx711_data->lock);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
static ssize_t hx711_scale_available_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -387,6 +430,13 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
.indexed = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
},
{
.type = IIO_VOLTAGE,
@@ -394,7 +444,15 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
.indexed = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
},
+ IIO_CHAN_SOFT_TIMESTAMP(2),
};
static int hx711_probe(struct platform_device *pdev)
@@ -459,10 +517,9 @@ static int hx711_probe(struct platform_device *pdev)
* 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV]
*/
ret = regulator_get_voltage(hx711_data->reg_avdd);
- if (ret < 0) {
- regulator_disable(hx711_data->reg_avdd);
- return ret;
- }
+ if (ret < 0)
+ goto error_regulator;
+
/* we need 10^-9 mV */
ret *= 100;
@@ -482,12 +539,27 @@ static int hx711_probe(struct platform_device *pdev)
indio_dev->channels = hx711_chan_spec;
indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
+ ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
+ hx711_trigger, NULL);
+ if (ret < 0) {
+ dev_err(dev, "setup of iio triggered buffer failed\n");
+ goto error_regulator;
+ }
+
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(dev, "Couldn't register the device\n");
- regulator_disable(hx711_data->reg_avdd);
+ goto error_buffer;
}
+ return 0;
+
+error_buffer:
+ iio_triggered_buffer_cleanup(indio_dev);
+
+error_regulator:
+ regulator_disable(hx711_data->reg_avdd);
+
return ret;
}
@@ -501,6 +573,8 @@ static int hx711_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+
regulator_disable(hx711_data->reg_avdd);
return 0;