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>
1623491b51SDenis Ciocca #include <asm/unaligned.h>
1723491b51SDenis Ciocca 
1823491b51SDenis Ciocca #include <linux/iio/common/st_sensors.h>
1923491b51SDenis Ciocca 
2023491b51SDenis Ciocca 
2123491b51SDenis Ciocca #define ST_SENSORS_WAI_ADDRESS		0x0f
2223491b51SDenis Ciocca 
23607a568aSDenis CIOCCA static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
24607a568aSDenis CIOCCA {
2523cde4d6SDenis CIOCCA 	return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
26607a568aSDenis CIOCCA }
27607a568aSDenis CIOCCA 
2823491b51SDenis Ciocca static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
2923491b51SDenis Ciocca 						u8 reg_addr, u8 mask, u8 data)
3023491b51SDenis Ciocca {
3123491b51SDenis Ciocca 	int err;
3223491b51SDenis Ciocca 	u8 new_data;
3323491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
3423491b51SDenis Ciocca 
3523491b51SDenis Ciocca 	err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
3623491b51SDenis Ciocca 	if (err < 0)
3723491b51SDenis Ciocca 		goto st_sensors_write_data_with_mask_error;
3823491b51SDenis Ciocca 
3923491b51SDenis Ciocca 	new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
4023491b51SDenis Ciocca 	err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
4123491b51SDenis Ciocca 
4223491b51SDenis Ciocca st_sensors_write_data_with_mask_error:
4323491b51SDenis Ciocca 	return err;
4423491b51SDenis Ciocca }
4523491b51SDenis Ciocca 
4623491b51SDenis Ciocca static int st_sensors_match_odr(struct st_sensors *sensor,
4723491b51SDenis Ciocca 			unsigned int odr, struct st_sensor_odr_avl *odr_out)
4823491b51SDenis Ciocca {
4923491b51SDenis Ciocca 	int i, ret = -EINVAL;
5023491b51SDenis Ciocca 
5123491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
5223491b51SDenis Ciocca 		if (sensor->odr.odr_avl[i].hz == 0)
5323491b51SDenis Ciocca 			goto st_sensors_match_odr_error;
5423491b51SDenis Ciocca 
5523491b51SDenis Ciocca 		if (sensor->odr.odr_avl[i].hz == odr) {
5623491b51SDenis Ciocca 			odr_out->hz = sensor->odr.odr_avl[i].hz;
5723491b51SDenis Ciocca 			odr_out->value = sensor->odr.odr_avl[i].value;
5823491b51SDenis Ciocca 			ret = 0;
5923491b51SDenis Ciocca 			break;
6023491b51SDenis Ciocca 		}
6123491b51SDenis Ciocca 	}
6223491b51SDenis Ciocca 
6323491b51SDenis Ciocca st_sensors_match_odr_error:
6423491b51SDenis Ciocca 	return ret;
6523491b51SDenis Ciocca }
6623491b51SDenis Ciocca 
6723491b51SDenis Ciocca int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
6823491b51SDenis Ciocca {
6923491b51SDenis Ciocca 	int err;
70852afe99SDenis CIOCCA 	struct st_sensor_odr_avl odr_out = {0, 0};
7123491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
7223491b51SDenis Ciocca 
7323491b51SDenis Ciocca 	err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
7423491b51SDenis Ciocca 	if (err < 0)
7523491b51SDenis Ciocca 		goto st_sensors_match_odr_error;
7623491b51SDenis Ciocca 
7723491b51SDenis Ciocca 	if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
7823491b51SDenis Ciocca 			(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
7923491b51SDenis Ciocca 		if (sdata->enabled == true) {
8023491b51SDenis Ciocca 			err = st_sensors_write_data_with_mask(indio_dev,
8123491b51SDenis Ciocca 				sdata->sensor->odr.addr,
8223491b51SDenis Ciocca 				sdata->sensor->odr.mask,
8323491b51SDenis Ciocca 				odr_out.value);
8423491b51SDenis Ciocca 		} else {
8523491b51SDenis Ciocca 			err = 0;
8623491b51SDenis Ciocca 		}
8723491b51SDenis Ciocca 	} else {
8823491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
8923491b51SDenis Ciocca 			sdata->sensor->odr.addr, sdata->sensor->odr.mask,
9023491b51SDenis Ciocca 			odr_out.value);
9123491b51SDenis Ciocca 	}
9223491b51SDenis Ciocca 	if (err >= 0)
9323491b51SDenis Ciocca 		sdata->odr = odr_out.hz;
9423491b51SDenis Ciocca 
9523491b51SDenis Ciocca st_sensors_match_odr_error:
9623491b51SDenis Ciocca 	return err;
9723491b51SDenis Ciocca }
9823491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_odr);
9923491b51SDenis Ciocca 
10023491b51SDenis Ciocca static int st_sensors_match_fs(struct st_sensors *sensor,
10123491b51SDenis Ciocca 					unsigned int fs, int *index_fs_avl)
10223491b51SDenis Ciocca {
10323491b51SDenis Ciocca 	int i, ret = -EINVAL;
10423491b51SDenis Ciocca 
10523491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
10623491b51SDenis Ciocca 		if (sensor->fs.fs_avl[i].num == 0)
10723491b51SDenis Ciocca 			goto st_sensors_match_odr_error;
10823491b51SDenis Ciocca 
10923491b51SDenis Ciocca 		if (sensor->fs.fs_avl[i].num == fs) {
11023491b51SDenis Ciocca 			*index_fs_avl = i;
11123491b51SDenis Ciocca 			ret = 0;
11223491b51SDenis Ciocca 			break;
11323491b51SDenis Ciocca 		}
11423491b51SDenis Ciocca 	}
11523491b51SDenis Ciocca 
11623491b51SDenis Ciocca st_sensors_match_odr_error:
11723491b51SDenis Ciocca 	return ret;
11823491b51SDenis Ciocca }
11923491b51SDenis Ciocca 
120607a568aSDenis CIOCCA static int st_sensors_set_fullscale(struct iio_dev *indio_dev,
121607a568aSDenis CIOCCA 								unsigned int fs)
12223491b51SDenis Ciocca {
123852afe99SDenis CIOCCA 	int err, i = 0;
12423491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
12523491b51SDenis Ciocca 
12623491b51SDenis Ciocca 	err = st_sensors_match_fs(sdata->sensor, fs, &i);
12723491b51SDenis Ciocca 	if (err < 0)
12823491b51SDenis Ciocca 		goto st_accel_set_fullscale_error;
12923491b51SDenis Ciocca 
13023491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
13123491b51SDenis Ciocca 				sdata->sensor->fs.addr,
13223491b51SDenis Ciocca 				sdata->sensor->fs.mask,
13323491b51SDenis Ciocca 				sdata->sensor->fs.fs_avl[i].value);
13423491b51SDenis Ciocca 	if (err < 0)
13523491b51SDenis Ciocca 		goto st_accel_set_fullscale_error;
13623491b51SDenis Ciocca 
13723491b51SDenis Ciocca 	sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
13823491b51SDenis Ciocca 						&sdata->sensor->fs.fs_avl[i];
13923491b51SDenis Ciocca 	return err;
14023491b51SDenis Ciocca 
14123491b51SDenis Ciocca st_accel_set_fullscale_error:
14223491b51SDenis Ciocca 	dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
14323491b51SDenis Ciocca 	return err;
14423491b51SDenis Ciocca }
14523491b51SDenis Ciocca 
14623491b51SDenis Ciocca int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
14723491b51SDenis Ciocca {
14823491b51SDenis Ciocca 	u8 tmp_value;
14923491b51SDenis Ciocca 	int err = -EINVAL;
150852afe99SDenis CIOCCA 	bool found = false;
151852afe99SDenis CIOCCA 	struct st_sensor_odr_avl odr_out = {0, 0};
15223491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
15323491b51SDenis Ciocca 
15423491b51SDenis Ciocca 	if (enable) {
15523491b51SDenis Ciocca 		tmp_value = sdata->sensor->pw.value_on;
15623491b51SDenis Ciocca 		if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
15723491b51SDenis Ciocca 			(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
15823491b51SDenis Ciocca 			err = st_sensors_match_odr(sdata->sensor,
15923491b51SDenis Ciocca 							sdata->odr, &odr_out);
16023491b51SDenis Ciocca 			if (err < 0)
16123491b51SDenis Ciocca 				goto set_enable_error;
16223491b51SDenis Ciocca 			tmp_value = odr_out.value;
16323491b51SDenis Ciocca 			found = true;
16423491b51SDenis Ciocca 		}
16523491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
16623491b51SDenis Ciocca 				sdata->sensor->pw.addr,
16723491b51SDenis Ciocca 				sdata->sensor->pw.mask, tmp_value);
16823491b51SDenis Ciocca 		if (err < 0)
16923491b51SDenis Ciocca 			goto set_enable_error;
17023491b51SDenis Ciocca 
17123491b51SDenis Ciocca 		sdata->enabled = true;
17223491b51SDenis Ciocca 
17323491b51SDenis Ciocca 		if (found)
17423491b51SDenis Ciocca 			sdata->odr = odr_out.hz;
17523491b51SDenis Ciocca 	} else {
17623491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
17723491b51SDenis Ciocca 				sdata->sensor->pw.addr,
17823491b51SDenis Ciocca 				sdata->sensor->pw.mask,
17923491b51SDenis Ciocca 				sdata->sensor->pw.value_off);
18023491b51SDenis Ciocca 		if (err < 0)
18123491b51SDenis Ciocca 			goto set_enable_error;
18223491b51SDenis Ciocca 
18323491b51SDenis Ciocca 		sdata->enabled = false;
18423491b51SDenis Ciocca 	}
18523491b51SDenis Ciocca 
18623491b51SDenis Ciocca set_enable_error:
18723491b51SDenis Ciocca 	return err;
18823491b51SDenis Ciocca }
18923491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_enable);
19023491b51SDenis Ciocca 
19123491b51SDenis Ciocca int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
19223491b51SDenis Ciocca {
19323491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
19423491b51SDenis Ciocca 
19523491b51SDenis Ciocca 	return st_sensors_write_data_with_mask(indio_dev,
19623491b51SDenis Ciocca 				sdata->sensor->enable_axis.addr,
19723491b51SDenis Ciocca 				sdata->sensor->enable_axis.mask, axis_enable);
19823491b51SDenis Ciocca }
19923491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_axis_enable);
20023491b51SDenis Ciocca 
20123cde4d6SDenis CIOCCA int st_sensors_init_sensor(struct iio_dev *indio_dev,
20223cde4d6SDenis CIOCCA 					struct st_sensors_platform_data *pdata)
20323491b51SDenis Ciocca {
20423491b51SDenis Ciocca 	int err;
20523491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
20623491b51SDenis Ciocca 
20723491b51SDenis Ciocca 	mutex_init(&sdata->tb.buf_lock);
20823491b51SDenis Ciocca 
20923cde4d6SDenis CIOCCA 	switch (pdata->drdy_int_pin) {
21023cde4d6SDenis CIOCCA 	case 1:
21123cde4d6SDenis CIOCCA 		if (sdata->sensor->drdy_irq.mask_int1 == 0) {
21223cde4d6SDenis CIOCCA 			dev_err(&indio_dev->dev,
21323cde4d6SDenis CIOCCA 					"DRDY on INT1 not available.\n");
21423cde4d6SDenis CIOCCA 			err = -EINVAL;
21523cde4d6SDenis CIOCCA 			goto init_error;
21623cde4d6SDenis CIOCCA 		}
21723cde4d6SDenis CIOCCA 		sdata->drdy_int_pin = 1;
21823cde4d6SDenis CIOCCA 		break;
21923cde4d6SDenis CIOCCA 	case 2:
22023cde4d6SDenis CIOCCA 		if (sdata->sensor->drdy_irq.mask_int2 == 0) {
22123cde4d6SDenis CIOCCA 			dev_err(&indio_dev->dev,
22223cde4d6SDenis CIOCCA 					"DRDY on INT2 not available.\n");
22323cde4d6SDenis CIOCCA 			err = -EINVAL;
22423cde4d6SDenis CIOCCA 			goto init_error;
22523cde4d6SDenis CIOCCA 		}
22623cde4d6SDenis CIOCCA 		sdata->drdy_int_pin = 2;
22723cde4d6SDenis CIOCCA 		break;
22823cde4d6SDenis CIOCCA 	default:
22923cde4d6SDenis CIOCCA 		dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
23023cde4d6SDenis CIOCCA 		err = -EINVAL;
23123cde4d6SDenis CIOCCA 		goto init_error;
23223cde4d6SDenis CIOCCA 	}
23323cde4d6SDenis CIOCCA 
23423491b51SDenis Ciocca 	err = st_sensors_set_enable(indio_dev, false);
23523491b51SDenis Ciocca 	if (err < 0)
23623491b51SDenis Ciocca 		goto init_error;
23723491b51SDenis Ciocca 
238362f2f86SLee Jones 	if (sdata->current_fullscale) {
23923491b51SDenis Ciocca 		err = st_sensors_set_fullscale(indio_dev,
24023491b51SDenis Ciocca 					       sdata->current_fullscale->num);
24123491b51SDenis Ciocca 		if (err < 0)
24223491b51SDenis Ciocca 			goto init_error;
243362f2f86SLee Jones 	} else
244362f2f86SLee Jones 		dev_info(&indio_dev->dev, "Full-scale not possible\n");
24523491b51SDenis Ciocca 
24623491b51SDenis Ciocca 	err = st_sensors_set_odr(indio_dev, sdata->odr);
24723491b51SDenis Ciocca 	if (err < 0)
24823491b51SDenis Ciocca 		goto init_error;
24923491b51SDenis Ciocca 
25023491b51SDenis Ciocca 	/* set BDU */
25123491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
25223491b51SDenis Ciocca 			sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
25323491b51SDenis Ciocca 	if (err < 0)
25423491b51SDenis Ciocca 		goto init_error;
25523491b51SDenis Ciocca 
25623491b51SDenis Ciocca 	err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
25723491b51SDenis Ciocca 
25823491b51SDenis Ciocca init_error:
25923491b51SDenis Ciocca 	return err;
26023491b51SDenis Ciocca }
26123491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_init_sensor);
26223491b51SDenis Ciocca 
26323491b51SDenis Ciocca int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
26423491b51SDenis Ciocca {
26523491b51SDenis Ciocca 	int err;
26623cde4d6SDenis CIOCCA 	u8 drdy_mask;
26723491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
26823491b51SDenis Ciocca 
26923491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator 1. */
27023491b51SDenis Ciocca 	if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
27123491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
27223491b51SDenis Ciocca 			sdata->sensor->drdy_irq.ig1.en_addr,
27323491b51SDenis Ciocca 			sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
27423491b51SDenis Ciocca 		if (err < 0)
27523491b51SDenis Ciocca 			goto st_accel_set_dataready_irq_error;
27623491b51SDenis Ciocca 	}
27723491b51SDenis Ciocca 
27823cde4d6SDenis CIOCCA 	if (sdata->drdy_int_pin == 1)
27923cde4d6SDenis CIOCCA 		drdy_mask = sdata->sensor->drdy_irq.mask_int1;
28023cde4d6SDenis CIOCCA 	else
28123cde4d6SDenis CIOCCA 		drdy_mask = sdata->sensor->drdy_irq.mask_int2;
28223cde4d6SDenis CIOCCA 
28323491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator for data ready. */
28423491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
28523cde4d6SDenis CIOCCA 			sdata->sensor->drdy_irq.addr, drdy_mask, (int)enable);
28623491b51SDenis Ciocca 
28723491b51SDenis Ciocca st_accel_set_dataready_irq_error:
28823491b51SDenis Ciocca 	return err;
28923491b51SDenis Ciocca }
29023491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_dataready_irq);
29123491b51SDenis Ciocca 
29223491b51SDenis Ciocca int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
29323491b51SDenis Ciocca {
29423491b51SDenis Ciocca 	int err = -EINVAL, i;
29523491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
29623491b51SDenis Ciocca 
29723491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
29823491b51SDenis Ciocca 		if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
29923491b51SDenis Ciocca 				(sdata->sensor->fs.fs_avl[i].gain != 0)) {
30023491b51SDenis Ciocca 			err = 0;
30123491b51SDenis Ciocca 			break;
30223491b51SDenis Ciocca 		}
30323491b51SDenis Ciocca 	}
30423491b51SDenis Ciocca 	if (err < 0)
30523491b51SDenis Ciocca 		goto st_sensors_match_scale_error;
30623491b51SDenis Ciocca 
30723491b51SDenis Ciocca 	err = st_sensors_set_fullscale(indio_dev,
30823491b51SDenis Ciocca 					sdata->sensor->fs.fs_avl[i].num);
30923491b51SDenis Ciocca 
31023491b51SDenis Ciocca st_sensors_match_scale_error:
31123491b51SDenis Ciocca 	return err;
31223491b51SDenis Ciocca }
31323491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
31423491b51SDenis Ciocca 
31523491b51SDenis Ciocca static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
316607a568aSDenis CIOCCA 				struct iio_chan_spec const *ch, int *data)
31723491b51SDenis Ciocca {
31823491b51SDenis Ciocca 	int err;
319607a568aSDenis CIOCCA 	u8 *outdata;
32023491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
321607a568aSDenis CIOCCA 	unsigned int byte_for_channel = ch->scan_type.storagebits >> 3;
322607a568aSDenis CIOCCA 
323607a568aSDenis CIOCCA 	outdata = kmalloc(byte_for_channel, GFP_KERNEL);
324607a568aSDenis CIOCCA 	if (!outdata) {
325607a568aSDenis CIOCCA 		err = -EINVAL;
326607a568aSDenis CIOCCA 		goto st_sensors_read_axis_data_error;
327607a568aSDenis CIOCCA 	}
32823491b51SDenis Ciocca 
32923491b51SDenis Ciocca 	err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
330607a568aSDenis CIOCCA 				ch->address, byte_for_channel,
33123491b51SDenis Ciocca 				outdata, sdata->multiread_bit);
33223491b51SDenis Ciocca 	if (err < 0)
333607a568aSDenis CIOCCA 		goto st_sensors_free_memory;
33423491b51SDenis Ciocca 
335607a568aSDenis CIOCCA 	if (byte_for_channel == 2)
33623491b51SDenis Ciocca 		*data = (s16)get_unaligned_le16(outdata);
337607a568aSDenis CIOCCA 	else if (byte_for_channel == 3)
338607a568aSDenis CIOCCA 		*data = (s32)st_sensors_get_unaligned_le24(outdata);
33923491b51SDenis Ciocca 
340607a568aSDenis CIOCCA st_sensors_free_memory:
341607a568aSDenis CIOCCA 	kfree(outdata);
342607a568aSDenis CIOCCA st_sensors_read_axis_data_error:
34323491b51SDenis Ciocca 	return err;
34423491b51SDenis Ciocca }
34523491b51SDenis Ciocca 
34623491b51SDenis Ciocca int st_sensors_read_info_raw(struct iio_dev *indio_dev,
34723491b51SDenis Ciocca 				struct iio_chan_spec const *ch, int *val)
34823491b51SDenis Ciocca {
34923491b51SDenis Ciocca 	int err;
35023491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
35123491b51SDenis Ciocca 
35223491b51SDenis Ciocca 	mutex_lock(&indio_dev->mlock);
35323491b51SDenis Ciocca 	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
35423491b51SDenis Ciocca 		err = -EBUSY;
35523491b51SDenis Ciocca 		goto read_error;
35623491b51SDenis Ciocca 	} else {
35723491b51SDenis Ciocca 		err = st_sensors_set_enable(indio_dev, true);
35823491b51SDenis Ciocca 		if (err < 0)
35923491b51SDenis Ciocca 			goto read_error;
36023491b51SDenis Ciocca 
36123491b51SDenis Ciocca 		msleep((sdata->sensor->bootime * 1000) / sdata->odr);
362607a568aSDenis CIOCCA 		err = st_sensors_read_axis_data(indio_dev, ch, val);
36323491b51SDenis Ciocca 		if (err < 0)
36423491b51SDenis Ciocca 			goto read_error;
36523491b51SDenis Ciocca 
36623491b51SDenis Ciocca 		*val = *val >> ch->scan_type.shift;
367d61a04dcSDenis CIOCCA 
368d61a04dcSDenis CIOCCA 		err = st_sensors_set_enable(indio_dev, false);
36923491b51SDenis Ciocca 	}
37023491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
37123491b51SDenis Ciocca 
37223491b51SDenis Ciocca 	return err;
37323491b51SDenis Ciocca 
37423491b51SDenis Ciocca read_error:
37523491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
37623491b51SDenis Ciocca 	return err;
37723491b51SDenis Ciocca }
37823491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_read_info_raw);
37923491b51SDenis Ciocca 
38023491b51SDenis Ciocca int st_sensors_check_device_support(struct iio_dev *indio_dev,
38123491b51SDenis Ciocca 			int num_sensors_list, const struct st_sensors *sensors)
38223491b51SDenis Ciocca {
38323491b51SDenis Ciocca 	u8 wai;
38423491b51SDenis Ciocca 	int i, n, err;
38523491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
38623491b51SDenis Ciocca 
38723491b51SDenis Ciocca 	err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
38823491b51SDenis Ciocca 					ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
38923491b51SDenis Ciocca 	if (err < 0) {
39023491b51SDenis Ciocca 		dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
39123491b51SDenis Ciocca 		goto read_wai_error;
39223491b51SDenis Ciocca 	}
39323491b51SDenis Ciocca 
39423491b51SDenis Ciocca 	for (i = 0; i < num_sensors_list; i++) {
39523491b51SDenis Ciocca 		if (sensors[i].wai == wai)
39623491b51SDenis Ciocca 			break;
39723491b51SDenis Ciocca 	}
39823491b51SDenis Ciocca 	if (i == num_sensors_list)
39923491b51SDenis Ciocca 		goto device_not_supported;
40023491b51SDenis Ciocca 
40123491b51SDenis Ciocca 	for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
40223491b51SDenis Ciocca 		if (strcmp(indio_dev->name,
40323491b51SDenis Ciocca 				&sensors[i].sensors_supported[n][0]) == 0)
40423491b51SDenis Ciocca 			break;
40523491b51SDenis Ciocca 	}
40623491b51SDenis Ciocca 	if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
40723491b51SDenis Ciocca 		dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
40823491b51SDenis Ciocca 		goto sensor_name_mismatch;
40923491b51SDenis Ciocca 	}
41023491b51SDenis Ciocca 
41123491b51SDenis Ciocca 	sdata->sensor = (struct st_sensors *)&sensors[i];
41223491b51SDenis Ciocca 
41323491b51SDenis Ciocca 	return i;
41423491b51SDenis Ciocca 
41523491b51SDenis Ciocca device_not_supported:
41623491b51SDenis Ciocca 	dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
41723491b51SDenis Ciocca sensor_name_mismatch:
41823491b51SDenis Ciocca 	err = -ENODEV;
41923491b51SDenis Ciocca read_wai_error:
42023491b51SDenis Ciocca 	return err;
42123491b51SDenis Ciocca }
42223491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_check_device_support);
42323491b51SDenis Ciocca 
42423491b51SDenis Ciocca ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
42523491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
42623491b51SDenis Ciocca {
42723491b51SDenis Ciocca 	struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
42823491b51SDenis Ciocca 
42923491b51SDenis Ciocca 	return sprintf(buf, "%d\n", adata->odr);
43023491b51SDenis Ciocca }
43123491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
43223491b51SDenis Ciocca 
43323491b51SDenis Ciocca ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
43423491b51SDenis Ciocca 		struct device_attribute *attr, const char *buf, size_t size)
43523491b51SDenis Ciocca {
43623491b51SDenis Ciocca 	int err;
43723491b51SDenis Ciocca 	unsigned int odr;
43823491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
43923491b51SDenis Ciocca 
44023491b51SDenis Ciocca 	err = kstrtoint(buf, 10, &odr);
44123491b51SDenis Ciocca 	if (err < 0)
44223491b51SDenis Ciocca 		goto conversion_error;
44323491b51SDenis Ciocca 
44423491b51SDenis Ciocca 	mutex_lock(&indio_dev->mlock);
44523491b51SDenis Ciocca 	err = st_sensors_set_odr(indio_dev, odr);
44623491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
44723491b51SDenis Ciocca 
44823491b51SDenis Ciocca conversion_error:
44923491b51SDenis Ciocca 	return err < 0 ? err : size;
45023491b51SDenis Ciocca }
45123491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
45223491b51SDenis Ciocca 
45323491b51SDenis Ciocca ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
45423491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
45523491b51SDenis Ciocca {
4564d2e4fc2SDenis CIOCCA 	int i, len = 0;
45723491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
4584d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
45923491b51SDenis Ciocca 
4604d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
4614d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
4624d2e4fc2SDenis CIOCCA 		if (sdata->sensor->odr.odr_avl[i].hz == 0)
4634d2e4fc2SDenis CIOCCA 			break;
4644d2e4fc2SDenis CIOCCA 
4654d2e4fc2SDenis CIOCCA 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
4664d2e4fc2SDenis CIOCCA 					sdata->sensor->odr.odr_avl[i].hz);
4674d2e4fc2SDenis CIOCCA 	}
4684d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
4694d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
4704d2e4fc2SDenis CIOCCA 
4714d2e4fc2SDenis CIOCCA 	return len;
47223491b51SDenis Ciocca }
47323491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
47423491b51SDenis Ciocca 
47523491b51SDenis Ciocca ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
47623491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
47723491b51SDenis Ciocca {
4784d2e4fc2SDenis CIOCCA 	int i, len = 0;
47923491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
4804d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
48123491b51SDenis Ciocca 
4824d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
4834d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
4844d2e4fc2SDenis CIOCCA 		if (sdata->sensor->fs.fs_avl[i].num == 0)
4854d2e4fc2SDenis CIOCCA 			break;
4864d2e4fc2SDenis CIOCCA 
4874d2e4fc2SDenis CIOCCA 		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
4884d2e4fc2SDenis CIOCCA 					sdata->sensor->fs.fs_avl[i].gain);
4894d2e4fc2SDenis CIOCCA 	}
4904d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
4914d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
4924d2e4fc2SDenis CIOCCA 
4934d2e4fc2SDenis CIOCCA 	return len;
49423491b51SDenis Ciocca }
49523491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
49623491b51SDenis Ciocca 
49723491b51SDenis Ciocca MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
49823491b51SDenis Ciocca MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
49923491b51SDenis Ciocca MODULE_LICENSE("GPL v2");
500