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 
466a7ee8839SDenis CIOCCA 	if (!sdata->sensor_settings->drdy_irq.addr)
46738d1c6a9SLee Jones 		return 0;
46838d1c6a9SLee Jones 
46923491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator 1. */
470a7ee8839SDenis CIOCCA 	if (sdata->sensor_settings->drdy_irq.ig1.en_addr > 0) {
47123491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
472a7ee8839SDenis CIOCCA 				sdata->sensor_settings->drdy_irq.ig1.en_addr,
473a7ee8839SDenis CIOCCA 				sdata->sensor_settings->drdy_irq.ig1.en_mask,
474a7ee8839SDenis CIOCCA 				(int)enable);
47523491b51SDenis Ciocca 		if (err < 0)
47623491b51SDenis Ciocca 			goto st_accel_set_dataready_irq_error;
47723491b51SDenis Ciocca 	}
47823491b51SDenis Ciocca 
47923cde4d6SDenis CIOCCA 	if (sdata->drdy_int_pin == 1)
480a7ee8839SDenis CIOCCA 		drdy_mask = sdata->sensor_settings->drdy_irq.mask_int1;
48123cde4d6SDenis CIOCCA 	else
482a7ee8839SDenis CIOCCA 		drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
48323cde4d6SDenis CIOCCA 
48465925b65SLinus Walleij 	/* Flag to the poll function that the hardware trigger is in use */
48565925b65SLinus Walleij 	sdata->hw_irq_trigger = enable;
48665925b65SLinus Walleij 
48723491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator for data ready. */
48823491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
489a7ee8839SDenis CIOCCA 					sdata->sensor_settings->drdy_irq.addr,
490a7ee8839SDenis CIOCCA 					drdy_mask, (int)enable);
49123491b51SDenis Ciocca 
49223491b51SDenis Ciocca st_accel_set_dataready_irq_error:
49323491b51SDenis Ciocca 	return err;
49423491b51SDenis Ciocca }
49523491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_dataready_irq);
49623491b51SDenis Ciocca 
49723491b51SDenis Ciocca int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
49823491b51SDenis Ciocca {
49923491b51SDenis Ciocca 	int err = -EINVAL, i;
50023491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
50123491b51SDenis Ciocca 
50223491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
503a7ee8839SDenis CIOCCA 		if ((sdata->sensor_settings->fs.fs_avl[i].gain == scale) &&
504a7ee8839SDenis CIOCCA 				(sdata->sensor_settings->fs.fs_avl[i].gain != 0)) {
50523491b51SDenis Ciocca 			err = 0;
50623491b51SDenis Ciocca 			break;
50723491b51SDenis Ciocca 		}
50823491b51SDenis Ciocca 	}
50923491b51SDenis Ciocca 	if (err < 0)
51023491b51SDenis Ciocca 		goto st_sensors_match_scale_error;
51123491b51SDenis Ciocca 
51223491b51SDenis Ciocca 	err = st_sensors_set_fullscale(indio_dev,
513a7ee8839SDenis CIOCCA 				sdata->sensor_settings->fs.fs_avl[i].num);
51423491b51SDenis Ciocca 
51523491b51SDenis Ciocca st_sensors_match_scale_error:
51623491b51SDenis Ciocca 	return err;
51723491b51SDenis Ciocca }
51823491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
51923491b51SDenis Ciocca 
52023491b51SDenis Ciocca static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
521607a568aSDenis CIOCCA 				struct iio_chan_spec const *ch, int *data)
52223491b51SDenis Ciocca {
52323491b51SDenis Ciocca 	int err;
524607a568aSDenis CIOCCA 	u8 *outdata;
52523491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
52665c8aea0SLorenzo Bianconi 	unsigned int byte_for_channel;
527607a568aSDenis CIOCCA 
52865c8aea0SLorenzo Bianconi 	byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
52965c8aea0SLorenzo Bianconi 					ch->scan_type.shift, 8);
530607a568aSDenis CIOCCA 	outdata = kmalloc(byte_for_channel, GFP_KERNEL);
531caf5ca12SLee Jones 	if (!outdata)
532caf5ca12SLee Jones 		return -ENOMEM;
53323491b51SDenis Ciocca 
53423491b51SDenis Ciocca 	err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
535607a568aSDenis CIOCCA 				ch->address, byte_for_channel,
53623491b51SDenis Ciocca 				outdata, sdata->multiread_bit);
53723491b51SDenis Ciocca 	if (err < 0)
538607a568aSDenis CIOCCA 		goto st_sensors_free_memory;
53923491b51SDenis Ciocca 
5404861a007SLinus Walleij 	if (byte_for_channel == 1)
5414861a007SLinus Walleij 		*data = (s8)*outdata;
5424861a007SLinus Walleij 	else if (byte_for_channel == 2)
54323491b51SDenis Ciocca 		*data = (s16)get_unaligned_le16(outdata);
544607a568aSDenis CIOCCA 	else if (byte_for_channel == 3)
545607a568aSDenis CIOCCA 		*data = (s32)st_sensors_get_unaligned_le24(outdata);
54623491b51SDenis Ciocca 
547607a568aSDenis CIOCCA st_sensors_free_memory:
548607a568aSDenis CIOCCA 	kfree(outdata);
549caf5ca12SLee Jones 
55023491b51SDenis Ciocca 	return err;
55123491b51SDenis Ciocca }
55223491b51SDenis Ciocca 
55323491b51SDenis Ciocca int st_sensors_read_info_raw(struct iio_dev *indio_dev,
55423491b51SDenis Ciocca 				struct iio_chan_spec const *ch, int *val)
55523491b51SDenis Ciocca {
55623491b51SDenis Ciocca 	int err;
55723491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
55823491b51SDenis Ciocca 
55923491b51SDenis Ciocca 	mutex_lock(&indio_dev->mlock);
56023491b51SDenis Ciocca 	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
56123491b51SDenis Ciocca 		err = -EBUSY;
5625bb8e72dSLee Jones 		goto out;
56323491b51SDenis Ciocca 	} else {
56423491b51SDenis Ciocca 		err = st_sensors_set_enable(indio_dev, true);
56523491b51SDenis Ciocca 		if (err < 0)
5665bb8e72dSLee Jones 			goto out;
56723491b51SDenis Ciocca 
568a7ee8839SDenis CIOCCA 		msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr);
569607a568aSDenis CIOCCA 		err = st_sensors_read_axis_data(indio_dev, ch, val);
57023491b51SDenis Ciocca 		if (err < 0)
5715bb8e72dSLee Jones 			goto out;
57223491b51SDenis Ciocca 
57323491b51SDenis Ciocca 		*val = *val >> ch->scan_type.shift;
574d61a04dcSDenis CIOCCA 
575d61a04dcSDenis CIOCCA 		err = st_sensors_set_enable(indio_dev, false);
57623491b51SDenis Ciocca 	}
5775bb8e72dSLee Jones out:
57823491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
57923491b51SDenis Ciocca 
58023491b51SDenis Ciocca 	return err;
58123491b51SDenis Ciocca }
58223491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_read_info_raw);
58323491b51SDenis Ciocca 
58423491b51SDenis Ciocca int st_sensors_check_device_support(struct iio_dev *indio_dev,
585a7ee8839SDenis CIOCCA 			int num_sensors_list,
586a7ee8839SDenis CIOCCA 			const struct st_sensor_settings *sensor_settings)
58723491b51SDenis Ciocca {
5884e68cfbfSJonathan Cameron 	int i, n, err = 0;
589bc27381eSGiuseppe Barba 	u8 wai;
59023491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
59123491b51SDenis Ciocca 
592bc27381eSGiuseppe Barba 	for (i = 0; i < num_sensors_list; i++) {
593bc27381eSGiuseppe Barba 		for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) {
594bc27381eSGiuseppe Barba 			if (strcmp(indio_dev->name,
595bc27381eSGiuseppe Barba 				sensor_settings[i].sensors_supported[n]) == 0) {
596bc27381eSGiuseppe Barba 				break;
597bc27381eSGiuseppe Barba 			}
598bc27381eSGiuseppe Barba 		}
599bc27381eSGiuseppe Barba 		if (n < ST_SENSORS_MAX_4WAI)
600bc27381eSGiuseppe Barba 			break;
601bc27381eSGiuseppe Barba 	}
602bc27381eSGiuseppe Barba 	if (i == num_sensors_list) {
603bc27381eSGiuseppe Barba 		dev_err(&indio_dev->dev, "device name %s not recognized.\n",
604bc27381eSGiuseppe Barba 							indio_dev->name);
605bc27381eSGiuseppe Barba 		return -ENODEV;
606bc27381eSGiuseppe Barba 	}
607bc27381eSGiuseppe Barba 
6084e68cfbfSJonathan Cameron 	if (sensor_settings[i].wai_addr) {
60923491b51SDenis Ciocca 		err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
610bc27381eSGiuseppe Barba 					   sensor_settings[i].wai_addr, &wai);
61123491b51SDenis Ciocca 		if (err < 0) {
6124e68cfbfSJonathan Cameron 			dev_err(&indio_dev->dev,
6134e68cfbfSJonathan Cameron 				"failed to read Who-Am-I register.\n");
614bc27381eSGiuseppe Barba 			return err;
61523491b51SDenis Ciocca 		}
61623491b51SDenis Ciocca 
617bc27381eSGiuseppe Barba 		if (sensor_settings[i].wai != wai) {
6184e68cfbfSJonathan Cameron 			dev_err(&indio_dev->dev,
6194e68cfbfSJonathan Cameron 				"%s: WhoAmI mismatch (0x%x).\n",
6205e02bac3SLinus Walleij 				indio_dev->name, wai);
621bc27381eSGiuseppe Barba 			return -EINVAL;
62223491b51SDenis Ciocca 		}
6234e68cfbfSJonathan Cameron 	}
62423491b51SDenis Ciocca 
625a7ee8839SDenis CIOCCA 	sdata->sensor_settings =
626a7ee8839SDenis CIOCCA 			(struct st_sensor_settings *)&sensor_settings[i];
62723491b51SDenis Ciocca 
62823491b51SDenis Ciocca 	return i;
62923491b51SDenis Ciocca }
63023491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_check_device_support);
63123491b51SDenis Ciocca 
63223491b51SDenis Ciocca ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
63323491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
63423491b51SDenis Ciocca {
6354d2e4fc2SDenis CIOCCA 	int i, len = 0;
63623491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
6374d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
63823491b51SDenis Ciocca 
6394d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
6404d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
641a7ee8839SDenis CIOCCA 		if (sdata->sensor_settings->odr.odr_avl[i].hz == 0)
6424d2e4fc2SDenis CIOCCA 			break;
6434d2e4fc2SDenis CIOCCA 
6444d2e4fc2SDenis CIOCCA 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
645a7ee8839SDenis CIOCCA 				sdata->sensor_settings->odr.odr_avl[i].hz);
6464d2e4fc2SDenis CIOCCA 	}
6474d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
6484d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
6494d2e4fc2SDenis CIOCCA 
6504d2e4fc2SDenis CIOCCA 	return len;
65123491b51SDenis Ciocca }
65223491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
65323491b51SDenis Ciocca 
65423491b51SDenis Ciocca ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
65523491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
65623491b51SDenis Ciocca {
657d304286aSLorenzo Bianconi 	int i, len = 0, q, r;
65823491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
6594d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
66023491b51SDenis Ciocca 
6614d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
6624d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
663a7ee8839SDenis CIOCCA 		if (sdata->sensor_settings->fs.fs_avl[i].num == 0)
6644d2e4fc2SDenis CIOCCA 			break;
6654d2e4fc2SDenis CIOCCA 
666d304286aSLorenzo Bianconi 		q = sdata->sensor_settings->fs.fs_avl[i].gain / 1000000;
667d304286aSLorenzo Bianconi 		r = sdata->sensor_settings->fs.fs_avl[i].gain % 1000000;
668d304286aSLorenzo Bianconi 
669d304286aSLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ", q, r);
6704d2e4fc2SDenis CIOCCA 	}
6714d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
6724d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
6734d2e4fc2SDenis CIOCCA 
6744d2e4fc2SDenis CIOCCA 	return len;
67523491b51SDenis Ciocca }
67623491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
67723491b51SDenis Ciocca 
67823491b51SDenis Ciocca MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
67923491b51SDenis Ciocca MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
68023491b51SDenis Ciocca MODULE_LICENSE("GPL v2");
681