162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * HX711: analog to digital converter for weight sensor module
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/err.h>
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/of.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/property.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/sched.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/iio/iio.h>
1762306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
1862306a36Sopenharmony_ci#include <linux/iio/buffer.h>
1962306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
2062306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
2162306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2262306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* gain to pulse and scale conversion */
2562306a36Sopenharmony_ci#define HX711_GAIN_MAX		3
2662306a36Sopenharmony_ci#define HX711_RESET_GAIN	128
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct hx711_gain_to_scale {
2962306a36Sopenharmony_ci	int			gain;
3062306a36Sopenharmony_ci	int			gain_pulse;
3162306a36Sopenharmony_ci	int			scale;
3262306a36Sopenharmony_ci	int			channel;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * .scale depends on AVDD which in turn is known as soon as the regulator
3762306a36Sopenharmony_ci * is available
3862306a36Sopenharmony_ci * therefore we set .scale in hx711_probe()
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * channel A in documentation is channel 0 in source code
4162306a36Sopenharmony_ci * channel B in documentation is channel 1 in source code
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_cistatic struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = {
4462306a36Sopenharmony_ci	{ 128, 1, 0, 0 },
4562306a36Sopenharmony_ci	{  32, 2, 0, 1 },
4662306a36Sopenharmony_ci	{  64, 3, 0, 0 }
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int hx711_get_gain_to_pulse(int gain)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	int i;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	for (i = 0; i < HX711_GAIN_MAX; i++)
5462306a36Sopenharmony_ci		if (hx711_gain_to_scale[i].gain == gain)
5562306a36Sopenharmony_ci			return hx711_gain_to_scale[i].gain_pulse;
5662306a36Sopenharmony_ci	return 1;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int hx711_get_gain_to_scale(int gain)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	int i;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	for (i = 0; i < HX711_GAIN_MAX; i++)
6462306a36Sopenharmony_ci		if (hx711_gain_to_scale[i].gain == gain)
6562306a36Sopenharmony_ci			return hx711_gain_to_scale[i].scale;
6662306a36Sopenharmony_ci	return 0;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int hx711_get_scale_to_gain(int scale)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int i;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	for (i = 0; i < HX711_GAIN_MAX; i++)
7462306a36Sopenharmony_ci		if (hx711_gain_to_scale[i].scale == scale)
7562306a36Sopenharmony_ci			return hx711_gain_to_scale[i].gain;
7662306a36Sopenharmony_ci	return -EINVAL;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistruct hx711_data {
8062306a36Sopenharmony_ci	struct device		*dev;
8162306a36Sopenharmony_ci	struct gpio_desc	*gpiod_pd_sck;
8262306a36Sopenharmony_ci	struct gpio_desc	*gpiod_dout;
8362306a36Sopenharmony_ci	struct regulator	*reg_avdd;
8462306a36Sopenharmony_ci	int			gain_set;	/* gain set on device */
8562306a36Sopenharmony_ci	int			gain_chan_a;	/* gain for channel A */
8662306a36Sopenharmony_ci	struct mutex		lock;
8762306a36Sopenharmony_ci	/*
8862306a36Sopenharmony_ci	 * triggered buffer
8962306a36Sopenharmony_ci	 * 2x32-bit channel + 64-bit naturally aligned timestamp
9062306a36Sopenharmony_ci	 */
9162306a36Sopenharmony_ci	u32			buffer[4] __aligned(8);
9262306a36Sopenharmony_ci	/*
9362306a36Sopenharmony_ci	 * delay after a rising edge on SCK until the data is ready DOUT
9462306a36Sopenharmony_ci	 * this is dependent on the hx711 where the datasheet tells a
9562306a36Sopenharmony_ci	 * maximum value of 100 ns
9662306a36Sopenharmony_ci	 * but also on potential parasitic capacities on the wiring
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	u32			data_ready_delay_ns;
9962306a36Sopenharmony_ci	u32			clock_frequency;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int hx711_cycle(struct hx711_data *hx711_data)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	unsigned long flags;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/*
10762306a36Sopenharmony_ci	 * if preempted for more then 60us while PD_SCK is high:
10862306a36Sopenharmony_ci	 * hx711 is going in reset
10962306a36Sopenharmony_ci	 * ==> measuring is false
11062306a36Sopenharmony_ci	 */
11162306a36Sopenharmony_ci	local_irq_save(flags);
11262306a36Sopenharmony_ci	gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/*
11562306a36Sopenharmony_ci	 * wait until DOUT is ready
11662306a36Sopenharmony_ci	 * it turned out that parasitic capacities are extending the time
11762306a36Sopenharmony_ci	 * until DOUT has reached it's value
11862306a36Sopenharmony_ci	 */
11962306a36Sopenharmony_ci	ndelay(hx711_data->data_ready_delay_ns);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/*
12262306a36Sopenharmony_ci	 * here we are not waiting for 0.2 us as suggested by the datasheet,
12362306a36Sopenharmony_ci	 * because the oscilloscope showed in a test scenario
12462306a36Sopenharmony_ci	 * at least 1.15 us for PD_SCK high (T3 in datasheet)
12562306a36Sopenharmony_ci	 * and 0.56 us for PD_SCK low on TI Sitara with 800 MHz
12662306a36Sopenharmony_ci	 */
12762306a36Sopenharmony_ci	gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
12862306a36Sopenharmony_ci	local_irq_restore(flags);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/*
13162306a36Sopenharmony_ci	 * make it a square wave for addressing cases with capacitance on
13262306a36Sopenharmony_ci	 * PC_SCK
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	ndelay(hx711_data->data_ready_delay_ns);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* sample as late as possible */
13762306a36Sopenharmony_ci	return gpiod_get_value(hx711_data->gpiod_dout);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int hx711_read(struct hx711_data *hx711_data)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	int i, ret;
14362306a36Sopenharmony_ci	int value = 0;
14462306a36Sopenharmony_ci	int val = gpiod_get_value(hx711_data->gpiod_dout);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* we double check if it's really down */
14762306a36Sopenharmony_ci	if (val)
14862306a36Sopenharmony_ci		return -EIO;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	for (i = 0; i < 24; i++) {
15162306a36Sopenharmony_ci		value <<= 1;
15262306a36Sopenharmony_ci		ret = hx711_cycle(hx711_data);
15362306a36Sopenharmony_ci		if (ret)
15462306a36Sopenharmony_ci			value++;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	value ^= 0x800000;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++)
16062306a36Sopenharmony_ci		hx711_cycle(hx711_data);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return value;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int hx711_wait_for_ready(struct hx711_data *hx711_data)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	int i, val;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/*
17062306a36Sopenharmony_ci	 * in some rare cases the reset takes quite a long time
17162306a36Sopenharmony_ci	 * especially when the channel is changed.
17262306a36Sopenharmony_ci	 * Allow up to one second for it
17362306a36Sopenharmony_ci	 */
17462306a36Sopenharmony_ci	for (i = 0; i < 100; i++) {
17562306a36Sopenharmony_ci		val = gpiod_get_value(hx711_data->gpiod_dout);
17662306a36Sopenharmony_ci		if (!val)
17762306a36Sopenharmony_ci			break;
17862306a36Sopenharmony_ci		/* sleep at least 10 ms */
17962306a36Sopenharmony_ci		msleep(10);
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci	if (val)
18262306a36Sopenharmony_ci		return -EIO;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int hx711_reset(struct hx711_data *hx711_data)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	int val = hx711_wait_for_ready(hx711_data);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (val) {
19262306a36Sopenharmony_ci		/*
19362306a36Sopenharmony_ci		 * an examination with the oszilloscope indicated
19462306a36Sopenharmony_ci		 * that the first value read after the reset is not stable
19562306a36Sopenharmony_ci		 * if we reset too short;
19662306a36Sopenharmony_ci		 * the shorter the reset cycle
19762306a36Sopenharmony_ci		 * the less reliable the first value after reset is;
19862306a36Sopenharmony_ci		 * there were no problems encountered with a value
19962306a36Sopenharmony_ci		 * of 10 ms or higher
20062306a36Sopenharmony_ci		 */
20162306a36Sopenharmony_ci		gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
20262306a36Sopenharmony_ci		msleep(10);
20362306a36Sopenharmony_ci		gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		val = hx711_wait_for_ready(hx711_data);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		/* after a reset the gain is 128 */
20862306a36Sopenharmony_ci		hx711_data->gain_set = HX711_RESET_GAIN;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return val;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	int ret;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (chan == 0) {
21962306a36Sopenharmony_ci		if (hx711_data->gain_set == 32) {
22062306a36Sopenharmony_ci			hx711_data->gain_set = hx711_data->gain_chan_a;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci			ret = hx711_read(hx711_data);
22362306a36Sopenharmony_ci			if (ret < 0)
22462306a36Sopenharmony_ci				return ret;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci			ret = hx711_wait_for_ready(hx711_data);
22762306a36Sopenharmony_ci			if (ret)
22862306a36Sopenharmony_ci				return ret;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci	} else {
23162306a36Sopenharmony_ci		if (hx711_data->gain_set != 32) {
23262306a36Sopenharmony_ci			hx711_data->gain_set = 32;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci			ret = hx711_read(hx711_data);
23562306a36Sopenharmony_ci			if (ret < 0)
23662306a36Sopenharmony_ci				return ret;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci			ret = hx711_wait_for_ready(hx711_data);
23962306a36Sopenharmony_ci			if (ret)
24062306a36Sopenharmony_ci				return ret;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int hx711_reset_read(struct hx711_data *hx711_data, int chan)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	int ret;
25062306a36Sopenharmony_ci	int val;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/*
25362306a36Sopenharmony_ci	 * hx711_reset() must be called from here
25462306a36Sopenharmony_ci	 * because it could be calling hx711_read() by itself
25562306a36Sopenharmony_ci	 */
25662306a36Sopenharmony_ci	if (hx711_reset(hx711_data)) {
25762306a36Sopenharmony_ci		dev_err(hx711_data->dev, "reset failed!");
25862306a36Sopenharmony_ci		return -EIO;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	ret = hx711_set_gain_for_channel(hx711_data, chan);
26262306a36Sopenharmony_ci	if (ret < 0)
26362306a36Sopenharmony_ci		return ret;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	val = hx711_read(hx711_data);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	return val;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic int hx711_read_raw(struct iio_dev *indio_dev,
27162306a36Sopenharmony_ci				const struct iio_chan_spec *chan,
27262306a36Sopenharmony_ci				int *val, int *val2, long mask)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct hx711_data *hx711_data = iio_priv(indio_dev);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	switch (mask) {
27762306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
27862306a36Sopenharmony_ci		mutex_lock(&hx711_data->lock);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci		*val = hx711_reset_read(hx711_data, chan->channel);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		mutex_unlock(&hx711_data->lock);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		if (*val < 0)
28562306a36Sopenharmony_ci			return *val;
28662306a36Sopenharmony_ci		return IIO_VAL_INT;
28762306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
28862306a36Sopenharmony_ci		*val = 0;
28962306a36Sopenharmony_ci		mutex_lock(&hx711_data->lock);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		*val2 = hx711_get_gain_to_scale(hx711_data->gain_set);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		mutex_unlock(&hx711_data->lock);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		return IIO_VAL_INT_PLUS_NANO;
29662306a36Sopenharmony_ci	default:
29762306a36Sopenharmony_ci		return -EINVAL;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic int hx711_write_raw(struct iio_dev *indio_dev,
30262306a36Sopenharmony_ci				struct iio_chan_spec const *chan,
30362306a36Sopenharmony_ci				int val,
30462306a36Sopenharmony_ci				int val2,
30562306a36Sopenharmony_ci				long mask)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct hx711_data *hx711_data = iio_priv(indio_dev);
30862306a36Sopenharmony_ci	int ret;
30962306a36Sopenharmony_ci	int gain;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	switch (mask) {
31262306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
31362306a36Sopenharmony_ci		/*
31462306a36Sopenharmony_ci		 * a scale greater than 1 mV per LSB is not possible
31562306a36Sopenharmony_ci		 * with the HX711, therefore val must be 0
31662306a36Sopenharmony_ci		 */
31762306a36Sopenharmony_ci		if (val != 0)
31862306a36Sopenharmony_ci			return -EINVAL;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci		mutex_lock(&hx711_data->lock);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		gain = hx711_get_scale_to_gain(val2);
32362306a36Sopenharmony_ci		if (gain < 0) {
32462306a36Sopenharmony_ci			mutex_unlock(&hx711_data->lock);
32562306a36Sopenharmony_ci			return gain;
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		if (gain != hx711_data->gain_set) {
32962306a36Sopenharmony_ci			hx711_data->gain_set = gain;
33062306a36Sopenharmony_ci			if (gain != 32)
33162306a36Sopenharmony_ci				hx711_data->gain_chan_a = gain;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci			ret = hx711_read(hx711_data);
33462306a36Sopenharmony_ci			if (ret < 0) {
33562306a36Sopenharmony_ci				mutex_unlock(&hx711_data->lock);
33662306a36Sopenharmony_ci				return ret;
33762306a36Sopenharmony_ci			}
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		mutex_unlock(&hx711_data->lock);
34162306a36Sopenharmony_ci		return 0;
34262306a36Sopenharmony_ci	default:
34362306a36Sopenharmony_ci		return -EINVAL;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int hx711_write_raw_get_fmt(struct iio_dev *indio_dev,
35062306a36Sopenharmony_ci		struct iio_chan_spec const *chan,
35162306a36Sopenharmony_ci		long mask)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	return IIO_VAL_INT_PLUS_NANO;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic irqreturn_t hx711_trigger(int irq, void *p)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
35962306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
36062306a36Sopenharmony_ci	struct hx711_data *hx711_data = iio_priv(indio_dev);
36162306a36Sopenharmony_ci	int i, j = 0;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	mutex_lock(&hx711_data->lock);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	memset(hx711_data->buffer, 0, sizeof(hx711_data->buffer));
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	for (i = 0; i < indio_dev->masklength; i++) {
36862306a36Sopenharmony_ci		if (!test_bit(i, indio_dev->active_scan_mask))
36962306a36Sopenharmony_ci			continue;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		hx711_data->buffer[j] = hx711_reset_read(hx711_data,
37262306a36Sopenharmony_ci					indio_dev->channels[i].channel);
37362306a36Sopenharmony_ci		j++;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, hx711_data->buffer,
37762306a36Sopenharmony_ci							pf->timestamp);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	mutex_unlock(&hx711_data->lock);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return IRQ_HANDLED;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic ssize_t hx711_scale_available_show(struct device *dev,
38762306a36Sopenharmony_ci				struct device_attribute *attr,
38862306a36Sopenharmony_ci				char *buf)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
39162306a36Sopenharmony_ci	int channel = iio_attr->address;
39262306a36Sopenharmony_ci	int i, len = 0;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	for (i = 0; i < HX711_GAIN_MAX; i++)
39562306a36Sopenharmony_ci		if (hx711_gain_to_scale[i].channel == channel)
39662306a36Sopenharmony_ci			len += sprintf(buf + len, "0.%09d ",
39762306a36Sopenharmony_ci					hx711_gain_to_scale[i].scale);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	len += sprintf(buf + len, "\n");
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return len;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(in_voltage0_scale_available, S_IRUGO,
40562306a36Sopenharmony_ci	hx711_scale_available_show, NULL, 0);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(in_voltage1_scale_available, S_IRUGO,
40862306a36Sopenharmony_ci	hx711_scale_available_show, NULL, 1);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic struct attribute *hx711_attributes[] = {
41162306a36Sopenharmony_ci	&iio_dev_attr_in_voltage0_scale_available.dev_attr.attr,
41262306a36Sopenharmony_ci	&iio_dev_attr_in_voltage1_scale_available.dev_attr.attr,
41362306a36Sopenharmony_ci	NULL,
41462306a36Sopenharmony_ci};
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic const struct attribute_group hx711_attribute_group = {
41762306a36Sopenharmony_ci	.attrs = hx711_attributes,
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const struct iio_info hx711_iio_info = {
42162306a36Sopenharmony_ci	.read_raw		= hx711_read_raw,
42262306a36Sopenharmony_ci	.write_raw		= hx711_write_raw,
42362306a36Sopenharmony_ci	.write_raw_get_fmt	= hx711_write_raw_get_fmt,
42462306a36Sopenharmony_ci	.attrs			= &hx711_attribute_group,
42562306a36Sopenharmony_ci};
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic const struct iio_chan_spec hx711_chan_spec[] = {
42862306a36Sopenharmony_ci	{
42962306a36Sopenharmony_ci		.type = IIO_VOLTAGE,
43062306a36Sopenharmony_ci		.channel = 0,
43162306a36Sopenharmony_ci		.indexed = 1,
43262306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
43362306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
43462306a36Sopenharmony_ci		.scan_index = 0,
43562306a36Sopenharmony_ci		.scan_type = {
43662306a36Sopenharmony_ci			.sign = 'u',
43762306a36Sopenharmony_ci			.realbits = 24,
43862306a36Sopenharmony_ci			.storagebits = 32,
43962306a36Sopenharmony_ci			.endianness = IIO_CPU,
44062306a36Sopenharmony_ci		},
44162306a36Sopenharmony_ci	},
44262306a36Sopenharmony_ci	{
44362306a36Sopenharmony_ci		.type = IIO_VOLTAGE,
44462306a36Sopenharmony_ci		.channel = 1,
44562306a36Sopenharmony_ci		.indexed = 1,
44662306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
44762306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
44862306a36Sopenharmony_ci		.scan_index = 1,
44962306a36Sopenharmony_ci		.scan_type = {
45062306a36Sopenharmony_ci			.sign = 'u',
45162306a36Sopenharmony_ci			.realbits = 24,
45262306a36Sopenharmony_ci			.storagebits = 32,
45362306a36Sopenharmony_ci			.endianness = IIO_CPU,
45462306a36Sopenharmony_ci		},
45562306a36Sopenharmony_ci	},
45662306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(2),
45762306a36Sopenharmony_ci};
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int hx711_probe(struct platform_device *pdev)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
46262306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
46362306a36Sopenharmony_ci	struct hx711_data *hx711_data;
46462306a36Sopenharmony_ci	struct iio_dev *indio_dev;
46562306a36Sopenharmony_ci	int ret;
46662306a36Sopenharmony_ci	int i;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data));
46962306a36Sopenharmony_ci	if (!indio_dev) {
47062306a36Sopenharmony_ci		dev_err(dev, "failed to allocate IIO device\n");
47162306a36Sopenharmony_ci		return -ENOMEM;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	hx711_data = iio_priv(indio_dev);
47562306a36Sopenharmony_ci	hx711_data->dev = dev;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	mutex_init(&hx711_data->lock);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/*
48062306a36Sopenharmony_ci	 * PD_SCK stands for power down and serial clock input of HX711
48162306a36Sopenharmony_ci	 * in the driver it is an output
48262306a36Sopenharmony_ci	 */
48362306a36Sopenharmony_ci	hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
48462306a36Sopenharmony_ci	if (IS_ERR(hx711_data->gpiod_pd_sck)) {
48562306a36Sopenharmony_ci		dev_err(dev, "failed to get sck-gpiod: err=%ld\n",
48662306a36Sopenharmony_ci					PTR_ERR(hx711_data->gpiod_pd_sck));
48762306a36Sopenharmony_ci		return PTR_ERR(hx711_data->gpiod_pd_sck);
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/*
49162306a36Sopenharmony_ci	 * DOUT stands for serial data output of HX711
49262306a36Sopenharmony_ci	 * for the driver it is an input
49362306a36Sopenharmony_ci	 */
49462306a36Sopenharmony_ci	hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN);
49562306a36Sopenharmony_ci	if (IS_ERR(hx711_data->gpiod_dout)) {
49662306a36Sopenharmony_ci		dev_err(dev, "failed to get dout-gpiod: err=%ld\n",
49762306a36Sopenharmony_ci					PTR_ERR(hx711_data->gpiod_dout));
49862306a36Sopenharmony_ci		return PTR_ERR(hx711_data->gpiod_dout);
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	hx711_data->reg_avdd = devm_regulator_get(dev, "avdd");
50262306a36Sopenharmony_ci	if (IS_ERR(hx711_data->reg_avdd))
50362306a36Sopenharmony_ci		return PTR_ERR(hx711_data->reg_avdd);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	ret = regulator_enable(hx711_data->reg_avdd);
50662306a36Sopenharmony_ci	if (ret < 0)
50762306a36Sopenharmony_ci		return ret;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/*
51062306a36Sopenharmony_ci	 * with
51162306a36Sopenharmony_ci	 * full scale differential input range: AVDD / GAIN
51262306a36Sopenharmony_ci	 * full scale output data: 2^24
51362306a36Sopenharmony_ci	 * we can say:
51462306a36Sopenharmony_ci	 *     AVDD / GAIN = 2^24
51562306a36Sopenharmony_ci	 * therefore:
51662306a36Sopenharmony_ci	 *     1 LSB = AVDD / GAIN / 2^24
51762306a36Sopenharmony_ci	 * AVDD is in uV, but we need 10^-9 mV
51862306a36Sopenharmony_ci	 * approximately to fit into a 32 bit number:
51962306a36Sopenharmony_ci	 * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV]
52062306a36Sopenharmony_ci	 */
52162306a36Sopenharmony_ci	ret = regulator_get_voltage(hx711_data->reg_avdd);
52262306a36Sopenharmony_ci	if (ret < 0)
52362306a36Sopenharmony_ci		goto error_regulator;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* we need 10^-9 mV */
52662306a36Sopenharmony_ci	ret *= 100;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	for (i = 0; i < HX711_GAIN_MAX; i++)
52962306a36Sopenharmony_ci		hx711_gain_to_scale[i].scale =
53062306a36Sopenharmony_ci			ret / hx711_gain_to_scale[i].gain / 1678;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	hx711_data->gain_set = 128;
53362306a36Sopenharmony_ci	hx711_data->gain_chan_a = 128;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	hx711_data->clock_frequency = 400000;
53662306a36Sopenharmony_ci	ret = of_property_read_u32(np, "clock-frequency",
53762306a36Sopenharmony_ci					&hx711_data->clock_frequency);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/*
54062306a36Sopenharmony_ci	 * datasheet says the high level of PD_SCK has a maximum duration
54162306a36Sopenharmony_ci	 * of 50 microseconds
54262306a36Sopenharmony_ci	 */
54362306a36Sopenharmony_ci	if (hx711_data->clock_frequency < 20000) {
54462306a36Sopenharmony_ci		dev_warn(dev, "clock-frequency too low - assuming 400 kHz\n");
54562306a36Sopenharmony_ci		hx711_data->clock_frequency = 400000;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	hx711_data->data_ready_delay_ns =
54962306a36Sopenharmony_ci				1000000000 / hx711_data->clock_frequency;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	platform_set_drvdata(pdev, indio_dev);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	indio_dev->name = "hx711";
55462306a36Sopenharmony_ci	indio_dev->info = &hx711_iio_info;
55562306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
55662306a36Sopenharmony_ci	indio_dev->channels = hx711_chan_spec;
55762306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
56062306a36Sopenharmony_ci							hx711_trigger, NULL);
56162306a36Sopenharmony_ci	if (ret < 0) {
56262306a36Sopenharmony_ci		dev_err(dev, "setup of iio triggered buffer failed\n");
56362306a36Sopenharmony_ci		goto error_regulator;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
56762306a36Sopenharmony_ci	if (ret < 0) {
56862306a36Sopenharmony_ci		dev_err(dev, "Couldn't register the device\n");
56962306a36Sopenharmony_ci		goto error_buffer;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cierror_buffer:
57562306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cierror_regulator:
57862306a36Sopenharmony_ci	regulator_disable(hx711_data->reg_avdd);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return ret;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic int hx711_remove(struct platform_device *pdev)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct hx711_data *hx711_data;
58662306a36Sopenharmony_ci	struct iio_dev *indio_dev;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	indio_dev = platform_get_drvdata(pdev);
58962306a36Sopenharmony_ci	hx711_data = iio_priv(indio_dev);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	iio_triggered_buffer_cleanup(indio_dev);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	regulator_disable(hx711_data->reg_avdd);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	return 0;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic const struct of_device_id of_hx711_match[] = {
60162306a36Sopenharmony_ci	{ .compatible = "avia,hx711", },
60262306a36Sopenharmony_ci	{},
60362306a36Sopenharmony_ci};
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_hx711_match);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic struct platform_driver hx711_driver = {
60862306a36Sopenharmony_ci	.probe		= hx711_probe,
60962306a36Sopenharmony_ci	.remove		= hx711_remove,
61062306a36Sopenharmony_ci	.driver		= {
61162306a36Sopenharmony_ci		.name		= "hx711-gpio",
61262306a36Sopenharmony_ci		.of_match_table	= of_hx711_match,
61362306a36Sopenharmony_ci	},
61462306a36Sopenharmony_ci};
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cimodule_platform_driver(hx711_driver);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
61962306a36Sopenharmony_ciMODULE_DESCRIPTION("HX711 bitbanging driver - ADC for weight cells");
62062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
62162306a36Sopenharmony_ciMODULE_ALIAS("platform:hx711-gpio");
62262306a36Sopenharmony_ci
623