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 
2323491b51SDenis Ciocca static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
2423491b51SDenis Ciocca 						u8 reg_addr, u8 mask, u8 data)
2523491b51SDenis Ciocca {
2623491b51SDenis Ciocca 	int err;
2723491b51SDenis Ciocca 	u8 new_data;
2823491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
2923491b51SDenis Ciocca 
3023491b51SDenis Ciocca 	err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
3123491b51SDenis Ciocca 	if (err < 0)
3223491b51SDenis Ciocca 		goto st_sensors_write_data_with_mask_error;
3323491b51SDenis Ciocca 
3423491b51SDenis Ciocca 	new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
3523491b51SDenis Ciocca 	err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
3623491b51SDenis Ciocca 
3723491b51SDenis Ciocca st_sensors_write_data_with_mask_error:
3823491b51SDenis Ciocca 	return err;
3923491b51SDenis Ciocca }
4023491b51SDenis Ciocca 
4123491b51SDenis Ciocca static int st_sensors_match_odr(struct st_sensors *sensor,
4223491b51SDenis Ciocca 			unsigned int odr, struct st_sensor_odr_avl *odr_out)
4323491b51SDenis Ciocca {
4423491b51SDenis Ciocca 	int i, ret = -EINVAL;
4523491b51SDenis Ciocca 
4623491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
4723491b51SDenis Ciocca 		if (sensor->odr.odr_avl[i].hz == 0)
4823491b51SDenis Ciocca 			goto st_sensors_match_odr_error;
4923491b51SDenis Ciocca 
5023491b51SDenis Ciocca 		if (sensor->odr.odr_avl[i].hz == odr) {
5123491b51SDenis Ciocca 			odr_out->hz = sensor->odr.odr_avl[i].hz;
5223491b51SDenis Ciocca 			odr_out->value = sensor->odr.odr_avl[i].value;
5323491b51SDenis Ciocca 			ret = 0;
5423491b51SDenis Ciocca 			break;
5523491b51SDenis Ciocca 		}
5623491b51SDenis Ciocca 	}
5723491b51SDenis Ciocca 
5823491b51SDenis Ciocca st_sensors_match_odr_error:
5923491b51SDenis Ciocca 	return ret;
6023491b51SDenis Ciocca }
6123491b51SDenis Ciocca 
6223491b51SDenis Ciocca int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
6323491b51SDenis Ciocca {
6423491b51SDenis Ciocca 	int err;
65852afe99SDenis CIOCCA 	struct st_sensor_odr_avl odr_out = {0, 0};
6623491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
6723491b51SDenis Ciocca 
6823491b51SDenis Ciocca 	err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
6923491b51SDenis Ciocca 	if (err < 0)
7023491b51SDenis Ciocca 		goto st_sensors_match_odr_error;
7123491b51SDenis Ciocca 
7223491b51SDenis Ciocca 	if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
7323491b51SDenis Ciocca 			(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
7423491b51SDenis Ciocca 		if (sdata->enabled == true) {
7523491b51SDenis Ciocca 			err = st_sensors_write_data_with_mask(indio_dev,
7623491b51SDenis Ciocca 				sdata->sensor->odr.addr,
7723491b51SDenis Ciocca 				sdata->sensor->odr.mask,
7823491b51SDenis Ciocca 				odr_out.value);
7923491b51SDenis Ciocca 		} else {
8023491b51SDenis Ciocca 			err = 0;
8123491b51SDenis Ciocca 		}
8223491b51SDenis Ciocca 	} else {
8323491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
8423491b51SDenis Ciocca 			sdata->sensor->odr.addr, sdata->sensor->odr.mask,
8523491b51SDenis Ciocca 			odr_out.value);
8623491b51SDenis Ciocca 	}
8723491b51SDenis Ciocca 	if (err >= 0)
8823491b51SDenis Ciocca 		sdata->odr = odr_out.hz;
8923491b51SDenis Ciocca 
9023491b51SDenis Ciocca st_sensors_match_odr_error:
9123491b51SDenis Ciocca 	return err;
9223491b51SDenis Ciocca }
9323491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_odr);
9423491b51SDenis Ciocca 
9523491b51SDenis Ciocca static int st_sensors_match_fs(struct st_sensors *sensor,
9623491b51SDenis Ciocca 					unsigned int fs, int *index_fs_avl)
9723491b51SDenis Ciocca {
9823491b51SDenis Ciocca 	int i, ret = -EINVAL;
9923491b51SDenis Ciocca 
10023491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
10123491b51SDenis Ciocca 		if (sensor->fs.fs_avl[i].num == 0)
10223491b51SDenis Ciocca 			goto st_sensors_match_odr_error;
10323491b51SDenis Ciocca 
10423491b51SDenis Ciocca 		if (sensor->fs.fs_avl[i].num == fs) {
10523491b51SDenis Ciocca 			*index_fs_avl = i;
10623491b51SDenis Ciocca 			ret = 0;
10723491b51SDenis Ciocca 			break;
10823491b51SDenis Ciocca 		}
10923491b51SDenis Ciocca 	}
11023491b51SDenis Ciocca 
11123491b51SDenis Ciocca st_sensors_match_odr_error:
11223491b51SDenis Ciocca 	return ret;
11323491b51SDenis Ciocca }
11423491b51SDenis Ciocca 
11523491b51SDenis Ciocca static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
11623491b51SDenis Ciocca {
117852afe99SDenis CIOCCA 	int err, i = 0;
11823491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
11923491b51SDenis Ciocca 
12023491b51SDenis Ciocca 	err = st_sensors_match_fs(sdata->sensor, fs, &i);
12123491b51SDenis Ciocca 	if (err < 0)
12223491b51SDenis Ciocca 		goto st_accel_set_fullscale_error;
12323491b51SDenis Ciocca 
12423491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
12523491b51SDenis Ciocca 				sdata->sensor->fs.addr,
12623491b51SDenis Ciocca 				sdata->sensor->fs.mask,
12723491b51SDenis Ciocca 				sdata->sensor->fs.fs_avl[i].value);
12823491b51SDenis Ciocca 	if (err < 0)
12923491b51SDenis Ciocca 		goto st_accel_set_fullscale_error;
13023491b51SDenis Ciocca 
13123491b51SDenis Ciocca 	sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
13223491b51SDenis Ciocca 						&sdata->sensor->fs.fs_avl[i];
13323491b51SDenis Ciocca 	return err;
13423491b51SDenis Ciocca 
13523491b51SDenis Ciocca st_accel_set_fullscale_error:
13623491b51SDenis Ciocca 	dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
13723491b51SDenis Ciocca 	return err;
13823491b51SDenis Ciocca }
13923491b51SDenis Ciocca 
14023491b51SDenis Ciocca int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
14123491b51SDenis Ciocca {
14223491b51SDenis Ciocca 	u8 tmp_value;
14323491b51SDenis Ciocca 	int err = -EINVAL;
144852afe99SDenis CIOCCA 	bool found = false;
145852afe99SDenis CIOCCA 	struct st_sensor_odr_avl odr_out = {0, 0};
14623491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
14723491b51SDenis Ciocca 
14823491b51SDenis Ciocca 	if (enable) {
14923491b51SDenis Ciocca 		tmp_value = sdata->sensor->pw.value_on;
15023491b51SDenis Ciocca 		if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
15123491b51SDenis Ciocca 			(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
15223491b51SDenis Ciocca 			err = st_sensors_match_odr(sdata->sensor,
15323491b51SDenis Ciocca 							sdata->odr, &odr_out);
15423491b51SDenis Ciocca 			if (err < 0)
15523491b51SDenis Ciocca 				goto set_enable_error;
15623491b51SDenis Ciocca 			tmp_value = odr_out.value;
15723491b51SDenis Ciocca 			found = true;
15823491b51SDenis Ciocca 		}
15923491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
16023491b51SDenis Ciocca 				sdata->sensor->pw.addr,
16123491b51SDenis Ciocca 				sdata->sensor->pw.mask, tmp_value);
16223491b51SDenis Ciocca 		if (err < 0)
16323491b51SDenis Ciocca 			goto set_enable_error;
16423491b51SDenis Ciocca 
16523491b51SDenis Ciocca 		sdata->enabled = true;
16623491b51SDenis Ciocca 
16723491b51SDenis Ciocca 		if (found)
16823491b51SDenis Ciocca 			sdata->odr = odr_out.hz;
16923491b51SDenis Ciocca 	} else {
17023491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
17123491b51SDenis Ciocca 				sdata->sensor->pw.addr,
17223491b51SDenis Ciocca 				sdata->sensor->pw.mask,
17323491b51SDenis Ciocca 				sdata->sensor->pw.value_off);
17423491b51SDenis Ciocca 		if (err < 0)
17523491b51SDenis Ciocca 			goto set_enable_error;
17623491b51SDenis Ciocca 
17723491b51SDenis Ciocca 		sdata->enabled = false;
17823491b51SDenis Ciocca 	}
17923491b51SDenis Ciocca 
18023491b51SDenis Ciocca set_enable_error:
18123491b51SDenis Ciocca 	return err;
18223491b51SDenis Ciocca }
18323491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_enable);
18423491b51SDenis Ciocca 
18523491b51SDenis Ciocca int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
18623491b51SDenis Ciocca {
18723491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
18823491b51SDenis Ciocca 
18923491b51SDenis Ciocca 	return st_sensors_write_data_with_mask(indio_dev,
19023491b51SDenis Ciocca 				sdata->sensor->enable_axis.addr,
19123491b51SDenis Ciocca 				sdata->sensor->enable_axis.mask, axis_enable);
19223491b51SDenis Ciocca }
19323491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_axis_enable);
19423491b51SDenis Ciocca 
19523491b51SDenis Ciocca int st_sensors_init_sensor(struct iio_dev *indio_dev)
19623491b51SDenis Ciocca {
19723491b51SDenis Ciocca 	int err;
19823491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
19923491b51SDenis Ciocca 
20023491b51SDenis Ciocca 	mutex_init(&sdata->tb.buf_lock);
20123491b51SDenis Ciocca 
20223491b51SDenis Ciocca 	err = st_sensors_set_enable(indio_dev, false);
20323491b51SDenis Ciocca 	if (err < 0)
20423491b51SDenis Ciocca 		goto init_error;
20523491b51SDenis Ciocca 
20623491b51SDenis Ciocca 	err = st_sensors_set_fullscale(indio_dev,
20723491b51SDenis Ciocca 						sdata->current_fullscale->num);
20823491b51SDenis Ciocca 	if (err < 0)
20923491b51SDenis Ciocca 		goto init_error;
21023491b51SDenis Ciocca 
21123491b51SDenis Ciocca 	err = st_sensors_set_odr(indio_dev, sdata->odr);
21223491b51SDenis Ciocca 	if (err < 0)
21323491b51SDenis Ciocca 		goto init_error;
21423491b51SDenis Ciocca 
21523491b51SDenis Ciocca 	/* set BDU */
21623491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
21723491b51SDenis Ciocca 			sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
21823491b51SDenis Ciocca 	if (err < 0)
21923491b51SDenis Ciocca 		goto init_error;
22023491b51SDenis Ciocca 
22123491b51SDenis Ciocca 	err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
22223491b51SDenis Ciocca 
22323491b51SDenis Ciocca init_error:
22423491b51SDenis Ciocca 	return err;
22523491b51SDenis Ciocca }
22623491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_init_sensor);
22723491b51SDenis Ciocca 
22823491b51SDenis Ciocca int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
22923491b51SDenis Ciocca {
23023491b51SDenis Ciocca 	int err;
23123491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
23223491b51SDenis Ciocca 
23323491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator 1. */
23423491b51SDenis Ciocca 	if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
23523491b51SDenis Ciocca 		err = st_sensors_write_data_with_mask(indio_dev,
23623491b51SDenis Ciocca 			sdata->sensor->drdy_irq.ig1.en_addr,
23723491b51SDenis Ciocca 			sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
23823491b51SDenis Ciocca 		if (err < 0)
23923491b51SDenis Ciocca 			goto st_accel_set_dataready_irq_error;
24023491b51SDenis Ciocca 	}
24123491b51SDenis Ciocca 
24223491b51SDenis Ciocca 	/* Enable/Disable the interrupt generator for data ready. */
24323491b51SDenis Ciocca 	err = st_sensors_write_data_with_mask(indio_dev,
24423491b51SDenis Ciocca 			sdata->sensor->drdy_irq.addr,
24523491b51SDenis Ciocca 			sdata->sensor->drdy_irq.mask, (int)enable);
24623491b51SDenis Ciocca 
24723491b51SDenis Ciocca st_accel_set_dataready_irq_error:
24823491b51SDenis Ciocca 	return err;
24923491b51SDenis Ciocca }
25023491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_dataready_irq);
25123491b51SDenis Ciocca 
25223491b51SDenis Ciocca int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
25323491b51SDenis Ciocca {
25423491b51SDenis Ciocca 	int err = -EINVAL, i;
25523491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
25623491b51SDenis Ciocca 
25723491b51SDenis Ciocca 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
25823491b51SDenis Ciocca 		if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
25923491b51SDenis Ciocca 				(sdata->sensor->fs.fs_avl[i].gain != 0)) {
26023491b51SDenis Ciocca 			err = 0;
26123491b51SDenis Ciocca 			break;
26223491b51SDenis Ciocca 		}
26323491b51SDenis Ciocca 	}
26423491b51SDenis Ciocca 	if (err < 0)
26523491b51SDenis Ciocca 		goto st_sensors_match_scale_error;
26623491b51SDenis Ciocca 
26723491b51SDenis Ciocca 	err = st_sensors_set_fullscale(indio_dev,
26823491b51SDenis Ciocca 					sdata->sensor->fs.fs_avl[i].num);
26923491b51SDenis Ciocca 
27023491b51SDenis Ciocca st_sensors_match_scale_error:
27123491b51SDenis Ciocca 	return err;
27223491b51SDenis Ciocca }
27323491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
27423491b51SDenis Ciocca 
27523491b51SDenis Ciocca static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
27623491b51SDenis Ciocca 							u8 ch_addr, int *data)
27723491b51SDenis Ciocca {
27823491b51SDenis Ciocca 	int err;
27923491b51SDenis Ciocca 	u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL];
28023491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
28123491b51SDenis Ciocca 
28223491b51SDenis Ciocca 	err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
28323491b51SDenis Ciocca 				ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL,
28423491b51SDenis Ciocca 				outdata, sdata->multiread_bit);
28523491b51SDenis Ciocca 	if (err < 0)
28623491b51SDenis Ciocca 		goto read_error;
28723491b51SDenis Ciocca 
28823491b51SDenis Ciocca 	*data = (s16)get_unaligned_le16(outdata);
28923491b51SDenis Ciocca 
29023491b51SDenis Ciocca read_error:
29123491b51SDenis Ciocca 	return err;
29223491b51SDenis Ciocca }
29323491b51SDenis Ciocca 
29423491b51SDenis Ciocca int st_sensors_read_info_raw(struct iio_dev *indio_dev,
29523491b51SDenis Ciocca 				struct iio_chan_spec const *ch, int *val)
29623491b51SDenis Ciocca {
29723491b51SDenis Ciocca 	int err;
29823491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
29923491b51SDenis Ciocca 
30023491b51SDenis Ciocca 	mutex_lock(&indio_dev->mlock);
30123491b51SDenis Ciocca 	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
30223491b51SDenis Ciocca 		err = -EBUSY;
30323491b51SDenis Ciocca 		goto read_error;
30423491b51SDenis Ciocca 	} else {
30523491b51SDenis Ciocca 		err = st_sensors_set_enable(indio_dev, true);
30623491b51SDenis Ciocca 		if (err < 0)
30723491b51SDenis Ciocca 			goto read_error;
30823491b51SDenis Ciocca 
30923491b51SDenis Ciocca 		msleep((sdata->sensor->bootime * 1000) / sdata->odr);
31023491b51SDenis Ciocca 		err = st_sensors_read_axis_data(indio_dev, ch->address, val);
31123491b51SDenis Ciocca 		if (err < 0)
31223491b51SDenis Ciocca 			goto read_error;
31323491b51SDenis Ciocca 
31423491b51SDenis Ciocca 		*val = *val >> ch->scan_type.shift;
315d61a04dcSDenis CIOCCA 
316d61a04dcSDenis CIOCCA 		err = st_sensors_set_enable(indio_dev, false);
31723491b51SDenis Ciocca 	}
31823491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
31923491b51SDenis Ciocca 
32023491b51SDenis Ciocca 	return err;
32123491b51SDenis Ciocca 
32223491b51SDenis Ciocca read_error:
32323491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
32423491b51SDenis Ciocca 	return err;
32523491b51SDenis Ciocca }
32623491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_read_info_raw);
32723491b51SDenis Ciocca 
32823491b51SDenis Ciocca int st_sensors_check_device_support(struct iio_dev *indio_dev,
32923491b51SDenis Ciocca 			int num_sensors_list, const struct st_sensors *sensors)
33023491b51SDenis Ciocca {
33123491b51SDenis Ciocca 	u8 wai;
33223491b51SDenis Ciocca 	int i, n, err;
33323491b51SDenis Ciocca 	struct st_sensor_data *sdata = iio_priv(indio_dev);
33423491b51SDenis Ciocca 
33523491b51SDenis Ciocca 	err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
33623491b51SDenis Ciocca 					ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
33723491b51SDenis Ciocca 	if (err < 0) {
33823491b51SDenis Ciocca 		dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
33923491b51SDenis Ciocca 		goto read_wai_error;
34023491b51SDenis Ciocca 	}
34123491b51SDenis Ciocca 
34223491b51SDenis Ciocca 	for (i = 0; i < num_sensors_list; i++) {
34323491b51SDenis Ciocca 		if (sensors[i].wai == wai)
34423491b51SDenis Ciocca 			break;
34523491b51SDenis Ciocca 	}
34623491b51SDenis Ciocca 	if (i == num_sensors_list)
34723491b51SDenis Ciocca 		goto device_not_supported;
34823491b51SDenis Ciocca 
34923491b51SDenis Ciocca 	for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
35023491b51SDenis Ciocca 		if (strcmp(indio_dev->name,
35123491b51SDenis Ciocca 				&sensors[i].sensors_supported[n][0]) == 0)
35223491b51SDenis Ciocca 			break;
35323491b51SDenis Ciocca 	}
35423491b51SDenis Ciocca 	if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
35523491b51SDenis Ciocca 		dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
35623491b51SDenis Ciocca 		goto sensor_name_mismatch;
35723491b51SDenis Ciocca 	}
35823491b51SDenis Ciocca 
35923491b51SDenis Ciocca 	sdata->sensor = (struct st_sensors *)&sensors[i];
36023491b51SDenis Ciocca 
36123491b51SDenis Ciocca 	return i;
36223491b51SDenis Ciocca 
36323491b51SDenis Ciocca device_not_supported:
36423491b51SDenis Ciocca 	dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
36523491b51SDenis Ciocca sensor_name_mismatch:
36623491b51SDenis Ciocca 	err = -ENODEV;
36723491b51SDenis Ciocca read_wai_error:
36823491b51SDenis Ciocca 	return err;
36923491b51SDenis Ciocca }
37023491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_check_device_support);
37123491b51SDenis Ciocca 
37223491b51SDenis Ciocca ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
37323491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
37423491b51SDenis Ciocca {
37523491b51SDenis Ciocca 	struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
37623491b51SDenis Ciocca 
37723491b51SDenis Ciocca 	return sprintf(buf, "%d\n", adata->odr);
37823491b51SDenis Ciocca }
37923491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
38023491b51SDenis Ciocca 
38123491b51SDenis Ciocca ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
38223491b51SDenis Ciocca 		struct device_attribute *attr, const char *buf, size_t size)
38323491b51SDenis Ciocca {
38423491b51SDenis Ciocca 	int err;
38523491b51SDenis Ciocca 	unsigned int odr;
38623491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
38723491b51SDenis Ciocca 
38823491b51SDenis Ciocca 	err = kstrtoint(buf, 10, &odr);
38923491b51SDenis Ciocca 	if (err < 0)
39023491b51SDenis Ciocca 		goto conversion_error;
39123491b51SDenis Ciocca 
39223491b51SDenis Ciocca 	mutex_lock(&indio_dev->mlock);
39323491b51SDenis Ciocca 	err = st_sensors_set_odr(indio_dev, odr);
39423491b51SDenis Ciocca 	mutex_unlock(&indio_dev->mlock);
39523491b51SDenis Ciocca 
39623491b51SDenis Ciocca conversion_error:
39723491b51SDenis Ciocca 	return err < 0 ? err : size;
39823491b51SDenis Ciocca }
39923491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
40023491b51SDenis Ciocca 
40123491b51SDenis Ciocca ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
40223491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
40323491b51SDenis Ciocca {
4044d2e4fc2SDenis CIOCCA 	int i, len = 0;
40523491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
4064d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
40723491b51SDenis Ciocca 
4084d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
4094d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
4104d2e4fc2SDenis CIOCCA 		if (sdata->sensor->odr.odr_avl[i].hz == 0)
4114d2e4fc2SDenis CIOCCA 			break;
4124d2e4fc2SDenis CIOCCA 
4134d2e4fc2SDenis CIOCCA 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
4144d2e4fc2SDenis CIOCCA 					sdata->sensor->odr.odr_avl[i].hz);
4154d2e4fc2SDenis CIOCCA 	}
4164d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
4174d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
4184d2e4fc2SDenis CIOCCA 
4194d2e4fc2SDenis CIOCCA 	return len;
42023491b51SDenis Ciocca }
42123491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
42223491b51SDenis Ciocca 
42323491b51SDenis Ciocca ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
42423491b51SDenis Ciocca 				struct device_attribute *attr, char *buf)
42523491b51SDenis Ciocca {
4264d2e4fc2SDenis CIOCCA 	int i, len = 0;
42723491b51SDenis Ciocca 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
4284d2e4fc2SDenis CIOCCA 	struct st_sensor_data *sdata = iio_priv(indio_dev);
42923491b51SDenis Ciocca 
4304d2e4fc2SDenis CIOCCA 	mutex_lock(&indio_dev->mlock);
4314d2e4fc2SDenis CIOCCA 	for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
4324d2e4fc2SDenis CIOCCA 		if (sdata->sensor->fs.fs_avl[i].num == 0)
4334d2e4fc2SDenis CIOCCA 			break;
4344d2e4fc2SDenis CIOCCA 
4354d2e4fc2SDenis CIOCCA 		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
4364d2e4fc2SDenis CIOCCA 					sdata->sensor->fs.fs_avl[i].gain);
4374d2e4fc2SDenis CIOCCA 	}
4384d2e4fc2SDenis CIOCCA 	mutex_unlock(&indio_dev->mlock);
4394d2e4fc2SDenis CIOCCA 	buf[len - 1] = '\n';
4404d2e4fc2SDenis CIOCCA 
4414d2e4fc2SDenis CIOCCA 	return len;
44223491b51SDenis Ciocca }
44323491b51SDenis Ciocca EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
44423491b51SDenis Ciocca 
44523491b51SDenis Ciocca MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
44623491b51SDenis Ciocca MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
44723491b51SDenis Ciocca MODULE_LICENSE("GPL v2");
448