1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
223491b51SDenis Ciocca /*
323491b51SDenis Ciocca * STMicroelectronics sensors core library driver
423491b51SDenis Ciocca *
523491b51SDenis Ciocca * Copyright 2012-2013 STMicroelectronics Inc.
623491b51SDenis Ciocca *
723491b51SDenis Ciocca * Denis Ciocca <denis.ciocca@st.com>
823491b51SDenis Ciocca */
923491b51SDenis Ciocca
1023491b51SDenis Ciocca #include <linux/kernel.h>
1123491b51SDenis Ciocca #include <linux/module.h>
1223491b51SDenis Ciocca #include <linux/slab.h>
1323491b51SDenis Ciocca #include <linux/delay.h>
1423491b51SDenis Ciocca #include <linux/iio/iio.h>
159c6cd755SJonathan Cameron #include <linux/mutex.h>
16efc78983SAndy Shevchenko #include <linux/property.h>
17ea7e586bSLinus Walleij #include <linux/regulator/consumer.h>
18062809efSDenis Ciocca #include <linux/regmap.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
st_sensors_write_data_with_mask(struct iio_dev * indio_dev,u8 reg_addr,u8 mask,u8 data)24a9fd053bSLinus Walleij int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
2523491b51SDenis Ciocca u8 reg_addr, u8 mask, u8 data)
2623491b51SDenis Ciocca {
2723491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
2823491b51SDenis Ciocca
29062809efSDenis Ciocca return regmap_update_bits(sdata->regmap,
30062809efSDenis Ciocca reg_addr, mask, data << __ffs(mask));
3123491b51SDenis Ciocca }
3223491b51SDenis Ciocca
st_sensors_debugfs_reg_access(struct iio_dev * indio_dev,unsigned reg,unsigned writeval,unsigned * readval)33a0175b9cSLinus Walleij int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
34a0175b9cSLinus Walleij unsigned reg, unsigned writeval,
35a0175b9cSLinus Walleij unsigned *readval)
36a0175b9cSLinus Walleij {
37a0175b9cSLinus Walleij struct st_sensor_data *sdata = iio_priv(indio_dev);
38a0175b9cSLinus Walleij int err;
39a0175b9cSLinus Walleij
40a0175b9cSLinus Walleij if (!readval)
41062809efSDenis Ciocca return regmap_write(sdata->regmap, reg, writeval);
42a0175b9cSLinus Walleij
43062809efSDenis Ciocca err = regmap_read(sdata->regmap, reg, readval);
44a0175b9cSLinus Walleij if (err < 0)
45a0175b9cSLinus Walleij return err;
46a0175b9cSLinus Walleij
47a0175b9cSLinus Walleij return 0;
48a0175b9cSLinus Walleij }
490805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_debugfs_reg_access, IIO_ST_SENSORS);
50a0175b9cSLinus Walleij
st_sensors_match_odr(struct st_sensor_settings * sensor_settings,unsigned int odr,struct st_sensor_odr_avl * odr_out)51a7ee8839SDenis CIOCCA static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
5223491b51SDenis Ciocca unsigned int odr, struct st_sensor_odr_avl *odr_out)
5323491b51SDenis Ciocca {
5423491b51SDenis Ciocca int i, ret = -EINVAL;
5523491b51SDenis Ciocca
5623491b51SDenis Ciocca for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
57a7ee8839SDenis CIOCCA if (sensor_settings->odr.odr_avl[i].hz == 0)
5823491b51SDenis Ciocca goto st_sensors_match_odr_error;
5923491b51SDenis Ciocca
60a7ee8839SDenis CIOCCA if (sensor_settings->odr.odr_avl[i].hz == odr) {
61a7ee8839SDenis CIOCCA odr_out->hz = sensor_settings->odr.odr_avl[i].hz;
62a7ee8839SDenis CIOCCA odr_out->value = sensor_settings->odr.odr_avl[i].value;
6323491b51SDenis Ciocca ret = 0;
6423491b51SDenis Ciocca break;
6523491b51SDenis Ciocca }
6623491b51SDenis Ciocca }
6723491b51SDenis Ciocca
6823491b51SDenis Ciocca st_sensors_match_odr_error:
6923491b51SDenis Ciocca return ret;
7023491b51SDenis Ciocca }
7123491b51SDenis Ciocca
st_sensors_set_odr(struct iio_dev * indio_dev,unsigned int odr)7223491b51SDenis Ciocca int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
7323491b51SDenis Ciocca {
7447401012SMiquel Raynal int err = 0;
75852afe99SDenis CIOCCA struct st_sensor_odr_avl odr_out = {0, 0};
7623491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
7723491b51SDenis Ciocca
7847401012SMiquel Raynal mutex_lock(&sdata->odr_lock);
7947401012SMiquel Raynal
80e450e07cSLary Gibaud if (!sdata->sensor_settings->odr.mask)
8147401012SMiquel Raynal goto unlock_mutex;
827d245172SLorenzo Bianconi
83a7ee8839SDenis CIOCCA err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
8423491b51SDenis Ciocca if (err < 0)
8547401012SMiquel Raynal goto unlock_mutex;
8623491b51SDenis Ciocca
87a7ee8839SDenis CIOCCA if ((sdata->sensor_settings->odr.addr ==
88a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.addr) &&
89a7ee8839SDenis CIOCCA (sdata->sensor_settings->odr.mask ==
90a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.mask)) {
9123491b51SDenis Ciocca if (sdata->enabled == true) {
9223491b51SDenis Ciocca err = st_sensors_write_data_with_mask(indio_dev,
93a7ee8839SDenis CIOCCA sdata->sensor_settings->odr.addr,
94a7ee8839SDenis CIOCCA sdata->sensor_settings->odr.mask,
9523491b51SDenis Ciocca odr_out.value);
9623491b51SDenis Ciocca } else {
9723491b51SDenis Ciocca err = 0;
9823491b51SDenis Ciocca }
9923491b51SDenis Ciocca } else {
10023491b51SDenis Ciocca err = st_sensors_write_data_with_mask(indio_dev,
101a7ee8839SDenis CIOCCA sdata->sensor_settings->odr.addr,
102a7ee8839SDenis CIOCCA sdata->sensor_settings->odr.mask,
10323491b51SDenis Ciocca odr_out.value);
10423491b51SDenis Ciocca }
10523491b51SDenis Ciocca if (err >= 0)
10623491b51SDenis Ciocca sdata->odr = odr_out.hz;
10723491b51SDenis Ciocca
10847401012SMiquel Raynal unlock_mutex:
10947401012SMiquel Raynal mutex_unlock(&sdata->odr_lock);
11047401012SMiquel Raynal
11123491b51SDenis Ciocca return err;
11223491b51SDenis Ciocca }
1130805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_set_odr, IIO_ST_SENSORS);
11423491b51SDenis Ciocca
st_sensors_match_fs(struct st_sensor_settings * sensor_settings,unsigned int fs,int * index_fs_avl)115a7ee8839SDenis CIOCCA static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
11623491b51SDenis Ciocca unsigned int fs, int *index_fs_avl)
11723491b51SDenis Ciocca {
11823491b51SDenis Ciocca int i, ret = -EINVAL;
11923491b51SDenis Ciocca
12023491b51SDenis Ciocca for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
121a7ee8839SDenis CIOCCA if (sensor_settings->fs.fs_avl[i].num == 0)
1222019738cSMartin Kelly return ret;
12323491b51SDenis Ciocca
124a7ee8839SDenis CIOCCA if (sensor_settings->fs.fs_avl[i].num == fs) {
12523491b51SDenis Ciocca *index_fs_avl = i;
12623491b51SDenis Ciocca ret = 0;
12723491b51SDenis Ciocca break;
12823491b51SDenis Ciocca }
12923491b51SDenis Ciocca }
13023491b51SDenis Ciocca
13123491b51SDenis Ciocca return ret;
13223491b51SDenis Ciocca }
13323491b51SDenis Ciocca
st_sensors_set_fullscale(struct iio_dev * indio_dev,unsigned int fs)134a7ee8839SDenis CIOCCA static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
13523491b51SDenis Ciocca {
136852afe99SDenis CIOCCA int err, i = 0;
13723491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
13823491b51SDenis Ciocca
139bb602f8cSGiuseppe Barba if (sdata->sensor_settings->fs.addr == 0)
140bb602f8cSGiuseppe Barba return 0;
141bb602f8cSGiuseppe Barba
142a7ee8839SDenis CIOCCA err = st_sensors_match_fs(sdata->sensor_settings, fs, &i);
14323491b51SDenis Ciocca if (err < 0)
14423491b51SDenis Ciocca goto st_accel_set_fullscale_error;
14523491b51SDenis Ciocca
14623491b51SDenis Ciocca err = st_sensors_write_data_with_mask(indio_dev,
147a7ee8839SDenis CIOCCA sdata->sensor_settings->fs.addr,
148a7ee8839SDenis CIOCCA sdata->sensor_settings->fs.mask,
149a7ee8839SDenis CIOCCA sdata->sensor_settings->fs.fs_avl[i].value);
15023491b51SDenis Ciocca if (err < 0)
15123491b51SDenis Ciocca goto st_accel_set_fullscale_error;
15223491b51SDenis Ciocca
1531f38527dSAndy Shevchenko sdata->current_fullscale = &sdata->sensor_settings->fs.fs_avl[i];
15423491b51SDenis Ciocca return err;
15523491b51SDenis Ciocca
15623491b51SDenis Ciocca st_accel_set_fullscale_error:
15723491b51SDenis Ciocca dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
15823491b51SDenis Ciocca return err;
15923491b51SDenis Ciocca }
16023491b51SDenis Ciocca
st_sensors_set_enable(struct iio_dev * indio_dev,bool enable)16123491b51SDenis Ciocca int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
16223491b51SDenis Ciocca {
16323491b51SDenis Ciocca u8 tmp_value;
16423491b51SDenis Ciocca int err = -EINVAL;
165852afe99SDenis CIOCCA bool found = false;
166852afe99SDenis CIOCCA struct st_sensor_odr_avl odr_out = {0, 0};
16723491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
16823491b51SDenis Ciocca
16923491b51SDenis Ciocca if (enable) {
170a7ee8839SDenis CIOCCA tmp_value = sdata->sensor_settings->pw.value_on;
171a7ee8839SDenis CIOCCA if ((sdata->sensor_settings->odr.addr ==
172a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.addr) &&
173a7ee8839SDenis CIOCCA (sdata->sensor_settings->odr.mask ==
174a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.mask)) {
175a7ee8839SDenis CIOCCA err = st_sensors_match_odr(sdata->sensor_settings,
17623491b51SDenis Ciocca sdata->odr, &odr_out);
17723491b51SDenis Ciocca if (err < 0)
17823491b51SDenis Ciocca goto set_enable_error;
17923491b51SDenis Ciocca tmp_value = odr_out.value;
18023491b51SDenis Ciocca found = true;
18123491b51SDenis Ciocca }
18223491b51SDenis Ciocca err = st_sensors_write_data_with_mask(indio_dev,
183a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.addr,
184a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.mask, tmp_value);
18523491b51SDenis Ciocca if (err < 0)
18623491b51SDenis Ciocca goto set_enable_error;
18723491b51SDenis Ciocca
18823491b51SDenis Ciocca sdata->enabled = true;
18923491b51SDenis Ciocca
19023491b51SDenis Ciocca if (found)
19123491b51SDenis Ciocca sdata->odr = odr_out.hz;
19223491b51SDenis Ciocca } else {
19323491b51SDenis Ciocca err = st_sensors_write_data_with_mask(indio_dev,
194a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.addr,
195a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.mask,
196a7ee8839SDenis CIOCCA sdata->sensor_settings->pw.value_off);
19723491b51SDenis Ciocca if (err < 0)
19823491b51SDenis Ciocca goto set_enable_error;
19923491b51SDenis Ciocca
20023491b51SDenis Ciocca sdata->enabled = false;
20123491b51SDenis Ciocca }
20223491b51SDenis Ciocca
20323491b51SDenis Ciocca set_enable_error:
20423491b51SDenis Ciocca return err;
20523491b51SDenis Ciocca }
2060805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_set_enable, IIO_ST_SENSORS);
20723491b51SDenis Ciocca
st_sensors_set_axis_enable(struct iio_dev * indio_dev,u8 axis_enable)20823491b51SDenis Ciocca int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
20923491b51SDenis Ciocca {
21023491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
2112e8325f4SLorenzo Bianconi int err = 0;
21223491b51SDenis Ciocca
2132e8325f4SLorenzo Bianconi if (sdata->sensor_settings->enable_axis.addr)
2142e8325f4SLorenzo Bianconi err = st_sensors_write_data_with_mask(indio_dev,
215a7ee8839SDenis CIOCCA sdata->sensor_settings->enable_axis.addr,
216a7ee8839SDenis CIOCCA sdata->sensor_settings->enable_axis.mask,
217a7ee8839SDenis CIOCCA axis_enable);
2182e8325f4SLorenzo Bianconi return err;
21923491b51SDenis Ciocca }
2200805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, IIO_ST_SENSORS);
22123491b51SDenis Ciocca
2225363c6c1SAlexandru Ardelean
st_sensors_power_enable(struct iio_dev * indio_dev)22314f295c8SGregor Boirie int st_sensors_power_enable(struct iio_dev *indio_dev)
224ea7e586bSLinus Walleij {
225*9e855d77SJonathan Cameron static const char * const regulator_names[] = { "vdd", "vddio" };
2265363c6c1SAlexandru Ardelean struct device *parent = indio_dev->dev.parent;
227ea7e586bSLinus Walleij int err;
228ea7e586bSLinus Walleij
229ea7e586bSLinus Walleij /* Regulators not mandatory, but if requested we should enable them. */
230*9e855d77SJonathan Cameron err = devm_regulator_bulk_get_enable(parent,
231*9e855d77SJonathan Cameron ARRAY_SIZE(regulator_names),
232*9e855d77SJonathan Cameron regulator_names);
2335363c6c1SAlexandru Ardelean if (err)
234*9e855d77SJonathan Cameron return dev_err_probe(&indio_dev->dev, err,
235*9e855d77SJonathan Cameron "unable to enable supplies\n");
2365363c6c1SAlexandru Ardelean
237*9e855d77SJonathan Cameron return 0;
238ea7e586bSLinus Walleij }
2390805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_power_enable, IIO_ST_SENSORS);
240ea7e586bSLinus Walleij
st_sensors_set_drdy_int_pin(struct iio_dev * indio_dev,struct st_sensors_platform_data * pdata)24138d1c6a9SLee Jones static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
24223cde4d6SDenis CIOCCA struct st_sensors_platform_data *pdata)
24323491b51SDenis Ciocca {
24423491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
24523491b51SDenis Ciocca
246d2bc4318SLinus Walleij /* Sensor does not support interrupts */
24775d4c6d2SLorenzo Bianconi if (!sdata->sensor_settings->drdy_irq.int1.addr &&
24875d4c6d2SLorenzo Bianconi !sdata->sensor_settings->drdy_irq.int2.addr) {
249d2bc4318SLinus Walleij if (pdata->drdy_int_pin)
250d2bc4318SLinus Walleij dev_info(&indio_dev->dev,
25138bc8015SAndy Shevchenko "DRDY on pin INT%d specified, but sensor does not support interrupts\n",
252d2bc4318SLinus Walleij pdata->drdy_int_pin);
253d2bc4318SLinus Walleij return 0;
254d2bc4318SLinus Walleij }
255d2bc4318SLinus Walleij
25623cde4d6SDenis CIOCCA switch (pdata->drdy_int_pin) {
25723cde4d6SDenis CIOCCA case 1:
25875d4c6d2SLorenzo Bianconi if (!sdata->sensor_settings->drdy_irq.int1.mask) {
25923cde4d6SDenis CIOCCA dev_err(&indio_dev->dev,
26023cde4d6SDenis CIOCCA "DRDY on INT1 not available.\n");
26138d1c6a9SLee Jones return -EINVAL;
26223cde4d6SDenis CIOCCA }
26323cde4d6SDenis CIOCCA sdata->drdy_int_pin = 1;
26423cde4d6SDenis CIOCCA break;
26523cde4d6SDenis CIOCCA case 2:
26675d4c6d2SLorenzo Bianconi if (!sdata->sensor_settings->drdy_irq.int2.mask) {
26723cde4d6SDenis CIOCCA dev_err(&indio_dev->dev,
26823cde4d6SDenis CIOCCA "DRDY on INT2 not available.\n");
26938d1c6a9SLee Jones return -EINVAL;
27023cde4d6SDenis CIOCCA }
27123cde4d6SDenis CIOCCA sdata->drdy_int_pin = 2;
27223cde4d6SDenis CIOCCA break;
27323cde4d6SDenis CIOCCA default:
27423cde4d6SDenis CIOCCA dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
27538d1c6a9SLee Jones return -EINVAL;
27623cde4d6SDenis CIOCCA }
27723cde4d6SDenis CIOCCA
2780e6f6871SLinus Walleij if (pdata->open_drain) {
279a542f9a0SLorenzo Bianconi if (!sdata->sensor_settings->drdy_irq.int1.addr_od &&
280a542f9a0SLorenzo Bianconi !sdata->sensor_settings->drdy_irq.int2.addr_od)
2810e6f6871SLinus Walleij dev_err(&indio_dev->dev,
2820e6f6871SLinus Walleij "open drain requested but unsupported.\n");
2830e6f6871SLinus Walleij else
2840e6f6871SLinus Walleij sdata->int_pin_open_drain = true;
2850e6f6871SLinus Walleij }
2860e6f6871SLinus Walleij
28738d1c6a9SLee Jones return 0;
28838d1c6a9SLee Jones }
28938d1c6a9SLee Jones
st_sensors_dev_probe(struct device * dev,struct st_sensors_platform_data * defdata)290ecb27c5eSAndy Shevchenko static struct st_sensors_platform_data *st_sensors_dev_probe(struct device *dev,
2913ce85cc4SLinus Walleij struct st_sensors_platform_data *defdata)
2923ce85cc4SLinus Walleij {
2933ce85cc4SLinus Walleij struct st_sensors_platform_data *pdata;
2943ce85cc4SLinus Walleij u32 val;
2953ce85cc4SLinus Walleij
296ecb27c5eSAndy Shevchenko if (!dev_fwnode(dev))
2973ce85cc4SLinus Walleij return NULL;
2983ce85cc4SLinus Walleij
2993ce85cc4SLinus Walleij pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
3009960c709SColin Ian King if (!pdata)
3019960c709SColin Ian King return ERR_PTR(-ENOMEM);
302ecb27c5eSAndy Shevchenko if (!device_property_read_u32(dev, "st,drdy-int-pin", &val) && (val <= 2))
3033ce85cc4SLinus Walleij pdata->drdy_int_pin = (u8) val;
3043ce85cc4SLinus Walleij else
305d2bc4318SLinus Walleij pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;
3063ce85cc4SLinus Walleij
307ecb27c5eSAndy Shevchenko pdata->open_drain = device_property_read_bool(dev, "drive-open-drain");
3080e6f6871SLinus Walleij
3093ce85cc4SLinus Walleij return pdata;
3103ce85cc4SLinus Walleij }
3113ce85cc4SLinus Walleij
312efc78983SAndy Shevchenko /**
313efc78983SAndy Shevchenko * st_sensors_dev_name_probe() - device probe for ST sensor name
314efc78983SAndy Shevchenko * @dev: driver model representation of the device.
315efc78983SAndy Shevchenko * @name: device name buffer reference.
316efc78983SAndy Shevchenko * @len: device name buffer length.
317efc78983SAndy Shevchenko *
318efc78983SAndy Shevchenko * In effect this function matches an ID to an internal kernel
319efc78983SAndy Shevchenko * name for a certain sensor device, so that the rest of the autodetection can
320efc78983SAndy Shevchenko * rely on that name from this point on. I2C/SPI devices will be renamed
321efc78983SAndy Shevchenko * to match the internal kernel convention.
322efc78983SAndy Shevchenko */
st_sensors_dev_name_probe(struct device * dev,char * name,int len)323efc78983SAndy Shevchenko void st_sensors_dev_name_probe(struct device *dev, char *name, int len)
324efc78983SAndy Shevchenko {
325efc78983SAndy Shevchenko const void *match;
326efc78983SAndy Shevchenko
327efc78983SAndy Shevchenko match = device_get_match_data(dev);
328efc78983SAndy Shevchenko if (!match)
329efc78983SAndy Shevchenko return;
330efc78983SAndy Shevchenko
331efc78983SAndy Shevchenko /* The name from the match takes precedence if present */
332ae2c9cf1SWolfram Sang strscpy(name, match, len);
333efc78983SAndy Shevchenko }
3340805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_dev_name_probe, IIO_ST_SENSORS);
335efc78983SAndy Shevchenko
st_sensors_init_sensor(struct iio_dev * indio_dev,struct st_sensors_platform_data * pdata)33638d1c6a9SLee Jones int st_sensors_init_sensor(struct iio_dev *indio_dev,
33738d1c6a9SLee Jones struct st_sensors_platform_data *pdata)
33838d1c6a9SLee Jones {
33938d1c6a9SLee Jones struct st_sensor_data *sdata = iio_priv(indio_dev);
3403ce85cc4SLinus Walleij struct st_sensors_platform_data *of_pdata;
34138d1c6a9SLee Jones int err = 0;
34238d1c6a9SLee Jones
34347401012SMiquel Raynal mutex_init(&sdata->odr_lock);
34447401012SMiquel Raynal
3453ce85cc4SLinus Walleij /* If OF/DT pdata exists, it will take precedence of anything else */
346ecb27c5eSAndy Shevchenko of_pdata = st_sensors_dev_probe(indio_dev->dev.parent, pdata);
3479960c709SColin Ian King if (IS_ERR(of_pdata))
3489960c709SColin Ian King return PTR_ERR(of_pdata);
3493ce85cc4SLinus Walleij if (of_pdata)
3503ce85cc4SLinus Walleij pdata = of_pdata;
3513ce85cc4SLinus Walleij
3523c8bf223SLee Jones if (pdata) {
35338d1c6a9SLee Jones err = st_sensors_set_drdy_int_pin(indio_dev, pdata);
3543c8bf223SLee Jones if (err < 0)
3553c8bf223SLee Jones return err;
3563c8bf223SLee Jones }
35738d1c6a9SLee Jones
35823491b51SDenis Ciocca err = st_sensors_set_enable(indio_dev, false);
35923491b51SDenis Ciocca if (err < 0)
360efd9566fSLee Jones return err;
36123491b51SDenis Ciocca
36299147606SCrestez Dan Leonard /* Disable DRDY, this might be still be enabled after reboot. */
36399147606SCrestez Dan Leonard err = st_sensors_set_dataready_irq(indio_dev, false);
36499147606SCrestez Dan Leonard if (err < 0)
36599147606SCrestez Dan Leonard return err;
36699147606SCrestez Dan Leonard
367362f2f86SLee Jones if (sdata->current_fullscale) {
36823491b51SDenis Ciocca err = st_sensors_set_fullscale(indio_dev,
36923491b51SDenis Ciocca sdata->current_fullscale->num);
37023491b51SDenis Ciocca if (err < 0)
371efd9566fSLee Jones return err;
372362f2f86SLee Jones } else
373362f2f86SLee Jones dev_info(&indio_dev->dev, "Full-scale not possible\n");
37423491b51SDenis Ciocca
37523491b51SDenis Ciocca err = st_sensors_set_odr(indio_dev, sdata->odr);
37623491b51SDenis Ciocca if (err < 0)
377efd9566fSLee Jones return err;
37823491b51SDenis Ciocca
37923491b51SDenis Ciocca /* set BDU */
380bb60646cSLinus Walleij if (sdata->sensor_settings->bdu.addr) {
38123491b51SDenis Ciocca err = st_sensors_write_data_with_mask(indio_dev,
382a7ee8839SDenis CIOCCA sdata->sensor_settings->bdu.addr,
383a7ee8839SDenis CIOCCA sdata->sensor_settings->bdu.mask, true);
38423491b51SDenis Ciocca if (err < 0)
385efd9566fSLee Jones return err;
386bb60646cSLinus Walleij }
38723491b51SDenis Ciocca
38865e4345cSLinus Walleij /* set DAS */
38965e4345cSLinus Walleij if (sdata->sensor_settings->das.addr) {
39065e4345cSLinus Walleij err = st_sensors_write_data_with_mask(indio_dev,
39165e4345cSLinus Walleij sdata->sensor_settings->das.addr,
39265e4345cSLinus Walleij sdata->sensor_settings->das.mask, 1);
39365e4345cSLinus Walleij if (err < 0)
39465e4345cSLinus Walleij return err;
39565e4345cSLinus Walleij }
39665e4345cSLinus Walleij
3970e6f6871SLinus Walleij if (sdata->int_pin_open_drain) {
398a542f9a0SLorenzo Bianconi u8 addr, mask;
399a542f9a0SLorenzo Bianconi
400a542f9a0SLorenzo Bianconi if (sdata->drdy_int_pin == 1) {
401a542f9a0SLorenzo Bianconi addr = sdata->sensor_settings->drdy_irq.int1.addr_od;
402a542f9a0SLorenzo Bianconi mask = sdata->sensor_settings->drdy_irq.int1.mask_od;
403a542f9a0SLorenzo Bianconi } else {
404a542f9a0SLorenzo Bianconi addr = sdata->sensor_settings->drdy_irq.int2.addr_od;
405a542f9a0SLorenzo Bianconi mask = sdata->sensor_settings->drdy_irq.int2.mask_od;
406a542f9a0SLorenzo Bianconi }
407a542f9a0SLorenzo Bianconi
4080e6f6871SLinus Walleij dev_info(&indio_dev->dev,
409a542f9a0SLorenzo Bianconi "set interrupt line to open drain mode on pin %d\n",
410a542f9a0SLorenzo Bianconi sdata->drdy_int_pin);
411a542f9a0SLorenzo Bianconi err = st_sensors_write_data_with_mask(indio_dev, addr,
412a542f9a0SLorenzo Bianconi mask, 1);
4130e6f6871SLinus Walleij if (err < 0)
4140e6f6871SLinus Walleij return err;
4150e6f6871SLinus Walleij }
4160e6f6871SLinus Walleij
41723491b51SDenis Ciocca err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
41823491b51SDenis Ciocca
41923491b51SDenis Ciocca return err;
42023491b51SDenis Ciocca }
4210805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_init_sensor, IIO_ST_SENSORS);
42223491b51SDenis Ciocca
st_sensors_set_dataready_irq(struct iio_dev * indio_dev,bool enable)42323491b51SDenis Ciocca int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
42423491b51SDenis Ciocca {
42523491b51SDenis Ciocca int err;
42675d4c6d2SLorenzo Bianconi u8 drdy_addr, drdy_mask;
42723491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
42823491b51SDenis Ciocca
42975d4c6d2SLorenzo Bianconi if (!sdata->sensor_settings->drdy_irq.int1.addr &&
43075d4c6d2SLorenzo Bianconi !sdata->sensor_settings->drdy_irq.int2.addr) {
431c65e3d6eSLorenzo Bianconi /*
432c65e3d6eSLorenzo Bianconi * there are some devices (e.g. LIS3MDL) where drdy line is
433c65e3d6eSLorenzo Bianconi * routed to a given pin and it is not possible to select a
434c65e3d6eSLorenzo Bianconi * different one. Take into account irq status register
435c65e3d6eSLorenzo Bianconi * to understand if irq trigger can be properly supported
436c65e3d6eSLorenzo Bianconi */
437e72a0601SLorenzo Bianconi if (sdata->sensor_settings->drdy_irq.stat_drdy.addr)
438c65e3d6eSLorenzo Bianconi sdata->hw_irq_trigger = enable;
43938d1c6a9SLee Jones return 0;
440c65e3d6eSLorenzo Bianconi }
44138d1c6a9SLee Jones
44223491b51SDenis Ciocca /* Enable/Disable the interrupt generator 1. */
443a7ee8839SDenis CIOCCA if (sdata->sensor_settings->drdy_irq.ig1.en_addr > 0) {
44423491b51SDenis Ciocca err = st_sensors_write_data_with_mask(indio_dev,
445a7ee8839SDenis CIOCCA sdata->sensor_settings->drdy_irq.ig1.en_addr,
446a7ee8839SDenis CIOCCA sdata->sensor_settings->drdy_irq.ig1.en_mask,
447a7ee8839SDenis CIOCCA (int)enable);
44823491b51SDenis Ciocca if (err < 0)
44923491b51SDenis Ciocca goto st_accel_set_dataready_irq_error;
45023491b51SDenis Ciocca }
45123491b51SDenis Ciocca
45275d4c6d2SLorenzo Bianconi if (sdata->drdy_int_pin == 1) {
45375d4c6d2SLorenzo Bianconi drdy_addr = sdata->sensor_settings->drdy_irq.int1.addr;
45475d4c6d2SLorenzo Bianconi drdy_mask = sdata->sensor_settings->drdy_irq.int1.mask;
45575d4c6d2SLorenzo Bianconi } else {
45675d4c6d2SLorenzo Bianconi drdy_addr = sdata->sensor_settings->drdy_irq.int2.addr;
45775d4c6d2SLorenzo Bianconi drdy_mask = sdata->sensor_settings->drdy_irq.int2.mask;
45875d4c6d2SLorenzo Bianconi }
45923cde4d6SDenis CIOCCA
46065925b65SLinus Walleij /* Flag to the poll function that the hardware trigger is in use */
46165925b65SLinus Walleij sdata->hw_irq_trigger = enable;
46265925b65SLinus Walleij
46323491b51SDenis Ciocca /* Enable/Disable the interrupt generator for data ready. */
46475d4c6d2SLorenzo Bianconi err = st_sensors_write_data_with_mask(indio_dev, drdy_addr,
465a7ee8839SDenis CIOCCA drdy_mask, (int)enable);
46623491b51SDenis Ciocca
46723491b51SDenis Ciocca st_accel_set_dataready_irq_error:
46823491b51SDenis Ciocca return err;
46923491b51SDenis Ciocca }
4700805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_set_dataready_irq, IIO_ST_SENSORS);
47123491b51SDenis Ciocca
st_sensors_set_fullscale_by_gain(struct iio_dev * indio_dev,int scale)47223491b51SDenis Ciocca int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
47323491b51SDenis Ciocca {
47423491b51SDenis Ciocca int err = -EINVAL, i;
47523491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
47623491b51SDenis Ciocca
47723491b51SDenis Ciocca for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
478a7ee8839SDenis CIOCCA if ((sdata->sensor_settings->fs.fs_avl[i].gain == scale) &&
479a7ee8839SDenis CIOCCA (sdata->sensor_settings->fs.fs_avl[i].gain != 0)) {
48023491b51SDenis Ciocca err = 0;
48123491b51SDenis Ciocca break;
48223491b51SDenis Ciocca }
48323491b51SDenis Ciocca }
48423491b51SDenis Ciocca if (err < 0)
48523491b51SDenis Ciocca goto st_sensors_match_scale_error;
48623491b51SDenis Ciocca
48723491b51SDenis Ciocca err = st_sensors_set_fullscale(indio_dev,
488a7ee8839SDenis CIOCCA sdata->sensor_settings->fs.fs_avl[i].num);
48923491b51SDenis Ciocca
49023491b51SDenis Ciocca st_sensors_match_scale_error:
49123491b51SDenis Ciocca return err;
49223491b51SDenis Ciocca }
4930805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_set_fullscale_by_gain, IIO_ST_SENSORS);
49423491b51SDenis Ciocca
st_sensors_read_axis_data(struct iio_dev * indio_dev,struct iio_chan_spec const * ch,int * data)49523491b51SDenis Ciocca static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
496607a568aSDenis CIOCCA struct iio_chan_spec const *ch, int *data)
49723491b51SDenis Ciocca {
49823491b51SDenis Ciocca int err;
499607a568aSDenis CIOCCA u8 *outdata;
50023491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
50165c8aea0SLorenzo Bianconi unsigned int byte_for_channel;
502607a568aSDenis CIOCCA
50365c8aea0SLorenzo Bianconi byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
50465c8aea0SLorenzo Bianconi ch->scan_type.shift, 8);
505062809efSDenis Ciocca outdata = kmalloc(byte_for_channel, GFP_DMA | GFP_KERNEL);
506caf5ca12SLee Jones if (!outdata)
507caf5ca12SLee Jones return -ENOMEM;
50823491b51SDenis Ciocca
509062809efSDenis Ciocca err = regmap_bulk_read(sdata->regmap, ch->address,
510062809efSDenis Ciocca outdata, byte_for_channel);
51123491b51SDenis Ciocca if (err < 0)
512607a568aSDenis CIOCCA goto st_sensors_free_memory;
51323491b51SDenis Ciocca
5144861a007SLinus Walleij if (byte_for_channel == 1)
5154861a007SLinus Walleij *data = (s8)*outdata;
5164861a007SLinus Walleij else if (byte_for_channel == 2)
51723491b51SDenis Ciocca *data = (s16)get_unaligned_le16(outdata);
518607a568aSDenis CIOCCA else if (byte_for_channel == 3)
5193009fb9cSAndy Shevchenko *data = (s32)sign_extend32(get_unaligned_le24(outdata), 23);
52023491b51SDenis Ciocca
521607a568aSDenis CIOCCA st_sensors_free_memory:
522607a568aSDenis CIOCCA kfree(outdata);
523caf5ca12SLee Jones
52423491b51SDenis Ciocca return err;
52523491b51SDenis Ciocca }
52623491b51SDenis Ciocca
st_sensors_read_info_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * ch,int * val)52723491b51SDenis Ciocca int st_sensors_read_info_raw(struct iio_dev *indio_dev,
52823491b51SDenis Ciocca struct iio_chan_spec const *ch, int *val)
52923491b51SDenis Ciocca {
53023491b51SDenis Ciocca int err;
53123491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
53223491b51SDenis Ciocca
5332da03b43SMiquel Raynal err = iio_device_claim_direct_mode(indio_dev);
5342da03b43SMiquel Raynal if (err)
5352da03b43SMiquel Raynal return err;
5362da03b43SMiquel Raynal
53747401012SMiquel Raynal mutex_lock(&sdata->odr_lock);
5382da03b43SMiquel Raynal
53923491b51SDenis Ciocca err = st_sensors_set_enable(indio_dev, true);
5402da03b43SMiquel Raynal if (err < 0)
5415bb8e72dSLee Jones goto out;
54223491b51SDenis Ciocca
543a7ee8839SDenis CIOCCA msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr);
544607a568aSDenis CIOCCA err = st_sensors_read_axis_data(indio_dev, ch, val);
5452da03b43SMiquel Raynal if (err < 0)
5465bb8e72dSLee Jones goto out;
54723491b51SDenis Ciocca
54823491b51SDenis Ciocca *val = *val >> ch->scan_type.shift;
549d61a04dcSDenis CIOCCA
550d61a04dcSDenis CIOCCA err = st_sensors_set_enable(indio_dev, false);
5512da03b43SMiquel Raynal
5525bb8e72dSLee Jones out:
5532da03b43SMiquel Raynal mutex_unlock(&sdata->odr_lock);
5542da03b43SMiquel Raynal iio_device_release_direct_mode(indio_dev);
55523491b51SDenis Ciocca
55623491b51SDenis Ciocca return err;
55723491b51SDenis Ciocca }
5580805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_read_info_raw, IIO_ST_SENSORS);
55923491b51SDenis Ciocca
560a090965bSDenis Ciocca /*
561a090965bSDenis Ciocca * st_sensors_get_settings_index() - get index of the sensor settings for a
562a090965bSDenis Ciocca * specific device from list of settings
563a090965bSDenis Ciocca * @name: device name buffer reference.
564a090965bSDenis Ciocca * @list: sensor settings list.
565a090965bSDenis Ciocca * @list_length: length of sensor settings list.
566a090965bSDenis Ciocca *
567a090965bSDenis Ciocca * Return: non negative number on success (valid index),
568a090965bSDenis Ciocca * negative error code otherwise.
569a090965bSDenis Ciocca */
st_sensors_get_settings_index(const char * name,const struct st_sensor_settings * list,const int list_length)570a090965bSDenis Ciocca int st_sensors_get_settings_index(const char *name,
571a090965bSDenis Ciocca const struct st_sensor_settings *list,
572a090965bSDenis Ciocca const int list_length)
573a090965bSDenis Ciocca {
574a090965bSDenis Ciocca int i, n;
575a090965bSDenis Ciocca
576a090965bSDenis Ciocca for (i = 0; i < list_length; i++) {
577a090965bSDenis Ciocca for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) {
578a090965bSDenis Ciocca if (strcmp(name, list[i].sensors_supported[n]) == 0)
579a090965bSDenis Ciocca return i;
580a090965bSDenis Ciocca }
581a090965bSDenis Ciocca }
582a090965bSDenis Ciocca
583a090965bSDenis Ciocca return -ENODEV;
584a090965bSDenis Ciocca }
5850805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_get_settings_index, IIO_ST_SENSORS);
586a090965bSDenis Ciocca
5871ecd245eSDenis Ciocca /*
5881ecd245eSDenis Ciocca * st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the
5891ecd245eSDenis Ciocca * expected value
5901ecd245eSDenis Ciocca * @indio_dev: IIO device reference.
5911ecd245eSDenis Ciocca *
5921ecd245eSDenis Ciocca * Return: 0 on success (valid sensor ID), else a negative error code.
5931ecd245eSDenis Ciocca */
st_sensors_verify_id(struct iio_dev * indio_dev)5941ecd245eSDenis Ciocca int st_sensors_verify_id(struct iio_dev *indio_dev)
59523491b51SDenis Ciocca {
59623491b51SDenis Ciocca struct st_sensor_data *sdata = iio_priv(indio_dev);
597062809efSDenis Ciocca int wai, err;
59823491b51SDenis Ciocca
5991ecd245eSDenis Ciocca if (sdata->sensor_settings->wai_addr) {
600062809efSDenis Ciocca err = regmap_read(sdata->regmap,
601062809efSDenis Ciocca sdata->sensor_settings->wai_addr, &wai);
60223491b51SDenis Ciocca if (err < 0) {
6034e68cfbfSJonathan Cameron dev_err(&indio_dev->dev,
6044e68cfbfSJonathan Cameron "failed to read Who-Am-I register.\n");
605bc27381eSGiuseppe Barba return err;
60623491b51SDenis Ciocca }
60723491b51SDenis Ciocca
6081ecd245eSDenis Ciocca if (sdata->sensor_settings->wai != wai) {
6094e68cfbfSJonathan Cameron dev_err(&indio_dev->dev,
6104e68cfbfSJonathan Cameron "%s: WhoAmI mismatch (0x%x).\n",
6115e02bac3SLinus Walleij indio_dev->name, wai);
612bc27381eSGiuseppe Barba return -EINVAL;
61323491b51SDenis Ciocca }
6144e68cfbfSJonathan Cameron }
61523491b51SDenis Ciocca
6161ecd245eSDenis Ciocca return 0;
61723491b51SDenis Ciocca }
6180805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_verify_id, IIO_ST_SENSORS);
61923491b51SDenis Ciocca
st_sensors_sysfs_sampling_frequency_avail(struct device * dev,struct device_attribute * attr,char * buf)62023491b51SDenis Ciocca ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
62123491b51SDenis Ciocca struct device_attribute *attr, char *buf)
62223491b51SDenis Ciocca {
6234d2e4fc2SDenis CIOCCA int i, len = 0;
6244498863cSLars-Peter Clausen struct iio_dev *indio_dev = dev_to_iio_dev(dev);
6254d2e4fc2SDenis CIOCCA struct st_sensor_data *sdata = iio_priv(indio_dev);
62623491b51SDenis Ciocca
6274d2e4fc2SDenis CIOCCA for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
628a7ee8839SDenis CIOCCA if (sdata->sensor_settings->odr.odr_avl[i].hz == 0)
6294d2e4fc2SDenis CIOCCA break;
6304d2e4fc2SDenis CIOCCA
6314d2e4fc2SDenis CIOCCA len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
632a7ee8839SDenis CIOCCA sdata->sensor_settings->odr.odr_avl[i].hz);
6334d2e4fc2SDenis CIOCCA }
6344d2e4fc2SDenis CIOCCA buf[len - 1] = '\n';
6354d2e4fc2SDenis CIOCCA
6364d2e4fc2SDenis CIOCCA return len;
63723491b51SDenis Ciocca }
6380805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_sysfs_sampling_frequency_avail, IIO_ST_SENSORS);
63923491b51SDenis Ciocca
st_sensors_sysfs_scale_avail(struct device * dev,struct device_attribute * attr,char * buf)64023491b51SDenis Ciocca ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
64123491b51SDenis Ciocca struct device_attribute *attr, char *buf)
64223491b51SDenis Ciocca {
643d304286aSLorenzo Bianconi int i, len = 0, q, r;
6444498863cSLars-Peter Clausen struct iio_dev *indio_dev = dev_to_iio_dev(dev);
6454d2e4fc2SDenis CIOCCA struct st_sensor_data *sdata = iio_priv(indio_dev);
64623491b51SDenis Ciocca
6474d2e4fc2SDenis CIOCCA for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
648a7ee8839SDenis CIOCCA if (sdata->sensor_settings->fs.fs_avl[i].num == 0)
6494d2e4fc2SDenis CIOCCA break;
6504d2e4fc2SDenis CIOCCA
651d304286aSLorenzo Bianconi q = sdata->sensor_settings->fs.fs_avl[i].gain / 1000000;
652d304286aSLorenzo Bianconi r = sdata->sensor_settings->fs.fs_avl[i].gain % 1000000;
653d304286aSLorenzo Bianconi
654d304286aSLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ", q, r);
6554d2e4fc2SDenis CIOCCA }
6564d2e4fc2SDenis CIOCCA buf[len - 1] = '\n';
6574d2e4fc2SDenis CIOCCA
6584d2e4fc2SDenis CIOCCA return len;
65923491b51SDenis Ciocca }
6600805b512SJonathan Cameron EXPORT_SYMBOL_NS(st_sensors_sysfs_scale_avail, IIO_ST_SENSORS);
66123491b51SDenis Ciocca
66223491b51SDenis Ciocca MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
66323491b51SDenis Ciocca MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
66423491b51SDenis Ciocca MODULE_LICENSE("GPL v2");
665