diff options
Diffstat (limited to 'drivers/iio/gyro/st_gyro_core.c')
| -rw-r--r-- | drivers/iio/gyro/st_gyro_core.c | 225 |
1 files changed, 145 insertions, 80 deletions
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index b31064ba37b9..7fd82cd707c7 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -1,28 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * STMicroelectronics gyroscopes driver * * Copyright 2012-2013 STMicroelectronics Inc. * * Denis Ciocca <denis.ciocca@st.com> - * - * Licensed under the GPL-2. */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> #include <linux/mutex.h> #include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/gpio.h> -#include <linux/irq.h> -#include <linux/delay.h> +#include <linux/sysfs.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> -#include <linux/iio/buffer.h> #include <linux/iio/common/st_sensors.h> #include "st_gyro.h" @@ -40,19 +32,36 @@ #define ST_GYRO_FS_AVL_500DPS 500 #define ST_GYRO_FS_AVL_2000DPS 2000 +static const struct iio_mount_matrix * +st_gyro_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct st_sensor_data *gdata = iio_priv(indio_dev); + + return &gdata->mount_matrix; +} + +static const struct iio_chan_spec_ext_info st_gyro_mount_matrix_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_gyro_get_mount_matrix), + { } +}; + static const struct iio_chan_spec st_gyro_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, - ST_GYRO_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + ST_GYRO_DEFAULT_OUT_X_L_ADDR, + st_gyro_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, - ST_GYRO_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + ST_GYRO_DEFAULT_OUT_Y_L_ADDR, + st_gyro_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, - ST_GYRO_DEFAULT_OUT_Z_L_ADDR), + ST_GYRO_DEFAULT_OUT_Z_L_ADDR, + st_gyro_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; @@ -141,7 +150,6 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { [2] = LSM330DLC_GYRO_DEV_NAME, [3] = L3G4IS_GYRO_DEV_NAME, [4] = LSM330_GYRO_DEV_NAME, - [5] = LSM9DS0_GYRO_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_gyro_16bit_channels, .odr = { @@ -212,6 +220,80 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { .bootime = 2, }, { + .wai = 0xd4, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LSM9DS0_GYRO_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_gyro_16bit_channels, + .odr = { + .addr = 0x20, + .mask = GENMASK(7, 6), + .odr_avl = { + { .hz = 95, .value = 0x00, }, + { .hz = 190, .value = 0x01, }, + { .hz = 380, .value = 0x02, }, + { .hz = 760, .value = 0x03, }, + }, + }, + .pw = { + .addr = 0x20, + .mask = BIT(3), + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = 0x23, + .mask = GENMASK(5, 4), + .fs_avl = { + [0] = { + .num = ST_GYRO_FS_AVL_245DPS, + .value = 0x00, + .gain = IIO_DEGREE_TO_RAD(8750), + }, + [1] = { + .num = ST_GYRO_FS_AVL_500DPS, + .value = 0x01, + .gain = IIO_DEGREE_TO_RAD(17500), + }, + [2] = { + .num = ST_GYRO_FS_AVL_2000DPS, + .value = 0x02, + .gain = IIO_DEGREE_TO_RAD(70000), + }, + }, + }, + .bdu = { + .addr = 0x23, + .mask = BIT(7), + }, + .drdy_irq = { + .int2 = { + .addr = 0x22, + .mask = BIT(3), + }, + /* + * The sensor has IHL (active low) and open + * drain settings, but only for INT1 and not + * for the DRDY line on INT2. + */ + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = GENMASK(2, 0), + }, + }, + .sim = { + .addr = 0x23, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, + { .wai = 0xd7, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { @@ -287,6 +369,11 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, }; +/* DRDY on gyros is available only on INT2 pin */ +static const struct st_sensors_platform_data gyro_pdata = { + .drdy_int_pin = 2, +}; + static int st_gyro_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) @@ -319,24 +406,17 @@ read_error: static int st_gyro_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int err; - switch (mask) { case IIO_CHAN_INFO_SCALE: - err = st_sensors_set_fullscale_by_gain(indio_dev, val2); - break; + return st_sensors_set_fullscale_by_gain(indio_dev, val2); case IIO_CHAN_INFO_SAMP_FREQ: if (val2) return -EINVAL; - mutex_lock(&indio_dev->mlock); - err = st_sensors_set_odr(indio_dev, val); - mutex_unlock(&indio_dev->mlock); - return err; + + return st_sensors_set_odr(indio_dev, val); default: - err = -EINVAL; + return -EINVAL; } - - return err; } static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL(); @@ -369,86 +449,71 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = { #define ST_GYRO_TRIGGER_OPS NULL #endif +/* + * st_gyro_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_gyro_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_gyro_sensors_settings, + ARRAY_SIZE(st_gyro_sensors_settings)); + if (index < 0) + return NULL; + + return &st_gyro_sensors_settings[index]; +} +EXPORT_SYMBOL_NS(st_gyro_get_settings, "IIO_ST_SENSORS"); + int st_gyro_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *gdata = iio_priv(indio_dev); - int irq = gdata->get_irq_data_ready(indio_dev); + struct st_sensors_platform_data *pdata; + struct device *parent = indio_dev->dev.parent; int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; - mutex_init(&gdata->tb.buf_lock); - - err = st_sensors_power_enable(indio_dev); - if (err) - return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_gyro_sensors_settings), - st_gyro_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) - goto st_gyro_power_off; + return err; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; - gdata->multiread_bit = gdata->sensor_settings->multi_read_bit; indio_dev->channels = gdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; - gdata->current_fullscale = (struct st_sensor_fullscale_avl *) - &gdata->sensor_settings->fs.fs_avl[0]; + err = iio_read_mount_matrix(parent, &gdata->mount_matrix); + if (err) + return err; + + gdata->current_fullscale = &gdata->sensor_settings->fs.fs_avl[0]; gdata->odr = gdata->sensor_settings->odr.odr_avl[0].hz; - err = st_sensors_init_sensor(indio_dev, - (struct st_sensors_platform_data *)&gyro_pdata); + pdata = (struct st_sensors_platform_data *)&gyro_pdata; + + err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_gyro_power_off; + return err; err = st_gyro_allocate_ring(indio_dev); if (err < 0) - goto st_gyro_power_off; + return err; - if (irq > 0) { + if (gdata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_GYRO_TRIGGER_OPS); if (err < 0) - goto st_gyro_probe_trigger_error; + return err; } - err = iio_device_register(indio_dev); - if (err) - goto st_gyro_device_register_error; - - dev_info(&indio_dev->dev, "registered gyroscope %s\n", - indio_dev->name); - - return 0; - -st_gyro_device_register_error: - if (irq > 0) - st_sensors_deallocate_trigger(indio_dev); -st_gyro_probe_trigger_error: - st_gyro_deallocate_ring(indio_dev); -st_gyro_power_off: - st_sensors_power_disable(indio_dev); - - return err; -} -EXPORT_SYMBOL(st_gyro_common_probe); - -void st_gyro_common_remove(struct iio_dev *indio_dev) -{ - struct st_sensor_data *gdata = iio_priv(indio_dev); - - st_sensors_power_disable(indio_dev); - - iio_device_unregister(indio_dev); - if (gdata->get_irq_data_ready(indio_dev) > 0) - st_sensors_deallocate_trigger(indio_dev); - - st_gyro_deallocate_ring(indio_dev); + return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL(st_gyro_common_remove); +EXPORT_SYMBOL_NS(st_gyro_common_probe, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics gyroscopes driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); |
