123491b51SDenis Ciocca /*
223491b51SDenis Ciocca  * STMicroelectronics sensors core library driver
323491b51SDenis Ciocca  *
423491b51SDenis Ciocca  * Copyright 2012-2013 STMicroelectronics Inc.
523491b51SDenis Ciocca  *
623491b51SDenis Ciocca  * Denis Ciocca <denis.ciocca@st.com>
723491b51SDenis Ciocca  *
823491b51SDenis Ciocca  * Licensed under the GPL-2.
923491b51SDenis Ciocca  */
1023491b51SDenis Ciocca 
1123491b51SDenis Ciocca #include <linux/kernel.h>
1223491b51SDenis Ciocca #include <linux/module.h>
1323491b51SDenis Ciocca #include <linux/slab.h>
1423491b51SDenis Ciocca #include <linux/delay.h>
1523491b51SDenis Ciocca #include <linux/iio/iio.h>
16ea7e586bSLinus Walleij #include <linux/regulator/consumer.h>
173ce85cc4SLinus Walleij #include <linux/of.h>
18250bbbdbSLorenzo Bianconi #include <linux/of_device.h>
1923491b51SDenis Ciocca #include <asm/unaligned.h>
2023491b51SDenis Ciocca #include <linux/iio/common/st_sensors.h>
2123491b51SDenis Ciocca 
22a9fd053bSLinus Walleij #include "st_sensors_core.h"
23a9fd053bSLinus Walleij 
24607a568aSDenis CIOCCA static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
25607a568aSDenis CIOCCA {
2623cde4d6SDenis CIOCCA 	return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
27607a568aSDenis CIOCCA }
28607a568aSDenis CIOCCA 
29a9fd053bSLinus Walleij int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
3023491b51SDenis Ciocca 				    u8 reg_addr, u8 mask, u8 data)
3123491b51SDenis Ciocca {
3223491b51SDenis Ciocca 	int err;
3323491b51SDenis Ciocca 	u8 new_data;
3423491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
3523491b51SDenis Ciocca 
3623491b51SDenis Ciocca 	err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
3723491b51SDenis Ciocca 	if (err < 0)
3823491b51SDenis Ciocca 		goto st_sensors_write_data_with_mask_error;
3923491b51SDenis Ciocca 
4023491b51SDenis Ciocca 	new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
4123491b51SDenis Ciocca 	err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
4223491b51SDenis Ciocca 
4323491b51SDenis Ciocca st_sensors_write_data_with_mask_error:
4423491b51SDenis Ciocca 	return err;
4523491b51SDenis Ciocca }
4623491b51SDenis Ciocca 
47a0175b9cSLinus Walleij int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
48a0175b9cSLinus Walleij 				  unsigned reg, unsigned writeval,
49a0175b9cSLinus Walleij 				  unsigned *readval)
50a0175b9cSLinus Walleij {
51a0175b9cSLinus Walleij 	struct st_sensor_data *sdata = iio_priv(indio_dev);
52a0175b9cSLinus Walleij 	u8 readdata;
53a0175b9cSLinus Walleij 	int err;
54a0175b9cSLinus Walleij 
55a0175b9cSLinus Walleij 	if (!readval)
56a0175b9cSLinus Walleij 		return sdata->tf->write_byte(&sdata->tb, sdata->dev,
57a0175b9cSLinus Walleij 					     (u8)reg, (u8)writeval);
58a0175b9cSLinus Walleij 
59a0175b9cSLinus Walleij 	err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata);
60a0175b9cSLinus Walleij 	if (err < 0)
61a0175b9cSLinus Walleij 		return err;
62a0175b9cSLinus Walleij 
63a0175b9cSLinus Walleij 	*readval = (unsigned)readdata;
64a0175b9cSLinus Walleij 
65a0175b9cSLinus Walleij 	return 0;
66a0175b9cSLinus Walleij }
67a0175b9cSLinus Walleij EXPORT_SYMBOL(st_sensors_debugfs_reg_access);
68a0175b9cSLinus Walleij 
69a7ee8839SDenis CIOCCA static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
7023491b51SDenis Ciocca 			unsigned int odr, struct st_sensor_odr_avl *odr_out)
7123491b51SDenis Ciocca {
7223491b51SDenis Ciocca 	int i, ret = -EINVAL;
7323491b51SDenis Ciocca 
7423491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
75a7ee8839SDenis CIOCCA 		if (sensor_settings->odr.odr_avl[i].hz == 0)
7623491b51SDenis Ciocca 			goto st_sensors_match_odr_error;
7723491b51SDenis Ciocca 
78a7ee8839SDenis CIOCCA 		if (sensor_settings->odr.odr_avl[i].hz == odr) {
79a7ee8839SDenis CIOCCA 			odr_out->hz = sensor_settings->odr.odr_avl[i].hz;
80a7ee8839SDenis CIOCCA 			odr_out->value = sensor_settings->odr.odr_avl[i].value;
8123491b51SDenis Ciocca 			ret = 0;
8223491b51SDenis Ciocca 			break;
8323491b51SDenis Ciocca 		}
8423491b51SDenis Ciocca 	}
8523491b51SDenis Ciocca 
8623491b51SDenis Ciocca st_sensors_match_odr_error:
8723491b51SDenis Ciocca 	return ret;
8823491b51SDenis Ciocca }
8923491b51SDenis Ciocca 
9023491b51SDenis Ciocca int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
9123491b51SDenis Ciocca {
9223491b51SDenis Ciocca 	int err;
93852afe99SDenis CIOCCA 	struct st_sensor_odr_avl odr_out = {0, 0};
9423491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
9523491b51SDenis Ciocca 
96a7ee8839SDenis CIOCCA 	err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
9723491b51SDenis Ciocca 	if (err < 0)
9823491b51SDenis Ciocca 		goto st_sensors_match_odr_error;
9923491b51SDenis Ciocca 
100a7ee8839SDenis CIOCCA 	if ((sdata->sensor_settings->odr.addr ==
101a7ee8839SDenis CIOCCA 					sdata->sensor_settings->pw.addr) &&
102a7ee8839SDenis CIOCCA 				(sdata->sensor_settings->odr.mask ==
103a7ee8839SDenis CIOCCA 					sdata->sensor_settings->pw.mask)) {
10423491b51SDenis Ciocca 		if (sdata->enabled == true) {
10523491b51SDenis Ciocca 			err = st_sensors_write_data_with_mask(indio_dev,
106a7ee8839SDenis CIOCCA 				sdata->sensor_settings->odr.addr,
107a7ee8839SDenis CIOCCA 				sdata->sensor_settings->odr.mask,
10823491b51SDenis Ciocca 				odr_out.value);
10923491b51SDenis Ciocca 		} else {
11023491b51SDenis Ciocca 			err = 0;
11123491b51SDenis Ciocca 		}
11223491b51SDenis Ciocca 	} else {
11323491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
114a7ee8839SDenis CIOCCA 			sdata->sensor_settings->odr.addr,
115a7ee8839SDenis CIOCCA 			sdata->sensor_settings->odr.mask,
11623491b51SDenis Ciocca 			odr_out.value);
11723491b51SDenis Ciocca 	}
11823491b51SDenis Ciocca 	if (err >= 0)
11923491b51SDenis Ciocca 		sdata->odr = odr_out.hz;
12023491b51SDenis Ciocca 
12123491b51SDenis Ciocca st_sensors_match_odr_error:
12223491b51SDenis Ciocca 	return err;
12323491b51SDenis Ciocca }
12423491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_odr);
12523491b51SDenis Ciocca 
126a7ee8839SDenis CIOCCA static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
12723491b51SDenis Ciocca 					unsigned int fs, int *index_fs_avl)
12823491b51SDenis Ciocca {
12923491b51SDenis Ciocca 	int i, ret = -EINVAL;
13023491b51SDenis Ciocca 
13123491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
132a7ee8839SDenis CIOCCA 		if (sensor_settings->fs.fs_avl[i].num == 0)
13323491b51SDenis Ciocca 			goto st_sensors_match_odr_error;
13423491b51SDenis Ciocca 
135a7ee8839SDenis CIOCCA 		if (sensor_settings->fs.fs_avl[i].num == fs) {
13623491b51SDenis Ciocca 			*index_fs_avl = i;
13723491b51SDenis Ciocca 			ret = 0;
13823491b51SDenis Ciocca 			break;
13923491b51SDenis Ciocca 		}
14023491b51SDenis Ciocca 	}
14123491b51SDenis Ciocca 
14223491b51SDenis Ciocca st_sensors_match_odr_error:
14323491b51SDenis Ciocca 	return ret;
14423491b51SDenis Ciocca }
14523491b51SDenis Ciocca 
146a7ee8839SDenis CIOCCA static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
14723491b51SDenis Ciocca {
148852afe99SDenis CIOCCA 	int err, i = 0;
14923491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
15023491b51SDenis Ciocca 
151bb602f8cSGiuseppe Barba 	if (sdata->sensor_settings->fs.addr == 0)
152bb602f8cSGiuseppe Barba 		return 0;
153bb602f8cSGiuseppe Barba 
154a7ee8839SDenis CIOCCA 	err = st_sensors_match_fs(sdata->sensor_settings, fs, &i);
15523491b51SDenis Ciocca 	if (err < 0)
15623491b51SDenis Ciocca 		goto st_accel_set_fullscale_error;
15723491b51SDenis Ciocca 
15823491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
159a7ee8839SDenis CIOCCA 				sdata->sensor_settings->fs.addr,
160a7ee8839SDenis CIOCCA 				sdata->sensor_settings->fs.mask,
161a7ee8839SDenis CIOCCA 				sdata->sensor_settings->fs.fs_avl[i].value);
16223491b51SDenis Ciocca 	if (err < 0)
16323491b51SDenis Ciocca 		goto st_accel_set_fullscale_error;
16423491b51SDenis Ciocca 
16523491b51SDenis Ciocca 	sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
166a7ee8839SDenis CIOCCA 					&sdata->sensor_settings->fs.fs_avl[i];
16723491b51SDenis Ciocca 	return err;
16823491b51SDenis Ciocca 
16923491b51SDenis Ciocca st_accel_set_fullscale_error:
17023491b51SDenis Ciocca 	dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
17123491b51SDenis Ciocca 	return err;
17223491b51SDenis Ciocca }
17323491b51SDenis Ciocca 
17423491b51SDenis Ciocca int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
17523491b51SDenis Ciocca {
17623491b51SDenis Ciocca 	u8 tmp_value;
17723491b51SDenis Ciocca 	int err = -EINVAL;
178852afe99SDenis CIOCCA 	bool found = false;
179852afe99SDenis CIOCCA 	struct st_sensor_odr_avl odr_out = {0, 0};
18023491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
18123491b51SDenis Ciocca 
18223491b51SDenis Ciocca 	if (enable) {
183a7ee8839SDenis CIOCCA 		tmp_value = sdata->sensor_settings->pw.value_on;
184a7ee8839SDenis CIOCCA 		if ((sdata->sensor_settings->odr.addr ==
185a7ee8839SDenis CIOCCA 					sdata->sensor_settings->pw.addr) &&
186a7ee8839SDenis CIOCCA 				(sdata->sensor_settings->odr.mask ==
187a7ee8839SDenis CIOCCA 					sdata->sensor_settings->pw.mask)) {
188a7ee8839SDenis CIOCCA 			err = st_sensors_match_odr(sdata->sensor_settings,
18923491b51SDenis Ciocca 							sdata->odr, &odr_out);
19023491b51SDenis Ciocca 			if (err < 0)
19123491b51SDenis Ciocca 				goto set_enable_error;
19223491b51SDenis Ciocca 			tmp_value = odr_out.value;
19323491b51SDenis Ciocca 			found = true;
19423491b51SDenis Ciocca 		}
19523491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
196a7ee8839SDenis CIOCCA 				sdata->sensor_settings->pw.addr,
197a7ee8839SDenis CIOCCA 				sdata->sensor_settings->pw.mask, tmp_value);
19823491b51SDenis Ciocca 		if (err < 0)
19923491b51SDenis Ciocca 			goto set_enable_error;
20023491b51SDenis Ciocca 
20123491b51SDenis Ciocca 		sdata->enabled = true;
20223491b51SDenis Ciocca 
20323491b51SDenis Ciocca 		if (found)
20423491b51SDenis Ciocca 			sdata->odr = odr_out.hz;
20523491b51SDenis Ciocca 	} else {
20623491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
207a7ee8839SDenis CIOCCA 				sdata->sensor_settings->pw.addr,
208a7ee8839SDenis CIOCCA 				sdata->sensor_settings->pw.mask,
209a7ee8839SDenis CIOCCA 				sdata->sensor_settings->pw.value_off);
21023491b51SDenis Ciocca 		if (err < 0)
21123491b51SDenis Ciocca 			goto set_enable_error;
21223491b51SDenis Ciocca 
21323491b51SDenis Ciocca 		sdata->enabled = false;
21423491b51SDenis Ciocca 	}
21523491b51SDenis Ciocca 
21623491b51SDenis Ciocca set_enable_error:
21723491b51SDenis Ciocca 	return err;
21823491b51SDenis Ciocca }
21923491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_enable);
22023491b51SDenis Ciocca 
22123491b51SDenis Ciocca int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
22223491b51SDenis Ciocca {
22323491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
22423491b51SDenis Ciocca 
22523491b51SDenis Ciocca 	return st_sensors_write_data_with_mask(indio_dev,
226a7ee8839SDenis CIOCCA 				sdata->sensor_settings->enable_axis.addr,
227a7ee8839SDenis CIOCCA 				sdata->sensor_settings->enable_axis.mask,
228a7ee8839SDenis CIOCCA 				axis_enable);
22923491b51SDenis Ciocca }
23023491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_axis_enable);
23123491b51SDenis Ciocca 
23214f295c8SGregor Boirie int st_sensors_power_enable(struct iio_dev *indio_dev)
233ea7e586bSLinus Walleij {
234ea7e586bSLinus Walleij 	struct st_sensor_data *pdata = iio_priv(indio_dev);
235ea7e586bSLinus Walleij 	int err;
236ea7e586bSLinus Walleij 
237ea7e586bSLinus Walleij 	/* Regulators not mandatory, but if requested we should enable them. */
238aeb55fffSLinus Walleij 	pdata->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
239aeb55fffSLinus Walleij 	if (IS_ERR(pdata->vdd)) {
240aeb55fffSLinus Walleij 		dev_err(&indio_dev->dev, "unable to get Vdd supply\n");
241aeb55fffSLinus Walleij 		return PTR_ERR(pdata->vdd);
242aeb55fffSLinus Walleij 	}
243ea7e586bSLinus Walleij 	err = regulator_enable(pdata->vdd);
24414f295c8SGregor Boirie 	if (err != 0) {
245ea7e586bSLinus Walleij 		dev_warn(&indio_dev->dev,
246ea7e586bSLinus Walleij 			 "Failed to enable specified Vdd supply\n");
24714f295c8SGregor Boirie 		return err;
24814f295c8SGregor Boirie 	}
249ea7e586bSLinus Walleij 
250aeb55fffSLinus Walleij 	pdata->vdd_io = devm_regulator_get(indio_dev->dev.parent, "vddio");
2511b246fcaSLinus Walleij 	if (IS_ERR(pdata->vdd_io)) {
252aeb55fffSLinus Walleij 		dev_err(&indio_dev->dev, "unable to get Vdd_IO supply\n");
2531b246fcaSLinus Walleij 		err = PTR_ERR(pdata->vdd_io);
254aeb55fffSLinus Walleij 		goto st_sensors_disable_vdd;
255aeb55fffSLinus Walleij 	}
256ea7e586bSLinus Walleij 	err = regulator_enable(pdata->vdd_io);
25714f295c8SGregor Boirie 	if (err != 0) {
258ea7e586bSLinus Walleij 		dev_warn(&indio_dev->dev,
259ea7e586bSLinus Walleij 			 "Failed to enable specified Vdd_IO supply\n");
26014f295c8SGregor Boirie 		goto st_sensors_disable_vdd;
261ea7e586bSLinus Walleij 	}
26214f295c8SGregor Boirie 
26314f295c8SGregor Boirie 	return 0;
26414f295c8SGregor Boirie 
26514f295c8SGregor Boirie st_sensors_disable_vdd:
26614f295c8SGregor Boirie 	regulator_disable(pdata->vdd);
26714f295c8SGregor Boirie 	return err;
268ea7e586bSLinus Walleij }
269ea7e586bSLinus Walleij EXPORT_SYMBOL(st_sensors_power_enable);
270ea7e586bSLinus Walleij 
271ea7e586bSLinus Walleij void st_sensors_power_disable(struct iio_dev *indio_dev)
272ea7e586bSLinus Walleij {
273ea7e586bSLinus Walleij 	struct st_sensor_data *pdata = iio_priv(indio_dev);
274ea7e586bSLinus Walleij 
275ea7e586bSLinus Walleij 	regulator_disable(pdata->vdd);
276ea7e586bSLinus Walleij 	regulator_disable(pdata->vdd_io);
277ea7e586bSLinus Walleij }
278ea7e586bSLinus Walleij EXPORT_SYMBOL(st_sensors_power_disable);
279ea7e586bSLinus Walleij 
28038d1c6a9SLee Jones static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
28123cde4d6SDenis CIOCCA 					struct st_sensors_platform_data *pdata)
28223491b51SDenis Ciocca {
28323491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
28423491b51SDenis Ciocca 
285d2bc4318SLinus Walleij 	/* Sensor does not support interrupts */
286d2bc4318SLinus Walleij 	if (sdata->sensor_settings->drdy_irq.addr == 0) {
287d2bc4318SLinus Walleij 		if (pdata->drdy_int_pin)
288d2bc4318SLinus Walleij 			dev_info(&indio_dev->dev,
289d2bc4318SLinus Walleij 				 "DRDY on pin INT%d specified, but sensor "
290d2bc4318SLinus Walleij 				 "does not support interrupts\n",
291d2bc4318SLinus Walleij 				 pdata->drdy_int_pin);
292d2bc4318SLinus Walleij 		return 0;
293d2bc4318SLinus Walleij 	}
294d2bc4318SLinus Walleij 
29523cde4d6SDenis CIOCCA 	switch (pdata->drdy_int_pin) {
29623cde4d6SDenis CIOCCA 	case 1:
297a7ee8839SDenis CIOCCA 		if (sdata->sensor_settings->drdy_irq.mask_int1 == 0) {
29823cde4d6SDenis CIOCCA 			dev_err(&indio_dev->dev,
29923cde4d6SDenis CIOCCA 					"DRDY on INT1 not available.\n");
30038d1c6a9SLee Jones 			return -EINVAL;
30123cde4d6SDenis CIOCCA 		}
30223cde4d6SDenis CIOCCA 		sdata->drdy_int_pin = 1;
30323cde4d6SDenis CIOCCA 		break;
30423cde4d6SDenis CIOCCA 	case 2:
305a7ee8839SDenis CIOCCA 		if (sdata->sensor_settings->drdy_irq.mask_int2 == 0) {
30623cde4d6SDenis CIOCCA 			dev_err(&indio_dev->dev,
30723cde4d6SDenis CIOCCA 					"DRDY on INT2 not available.\n");
30838d1c6a9SLee Jones 			return -EINVAL;
30923cde4d6SDenis CIOCCA 		}
31023cde4d6SDenis CIOCCA 		sdata->drdy_int_pin = 2;
31123cde4d6SDenis CIOCCA 		break;
31223cde4d6SDenis CIOCCA 	default:
31323cde4d6SDenis CIOCCA 		dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
31438d1c6a9SLee Jones 		return -EINVAL;
31523cde4d6SDenis CIOCCA 	}
31623cde4d6SDenis CIOCCA 
3170e6f6871SLinus Walleij 	if (pdata->open_drain) {
3180e6f6871SLinus Walleij 		if (!sdata->sensor_settings->drdy_irq.addr_od)
3190e6f6871SLinus Walleij 			dev_err(&indio_dev->dev,
3200e6f6871SLinus Walleij 				"open drain requested but unsupported.\n");
3210e6f6871SLinus Walleij 		else
3220e6f6871SLinus Walleij 			sdata->int_pin_open_drain = true;
3230e6f6871SLinus Walleij 	}
3240e6f6871SLinus Walleij 
32538d1c6a9SLee Jones 	return 0;
32638d1c6a9SLee Jones }
32738d1c6a9SLee Jones 
3283ce85cc4SLinus Walleij #ifdef CONFIG_OF
3293ce85cc4SLinus Walleij static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
3303ce85cc4SLinus Walleij 		struct st_sensors_platform_data *defdata)
3313ce85cc4SLinus Walleij {
3323ce85cc4SLinus Walleij 	struct st_sensors_platform_data *pdata;
3333ce85cc4SLinus Walleij 	struct device_node *np = dev->of_node;
3343ce85cc4SLinus Walleij 	u32 val;
3353ce85cc4SLinus Walleij 
3363ce85cc4SLinus Walleij 	if (!np)
3373ce85cc4SLinus Walleij 		return NULL;
3383ce85cc4SLinus Walleij 
3393ce85cc4SLinus Walleij 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3403ce85cc4SLinus Walleij 	if (!of_property_read_u32(np, "st,drdy-int-pin", &val) && (val <= 2))
3413ce85cc4SLinus Walleij 		pdata->drdy_int_pin = (u8) val;
3423ce85cc4SLinus Walleij 	else
343d2bc4318SLinus Walleij 		pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;
3443ce85cc4SLinus Walleij 
3450e6f6871SLinus Walleij 	pdata->open_drain = of_property_read_bool(np, "drive-open-drain");
3460e6f6871SLinus Walleij 
3473ce85cc4SLinus Walleij 	return pdata;
3483ce85cc4SLinus Walleij }
349250bbbdbSLorenzo Bianconi 
350250bbbdbSLorenzo Bianconi /**
351250bbbdbSLorenzo Bianconi  * st_sensors_of_name_probe() - device tree probe for ST sensor name
352250bbbdbSLorenzo Bianconi  * @dev: driver model representation of the device.
353250bbbdbSLorenzo Bianconi  * @match: the OF match table for the device, containing compatible strings
354250bbbdbSLorenzo Bianconi  *	but also a .data field with the corresponding internal kernel name
355250bbbdbSLorenzo Bianconi  *	used by this sensor.
356250bbbdbSLorenzo Bianconi  * @name: device name buffer reference.
357250bbbdbSLorenzo Bianconi  * @len: device name buffer length.
358250bbbdbSLorenzo Bianconi  *
359250bbbdbSLorenzo Bianconi  * In effect this function matches a compatible string to an internal kernel
360250bbbdbSLorenzo Bianconi  * name for a certain sensor device, so that the rest of the autodetection can
361250bbbdbSLorenzo Bianconi  * rely on that name from this point on. I2C/SPI devices will be renamed
362250bbbdbSLorenzo Bianconi  * to match the internal kernel convention.
363250bbbdbSLorenzo Bianconi  */
364250bbbdbSLorenzo Bianconi void st_sensors_of_name_probe(struct device *dev,
365250bbbdbSLorenzo Bianconi 			      const struct of_device_id *match,
366250bbbdbSLorenzo Bianconi 			      char *name, int len)
367250bbbdbSLorenzo Bianconi {
368250bbbdbSLorenzo Bianconi 	const struct of_device_id *of_id;
369250bbbdbSLorenzo Bianconi 
370250bbbdbSLorenzo Bianconi 	of_id = of_match_device(match, dev);
371250bbbdbSLorenzo Bianconi 	if (!of_id || !of_id->data)
372250bbbdbSLorenzo Bianconi 		return;
373250bbbdbSLorenzo Bianconi 
374250bbbdbSLorenzo Bianconi 	/* The name from the OF match takes precedence if present */
375250bbbdbSLorenzo Bianconi 	strncpy(name, of_id->data, len);
376250bbbdbSLorenzo Bianconi 	name[len - 1] = '\0';
377250bbbdbSLorenzo Bianconi }
378250bbbdbSLorenzo Bianconi EXPORT_SYMBOL(st_sensors_of_name_probe);
3793ce85cc4SLinus Walleij #else
3803ce85cc4SLinus Walleij static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
3813ce85cc4SLinus Walleij 		struct st_sensors_platform_data *defdata)
3823ce85cc4SLinus Walleij {
3833ce85cc4SLinus Walleij 	return NULL;
3843ce85cc4SLinus Walleij }
3853ce85cc4SLinus Walleij #endif
3863ce85cc4SLinus Walleij 
38738d1c6a9SLee Jones int st_sensors_init_sensor(struct iio_dev *indio_dev,
38838d1c6a9SLee Jones 					struct st_sensors_platform_data *pdata)
38938d1c6a9SLee Jones {
39038d1c6a9SLee Jones 	struct st_sensor_data *sdata = iio_priv(indio_dev);
3913ce85cc4SLinus Walleij 	struct st_sensors_platform_data *of_pdata;
39238d1c6a9SLee Jones 	int err = 0;
39338d1c6a9SLee Jones 
3943ce85cc4SLinus Walleij 	/* If OF/DT pdata exists, it will take precedence of anything else */
3953ce85cc4SLinus Walleij 	of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata);
3963ce85cc4SLinus Walleij 	if (of_pdata)
3973ce85cc4SLinus Walleij 		pdata = of_pdata;
3983ce85cc4SLinus Walleij 
3993c8bf223SLee Jones 	if (pdata) {
40038d1c6a9SLee Jones 		err = st_sensors_set_drdy_int_pin(indio_dev, pdata);
4013c8bf223SLee Jones 		if (err < 0)
4023c8bf223SLee Jones 			return err;
4033c8bf223SLee Jones 	}
40438d1c6a9SLee Jones 
40523491b51SDenis Ciocca 	err = st_sensors_set_enable(indio_dev, false);
40623491b51SDenis Ciocca 	if (err < 0)
407efd9566fSLee Jones 		return err;
40823491b51SDenis Ciocca 
40999147606SCrestez Dan Leonard 	/* Disable DRDY, this might be still be enabled after reboot. */
41099147606SCrestez Dan Leonard 	err = st_sensors_set_dataready_irq(indio_dev, false);
41199147606SCrestez Dan Leonard 	if (err < 0)
41299147606SCrestez Dan Leonard 		return err;
41399147606SCrestez Dan Leonard 
414362f2f86SLee Jones 	if (sdata->current_fullscale) {
41523491b51SDenis Ciocca 		err = st_sensors_set_fullscale(indio_dev,
41623491b51SDenis Ciocca 						sdata->current_fullscale->num);
41723491b51SDenis Ciocca 		if (err < 0)
418efd9566fSLee Jones 			return err;
419362f2f86SLee Jones 	} else
420362f2f86SLee Jones 		dev_info(&indio_dev->dev, "Full-scale not possible\n");
42123491b51SDenis Ciocca 
42223491b51SDenis Ciocca 	err = st_sensors_set_odr(indio_dev, sdata->odr);
42323491b51SDenis Ciocca 	if (err < 0)
424efd9566fSLee Jones 		return err;
42523491b51SDenis Ciocca 
42623491b51SDenis Ciocca 	/* set BDU */
427bb60646cSLinus Walleij 	if (sdata->sensor_settings->bdu.addr) {
42823491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
429a7ee8839SDenis CIOCCA 					sdata->sensor_settings->bdu.addr,
430a7ee8839SDenis CIOCCA 					sdata->sensor_settings->bdu.mask, true);
43123491b51SDenis Ciocca 		if (err < 0)
432efd9566fSLee Jones 			return err;
433bb60646cSLinus Walleij 	}
43423491b51SDenis Ciocca 
43565e4345cSLinus Walleij 	/* set DAS */
43665e4345cSLinus Walleij 	if (sdata->sensor_settings->das.addr) {
43765e4345cSLinus Walleij 		err = st_sensors_write_data_with_mask(indio_dev,
43865e4345cSLinus Walleij 					sdata->sensor_settings->das.addr,
43965e4345cSLinus Walleij 					sdata->sensor_settings->das.mask, 1);
44065e4345cSLinus Walleij 		if (err < 0)
44165e4345cSLinus Walleij 			return err;
44265e4345cSLinus Walleij 	}
44365e4345cSLinus Walleij 
4440e6f6871SLinus Walleij 	if (sdata->int_pin_open_drain) {
4450e6f6871SLinus Walleij 		dev_info(&indio_dev->dev,
4460e6f6871SLinus Walleij 			 "set interrupt line to open drain mode\n");
4470e6f6871SLinus Walleij 		err = st_sensors_write_data_with_mask(indio_dev,
4480e6f6871SLinus Walleij 				sdata->sensor_settings->drdy_irq.addr_od,
4490e6f6871SLinus Walleij 				sdata->sensor_settings->drdy_irq.mask_od, 1);
4500e6f6871SLinus Walleij 		if (err < 0)
4510e6f6871SLinus Walleij 			return err;
4520e6f6871SLinus Walleij 	}
4530e6f6871SLinus Walleij 
45423491b51SDenis Ciocca 	err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
45523491b51SDenis Ciocca 
45623491b51SDenis Ciocca 	return err;
45723491b51SDenis Ciocca }
45823491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_init_sensor);
45923491b51SDenis Ciocca 
46023491b51SDenis Ciocca int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
46123491b51SDenis Ciocca {
46223491b51SDenis Ciocca 	int err;
46323cde4d6SDenis CIOCCA 	u8 drdy_mask;
46423491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
46523491b51SDenis Ciocca 
466c65e3d6eSLorenzo Bianconi 	if (!sdata->sensor_settings->drdy_irq.addr) {
467c65e3d6eSLorenzo Bianconi 		/*
468c65e3d6eSLorenzo Bianconi 		 * there are some devices (e.g. LIS3MDL) where drdy line is
469c65e3d6eSLorenzo Bianconi 		 * routed to a given pin and it is not possible to select a
470c65e3d6eSLorenzo Bianconi 		 * different one. Take into account irq status register
471c65e3d6eSLorenzo Bianconi 		 * to understand if irq trigger can be properly supported
472c65e3d6eSLorenzo Bianconi 		 */
473c65e3d6eSLorenzo Bianconi 		if (sdata->sensor_settings->drdy_irq.addr_stat_drdy)
474c65e3d6eSLorenzo Bianconi 			sdata->hw_irq_trigger = enable;
47538d1c6a9SLee Jones 		return 0;
476c65e3d6eSLorenzo Bianconi 	}
47738d1c6a9SLee Jones 
47823491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator 1. */
479a7ee8839SDenis CIOCCA 	if (sdata->sensor_settings->drdy_irq.ig1.en_addr > 0) {
48023491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
481a7ee8839SDenis CIOCCA 				sdata->sensor_settings->drdy_irq.ig1.en_addr,
482a7ee8839SDenis CIOCCA 				sdata->sensor_settings->drdy_irq.ig1.en_mask,
483a7ee8839SDenis CIOCCA 				(int)enable);
48423491b51SDenis Ciocca 		if (err < 0)
48523491b51SDenis Ciocca 			goto st_accel_set_dataready_irq_error;
48623491b51SDenis Ciocca 	}
48723491b51SDenis Ciocca 
48823cde4d6SDenis CIOCCA 	if (sdata->drdy_int_pin == 1)
489a7ee8839SDenis CIOCCA 		drdy_mask = sdata->sensor_settings->drdy_irq.mask_int1;
49023cde4d6SDenis CIOCCA 	else
491a7ee8839SDenis CIOCCA 		drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
49223cde4d6SDenis CIOCCA 
49365925b65SLinus Walleij 	/* Flag to the poll function that the hardware trigger is in use */
49465925b65SLinus Walleij 	sdata->hw_irq_trigger = enable;
49565925b65SLinus Walleij 
49623491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator for data ready. */
49723491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
498a7ee8839SDenis CIOCCA 					sdata->sensor_settings->drdy_irq.addr,
499a7ee8839SDenis CIOCCA 					drdy_mask, (int)enable);
50023491b51SDenis Ciocca 
50123491b51SDenis Ciocca st_accel_set_dataready_irq_error:
50223491b51SDenis Ciocca 	return err;
50323491b51SDenis Ciocca }
50423491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_dataready_irq);
50523491b51SDenis Ciocca 
50623491b51SDenis Ciocca int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
50723491b51SDenis Ciocca {
50823491b51SDenis Ciocca 	int err = -EINVAL, i;
50923491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
51023491b51SDenis Ciocca 
51123491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
512a7ee8839SDenis CIOCCA 		if ((sdata->sensor_settings->fs.fs_avl[i].gain == scale) &&
513a7ee8839SDenis CIOCCA 				(sdata->sensor_settings->fs.fs_avl[i].gain != 0)) {
51423491b51SDenis Ciocca 			err = 0;
51523491b51SDenis Ciocca 			break;
51623491b51SDenis Ciocca 		}
51723491b51SDenis Ciocca 	}
51823491b51SDenis Ciocca 	if (err < 0)
51923491b51SDenis Ciocca 		goto st_sensors_match_scale_error;
52023491b51SDenis Ciocca 
52123491b51SDenis Ciocca 	err = st_sensors_set_fullscale(indio_dev,
522a7ee8839SDenis CIOCCA 				sdata->sensor_settings->fs.fs_avl[i].num);
52323491b51SDenis Ciocca 
52423491b51SDenis Ciocca st_sensors_match_scale_error:
52523491b51SDenis Ciocca 	return err;
52623491b51SDenis Ciocca }
52723491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
52823491b51SDenis Ciocca 
52923491b51SDenis Ciocca static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
530607a568aSDenis CIOCCA 				struct iio_chan_spec const *ch, int *data)
53123491b51SDenis Ciocca {
53223491b51SDenis Ciocca 	int err;
533607a568aSDenis CIOCCA 	u8 *outdata;
53423491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
53565c8aea0SLorenzo Bianconi 	unsigned int byte_for_channel;
536607a568aSDenis CIOCCA 
53765c8aea0SLorenzo Bianconi 	byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
53865c8aea0SLorenzo Bianconi 					ch->scan_type.shift, 8);
539607a568aSDenis CIOCCA 	outdata = kmalloc(byte_for_channel, GFP_KERNEL);
540caf5ca12SLee Jones 	if (!outdata)
541caf5ca12SLee Jones 		return -ENOMEM;
54223491b51SDenis Ciocca 
54323491b51SDenis Ciocca 	err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
544607a568aSDenis CIOCCA 				ch->address, byte_for_channel,
54523491b51SDenis Ciocca 				outdata, sdata->multiread_bit);
54623491b51SDenis Ciocca 	if (err < 0)
547607a568aSDenis CIOCCA 		goto st_sensors_free_memory;
54823491b51SDenis Ciocca 
5494861a007SLinus Walleij 	if (byte_for_channel == 1)
5504861a007SLinus Walleij 		*data = (s8)*outdata;
5514861a007SLinus Walleij 	else if (byte_for_channel == 2)
55223491b51SDenis Ciocca 		*data = (s16)get_unaligned_le16(outdata);
553607a568aSDenis CIOCCA 	else if (byte_for_channel == 3)
554607a568aSDenis CIOCCA 		*data = (s32)st_sensors_get_unaligned_le24(outdata);
55523491b51SDenis Ciocca 
556607a568aSDenis CIOCCA st_sensors_free_memory:
557607a568aSDenis CIOCCA 	kfree(outdata);
558caf5ca12SLee Jones 
55923491b51SDenis Ciocca 	return err;
56023491b51SDenis Ciocca }
56123491b51SDenis Ciocca 
56223491b51SDenis Ciocca int st_sensors_read_info_raw(struct iio_dev *indio_dev,
56323491b51SDenis Ciocca 				struct iio_chan_spec const *ch, int *val)
56423491b51SDenis Ciocca {
56523491b51SDenis Ciocca 	int err;
56623491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
56723491b51SDenis Ciocca 
56823491b51SDenis Ciocca 	mutex_lock(&indio_dev->mlock);
56923491b51SDenis Ciocca 	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
57023491b51SDenis Ciocca 		err = -EBUSY;
5715bb8e72dSLee Jones 		goto out;
57223491b51SDenis Ciocca 	} else {
57323491b51SDenis Ciocca 		err = st_sensors_set_enable(indio_dev, true);
57423491b51SDenis Ciocca 		if (err < 0)
5755bb8e72dSLee Jones 			goto out;
57623491b51SDenis Ciocca 
577a7ee8839SDenis CIOCCA 		msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr);
578607a568aSDenis CIOCCA 		err = st_sensors_read_axis_data(indio_dev, ch, val);
57923491b51SDenis Ciocca 		if (err < 0)
5805bb8e72dSLee Jones 			goto out;
58123491b51SDenis Ciocca 
58223491b51SDenis Ciocca 		*val = *val >> ch->scan_type.shift;
583d61a04dcSDenis CIOCCA 
584d61a04dcSDenis CIOCCA 		err = st_sensors_set_enable(indio_dev, false);
58523491b51SDenis Ciocca 	}
5865bb8e72dSLee Jones out:
58723491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
58823491b51SDenis Ciocca 
58923491b51SDenis Ciocca 	return err;
59023491b51SDenis Ciocca }
59123491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_read_info_raw);
59223491b51SDenis Ciocca 
593a7b8829dSLorenzo Bianconi static int st_sensors_init_interface_mode(struct iio_dev *indio_dev,
594a7b8829dSLorenzo Bianconi 			const struct st_sensor_settings *sensor_settings)
595a7b8829dSLorenzo Bianconi {
596a7b8829dSLorenzo Bianconi 	struct st_sensor_data *sdata = iio_priv(indio_dev);
597a7b8829dSLorenzo Bianconi 	struct device_node *np = sdata->dev->of_node;
598a7b8829dSLorenzo Bianconi 	struct st_sensors_platform_data *pdata;
599a7b8829dSLorenzo Bianconi 
600a7b8829dSLorenzo Bianconi 	pdata = (struct st_sensors_platform_data *)sdata->dev->platform_data;
601a7b8829dSLorenzo Bianconi 	if (((np && of_property_read_bool(np, "spi-3wire")) ||
602a7b8829dSLorenzo Bianconi 	     (pdata && pdata->spi_3wire)) && sensor_settings->sim.addr) {
603a7b8829dSLorenzo Bianconi 		int err;
604a7b8829dSLorenzo Bianconi 
605a7b8829dSLorenzo Bianconi 		err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
606a7b8829dSLorenzo Bianconi 					    sensor_settings->sim.addr,
607a7b8829dSLorenzo Bianconi 					    sensor_settings->sim.value);
608a7b8829dSLorenzo Bianconi 		if (err < 0) {
609a7b8829dSLorenzo Bianconi 			dev_err(&indio_dev->dev,
610a7b8829dSLorenzo Bianconi 				"failed to init interface mode\n");
611a7b8829dSLorenzo Bianconi 			return err;
612a7b8829dSLorenzo Bianconi 		}
613a7b8829dSLorenzo Bianconi 	}
614a7b8829dSLorenzo Bianconi 
615a7b8829dSLorenzo Bianconi 	return 0;
616a7b8829dSLorenzo Bianconi }
617a7b8829dSLorenzo Bianconi 
61823491b51SDenis Ciocca int st_sensors_check_device_support(struct iio_dev *indio_dev,
619a7ee8839SDenis CIOCCA 			int num_sensors_list,
620a7ee8839SDenis CIOCCA 			const struct st_sensor_settings *sensor_settings)
62123491b51SDenis Ciocca {
6224e68cfbfSJonathan Cameron 	int i, n, err = 0;
623bc27381eSGiuseppe Barba 	u8 wai;
62423491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
62523491b51SDenis Ciocca 
626bc27381eSGiuseppe Barba 	for (i = 0; i < num_sensors_list; i++) {
627bc27381eSGiuseppe Barba 		for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) {
628bc27381eSGiuseppe Barba 			if (strcmp(indio_dev->name,
629bc27381eSGiuseppe Barba 				sensor_settings[i].sensors_supported[n]) == 0) {
630bc27381eSGiuseppe Barba 				break;
631bc27381eSGiuseppe Barba 			}
632bc27381eSGiuseppe Barba 		}
633bc27381eSGiuseppe Barba 		if (n < ST_SENSORS_MAX_4WAI)
634bc27381eSGiuseppe Barba 			break;
635bc27381eSGiuseppe Barba 	}
636bc27381eSGiuseppe Barba 	if (i == num_sensors_list) {
637bc27381eSGiuseppe Barba 		dev_err(&indio_dev->dev, "device name %s not recognized.\n",
638bc27381eSGiuseppe Barba 							indio_dev->name);
639bc27381eSGiuseppe Barba 		return -ENODEV;
640bc27381eSGiuseppe Barba 	}
641bc27381eSGiuseppe Barba 
642a7b8829dSLorenzo Bianconi 	err = st_sensors_init_interface_mode(indio_dev, &sensor_settings[i]);
643a7b8829dSLorenzo Bianconi 	if (err < 0)
644a7b8829dSLorenzo Bianconi 		return err;
645a7b8829dSLorenzo Bianconi 
6464e68cfbfSJonathan Cameron 	if (sensor_settings[i].wai_addr) {
64723491b51SDenis Ciocca 		err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
648bc27381eSGiuseppe Barba 					   sensor_settings[i].wai_addr, &wai);
64923491b51SDenis Ciocca 		if (err < 0) {
6504e68cfbfSJonathan Cameron 			dev_err(&indio_dev->dev,
6514e68cfbfSJonathan Cameron 				"failed to read Who-Am-I register.\n");
652bc27381eSGiuseppe Barba 			return err;
65323491b51SDenis Ciocca 		}
65423491b51SDenis Ciocca 
655bc27381eSGiuseppe Barba 		if (sensor_settings[i].wai != wai) {
6564e68cfbfSJonathan Cameron 			dev_err(&indio_dev->dev,
6574e68cfbfSJonathan Cameron 				"%s: WhoAmI mismatch (0x%x).\n",
6585e02bac3SLinus Walleij 				indio_dev->name, wai);
659bc27381eSGiuseppe Barba 			return -EINVAL;
66023491b51SDenis Ciocca 		}
6614e68cfbfSJonathan Cameron 	}
66223491b51SDenis Ciocca 
663a7ee8839SDenis CIOCCA 	sdata->sensor_settings =
664a7ee8839SDenis CIOCCA 			(struct st_sensor_settings *)&sensor_settings[i];
66523491b51SDenis Ciocca 
66623491b51SDenis Ciocca 	return i;
66723491b51SDenis Ciocca }
66823491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_check_device_support);
66923491b51SDenis Ciocca 
67023491b51SDenis Ciocca ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
67123491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
67223491b51SDenis Ciocca {
6734d2e4fc2SDenis CIOCCA 	int i, len = 0;
67423491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
6754d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
67623491b51SDenis Ciocca 
6774d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
6784d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
679a7ee8839SDenis CIOCCA 		if (sdata->sensor_settings->odr.odr_avl[i].hz == 0)
6804d2e4fc2SDenis CIOCCA 			break;
6814d2e4fc2SDenis CIOCCA 
6824d2e4fc2SDenis CIOCCA 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
683a7ee8839SDenis CIOCCA 				sdata->sensor_settings->odr.odr_avl[i].hz);
6844d2e4fc2SDenis CIOCCA 	}
6854d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
6864d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
6874d2e4fc2SDenis CIOCCA 
6884d2e4fc2SDenis CIOCCA 	return len;
68923491b51SDenis Ciocca }
69023491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
69123491b51SDenis Ciocca 
69223491b51SDenis Ciocca ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
69323491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
69423491b51SDenis Ciocca {
695d304286aSLorenzo Bianconi 	int i, len = 0, q, r;
69623491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
6974d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
69823491b51SDenis Ciocca 
6994d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
7004d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
701a7ee8839SDenis CIOCCA 		if (sdata->sensor_settings->fs.fs_avl[i].num == 0)
7024d2e4fc2SDenis CIOCCA 			break;
7034d2e4fc2SDenis CIOCCA 
704d304286aSLorenzo Bianconi 		q = sdata->sensor_settings->fs.fs_avl[i].gain / 1000000;
705d304286aSLorenzo Bianconi 		r = sdata->sensor_settings->fs.fs_avl[i].gain % 1000000;
706d304286aSLorenzo Bianconi 
707d304286aSLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ", q, r);
7084d2e4fc2SDenis CIOCCA 	}
7094d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
7104d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
7114d2e4fc2SDenis CIOCCA 
7124d2e4fc2SDenis CIOCCA 	return len;
71323491b51SDenis Ciocca }
71423491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
71523491b51SDenis Ciocca 
71623491b51SDenis Ciocca MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
71723491b51SDenis Ciocca MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
71823491b51SDenis Ciocca MODULE_LICENSE("GPL v2");
719