diff options
Diffstat (limited to 'drivers/iio/accel')
76 files changed, 4401 insertions, 1178 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index c2da5066e9a7..8c3f7cf55d5f 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -177,6 +177,33 @@ config ADXL372_I2C To compile this driver as a module, choose M here: the module will be called adxl372_i2c. +config ADXL380 + tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + +config ADXL380_SPI + tristate "Analog Devices ADXL380 3-Axis Accelerometer SPI Driver" + depends on SPI + select ADXL380 + select REGMAP_SPI + help + Say yes here to add support for the Analog Devices ADXL380 triaxial + acceleration sensor. + To compile this driver as a module, choose M here: the + module will be called adxl380_spi. + +config ADXL380_I2C + tristate "Analog Devices ADXL380 3-Axis Accelerometer I2C Driver" + depends on I2C + select ADXL380 + select REGMAP_I2C + help + Say yes here to add support for the Analog Devices ADXL380 triaxial + acceleration sensor. + To compile this driver as a module, choose M here: the + module will be called adxl380_i2c. + config BMA180 tristate "Bosch BMA023/BMA1x0/BMA250 3-Axis Accelerometer Driver" depends on I2C && INPUT_BMA150=n @@ -330,6 +357,8 @@ config DMARD10 config FXLS8962AF tristate depends on I2C || !I2C # cannot be built-in for modular I2C + select IIO_BUFFER + select IIO_KFIFO_BUF config FXLS8962AF_I2C tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver" @@ -418,6 +447,8 @@ config IIO_ST_ACCEL_SPI_3AXIS config IIO_KX022A tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER config IIO_KX022A_SPI tristate "Kionix KX022A tri-axis digital accelerometer SPI interface" diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index db90532ba24a..ca8569e25aba 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -21,6 +21,9 @@ obj-$(CONFIG_ADXL367_SPI) += adxl367_spi.o obj-$(CONFIG_ADXL372) += adxl372.o obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o +obj-$(CONFIG_ADXL380) += adxl380.o +obj-$(CONFIG_ADXL380_I2C) += adxl380_i2c.o +obj-$(CONFIG_ADXL380_SPI) += adxl380_spi.o obj-$(CONFIG_BMA180) += bma180.o obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMA400) += bma400_core.o diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index d054721859b3..5127e58eebc7 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -211,9 +211,9 @@ static const struct iio_chan_spec adis16201_channels[] = { BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12), ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), IIO_CHAN_SOFT_TIMESTAMP(7) }; @@ -300,4 +300,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16201"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c index 0035e4f4db63..41ffd92f27fd 100644 --- a/drivers/iio/accel/adis16209.c +++ b/drivers/iio/accel/adis16209.c @@ -310,4 +310,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16209"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index 4de0a41bd679..46cca10e776f 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -32,19 +32,19 @@ const struct regmap_access_table adxl312_readable_regs_table = { .yes_ranges = adxl312_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl312_readable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl312_readable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl313_readable_regs_table = { .yes_ranges = adxl313_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl314_readable_regs_table = { .yes_ranges = adxl312_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, "IIO_ADXL313"); static int adxl312_check_id(struct device *dev, struct adxl313_data *data) @@ -121,7 +121,7 @@ const struct adxl313_chip_info adxl31x_chip_info[] = { .check_id = &adxl312_check_id, }, }; -EXPORT_SYMBOL_NS_GPL(adxl31x_chip_info, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl31x_chip_info, "IIO_ADXL313"); static const struct regmap_range adxl312_writable_reg_range[] = { regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)), @@ -144,19 +144,19 @@ const struct regmap_access_table adxl312_writable_regs_table = { .yes_ranges = adxl312_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl312_writable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl312_writable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl313_writable_regs_table = { .yes_ranges = adxl313_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl314_writable_regs_table = { .yes_ranges = adxl312_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl314_writable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl314_writable_regs_table, "IIO_ADXL313"); static const int adxl313_odr_freqs[][2] = { [0] = { 6, 250000 }, @@ -417,7 +417,7 @@ int adxl313_core_probe(struct device *dev, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, "IIO_ADXL313"); MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>"); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index a4cf0cf2c5aa..dfa51860cd83 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -92,4 +92,4 @@ module_i2c_driver(adxl313_i2c_driver); MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>"); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL313); +MODULE_IMPORT_NS("IIO_ADXL313"); diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index b7cc15678a2b..ebc5d09f108d 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -72,13 +72,7 @@ static int adxl313_spi_probe(struct spi_device *spi) if (ret) return ret; - /* - * Retrieves device specific data as a pointer to a - * adxl313_chip_info structure - */ - chip_data = device_get_match_data(&spi->dev); - if (!chip_data) - chip_data = (const struct adxl313_chip_info *)spi_get_device_id(spi)->driver_data; + chip_data = spi_get_device_match_data(spi); regmap = devm_regmap_init_spi(spi, &adxl31x_spi_regmap_config[chip_data->type]); @@ -125,4 +119,4 @@ module_spi_driver(adxl313_spi_driver); MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>"); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL313); +MODULE_IMPORT_NS("IIO_ADXL313"); diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 284bd387ce69..7d482dd595fa 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -8,6 +8,94 @@ #ifndef _ADXL345_H_ #define _ADXL345_H_ +#define ADXL345_REG_DEVID 0x00 +#define ADXL345_REG_THRESH_TAP 0x1D +#define ADXL345_REG_OFSX 0x1E +#define ADXL345_REG_OFSY 0x1F +#define ADXL345_REG_OFSZ 0x20 +#define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index)) + +/* Tap duration */ +#define ADXL345_REG_DUR 0x21 +/* Tap latency */ +#define ADXL345_REG_LATENT 0x22 +/* Tap window */ +#define ADXL345_REG_WINDOW 0x23 +/* Activity threshold */ +#define ADXL345_REG_THRESH_ACT 0x24 +/* Inactivity threshold */ +#define ADXL345_REG_THRESH_INACT 0x25 +/* Inactivity time */ +#define ADXL345_REG_TIME_INACT 0x26 +/* Axis enable control for activity and inactivity detection */ +#define ADXL345_REG_ACT_INACT_CTRL 0x27 +/* Free-fall threshold */ +#define ADXL345_REG_THRESH_FF 0x28 +/* Free-fall time */ +#define ADXL345_REG_TIME_FF 0x29 +/* Axis control for single tap or double tap */ +#define ADXL345_REG_TAP_AXIS 0x2A +/* Source of single tap or double tap */ +#define ADXL345_REG_ACT_TAP_STATUS 0x2B +/* Data rate and power mode control */ +#define ADXL345_REG_BW_RATE 0x2C +#define ADXL345_REG_POWER_CTL 0x2D +#define ADXL345_REG_INT_ENABLE 0x2E +#define ADXL345_REG_INT_MAP 0x2F +#define ADXL345_REG_INT_SOURCE 0x30 +#define ADXL345_REG_DATA_FORMAT 0x31 +#define ADXL345_REG_XYZ_BASE 0x32 +#define ADXL345_REG_DATA_AXIS(index) \ + (ADXL345_REG_XYZ_BASE + (index) * sizeof(__le16)) + +#define ADXL345_REG_FIFO_CTL 0x38 +#define ADXL345_FIFO_CTL_SAMPLES_MSK GENMASK(4, 0) +/* 0: INT1, 1: INT2 */ +#define ADXL345_FIFO_CTL_TRIGGER_MSK BIT(5) +#define ADXL345_FIFO_CTL_MODE_MSK GENMASK(7, 6) +#define ADXL345_REG_FIFO_STATUS 0x39 +#define ADXL345_REG_FIFO_STATUS_MSK 0x3F + +#define ADXL345_INT_OVERRUN BIT(0) +#define ADXL345_INT_WATERMARK BIT(1) +#define ADXL345_INT_FREE_FALL BIT(2) +#define ADXL345_INT_INACTIVITY BIT(3) +#define ADXL345_INT_ACTIVITY BIT(4) +#define ADXL345_INT_DOUBLE_TAP BIT(5) +#define ADXL345_INT_SINGLE_TAP BIT(6) +#define ADXL345_INT_DATA_READY BIT(7) + +/* + * BW_RATE bits - Bandwidth and output data rate. The default value is + * 0x0A, which translates to a 100 Hz output data rate + */ +#define ADXL345_BW_RATE GENMASK(3, 0) +#define ADXL345_BW_LOW_POWER BIT(4) +#define ADXL345_BASE_RATE_NANO_HZ 97656250LL + +#define ADXL345_POWER_CTL_STANDBY 0x00 +#define ADXL345_POWER_CTL_WAKEUP GENMASK(1, 0) +#define ADXL345_POWER_CTL_SLEEP BIT(2) +#define ADXL345_POWER_CTL_MEASURE BIT(3) +#define ADXL345_POWER_CTL_AUTO_SLEEP BIT(4) +#define ADXL345_POWER_CTL_LINK BIT(5) + +/* Set the g range */ +#define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) +/* Data is left justified */ +#define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) +/* Up to 13-bits resolution */ +#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) +#define ADXL345_DATA_FORMAT_SPI_3WIRE BIT(6) +#define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) +#define ADXL345_DATA_FORMAT_2G 0 +#define ADXL345_DATA_FORMAT_4G 1 +#define ADXL345_DATA_FORMAT_8G 2 +#define ADXL345_DATA_FORMAT_16G 3 + +#define ADXL345_DEVID 0xE5 +#define ADXL345_FIFO_SIZE 32 + /* * In full-resolution mode, scale factor is maintained at ~4 mg/LSB * in all g ranges. @@ -23,11 +111,17 @@ */ #define ADXL375_USCALE 480000 +struct regmap; + +bool adxl345_is_volatile_reg(struct device *dev, unsigned int reg); + struct adxl345_chip_info { const char *name; int uscale; }; -int adxl345_core_probe(struct device *dev, struct regmap *regmap); +int adxl345_core_probe(struct device *dev, struct regmap *regmap, + bool fifo_delay_default, + int (*setup)(struct device*, struct regmap*)); #endif /* _ADXL345_H_ */ diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 8bd30a23ed3b..2e5fdd479e8d 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -7,6 +7,9 @@ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf */ +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/property.h> #include <linux/regmap.h> @@ -14,65 +17,377 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/kfifo_buf.h> #include "adxl345.h" -#define ADXL345_REG_DEVID 0x00 -#define ADXL345_REG_OFSX 0x1e -#define ADXL345_REG_OFSY 0x1f -#define ADXL345_REG_OFSZ 0x20 -#define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index)) -#define ADXL345_REG_BW_RATE 0x2C -#define ADXL345_REG_POWER_CTL 0x2D -#define ADXL345_REG_DATA_FORMAT 0x31 -#define ADXL345_REG_DATAX0 0x32 -#define ADXL345_REG_DATAY0 0x34 -#define ADXL345_REG_DATAZ0 0x36 -#define ADXL345_REG_DATA_AXIS(index) \ - (ADXL345_REG_DATAX0 + (index) * sizeof(__le16)) - -#define ADXL345_BW_RATE GENMASK(3, 0) -#define ADXL345_BASE_RATE_NANO_HZ 97656250LL - -#define ADXL345_POWER_CTL_MEASURE BIT(3) -#define ADXL345_POWER_CTL_STANDBY 0x00 - -#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ -#define ADXL345_DATA_FORMAT_2G 0 -#define ADXL345_DATA_FORMAT_4G 1 -#define ADXL345_DATA_FORMAT_8G 2 -#define ADXL345_DATA_FORMAT_16G 3 - -#define ADXL345_DEVID 0xE5 - -struct adxl345_data { +#define ADXL345_FIFO_BYPASS 0 +#define ADXL345_FIFO_FIFO 1 +#define ADXL345_FIFO_STREAM 2 + +#define ADXL345_DIRS 3 + +#define ADXL345_INT_NONE 0xff +#define ADXL345_INT1 0 +#define ADXL345_INT2 1 + +#define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0) +#define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3) +#define ADXL345_REG_TAP_SUPPRESS BIT(3) + +#define ADXL345_TAP_Z_EN BIT(0) +#define ADXL345_TAP_Y_EN BIT(1) +#define ADXL345_TAP_X_EN BIT(2) + +/* single/double tap */ +enum adxl345_tap_type { + ADXL345_SINGLE_TAP, + ADXL345_DOUBLE_TAP, +}; + +static const unsigned int adxl345_tap_int_reg[] = { + [ADXL345_SINGLE_TAP] = ADXL345_INT_SINGLE_TAP, + [ADXL345_DOUBLE_TAP] = ADXL345_INT_DOUBLE_TAP, +}; + +enum adxl345_tap_time_type { + ADXL345_TAP_TIME_LATENT, + ADXL345_TAP_TIME_WINDOW, + ADXL345_TAP_TIME_DUR, +}; + +static const unsigned int adxl345_tap_time_reg[] = { + [ADXL345_TAP_TIME_LATENT] = ADXL345_REG_LATENT, + [ADXL345_TAP_TIME_WINDOW] = ADXL345_REG_WINDOW, + [ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR, +}; + +struct adxl345_state { const struct adxl345_chip_info *info; struct regmap *regmap; - u8 data_range; + bool fifo_delay; /* delay: delay is needed for SPI */ + int irq; + u8 watermark; + u8 fifo_mode; + + u32 tap_duration_us; + u32 tap_latent_us; + u32 tap_window_us; + + __le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN); }; -#define ADXL345_CHANNEL(index, axis) { \ +static struct iio_event_spec adxl345_events[] = { + { + /* single tap */ + .type = IIO_EV_TYPE_GESTURE, + .dir = IIO_EV_DIR_SINGLETAP, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_TIMEOUT), + }, + { + /* double tap */ + .type = IIO_EV_TYPE_GESTURE, + .dir = IIO_EV_DIR_DOUBLETAP, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_RESET_TIMEOUT) | + BIT(IIO_EV_INFO_TAP2_MIN_DELAY), + }, +}; + +#define ADXL345_CHANNEL(index, reg, axis) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .address = index, \ + .address = (reg), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = (index), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 13, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ + .event_spec = adxl345_events, \ + .num_event_specs = ARRAY_SIZE(adxl345_events), \ } +enum adxl345_chans { + chan_x, chan_y, chan_z, +}; + static const struct iio_chan_spec adxl345_channels[] = { - ADXL345_CHANNEL(0, X), - ADXL345_CHANNEL(1, Y), - ADXL345_CHANNEL(2, Z), + ADXL345_CHANNEL(0, chan_x, X), + ADXL345_CHANNEL(1, chan_y, Y), + ADXL345_CHANNEL(2, chan_z, Z), }; +static const unsigned long adxl345_scan_masks[] = { + BIT(chan_x) | BIT(chan_y) | BIT(chan_z), + 0 +}; + +bool adxl345_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADXL345_REG_DATA_AXIS(0): + case ADXL345_REG_DATA_AXIS(1): + case ADXL345_REG_DATA_AXIS(2): + case ADXL345_REG_DATA_AXIS(3): + case ADXL345_REG_DATA_AXIS(4): + case ADXL345_REG_DATA_AXIS(5): + case ADXL345_REG_ACT_TAP_STATUS: + case ADXL345_REG_FIFO_STATUS: + case ADXL345_REG_INT_SOURCE: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_NS_GPL(adxl345_is_volatile_reg, "IIO_ADXL345"); + +/** + * adxl345_set_measure_en() - Enable and disable measuring. + * + * @st: The device data. + * @en: Enable measurements, else standby mode. + * + * For lowest power operation, standby mode can be used. In standby mode, + * current consumption is supposed to be reduced to 0.1uA (typical). In this + * mode no measurements are made. Placing the device into standby mode + * preserves the contents of FIFO. + * + * Return: Returns 0 if successful, or a negative error value. + */ +static int adxl345_set_measure_en(struct adxl345_state *st, bool en) +{ + unsigned int val = en ? ADXL345_POWER_CTL_MEASURE : ADXL345_POWER_CTL_STANDBY; + + return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val); +} + +/* tap */ + +static int _adxl345_set_tap_int(struct adxl345_state *st, + enum adxl345_tap_type type, bool state) +{ + unsigned int int_map = 0x00; + unsigned int tap_threshold; + bool axis_valid; + bool singletap_args_valid = false; + bool doubletap_args_valid = false; + bool en = false; + u32 axis_ctrl; + int ret; + + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); + if (ret) + return ret; + + axis_valid = FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) > 0; + + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, &tap_threshold); + if (ret) + return ret; + + /* + * Note: A value of 0 for threshold and/or dur may result in undesirable + * behavior if single tap/double tap interrupts are enabled. + */ + singletap_args_valid = tap_threshold > 0 && st->tap_duration_us > 0; + + if (type == ADXL345_SINGLE_TAP) { + en = axis_valid && singletap_args_valid; + } else { + /* doubletap: Window must be equal or greater than latent! */ + doubletap_args_valid = st->tap_latent_us > 0 && + st->tap_window_us > 0 && + st->tap_window_us >= st->tap_latent_us; + + en = axis_valid && singletap_args_valid && doubletap_args_valid; + } + + if (state && en) + int_map |= adxl345_tap_int_reg[type]; + + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, + adxl345_tap_int_reg[type], int_map); +} + +static int adxl345_is_tap_en(struct adxl345_state *st, + enum iio_modifier axis, + enum adxl345_tap_type type, bool *en) +{ + unsigned int regval; + u32 axis_ctrl; + int ret; + + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); + if (ret) + return ret; + + /* Verify if axis is enabled for the tap detection. */ + switch (axis) { + case IIO_MOD_X: + *en = FIELD_GET(ADXL345_TAP_X_EN, axis_ctrl); + break; + case IIO_MOD_Y: + *en = FIELD_GET(ADXL345_TAP_Y_EN, axis_ctrl); + break; + case IIO_MOD_Z: + *en = FIELD_GET(ADXL345_TAP_Z_EN, axis_ctrl); + break; + default: + *en = false; + return -EINVAL; + } + + if (*en) { + /* + * If axis allow for tap detection, verify if the interrupt is + * enabled for tap detection. + */ + ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val); + if (ret) + return ret; + + *en = adxl345_tap_int_reg[type] & regval; + } + + return 0; +} + +static int adxl345_set_singletap_en(struct adxl345_state *st, + enum iio_modifier axis, bool en) +{ + int ret; + u32 axis_ctrl; + + switch (axis) { + case IIO_MOD_X: + axis_ctrl = ADXL345_TAP_X_EN; + break; + case IIO_MOD_Y: + axis_ctrl = ADXL345_TAP_Y_EN; + break; + case IIO_MOD_Z: + axis_ctrl = ADXL345_TAP_Z_EN; + break; + default: + return -EINVAL; + } + + if (en) + ret = regmap_set_bits(st->regmap, ADXL345_REG_TAP_AXIS, + axis_ctrl); + else + ret = regmap_clear_bits(st->regmap, ADXL345_REG_TAP_AXIS, + axis_ctrl); + if (ret) + return ret; + + return _adxl345_set_tap_int(st, ADXL345_SINGLE_TAP, en); +} + +static int adxl345_set_doubletap_en(struct adxl345_state *st, bool en) +{ + int ret; + + /* + * Generally suppress detection of spikes during the latency period as + * double taps here, this is fully optional for double tap detection + */ + ret = regmap_update_bits(st->regmap, ADXL345_REG_TAP_AXIS, + ADXL345_REG_TAP_SUPPRESS_MSK, + en ? ADXL345_REG_TAP_SUPPRESS : 0x00); + if (ret) + return ret; + + return _adxl345_set_tap_int(st, ADXL345_DOUBLE_TAP, en); +} + +static int _adxl345_set_tap_time(struct adxl345_state *st, + enum adxl345_tap_time_type type, u32 val_us) +{ + unsigned int regval; + + switch (type) { + case ADXL345_TAP_TIME_WINDOW: + st->tap_window_us = val_us; + break; + case ADXL345_TAP_TIME_LATENT: + st->tap_latent_us = val_us; + break; + case ADXL345_TAP_TIME_DUR: + st->tap_duration_us = val_us; + break; + } + + /* + * The scale factor is 1250us / LSB for tap_window_us and tap_latent_us. + * For tap_duration_us the scale factor is 625us / LSB. + */ + if (type == ADXL345_TAP_TIME_DUR) + regval = DIV_ROUND_CLOSEST(val_us, 625); + else + regval = DIV_ROUND_CLOSEST(val_us, 1250); + + return regmap_write(st->regmap, adxl345_tap_time_reg[type], regval); +} + +static int adxl345_set_tap_duration(struct adxl345_state *st, u32 val_int, + u32 val_fract_us) +{ + /* + * Max value is 255 * 625 us = 0.159375 seconds + * + * Note: the scaling is similar to the scaling in the ADXL380 + */ + if (val_int || val_fract_us > 159375) + return -EINVAL; + + return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_DUR, val_fract_us); +} + +static int adxl345_set_tap_window(struct adxl345_state *st, u32 val_int, + u32 val_fract_us) +{ + /* + * Max value is 255 * 1250 us = 0.318750 seconds + * + * Note: the scaling is similar to the scaling in the ADXL380 + */ + if (val_int || val_fract_us > 318750) + return -EINVAL; + + return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_WINDOW, val_fract_us); +} + +static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int, + u32 val_fract_us) +{ + /* + * Max value is 255 * 1250 us = 0.318750 seconds + * + * Note: the scaling is similar to the scaling in the ADXL380 + */ + if (val_int || val_fract_us > 318750) + return -EINVAL; + + return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us); +} + static int adxl345_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - struct adxl345_data *data = iio_priv(indio_dev); + struct adxl345_state *st = iio_priv(indio_dev); __le16 accel; long long samp_freq_nhz; unsigned int regval; @@ -85,22 +400,22 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte */ - ret = regmap_bulk_read(data->regmap, + ret = regmap_bulk_read(st->regmap, ADXL345_REG_DATA_AXIS(chan->address), &accel, sizeof(accel)); - if (ret < 0) + if (ret) return ret; *val = sign_extend32(le16_to_cpu(accel), 12); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = data->info->uscale; + *val2 = st->info->uscale; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS: - ret = regmap_read(data->regmap, + ret = regmap_read(st->regmap, ADXL345_REG_OFS_AXIS(chan->address), ®val); - if (ret < 0) + if (ret) return ret; /* * 8-bit resolution at +/- 2g, that is 4x accel data scale @@ -110,8 +425,8 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: - ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, ®val); - if (ret < 0) + ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); + if (ret) return ret; samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ << @@ -128,7 +443,7 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - struct adxl345_data *data = iio_priv(indio_dev); + struct adxl345_state *st = iio_priv(indio_dev); s64 n; switch (mask) { @@ -137,14 +452,14 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, * 8-bit resolution at +/- 2g, that is 4x accel data scale * factor */ - return regmap_write(data->regmap, + return regmap_write(st->regmap, ADXL345_REG_OFS_AXIS(chan->address), val / 4); case IIO_CHAN_INFO_SAMP_FREQ: n = div_s64(val * NANOHZ_PER_HZ + val2, ADXL345_BASE_RATE_NANO_HZ); - return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE, + return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, ADXL345_BW_RATE, clamp_val(ilog2(n), 0, ADXL345_BW_RATE)); @@ -153,6 +468,184 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, return -EINVAL; } +static int adxl345_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct adxl345_state *st = iio_priv(indio_dev); + bool int_en; + int ret; + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (dir) { + case IIO_EV_DIR_SINGLETAP: + ret = adxl345_is_tap_en(st, chan->channel2, + ADXL345_SINGLE_TAP, &int_en); + if (ret) + return ret; + return int_en; + case IIO_EV_DIR_DOUBLETAP: + ret = adxl345_is_tap_en(st, chan->channel2, + ADXL345_DOUBLE_TAP, &int_en); + if (ret) + return ret; + return int_en; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct adxl345_state *st = iio_priv(indio_dev); + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (dir) { + case IIO_EV_DIR_SINGLETAP: + return adxl345_set_singletap_en(st, chan->channel2, state); + case IIO_EV_DIR_DOUBLETAP: + return adxl345_set_doubletap_en(st, state); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct adxl345_state *st = iio_priv(indio_dev); + unsigned int tap_threshold; + int ret; + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (info) { + case IIO_EV_INFO_VALUE: + /* + * The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but + * not applied here. In context of this general purpose sensor, + * what imports is rather signal intensity than the absolute + * measured g value. + */ + ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, + &tap_threshold); + if (ret) + return ret; + *val = sign_extend32(tap_threshold, 7); + return IIO_VAL_INT; + case IIO_EV_INFO_TIMEOUT: + *val = st->tap_duration_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_INFO_RESET_TIMEOUT: + *val = st->tap_window_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_INFO_TAP2_MIN_DELAY: + *val = st->tap_latent_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct adxl345_state *st = iio_priv(indio_dev); + int ret; + + ret = adxl345_set_measure_en(st, false); + if (ret) + return ret; + + switch (type) { + case IIO_EV_TYPE_GESTURE: + switch (info) { + case IIO_EV_INFO_VALUE: + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, + min(val, 0xFF)); + if (ret) + return ret; + break; + case IIO_EV_INFO_TIMEOUT: + ret = adxl345_set_tap_duration(st, val, val2); + if (ret) + return ret; + break; + case IIO_EV_INFO_RESET_TIMEOUT: + ret = adxl345_set_tap_window(st, val, val2); + if (ret) + return ret; + break; + case IIO_EV_INFO_TAP2_MIN_DELAY: + ret = adxl345_set_tap_latent(st, val, val2); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return adxl345_set_measure_en(st, true); +} + +static int adxl345_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct adxl345_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + return regmap_write(st->regmap, reg, writeval); +} + +static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value) +{ + struct adxl345_state *st = iio_priv(indio_dev); + const unsigned int fifo_mask = 0x1F, watermark_mask = 0x02; + int ret; + + value = min(value, ADXL345_FIFO_SIZE - 1); + + ret = regmap_update_bits(st->regmap, ADXL345_REG_FIFO_CTL, fifo_mask, value); + if (ret) + return ret; + + st->watermark = value; + return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE, + watermark_mask, ADXL345_INT_WATERMARK); +} + static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) @@ -167,6 +660,13 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev, } } +static void adxl345_powerdown(void *ptr) +{ + struct adxl345_state *st = ptr; + + adxl345_set_measure_en(st, false); +} + static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( "0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200" ); @@ -180,73 +680,416 @@ static const struct attribute_group adxl345_attrs_group = { .attrs = adxl345_attrs, }; -static const struct iio_info adxl345_info = { - .attrs = &adxl345_attrs_group, - .read_raw = adxl345_read_raw, - .write_raw = adxl345_write_raw, - .write_raw_get_fmt = adxl345_write_raw_get_fmt, +static int adxl345_set_fifo(struct adxl345_state *st) +{ + unsigned int intio; + int ret; + + /* FIFO should only be configured while in standby mode */ + ret = adxl345_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADXL345_REG_INT_MAP, &intio); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL, + FIELD_PREP(ADXL345_FIFO_CTL_SAMPLES_MSK, + st->watermark) | + FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK, intio) | + FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK, + st->fifo_mode)); + if (ret) + return ret; + + return adxl345_set_measure_en(st, true); +} + +/** + * adxl345_get_samples() - Read number of FIFO entries. + * @st: The initialized state instance of this driver. + * + * The sensor does not support treating any axis individually, or exclude them + * from measuring. + * + * Return: negative error, or value. + */ +static int adxl345_get_samples(struct adxl345_state *st) +{ + unsigned int regval = 0; + int ret; + + ret = regmap_read(st->regmap, ADXL345_REG_FIFO_STATUS, ®val); + if (ret) + return ret; + + return FIELD_GET(ADXL345_REG_FIFO_STATUS_MSK, regval); +} + +/** + * adxl345_fifo_transfer() - Read samples number of elements. + * @st: The instance of the state object of this sensor. + * @samples: The number of lines in the FIFO referred to as fifo_entry. + * + * It is recommended that a multiple-byte read of all registers be performed to + * prevent a change in data between reads of sequential registers. That is to + * read out the data registers X0, X1, Y0, Y1, Z0, Z1, i.e. 6 bytes at once. + * + * Return: 0 or error value. + */ +static int adxl345_fifo_transfer(struct adxl345_state *st, int samples) +{ + size_t count; + int i, ret = 0; + + /* count is the 3x the fifo_buf element size, hence 6B */ + count = sizeof(st->fifo_buf[0]) * ADXL345_DIRS; + for (i = 0; i < samples; i++) { + /* read 3x 2 byte elements from base address into next fifo_buf position */ + ret = regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE, + st->fifo_buf + (i * count / 2), count); + if (ret) + return ret; + + /* + * To ensure that the FIFO has completely popped, there must be at least 5 + * us between the end of reading the data registers, signified by the + * transition to register 0x38 from 0x37 or the CS pin going high, and the + * start of new reads of the FIFO or reading the FIFO_STATUS register. For + * SPI operation at 1.5 MHz or lower, the register addressing portion of the + * transmission is sufficient delay to ensure the FIFO has completely + * popped. It is necessary for SPI operation greater than 1.5 MHz to + * de-assert the CS pin to ensure a total of 5 us, which is at most 3.4 us + * at 5 MHz operation. + */ + if (st->fifo_delay && samples > 1) + udelay(3); + } + return ret; +} + +/** + * adxl345_fifo_reset() - Empty the FIFO in error condition. + * @st: The instance to the state object of the sensor. + * + * Read all elements of the FIFO. Reading the interrupt source register + * resets the sensor. + */ +static void adxl345_fifo_reset(struct adxl345_state *st) +{ + int regval; + int samples; + + adxl345_set_measure_en(st, false); + + samples = adxl345_get_samples(st); + if (samples > 0) + adxl345_fifo_transfer(st, samples); + + regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, ®val); + + adxl345_set_measure_en(st, true); +} + +static int adxl345_buffer_postenable(struct iio_dev *indio_dev) +{ + struct adxl345_state *st = iio_priv(indio_dev); + + st->fifo_mode = ADXL345_FIFO_STREAM; + return adxl345_set_fifo(st); +} + +static int adxl345_buffer_predisable(struct iio_dev *indio_dev) +{ + struct adxl345_state *st = iio_priv(indio_dev); + int ret; + + st->fifo_mode = ADXL345_FIFO_BYPASS; + ret = adxl345_set_fifo(st); + if (ret) + return ret; + + return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00); +} + +static const struct iio_buffer_setup_ops adxl345_buffer_ops = { + .postenable = adxl345_buffer_postenable, + .predisable = adxl345_buffer_predisable, }; -static int adxl345_powerup(void *regmap) +static int adxl345_fifo_push(struct iio_dev *indio_dev, + int samples) { - return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE); + struct adxl345_state *st = iio_priv(indio_dev); + int i, ret; + + if (samples <= 0) + return -EINVAL; + + ret = adxl345_fifo_transfer(st, samples); + if (ret) + return ret; + + for (i = 0; i < ADXL345_DIRS * samples; i += ADXL345_DIRS) + iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); + + return 0; } -static void adxl345_powerdown(void *regmap) +static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, + enum iio_modifier tap_dir) { - regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); + s64 ts = iio_get_time_ns(indio_dev); + struct adxl345_state *st = iio_priv(indio_dev); + int samples; + int ret = -ENOENT; + + if (FIELD_GET(ADXL345_INT_SINGLE_TAP, int_stat)) { + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir, + IIO_EV_TYPE_GESTURE, + IIO_EV_DIR_SINGLETAP), + ts); + if (ret) + return ret; + } + + if (FIELD_GET(ADXL345_INT_DOUBLE_TAP, int_stat)) { + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir, + IIO_EV_TYPE_GESTURE, + IIO_EV_DIR_DOUBLETAP), + ts); + if (ret) + return ret; + } + + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { + samples = adxl345_get_samples(st); + if (samples < 0) + return -EINVAL; + + if (adxl345_fifo_push(indio_dev, samples) < 0) + return -EINVAL; + + ret = 0; + } + + return ret; } -int adxl345_core_probe(struct device *dev, struct regmap *regmap) +/** + * adxl345_irq_handler() - Handle irqs of the ADXL345. + * @irq: The irq being handled. + * @p: The struct iio_device pointer for the device. + * + * Return: The interrupt was handled. + */ +static irqreturn_t adxl345_irq_handler(int irq, void *p) { - struct adxl345_data *data; - struct iio_dev *indio_dev; - u32 regval; + struct iio_dev *indio_dev = p; + struct adxl345_state *st = iio_priv(indio_dev); + unsigned int regval; + enum iio_modifier tap_dir = IIO_NO_MOD; + u32 axis_ctrl; + int int_stat; int ret; - ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); - if (ret < 0) - return dev_err_probe(dev, ret, "Error reading device ID\n"); + ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl); + if (ret) + return IRQ_NONE; - if (regval != ADXL345_DEVID) - return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n", - regval, ADXL345_DEVID); + if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl)) { + ret = regmap_read(st->regmap, ADXL345_REG_ACT_TAP_STATUS, ®val); + if (ret) + return IRQ_NONE; + + if (FIELD_GET(ADXL345_TAP_Z_EN, regval)) + tap_dir = IIO_MOD_Z; + else if (FIELD_GET(ADXL345_TAP_Y_EN, regval)) + tap_dir = IIO_MOD_Y; + else if (FIELD_GET(ADXL345_TAP_X_EN, regval)) + tap_dir = IIO_MOD_X; + } + + if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat)) + return IRQ_NONE; + + if (adxl345_push_event(indio_dev, int_stat, tap_dir)) + goto err; + + if (FIELD_GET(ADXL345_INT_OVERRUN, int_stat)) + goto err; + + return IRQ_HANDLED; + +err: + adxl345_fifo_reset(st); + + return IRQ_HANDLED; +} + +static const struct iio_info adxl345_info = { + .attrs = &adxl345_attrs_group, + .read_raw = adxl345_read_raw, + .write_raw = adxl345_write_raw, + .write_raw_get_fmt = adxl345_write_raw_get_fmt, + .read_event_config = adxl345_read_event_config, + .write_event_config = adxl345_write_event_config, + .read_event_value = adxl345_read_event_value, + .write_event_value = adxl345_write_event_value, + .debugfs_reg_access = &adxl345_reg_access, + .hwfifo_set_watermark = adxl345_set_watermark, +}; - indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); +/** + * adxl345_core_probe() - Probe and setup for the accelerometer. + * @dev: Driver model representation of the device + * @regmap: Regmap instance for the device + * @fifo_delay_default: Using FIFO with SPI needs delay + * @setup: Setup routine to be executed right before the standard device + * setup + * + * For SPI operation greater than 1.6 MHz, it is necessary to deassert the CS + * pin to ensure a total delay of 5 us; otherwise, the delay is not sufficient. + * The total delay necessary for 5 MHz operation is at most 3.4 us. This is not + * a concern when using I2C mode because the communication rate is low enough + * to ensure a sufficient delay between FIFO reads. + * Ref: "Retrieving Data from FIFO", p. 21 of 36, Data Sheet ADXL345 Rev. G + * + * Return: 0 on success, negative errno on error + */ +int adxl345_core_probe(struct device *dev, struct regmap *regmap, + bool fifo_delay_default, + int (*setup)(struct device*, struct regmap*)) +{ + struct adxl345_state *st; + struct iio_dev *indio_dev; + u32 regval; + u8 intio = ADXL345_INT1; + unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE | + ADXL345_DATA_FORMAT_JUSTIFY | + ADXL345_DATA_FORMAT_FULL_RES | + ADXL345_DATA_FORMAT_SELF_TEST); + unsigned int tap_threshold; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; - data = iio_priv(indio_dev); - data->regmap = regmap; - /* Enable full-resolution mode */ - data->data_range = ADXL345_DATA_FORMAT_FULL_RES; - data->info = device_get_match_data(dev); - if (!data->info) + st = iio_priv(indio_dev); + st->regmap = regmap; + st->info = device_get_match_data(dev); + if (!st->info) return -ENODEV; + st->fifo_delay = fifo_delay_default; - ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, - data->data_range); - if (ret < 0) - return dev_err_probe(dev, ret, "Failed to set data range\n"); + /* Init with reasonable values */ + tap_threshold = 48; /* 48 [0x30] -> ~3g */ + st->tap_duration_us = 16; /* 16 [0x10] -> .010 */ + st->tap_window_us = 64; /* 64 [0x40] -> .080 */ + st->tap_latent_us = 16; /* 16 [0x10] -> .020 */ - indio_dev->name = data->info->name; + indio_dev->name = st->info->name; indio_dev->info = &adxl345_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = adxl345_channels; indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); + indio_dev->available_scan_masks = adxl345_scan_masks; + + /* Reset interrupts at start up */ + ret = regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00); + if (ret) + return ret; + + if (setup) { + /* Perform optional initial bus specific configuration */ + ret = setup(dev, st->regmap); + if (ret) + return ret; + + /* Enable full-resolution mode */ + ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, + data_format_mask, + ADXL345_DATA_FORMAT_FULL_RES); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set data range\n"); + + } else { + /* Enable full-resolution mode (init all data_format bits) */ + ret = regmap_write(st->regmap, ADXL345_REG_DATA_FORMAT, + ADXL345_DATA_FORMAT_FULL_RES); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set data range\n"); + } + + ret = regmap_read(st->regmap, ADXL345_REG_DEVID, ®val); + if (ret) + return dev_err_probe(dev, ret, "Error reading device ID\n"); + + if (regval != ADXL345_DEVID) + return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n", + regval, ADXL345_DEVID); /* Enable measurement mode */ - ret = adxl345_powerup(data->regmap); - if (ret < 0) + ret = adxl345_set_measure_en(st, true); + if (ret) return dev_err_probe(dev, ret, "Failed to enable measurement mode\n"); - ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap); - if (ret < 0) + ret = devm_add_action_or_reset(dev, adxl345_powerdown, st); + if (ret) return ret; + st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1"); + if (st->irq < 0) { + intio = ADXL345_INT2; + st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); + if (st->irq < 0) + intio = ADXL345_INT_NONE; + } + + if (intio != ADXL345_INT_NONE) { + /* + * Any bits set to 0 in the INT map register send their respective + * interrupts to the INT1 pin, whereas bits set to 1 send their respective + * interrupts to the INT2 pin. The intio shall convert this accordingly. + */ + regval = intio ? 0xff : 0; + + ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, regval); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold); + if (ret) + return ret; + + /* FIFO_STREAM mode is going to be activated later */ + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops); + if (ret) + return ret; + + ret = devm_request_threaded_irq(dev, st->irq, NULL, + &adxl345_irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return ret; + } else { + ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL, + FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK, + ADXL345_FIFO_BYPASS)); + if (ret) + return ret; + } + return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, IIO_ADXL345); +EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, "IIO_ADXL345"); MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>"); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index a3084b0a8f78..af84c0043c6c 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -17,6 +17,8 @@ static const struct regmap_config adxl345_i2c_regmap_config = { .reg_bits = 8, .val_bits = 8, + .volatile_reg = adxl345_is_volatile_reg, + .cache_type = REGCACHE_MAPLE, }; static int adxl345_i2c_probe(struct i2c_client *client) @@ -27,7 +29,7 @@ static int adxl345_i2c_probe(struct i2c_client *client) if (IS_ERR(regmap)) return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&client->dev, regmap); + return adxl345_core_probe(&client->dev, regmap, false, NULL); } static const struct adxl345_chip_info adxl345_i2c_info = { @@ -74,4 +76,4 @@ module_i2c_driver(adxl345_i2c_driver); MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>"); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL345); +MODULE_IMPORT_NS("IIO_ADXL345"); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 93ca349f1780..0315f4bfd69a 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -12,17 +12,26 @@ #include "adxl345.h" #define ADXL345_MAX_SPI_FREQ_HZ 5000000 +#define ADXL345_MAX_FREQ_NO_FIFO_DELAY 1500000 static const struct regmap_config adxl345_spi_regmap_config = { .reg_bits = 8, .val_bits = 8, /* Setting bits 7 and 6 enables multiple-byte read */ .read_flag_mask = BIT(7) | BIT(6), + .volatile_reg = adxl345_is_volatile_reg, + .cache_type = REGCACHE_MAPLE, }; +static int adxl345_spi_setup(struct device *dev, struct regmap *regmap) +{ + return regmap_write(regmap, ADXL345_REG_DATA_FORMAT, ADXL345_DATA_FORMAT_SPI_3WIRE); +} + static int adxl345_spi_probe(struct spi_device *spi) { struct regmap *regmap; + bool needs_delay; /* Bail out if max_speed_hz exceeds 5 MHz */ if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ) @@ -33,7 +42,11 @@ static int adxl345_spi_probe(struct spi_device *spi) if (IS_ERR(regmap)) return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&spi->dev, regmap); + needs_delay = spi->max_speed_hz > ADXL345_MAX_FREQ_NO_FIFO_DELAY; + if (spi->mode & SPI_3WIRE) + return adxl345_core_probe(&spi->dev, regmap, needs_delay, adxl345_spi_setup); + else + return adxl345_core_probe(&spi->dev, regmap, needs_delay, NULL); } static const struct adxl345_chip_info adxl345_spi_info = { @@ -80,4 +93,4 @@ module_spi_driver(adxl345_spi_driver); MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>"); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL345); +MODULE_IMPORT_NS("IIO_ADXL345"); diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 0c9225d18fb2..2e00fd51b4d5 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -22,7 +22,7 @@ #include <linux/regmap.h> #include <linux/units.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "adxl355.h" @@ -72,7 +72,7 @@ const struct regmap_access_table adxl355_readable_regs_tbl = { .yes_ranges = adxl355_read_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl355_read_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl355_readable_regs_tbl, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl355_readable_regs_tbl, "IIO_ADXL355"); static const struct regmap_range adxl355_write_reg_range[] = { regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_RESET_REG), @@ -82,7 +82,7 @@ const struct regmap_access_table adxl355_writeable_regs_tbl = { .yes_ranges = adxl355_write_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl355_write_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, "IIO_ADXL355"); const struct adxl355_chip_info adxl35x_chip_info[] = { [ADXL355] = { @@ -136,7 +136,7 @@ const struct adxl355_chip_info adxl35x_chip_info[] = { }, }, }; -EXPORT_SYMBOL_NS_GPL(adxl35x_chip_info, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl35x_chip_info, "IIO_ADXL355"); enum adxl355_op_mode { ADXL355_MEASUREMENT, @@ -231,7 +231,7 @@ struct adxl355_data { u8 transf_buf[3]; struct { u8 buf[14]; - s64 ts; + aligned_s64 ts; } buffer; } __aligned(IIO_DMA_MINALIGN); }; @@ -643,7 +643,7 @@ static irqreturn_t adxl355_trigger_handler(int irq, void *p) * The acceleration data is 24 bits and big endian. It has to be saved * in 32 bits, hence, it is saved in the 2nd byte of the 4 byte buffer. * The buf array is 14 bytes as it includes 3x4=12 bytes for - * accelaration data of x, y, and z axis. It also includes 2 bytes for + * acceleration data of x, y, and z axis. It also includes 2 bytes for * temperature data. */ ret = regmap_bulk_read(data->regmap, ADXL355_XDATA3_REG, @@ -666,8 +666,8 @@ static irqreturn_t adxl355_trigger_handler(int irq, void *p) if (ret) goto out_unlock_notify; - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), pf->timestamp); out_unlock_notify: mutex_unlock(&data->lock); @@ -801,7 +801,7 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl355_core_probe, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl355_core_probe, "IIO_ADXL355"); MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>"); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 32398cde9608..1a512c7b792b 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -67,4 +67,4 @@ module_i2c_driver(adxl355_i2c_driver); MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>"); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL355); +MODULE_IMPORT_NS("IIO_ADXL355"); diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index fc99534d91ff..869e3e57d6f7 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -28,13 +28,9 @@ static int adxl355_spi_probe(struct spi_device *spi) const struct adxl355_chip_info *chip_data; struct regmap *regmap; - chip_data = device_get_match_data(&spi->dev); - if (!chip_data) { - chip_data = (void *)spi_get_device_id(spi)->driver_data; - - if (!chip_data) - return -EINVAL; - } + chip_data = spi_get_device_match_data(spi); + if (!chip_data) + return -EINVAL; regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config); if (IS_ERR(regmap)) { @@ -74,4 +70,4 @@ module_spi_driver(adxl355_spi_driver); MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>"); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL355); +MODULE_IMPORT_NS("IIO_ADXL355"); diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index 210228affb80..0c04b2bb7efb 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -16,7 +16,7 @@ #include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "adxl367.h" @@ -477,45 +477,42 @@ static int adxl367_set_fifo_watermark(struct adxl367_state *st, static int adxl367_set_range(struct iio_dev *indio_dev, enum adxl367_range range) { - iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - struct adxl367_state *st = iio_priv(indio_dev); - int ret; + struct adxl367_state *st = iio_priv(indio_dev); + int ret; - guard(mutex)(&st->lock); + guard(mutex)(&st->lock); - ret = adxl367_set_measure_en(st, false); - if (ret) - return ret; + ret = adxl367_set_measure_en(st, false); + if (ret) + return ret; - ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, - ADXL367_FILTER_CTL_RANGE_MASK, - FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, - range)); - if (ret) - return ret; + ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, + ADXL367_FILTER_CTL_RANGE_MASK, + FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, + range)); + if (ret) + return ret; - adxl367_scale_act_thresholds(st, st->range, range); + adxl367_scale_act_thresholds(st, st->range, range); - /* Activity thresholds depend on range */ - ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, - st->act_threshold); - if (ret) - return ret; + /* Activity thresholds depend on range */ + ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, + st->act_threshold); + if (ret) + return ret; - ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, - st->inact_threshold); - if (ret) - return ret; + ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, + st->inact_threshold); + if (ret) + return ret; - ret = adxl367_set_measure_en(st, true); - if (ret) - return ret; + ret = adxl367_set_measure_en(st, true); + if (ret) + return ret; - st->range = range; + st->range = range; - return 0; - } - unreachable(); + return 0; } static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms) @@ -604,39 +601,32 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) if (ret) return ret; + st->odr = odr; + /* Activity timers depend on ODR */ ret = _adxl367_set_act_time_ms(st, st->act_time_ms); if (ret) return ret; - ret = _adxl367_set_inact_time_ms(st, st->inact_time_ms); - if (ret) - return ret; - - st->odr = odr; - - return 0; + return _adxl367_set_inact_time_ms(st, st->inact_time_ms); } static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) { - iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - struct adxl367_state *st = iio_priv(indio_dev);; - int ret; + struct adxl367_state *st = iio_priv(indio_dev); + int ret; - guard(mutex)(&st->lock); + guard(mutex)(&st->lock); - ret = adxl367_set_measure_en(st, false); - if (ret) - return ret; + ret = adxl367_set_measure_en(st, false); + if (ret) + return ret; - ret = _adxl367_set_odr(st, odr); - if (ret) - return ret; + ret = _adxl367_set_odr(st, odr); + if (ret) + return ret; - return adxl367_set_measure_en(st, true); - } - unreachable(); + return adxl367_set_measure_en(st, true); } static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg, @@ -725,32 +715,29 @@ static int adxl367_read_sample(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { - iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - struct adxl367_state *st = iio_priv(indio_dev); - u16 sample; - int ret; + struct adxl367_state *st = iio_priv(indio_dev); + u16 sample; + int ret; - guard(mutex)(&st->lock); + guard(mutex)(&st->lock); - ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); - if (ret) - return ret; + ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); + if (ret) + return ret; - ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, - sizeof(st->sample_buf)); - if (ret) - return ret; + ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, + sizeof(st->sample_buf)); + if (ret) + return ret; - sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); - *val = sign_extend32(sample, chan->scan_type.realbits - 1); + sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); + *val = sign_extend32(sample, chan->scan_type.realbits - 1); - ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); - if (ret) - return ret; + ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); + if (ret) + return ret; - return IIO_VAL_INT; - } - unreachable(); + return IIO_VAL_INT; } static int adxl367_get_status(struct adxl367_state *st, u8 *status, @@ -852,10 +839,15 @@ static int adxl367_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long info) { struct adxl367_state *st = iio_priv(indio_dev); + int ret; switch (info) { case IIO_CHAN_INFO_RAW: - return adxl367_read_sample(indio_dev, chan, val); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = adxl367_read_sample(indio_dev, chan, val); + iio_device_release_direct(indio_dev); + return ret; case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ACCEL: { @@ -912,7 +904,12 @@ static int adxl367_write_raw(struct iio_dev *indio_dev, if (ret) return ret; - return adxl367_set_odr(indio_dev, odr); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = adxl367_set_odr(indio_dev, odr); + iio_device_release_direct(indio_dev); + return ret; } case IIO_CHAN_INFO_SCALE: { enum adxl367_range range; @@ -921,7 +918,12 @@ static int adxl367_write_raw(struct iio_dev *indio_dev, if (ret) return ret; - return adxl367_set_range(indio_dev, range); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = adxl367_set_range(indio_dev, range); + iio_device_release_direct(indio_dev); + return ret; } default: return -EINVAL; @@ -1069,13 +1071,15 @@ static int adxl367_read_event_config(struct iio_dev *indio_dev, } } -static int adxl367_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int state) +static int __adxl367_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) { + struct adxl367_state *st = iio_priv(indio_dev); enum adxl367_activity_type act; + int ret; switch (dir) { case IIO_EV_DIR_RISING: @@ -1088,28 +1092,38 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev, return -EINVAL; } - iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - struct adxl367_state *st = iio_priv(indio_dev); - int ret; + guard(mutex)(&st->lock); - guard(mutex)(&st->lock); + ret = adxl367_set_measure_en(st, false); + if (ret) + return ret; - ret = adxl367_set_measure_en(st, false); - if (ret) - return ret; + ret = adxl367_set_act_interrupt_en(st, act, state); + if (ret) + return ret; - ret = adxl367_set_act_interrupt_en(st, act, state); - if (ret) - return ret; + ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED + : ADXL367_ACT_DISABLED); + if (ret) + return ret; - ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED - : ADXL367_ACT_DISABLED); - if (ret) - return ret; + return adxl367_set_measure_en(st, true); +} - return adxl367_set_measure_en(st, true); - } - unreachable(); +static int adxl367_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = __adxl367_write_event_config(indio_dev, chan, type, dir, state); + iio_device_release_direct(indio_dev); + return ret; } static ssize_t adxl367_get_fifo_enabled(struct device *dev, @@ -1220,7 +1234,7 @@ static int adxl367_update_scan_mode(struct iio_dev *indio_dev, return ret; st->fifo_set_size = bitmap_weight(active_scan_mask, - indio_dev->masklength); + iio_get_masklength(indio_dev)); return 0; } @@ -1475,7 +1489,7 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl367_probe, IIO_ADXL367); +EXPORT_SYMBOL_NS_GPL(adxl367_probe, "IIO_ADXL367"); MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>"); MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer driver"); diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index 62c74bdc0d77..1c7d2eb054a2 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -61,14 +61,14 @@ static int adxl367_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl367_i2c_id[] = { - { "adxl367", 0 }, - { }, + { "adxl367" }, + { } }; MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id); static const struct of_device_id adxl367_of_match[] = { { .compatible = "adi,adxl367" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adxl367_of_match); @@ -83,7 +83,7 @@ static struct i2c_driver adxl367_i2c_driver = { module_i2c_driver(adxl367_i2c_driver); -MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_IMPORT_NS("IIO_ADXL367"); MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>"); MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer I2C driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c index 118c894015a5..3fed56bb9054 100644 --- a/drivers/iio/accel/adxl367_spi.c +++ b/drivers/iio/accel/adxl367_spi.c @@ -72,7 +72,7 @@ static int adxl367_write(void *context, const void *val_buf, size_t val_size) return spi_sync(st->spi, &st->reg_write_msg); } -static struct regmap_bus adxl367_spi_regmap_bus = { +static const struct regmap_bus adxl367_spi_regmap_bus = { .read = adxl367_read, .write = adxl367_write, }; @@ -139,13 +139,13 @@ static int adxl367_spi_probe(struct spi_device *spi) static const struct spi_device_id adxl367_spi_id[] = { { "adxl367", 0 }, - { }, + { } }; MODULE_DEVICE_TABLE(spi, adxl367_spi_id); static const struct of_device_id adxl367_of_match[] = { { .compatible = "adi,adxl367" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, adxl367_of_match); @@ -160,7 +160,7 @@ static struct spi_driver adxl367_spi_driver = { module_spi_driver(adxl367_spi_driver); -MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_IMPORT_NS("IIO_ADXL367"); MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>"); MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer SPI driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index c4193286eb05..961145b50293 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -763,12 +763,11 @@ static int adxl372_read_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = adxl372_read_axis(st, chan->address); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -940,7 +939,7 @@ static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int state) + bool state) { struct adxl372_state *st = iio_priv(indio_dev); @@ -1050,7 +1049,7 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev) st->fifo_format = adxl372_axis_lookup_table[i].fifo_format; st->fifo_axis_mask = adxl372_axis_lookup_table[i].bits; st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength); + iio_get_masklength(indio_dev)); /* Configure the FIFO to store sets of impact event peak. */ if (st->peak_fifo_mode_en) { @@ -1176,7 +1175,7 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg) { return (reg == ADXL372_FIFO_DATA); } -EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, IIO_ADXL372); +EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, "IIO_ADXL372"); int adxl372_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) @@ -1260,7 +1259,7 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl372_probe, IIO_ADXL372); +EXPORT_SYMBOL_NS_GPL(adxl372_probe, "IIO_ADXL372"); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver"); diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index d0690417fd36..186d4fe9a556 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -42,8 +42,8 @@ static int adxl372_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl372_i2c_id[] = { - { "adxl372", 0 }, - {} + { "adxl372" }, + { } }; MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id); @@ -67,4 +67,4 @@ module_i2c_driver(adxl372_i2c_driver); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADXL372); +MODULE_IMPORT_NS("IIO_ADXL372"); diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c index 787699773f96..39941b519c3b 100644 --- a/drivers/iio/accel/adxl372_spi.c +++ b/drivers/iio/accel/adxl372_spi.c @@ -34,7 +34,7 @@ static int adxl372_spi_probe(struct spi_device *spi) static const struct spi_device_id adxl372_spi_id[] = { { "adxl372", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, adxl372_spi_id); @@ -58,4 +58,4 @@ module_spi_driver(adxl372_spi_driver); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADXL372); +MODULE_IMPORT_NS("IIO_ADXL372"); diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c new file mode 100644 index 000000000000..0cf3c6815829 --- /dev/null +++ b/drivers/iio/accel/adxl380.c @@ -0,0 +1,1899 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ADXL380 3-Axis Digital Accelerometer core driver + * + * Copyright 2024 Analog Devices Inc. + */ + +#include <linux/bitfield.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/units.h> + +#include <linux/unaligned.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/kfifo_buf.h> +#include <linux/iio/sysfs.h> + +#include <linux/regulator/consumer.h> + +#include "adxl380.h" + +#define ADXL380_ID_VAL 380 +#define ADXL382_ID_VAL 382 + +#define ADXL380_DEVID_AD_REG 0x00 +#define ADLX380_PART_ID_REG 0x02 + +#define ADXL380_X_DATA_H_REG 0x15 +#define ADXL380_Y_DATA_H_REG 0x17 +#define ADXL380_Z_DATA_H_REG 0x19 +#define ADXL380_T_DATA_H_REG 0x1B + +#define ADXL380_MISC_0_REG 0x20 +#define ADXL380_XL382_MSK BIT(7) + +#define ADXL380_MISC_1_REG 0x21 + +#define ADXL380_X_DSM_OFFSET_REG 0x4D + +#define ADXL380_ACT_INACT_CTL_REG 0x37 +#define ADXL380_INACT_EN_MSK BIT(2) +#define ADXL380_ACT_EN_MSK BIT(0) + +#define ADXL380_SNSR_AXIS_EN_REG 0x38 +#define ADXL380_ACT_INACT_AXIS_EN_MSK GENMASK(2, 0) + +#define ADXL380_THRESH_ACT_H_REG 0x39 +#define ADXL380_TIME_ACT_H_REG 0x3B +#define ADXL380_THRESH_INACT_H_REG 0x3E +#define ADXL380_TIME_INACT_H_REG 0x40 +#define ADXL380_THRESH_MAX GENMASK(12, 0) +#define ADXL380_TIME_MAX GENMASK(24, 0) + +#define ADXL380_FIFO_CONFIG_0_REG 0x30 +#define ADXL380_FIFO_SAMPLES_8_MSK BIT(0) +#define ADXL380_FIFO_MODE_MSK GENMASK(5, 4) + +#define ADXL380_FIFO_DISABLED 0 +#define ADXL380_FIFO_NORMAL 1 +#define ADXL380_FIFO_STREAMED 2 +#define ADXL380_FIFO_TRIGGERED 3 + +#define ADXL380_FIFO_CONFIG_1_REG 0x31 +#define ADXL380_FIFO_STATUS_0_REG 0x1E + +#define ADXL380_TAP_THRESH_REG 0x43 +#define ADXL380_TAP_DUR_REG 0x44 +#define ADXL380_TAP_LATENT_REG 0x45 +#define ADXL380_TAP_WINDOW_REG 0x46 +#define ADXL380_TAP_TIME_MAX GENMASK(7, 0) + +#define ADXL380_TAP_CFG_REG 0x47 +#define ADXL380_TAP_AXIS_MSK GENMASK(1, 0) + +#define ADXL380_TRIG_CFG_REG 0x49 +#define ADXL380_TRIG_CFG_DEC_2X_MSK BIT(7) +#define ADXL380_TRIG_CFG_SINC_RATE_MSK BIT(6) + +#define ADXL380_FILTER_REG 0x50 +#define ADXL380_FILTER_EQ_FILT_MSK BIT(6) +#define ADXL380_FILTER_LPF_MODE_MSK GENMASK(5, 4) +#define ADXL380_FILTER_HPF_PATH_MSK BIT(3) +#define ADXL380_FILTER_HPF_CORNER_MSK GENMASK(2, 0) + +#define ADXL380_OP_MODE_REG 0x26 +#define ADXL380_OP_MODE_RANGE_MSK GENMASK(7, 6) +#define ADXL380_OP_MODE_MSK GENMASK(3, 0) +#define ADXL380_OP_MODE_STANDBY 0 +#define ADXL380_OP_MODE_HEART_SOUND 1 +#define ADXL380_OP_MODE_ULP 2 +#define ADXL380_OP_MODE_VLP 3 +#define ADXL380_OP_MODE_LP 4 +#define ADXL380_OP_MODE_LP_ULP 6 +#define ADXL380_OP_MODE_LP_VLP 7 +#define ADXL380_OP_MODE_RBW 8 +#define ADXL380_OP_MODE_RBW_ULP 10 +#define ADXL380_OP_MODE_RBW_VLP 11 +#define ADXL380_OP_MODE_HP 12 +#define ADXL380_OP_MODE_HP_ULP 14 +#define ADXL380_OP_MODE_HP_VLP 15 + +#define ADXL380_OP_MODE_4G_RANGE 0 +#define ADXL382_OP_MODE_15G_RANGE 0 +#define ADXL380_OP_MODE_8G_RANGE 1 +#define ADXL382_OP_MODE_30G_RANGE 1 +#define ADXL380_OP_MODE_16G_RANGE 2 +#define ADXL382_OP_MODE_60G_RANGE 2 + +#define ADXL380_DIG_EN_REG 0x27 +#define ADXL380_CHAN_EN_MSK(chan) BIT(4 + (chan)) +#define ADXL380_FIFO_EN_MSK BIT(3) + +#define ADXL380_INT0_MAP0_REG 0x2B +#define ADXL380_INT1_MAP0_REG 0x2D +#define ADXL380_INT_MAP0_INACT_INT0_MSK BIT(6) +#define ADXL380_INT_MAP0_ACT_INT0_MSK BIT(5) +#define ADXL380_INT_MAP0_FIFO_WM_INT0_MSK BIT(3) + +#define ADXL380_INT0_MAP1_REG 0x2C +#define ADXL380_INT1_MAP1_REG 0x2E +#define ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK BIT(1) +#define ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK BIT(0) + +#define ADXL380_INT0_REG 0x5D +#define ADXL380_INT0_POL_MSK BIT(7) + +#define ADXL380_RESET_REG 0x2A +#define ADXL380_FIFO_DATA 0x1D + +#define ADXL380_DEVID_AD_VAL 0xAD +#define ADXL380_RESET_CODE 0x52 + +#define ADXL380_STATUS_0_REG 0x11 +#define ADXL380_STATUS_0_FIFO_FULL_MSK BIT(1) +#define ADXL380_STATUS_0_FIFO_WM_MSK BIT(3) + +#define ADXL380_STATUS_1_INACT_MSK BIT(6) +#define ADXL380_STATUS_1_ACT_MSK BIT(5) +#define ADXL380_STATUS_1_DOUBLE_TAP_MSK BIT(1) +#define ADXL380_STATUS_1_SINGLE_TAP_MSK BIT(0) + +#define ADXL380_FIFO_SAMPLES 315UL + +enum adxl380_channels { + ADXL380_ACCEL_X, + ADXL380_ACCEL_Y, + ADXL380_ACCEL_Z, + ADXL380_TEMP, + ADXL380_CH_NUM +}; + +enum adxl380_axis { + ADXL380_X_AXIS, + ADXL380_Y_AXIS, + ADXL380_Z_AXIS, +}; + +enum adxl380_activity_type { + ADXL380_ACTIVITY, + ADXL380_INACTIVITY, +}; + +enum adxl380_tap_type { + ADXL380_SINGLE_TAP, + ADXL380_DOUBLE_TAP, +}; + +enum adxl380_tap_time_type { + ADXL380_TAP_TIME_LATENT, + ADXL380_TAP_TIME_WINDOW, +}; + +static const int adxl380_range_scale_factor_tbl[] = { 1, 2, 4 }; + +const struct adxl380_chip_info adxl380_chip_info = { + .name = "adxl380", + .chip_id = ADXL380_ID_VAL, + .scale_tbl = { + [ADXL380_OP_MODE_4G_RANGE] = { 0, 1307226 }, + [ADXL380_OP_MODE_8G_RANGE] = { 0, 2615434 }, + [ADXL380_OP_MODE_16G_RANGE] = { 0, 5229886 }, + }, + .samp_freq_tbl = { 8000, 16000, 32000 }, + /* + * The datasheet defines an intercept of 470 LSB at 25 degC + * and a sensitivity of 10.2 LSB/C. + */ + .temp_offset = 25 * 102 / 10 - 470, + +}; +EXPORT_SYMBOL_NS_GPL(adxl380_chip_info, "IIO_ADXL380"); + +const struct adxl380_chip_info adxl382_chip_info = { + .name = "adxl382", + .chip_id = ADXL382_ID_VAL, + .scale_tbl = { + [ADXL382_OP_MODE_15G_RANGE] = { 0, 4903325 }, + [ADXL382_OP_MODE_30G_RANGE] = { 0, 9806650 }, + [ADXL382_OP_MODE_60G_RANGE] = { 0, 19613300 }, + }, + .samp_freq_tbl = { 16000, 32000, 64000 }, + /* + * The datasheet defines an intercept of 570 LSB at 25 degC + * and a sensitivity of 10.2 LSB/C. + */ + .temp_offset = 25 * 102 / 10 - 570, +}; +EXPORT_SYMBOL_NS_GPL(adxl382_chip_info, "IIO_ADXL380"); + +static const unsigned int adxl380_th_reg_high_addr[2] = { + [ADXL380_ACTIVITY] = ADXL380_THRESH_ACT_H_REG, + [ADXL380_INACTIVITY] = ADXL380_THRESH_INACT_H_REG, +}; + +static const unsigned int adxl380_time_reg_high_addr[2] = { + [ADXL380_ACTIVITY] = ADXL380_TIME_ACT_H_REG, + [ADXL380_INACTIVITY] = ADXL380_TIME_INACT_H_REG, +}; + +static const unsigned int adxl380_tap_time_reg[2] = { + [ADXL380_TAP_TIME_LATENT] = ADXL380_TAP_LATENT_REG, + [ADXL380_TAP_TIME_WINDOW] = ADXL380_TAP_WINDOW_REG, +}; + +struct adxl380_state { + struct regmap *regmap; + struct device *dev; + const struct adxl380_chip_info *chip_info; + /* + * Synchronize access to members of driver state, and ensure atomicity + * of consecutive regmap operations. + */ + struct mutex lock; + enum adxl380_axis tap_axis_en; + u8 range; + u8 odr; + u8 fifo_set_size; + u8 transf_buf[3]; + u16 watermark; + u32 act_time_ms; + u32 act_threshold; + u32 inact_time_ms; + u32 inact_threshold; + u32 tap_latent_us; + u32 tap_window_us; + u32 tap_duration_us; + u32 tap_threshold; + int irq; + int int_map[2]; + int lpf_tbl[4]; + int hpf_tbl[7][2]; + + __be16 fifo_buf[ADXL380_FIFO_SAMPLES] __aligned(IIO_DMA_MINALIGN); +}; + +bool adxl380_readable_noinc_reg(struct device *dev, unsigned int reg) +{ + return reg == ADXL380_FIFO_DATA; +} +EXPORT_SYMBOL_NS_GPL(adxl380_readable_noinc_reg, "IIO_ADXL380"); + +static int adxl380_set_measure_en(struct adxl380_state *st, bool en) +{ + int ret; + unsigned int act_inact_ctl; + u8 op_mode = ADXL380_OP_MODE_STANDBY; + + if (en) { + ret = regmap_read(st->regmap, ADXL380_ACT_INACT_CTL_REG, &act_inact_ctl); + if (ret) + return ret; + + /* Activity/ Inactivity detection available only in VLP/ULP mode */ + if (FIELD_GET(ADXL380_ACT_EN_MSK, act_inact_ctl) || + FIELD_GET(ADXL380_INACT_EN_MSK, act_inact_ctl)) + op_mode = ADXL380_OP_MODE_VLP; + else + op_mode = ADXL380_OP_MODE_HP; + } + + return regmap_update_bits(st->regmap, ADXL380_OP_MODE_REG, + ADXL380_OP_MODE_MSK, + FIELD_PREP(ADXL380_OP_MODE_MSK, op_mode)); +} + +static void adxl380_scale_act_inact_thresholds(struct adxl380_state *st, + u8 old_range, + u8 new_range) +{ + st->act_threshold = mult_frac(st->act_threshold, + adxl380_range_scale_factor_tbl[old_range], + adxl380_range_scale_factor_tbl[new_range]); + st->inact_threshold = mult_frac(st->inact_threshold, + adxl380_range_scale_factor_tbl[old_range], + adxl380_range_scale_factor_tbl[new_range]); +} + +static int adxl380_write_act_inact_threshold(struct adxl380_state *st, + enum adxl380_activity_type act, + unsigned int th) +{ + int ret; + u8 reg = adxl380_th_reg_high_addr[act]; + + if (th > ADXL380_THRESH_MAX) + return -EINVAL; + + ret = regmap_write(st->regmap, reg + 1, th & GENMASK(7, 0)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, reg, GENMASK(2, 0), th >> 8); + if (ret) + return ret; + + if (act == ADXL380_ACTIVITY) + st->act_threshold = th; + else + st->inact_threshold = th; + + return 0; +} + +static int adxl380_set_act_inact_threshold(struct iio_dev *indio_dev, + enum adxl380_activity_type act, + u16 th) +{ + struct adxl380_state *st = iio_priv(indio_dev); + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = adxl380_write_act_inact_threshold(st, act, th); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_set_tap_threshold_value(struct iio_dev *indio_dev, u8 th) +{ + int ret; + struct adxl380_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADXL380_TAP_THRESH_REG, th); + if (ret) + return ret; + + st->tap_threshold = th; + + return adxl380_set_measure_en(st, true); +} + +static int _adxl380_write_tap_time_us(struct adxl380_state *st, + enum adxl380_tap_time_type tap_time_type, + u32 us) +{ + u8 reg = adxl380_tap_time_reg[tap_time_type]; + unsigned int reg_val; + int ret; + + /* scale factor for tap window is 1250us / LSB */ + reg_val = DIV_ROUND_CLOSEST(us, 1250); + if (reg_val > ADXL380_TAP_TIME_MAX) + reg_val = ADXL380_TAP_TIME_MAX; + + ret = regmap_write(st->regmap, reg, reg_val); + if (ret) + return ret; + + if (tap_time_type == ADXL380_TAP_TIME_WINDOW) + st->tap_window_us = us; + else + st->tap_latent_us = us; + + return 0; +} + +static int adxl380_write_tap_time_us(struct adxl380_state *st, + enum adxl380_tap_time_type tap_time_type, u32 us) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = _adxl380_write_tap_time_us(st, tap_time_type, us); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_write_tap_dur_us(struct iio_dev *indio_dev, u32 us) +{ + int ret; + unsigned int reg_val; + struct adxl380_state *st = iio_priv(indio_dev); + + /* 625us per code is the scale factor of TAP_DUR register */ + reg_val = DIV_ROUND_CLOSEST(us, 625); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADXL380_TAP_DUR_REG, reg_val); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_read_chn(struct adxl380_state *st, u8 addr) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = regmap_bulk_read(st->regmap, addr, &st->transf_buf, 2); + if (ret) + return ret; + + return get_unaligned_be16(st->transf_buf); +} + +static int adxl380_get_odr(struct adxl380_state *st, int *odr) +{ + int ret; + unsigned int trig_cfg, odr_idx; + + ret = regmap_read(st->regmap, ADXL380_TRIG_CFG_REG, &trig_cfg); + if (ret) + return ret; + + odr_idx = (FIELD_GET(ADXL380_TRIG_CFG_SINC_RATE_MSK, trig_cfg) << 1) | + (FIELD_GET(ADXL380_TRIG_CFG_DEC_2X_MSK, trig_cfg) & 1); + + *odr = st->chip_info->samp_freq_tbl[odr_idx]; + + return 0; +} + +static const int adxl380_lpf_div[] = { + 1, 4, 8, 16, +}; + +static int adxl380_fill_lpf_tbl(struct adxl380_state *st) +{ + int ret, i; + int odr; + + ret = adxl380_get_odr(st, &odr); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(st->lpf_tbl); i++) + st->lpf_tbl[i] = DIV_ROUND_CLOSEST(odr, adxl380_lpf_div[i]); + + return 0; +} + +static const int adxl380_hpf_mul[] = { + 0, 247000, 62084, 15545, 3862, 954, 238, +}; + +static int adxl380_fill_hpf_tbl(struct adxl380_state *st) +{ + int i, ret, odr_hz; + u32 multiplier; + u64 div, rem, odr; + + ret = adxl380_get_odr(st, &odr_hz); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(adxl380_hpf_mul); i++) { + odr = mul_u64_u32_shr(odr_hz, MEGA, 0); + multiplier = adxl380_hpf_mul[i]; + div = div64_u64_rem(mul_u64_u32_shr(odr, multiplier, 0), + TERA * 100, &rem); + + st->hpf_tbl[i][0] = div; + st->hpf_tbl[i][1] = div_u64(rem, MEGA * 100); + } + + return 0; +} + +static int adxl380_set_odr(struct adxl380_state *st, u8 odr) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADXL380_TRIG_CFG_REG, + ADXL380_TRIG_CFG_DEC_2X_MSK, + FIELD_PREP(ADXL380_TRIG_CFG_DEC_2X_MSK, odr & 1)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADXL380_TRIG_CFG_REG, + ADXL380_TRIG_CFG_SINC_RATE_MSK, + FIELD_PREP(ADXL380_TRIG_CFG_SINC_RATE_MSK, odr >> 1)); + if (ret) + return ret; + + ret = adxl380_set_measure_en(st, true); + if (ret) + return ret; + + ret = adxl380_fill_lpf_tbl(st); + if (ret) + return ret; + + return adxl380_fill_hpf_tbl(st); +} + +static int adxl380_find_match_1d_tbl(const int *array, unsigned int size, + int val) +{ + int i; + + for (i = 0; i < size; i++) { + if (val == array[i]) + return i; + } + + return size - 1; +} + +static int adxl380_find_match_2d_tbl(const int (*freq_tbl)[2], int n, int val, int val2) +{ + int i; + + for (i = 0; i < n; i++) { + if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2) + return i; + } + + return -EINVAL; +} + +static int adxl380_get_lpf(struct adxl380_state *st, int *lpf) +{ + int ret; + unsigned int trig_cfg, lpf_idx; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, ADXL380_FILTER_REG, &trig_cfg); + if (ret) + return ret; + + lpf_idx = FIELD_GET(ADXL380_FILTER_LPF_MODE_MSK, trig_cfg); + + *lpf = st->lpf_tbl[lpf_idx]; + + return 0; +} + +static int adxl380_set_lpf(struct adxl380_state *st, u8 lpf) +{ + int ret; + u8 eq_bypass = 0; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + if (lpf) + eq_bypass = 1; + + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, + ADXL380_FILTER_EQ_FILT_MSK, + FIELD_PREP(ADXL380_FILTER_EQ_FILT_MSK, eq_bypass)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, + ADXL380_FILTER_LPF_MODE_MSK, + FIELD_PREP(ADXL380_FILTER_LPF_MODE_MSK, lpf)); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_get_hpf(struct adxl380_state *st, int *hpf_int, int *hpf_frac) +{ + int ret; + unsigned int trig_cfg, hpf_idx; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, ADXL380_FILTER_REG, &trig_cfg); + if (ret) + return ret; + + hpf_idx = FIELD_GET(ADXL380_FILTER_HPF_CORNER_MSK, trig_cfg); + + *hpf_int = st->hpf_tbl[hpf_idx][0]; + *hpf_frac = st->hpf_tbl[hpf_idx][1]; + + return 0; +} + +static int adxl380_set_hpf(struct adxl380_state *st, u8 hpf) +{ + int ret; + u8 hpf_path = 0; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + if (hpf) + hpf_path = 1; + + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, + ADXL380_FILTER_HPF_PATH_MSK, + FIELD_PREP(ADXL380_FILTER_HPF_PATH_MSK, hpf_path)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADXL380_FILTER_REG, + ADXL380_FILTER_HPF_CORNER_MSK, + FIELD_PREP(ADXL380_FILTER_HPF_CORNER_MSK, hpf)); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int _adxl380_set_act_inact_time_ms(struct adxl380_state *st, + enum adxl380_activity_type act, + u32 ms) +{ + u8 reg = adxl380_time_reg_high_addr[act]; + unsigned int reg_val; + int ret; + + /* 500us per code is the scale factor of TIME_ACT / TIME_INACT registers */ + reg_val = min(DIV_ROUND_CLOSEST(ms * 1000, 500), ADXL380_TIME_MAX); + + put_unaligned_be24(reg_val, &st->transf_buf[0]); + + ret = regmap_bulk_write(st->regmap, reg, st->transf_buf, sizeof(st->transf_buf)); + if (ret) + return ret; + + if (act == ADXL380_ACTIVITY) + st->act_time_ms = ms; + else + st->inact_time_ms = ms; + + return 0; +} + +static int adxl380_set_act_inact_time_ms(struct adxl380_state *st, + enum adxl380_activity_type act, + u32 ms) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = _adxl380_set_act_inact_time_ms(st, act, ms); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_set_range(struct adxl380_state *st, u8 range) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADXL380_OP_MODE_REG, + ADXL380_OP_MODE_RANGE_MSK, + FIELD_PREP(ADXL380_OP_MODE_RANGE_MSK, range)); + + if (ret) + return ret; + + adxl380_scale_act_inact_thresholds(st, st->range, range); + + /* Activity thresholds depend on range */ + ret = adxl380_write_act_inact_threshold(st, ADXL380_ACTIVITY, + st->act_threshold); + if (ret) + return ret; + + ret = adxl380_write_act_inact_threshold(st, ADXL380_INACTIVITY, + st->inact_threshold); + if (ret) + return ret; + + st->range = range; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_write_act_inact_en(struct adxl380_state *st, + enum adxl380_activity_type type, + bool en) +{ + if (type == ADXL380_ACTIVITY) + return regmap_update_bits(st->regmap, ADXL380_ACT_INACT_CTL_REG, + ADXL380_ACT_EN_MSK, + FIELD_PREP(ADXL380_ACT_EN_MSK, en)); + + return regmap_update_bits(st->regmap, ADXL380_ACT_INACT_CTL_REG, + ADXL380_INACT_EN_MSK, + FIELD_PREP(ADXL380_INACT_EN_MSK, en)); +} + +static int adxl380_read_act_inact_int(struct adxl380_state *st, + enum adxl380_activity_type type, + bool *en) +{ + int ret; + unsigned int reg_val; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, st->int_map[0], ®_val); + if (ret) + return ret; + + if (type == ADXL380_ACTIVITY) + *en = FIELD_GET(ADXL380_INT_MAP0_ACT_INT0_MSK, reg_val); + else + *en = FIELD_GET(ADXL380_INT_MAP0_INACT_INT0_MSK, reg_val); + + return 0; +} + +static int adxl380_write_act_inact_int(struct adxl380_state *st, + enum adxl380_activity_type act, + bool en) +{ + if (act == ADXL380_ACTIVITY) + return regmap_update_bits(st->regmap, st->int_map[0], + ADXL380_INT_MAP0_ACT_INT0_MSK, + FIELD_PREP(ADXL380_INT_MAP0_ACT_INT0_MSK, en)); + + return regmap_update_bits(st->regmap, st->int_map[0], + ADXL380_INT_MAP0_INACT_INT0_MSK, + FIELD_PREP(ADXL380_INT_MAP0_INACT_INT0_MSK, en)); +} + +static int adxl380_act_inact_config(struct adxl380_state *st, + enum adxl380_activity_type type, + bool en) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = adxl380_write_act_inact_en(st, type, en); + if (ret) + return ret; + + ret = adxl380_write_act_inact_int(st, type, en); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_write_tap_axis(struct adxl380_state *st, + enum adxl380_axis axis) +{ + int ret; + + ret = regmap_update_bits(st->regmap, ADXL380_TAP_CFG_REG, + ADXL380_TAP_AXIS_MSK, + FIELD_PREP(ADXL380_TAP_AXIS_MSK, axis)); + + if (ret) + return ret; + + st->tap_axis_en = axis; + + return 0; +} + +static int adxl380_read_tap_int(struct adxl380_state *st, enum adxl380_tap_type type, bool *en) +{ + int ret; + unsigned int reg_val; + + ret = regmap_read(st->regmap, st->int_map[1], ®_val); + if (ret) + return ret; + + if (type == ADXL380_SINGLE_TAP) + *en = FIELD_GET(ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK, reg_val); + else + *en = FIELD_GET(ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK, reg_val); + + return 0; +} + +static int adxl380_write_tap_int(struct adxl380_state *st, enum adxl380_tap_type type, bool en) +{ + if (type == ADXL380_SINGLE_TAP) + return regmap_update_bits(st->regmap, st->int_map[1], + ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK, + FIELD_PREP(ADXL380_INT_MAP1_SINGLE_TAP_INT0_MSK, en)); + + return regmap_update_bits(st->regmap, st->int_map[1], + ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK, + FIELD_PREP(ADXL380_INT_MAP1_DOUBLE_TAP_INT0_MSK, en)); +} + +static int adxl380_tap_config(struct adxl380_state *st, + enum adxl380_axis axis, + enum adxl380_tap_type type, + bool en) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = adxl380_write_tap_axis(st, axis); + if (ret) + return ret; + + ret = adxl380_write_tap_int(st, type, en); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_set_fifo_samples(struct adxl380_state *st) +{ + int ret; + u16 fifo_samples = st->watermark * st->fifo_set_size; + + ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG, + ADXL380_FIFO_SAMPLES_8_MSK, + FIELD_PREP(ADXL380_FIFO_SAMPLES_8_MSK, + (fifo_samples & BIT(8)))); + if (ret) + return ret; + + return regmap_write(st->regmap, ADXL380_FIFO_CONFIG_1_REG, + fifo_samples & 0xFF); +} + +static int adxl380_get_status(struct adxl380_state *st, u8 *status0, u8 *status1) +{ + int ret; + + /* STATUS0, STATUS1 are adjacent regs */ + ret = regmap_bulk_read(st->regmap, ADXL380_STATUS_0_REG, + &st->transf_buf, 2); + if (ret) + return ret; + + *status0 = st->transf_buf[0]; + *status1 = st->transf_buf[1]; + + return 0; +} + +static int adxl380_get_fifo_entries(struct adxl380_state *st, u16 *fifo_entries) +{ + int ret; + + ret = regmap_bulk_read(st->regmap, ADXL380_FIFO_STATUS_0_REG, + &st->transf_buf, 2); + if (ret) + return ret; + + *fifo_entries = st->transf_buf[0] | ((BIT(0) & st->transf_buf[1]) << 8); + + return 0; +} + +static void adxl380_push_event(struct iio_dev *indio_dev, s64 timestamp, + u8 status1) +{ + if (FIELD_GET(ADXL380_STATUS_1_ACT_MSK, status1)) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), + timestamp); + + if (FIELD_GET(ADXL380_STATUS_1_INACT_MSK, status1)) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), + timestamp); + if (FIELD_GET(ADXL380_STATUS_1_SINGLE_TAP_MSK, status1)) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_GESTURE, IIO_EV_DIR_SINGLETAP), + timestamp); + + if (FIELD_GET(ADXL380_STATUS_1_DOUBLE_TAP_MSK, status1)) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_GESTURE, IIO_EV_DIR_DOUBLETAP), + timestamp); +} + +static irqreturn_t adxl380_irq_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct adxl380_state *st = iio_priv(indio_dev); + u8 status0, status1; + u16 fifo_entries; + int i; + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_get_status(st, &status0, &status1); + if (ret) + return IRQ_HANDLED; + + adxl380_push_event(indio_dev, iio_get_time_ns(indio_dev), status1); + + if (!FIELD_GET(ADXL380_STATUS_0_FIFO_WM_MSK, status0)) + return IRQ_HANDLED; + + ret = adxl380_get_fifo_entries(st, &fifo_entries); + if (ret) + return IRQ_HANDLED; + + for (i = 0; i < fifo_entries; i += st->fifo_set_size) { + ret = regmap_noinc_read(st->regmap, ADXL380_FIFO_DATA, + &st->fifo_buf[i], + 2 * st->fifo_set_size); + if (ret) + return IRQ_HANDLED; + iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); + } + + return IRQ_HANDLED; +} + +static int adxl380_write_calibbias_value(struct adxl380_state *st, + unsigned long chan_addr, + s8 calibbias) +{ + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADXL380_X_DSM_OFFSET_REG + chan_addr, calibbias); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_read_calibbias_value(struct adxl380_state *st, + unsigned long chan_addr, + int *calibbias) +{ + int ret; + unsigned int reg_val; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, ADXL380_X_DSM_OFFSET_REG + chan_addr, ®_val); + if (ret) + return ret; + + *calibbias = sign_extend32(reg_val, 7); + + return 0; +} + +static ssize_t hwfifo_watermark_min_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "1\n"); +} + +static ssize_t hwfifo_watermark_max_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%lu\n", ADXL380_FIFO_SAMPLES); +} + +static ssize_t adxl380_get_fifo_watermark(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adxl380_state *st = iio_priv(indio_dev); + + return sysfs_emit(buf, "%d\n", st->watermark); +} + +static ssize_t adxl380_get_fifo_enabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adxl380_state *st = iio_priv(indio_dev); + int ret; + unsigned int reg_val; + + ret = regmap_read(st->regmap, ADXL380_DIG_EN_REG, ®_val); + if (ret) + return ret; + + return sysfs_emit(buf, "%lu\n", + FIELD_GET(ADXL380_FIFO_EN_MSK, reg_val)); +} + +static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0); +static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0); +static IIO_DEVICE_ATTR(hwfifo_watermark, 0444, + adxl380_get_fifo_watermark, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, + adxl380_get_fifo_enabled, NULL, 0); + +static const struct iio_dev_attr *adxl380_fifo_attributes[] = { + &iio_dev_attr_hwfifo_watermark_min, + &iio_dev_attr_hwfifo_watermark_max, + &iio_dev_attr_hwfifo_watermark, + &iio_dev_attr_hwfifo_enabled, + NULL +}; + +static int adxl380_buffer_postenable(struct iio_dev *indio_dev) +{ + struct adxl380_state *st = iio_priv(indio_dev); + int i; + int ret; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, + st->int_map[0], + ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, + FIELD_PREP(ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, 1)); + if (ret) + return ret; + + for_each_clear_bit(i, indio_dev->active_scan_mask, ADXL380_CH_NUM) { + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, + ADXL380_CHAN_EN_MSK(i), + 0 << (4 + i)); + if (ret) + return ret; + } + + st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + + if ((st->watermark * st->fifo_set_size) > ADXL380_FIFO_SAMPLES) + st->watermark = (ADXL380_FIFO_SAMPLES / st->fifo_set_size); + + ret = adxl380_set_fifo_samples(st); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, ADXL380_FIFO_EN_MSK, + FIELD_PREP(ADXL380_FIFO_EN_MSK, 1)); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static int adxl380_buffer_predisable(struct iio_dev *indio_dev) +{ + struct adxl380_state *st = iio_priv(indio_dev); + int ret, i; + + guard(mutex)(&st->lock); + + ret = adxl380_set_measure_en(st, false); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, + st->int_map[0], + ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, + FIELD_PREP(ADXL380_INT_MAP0_FIFO_WM_INT0_MSK, 0)); + if (ret) + return ret; + + for (i = 0; i < indio_dev->num_channels; i++) { + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, + ADXL380_CHAN_EN_MSK(i), + 1 << (4 + i)); + if (ret) + return ret; + } + + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, ADXL380_FIFO_EN_MSK, + FIELD_PREP(ADXL380_FIFO_EN_MSK, 0)); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +static const struct iio_buffer_setup_ops adxl380_buffer_ops = { + .postenable = adxl380_buffer_postenable, + .predisable = adxl380_buffer_predisable, +}; + +static int adxl380_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct adxl380_state *st = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = adxl380_read_chn(st, chan->address); + iio_device_release_direct(indio_dev); + if (ret < 0) + return ret; + + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ACCEL: + scoped_guard(mutex, &st->lock) { + *val = st->chip_info->scale_tbl[st->range][0]; + *val2 = st->chip_info->scale_tbl[st->range][1]; + } + return IIO_VAL_INT_PLUS_NANO; + case IIO_TEMP: + /* 10.2 LSB / Degree Celsius */ + *val = 10000; + *val2 = 102; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = st->chip_info->temp_offset; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ACCEL: + ret = adxl380_read_calibbias_value(st, chan->scan_index, val); + if (ret) + return ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + ret = adxl380_get_odr(st, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + ret = adxl380_get_lpf(st, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: + ret = adxl380_get_hpf(st, val, val2); + if (ret) + return ret; + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +static int adxl380_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct adxl380_state *st = iio_priv(indio_dev); + + if (chan->type != IIO_ACCEL) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)st->chip_info->scale_tbl; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(st->chip_info->scale_tbl) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (const int *)st->chip_info->samp_freq_tbl; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(st->chip_info->samp_freq_tbl); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = (const int *)st->lpf_tbl; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(st->lpf_tbl); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: + *vals = (const int *)st->hpf_tbl; + *type = IIO_VAL_INT_PLUS_MICRO; + /* Values are stored in a 2D matrix */ + *length = ARRAY_SIZE(st->hpf_tbl) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int adxl380_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct adxl380_state *st = iio_priv(indio_dev); + int odr_index, lpf_index, hpf_index, range_index; + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + odr_index = adxl380_find_match_1d_tbl(st->chip_info->samp_freq_tbl, + ARRAY_SIZE(st->chip_info->samp_freq_tbl), + val); + return adxl380_set_odr(st, odr_index); + case IIO_CHAN_INFO_CALIBBIAS: + return adxl380_write_calibbias_value(st, chan->scan_index, val); + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + lpf_index = adxl380_find_match_1d_tbl(st->lpf_tbl, + ARRAY_SIZE(st->lpf_tbl), + val); + return adxl380_set_lpf(st, lpf_index); + case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: + hpf_index = adxl380_find_match_2d_tbl(st->hpf_tbl, + ARRAY_SIZE(st->hpf_tbl), + val, val2); + if (hpf_index < 0) + return hpf_index; + return adxl380_set_hpf(st, hpf_index); + case IIO_CHAN_INFO_SCALE: + range_index = adxl380_find_match_2d_tbl(st->chip_info->scale_tbl, + ARRAY_SIZE(st->chip_info->scale_tbl), + val, val2); + if (range_index < 0) + return range_index; + return adxl380_set_range(st, range_index); + default: + return -EINVAL; + } +} + +static int adxl380_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ACCEL) + return -EINVAL; + + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + +static int adxl380_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct adxl380_state *st = iio_priv(indio_dev); + int ret; + bool int_en; + bool tap_axis_en = false; + + switch (chan->channel2) { + case IIO_MOD_X: + tap_axis_en = st->tap_axis_en == ADXL380_X_AXIS; + break; + case IIO_MOD_Y: + tap_axis_en = st->tap_axis_en == ADXL380_Y_AXIS; + break; + case IIO_MOD_Z: + tap_axis_en = st->tap_axis_en == ADXL380_Z_AXIS; + break; + default: + return -EINVAL; + } + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = adxl380_read_act_inact_int(st, ADXL380_ACTIVITY, &int_en); + if (ret) + return ret; + return int_en; + case IIO_EV_DIR_FALLING: + ret = adxl380_read_act_inact_int(st, ADXL380_INACTIVITY, &int_en); + if (ret) + return ret; + return int_en; + case IIO_EV_DIR_SINGLETAP: + ret = adxl380_read_tap_int(st, ADXL380_SINGLE_TAP, &int_en); + if (ret) + return ret; + return int_en && tap_axis_en; + case IIO_EV_DIR_DOUBLETAP: + ret = adxl380_read_tap_int(st, ADXL380_DOUBLE_TAP, &int_en); + if (ret) + return ret; + return int_en && tap_axis_en; + default: + return -EINVAL; + } +} + +static int adxl380_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct adxl380_state *st = iio_priv(indio_dev); + enum adxl380_axis axis; + + switch (chan->channel2) { + case IIO_MOD_X: + axis = ADXL380_X_AXIS; + break; + case IIO_MOD_Y: + axis = ADXL380_Y_AXIS; + break; + case IIO_MOD_Z: + axis = ADXL380_Z_AXIS; + break; + default: + return -EINVAL; + } + + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl380_act_inact_config(st, ADXL380_ACTIVITY, state); + case IIO_EV_DIR_FALLING: + return adxl380_act_inact_config(st, ADXL380_INACTIVITY, state); + case IIO_EV_DIR_SINGLETAP: + return adxl380_tap_config(st, axis, ADXL380_SINGLE_TAP, state); + case IIO_EV_DIR_DOUBLETAP: + return adxl380_tap_config(st, axis, ADXL380_DOUBLE_TAP, state); + default: + return -EINVAL; + } +} + +static int adxl380_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct adxl380_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + + switch (type) { + case IIO_EV_TYPE_THRESH: + switch (info) { + case IIO_EV_INFO_VALUE: { + switch (dir) { + case IIO_EV_DIR_RISING: + *val = st->act_threshold; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + *val = st->inact_threshold; + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + *val = st->act_time_ms; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_DIR_FALLING: + *val = st->inact_time_ms; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } + case IIO_EV_TYPE_GESTURE: + switch (info) { + case IIO_EV_INFO_VALUE: + *val = st->tap_threshold; + return IIO_VAL_INT; + case IIO_EV_INFO_RESET_TIMEOUT: + *val = st->tap_window_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + case IIO_EV_INFO_TAP2_MIN_DELAY: + *val = st->tap_latent_us; + *val2 = 1000000; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl380_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, enum iio_event_direction dir, + enum iio_event_info info, int val, int val2) +{ + struct adxl380_state *st = iio_priv(indio_dev); + u32 val_ms, val_us; + + if (chan->type != IIO_ACCEL) + return -EINVAL; + + switch (type) { + case IIO_EV_TYPE_THRESH: + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl380_set_act_inact_threshold(indio_dev, + ADXL380_ACTIVITY, val); + case IIO_EV_DIR_FALLING: + return adxl380_set_act_inact_threshold(indio_dev, + ADXL380_INACTIVITY, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_PERIOD: + val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000); + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl380_set_act_inact_time_ms(st, + ADXL380_ACTIVITY, val_ms); + case IIO_EV_DIR_FALLING: + return adxl380_set_act_inact_time_ms(st, + ADXL380_INACTIVITY, val_ms); + default: + return -EINVAL; + } + + default: + return -EINVAL; + } + case IIO_EV_TYPE_GESTURE: + switch (info) { + case IIO_EV_INFO_VALUE: + return adxl380_set_tap_threshold_value(indio_dev, val); + case IIO_EV_INFO_RESET_TIMEOUT: + val_us = val * 1000000 + val2; + return adxl380_write_tap_time_us(st, + ADXL380_TAP_TIME_WINDOW, + val_us); + case IIO_EV_INFO_TAP2_MIN_DELAY: + val_us = val * 1000000 + val2; + return adxl380_write_tap_time_us(st, + ADXL380_TAP_TIME_LATENT, + val_us); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static ssize_t in_accel_gesture_tap_maxtomin_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int vals[2]; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adxl380_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + + vals[0] = st->tap_duration_us; + vals[1] = MICRO; + + return iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, vals); +} + +static ssize_t in_accel_gesture_tap_maxtomin_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adxl380_state *st = iio_priv(indio_dev); + int ret, val_int, val_fract_us; + + guard(mutex)(&st->lock); + + ret = iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract_us); + if (ret) + return ret; + + /* maximum value is 255 * 625 us = 0.159375 seconds */ + if (val_int || val_fract_us > 159375 || val_fract_us < 0) + return -EINVAL; + + ret = adxl380_write_tap_dur_us(indio_dev, val_fract_us); + if (ret) + return ret; + + return len; +} + +static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_maxtomin_time, 0); + +static struct attribute *adxl380_event_attributes[] = { + &iio_dev_attr_in_accel_gesture_tap_maxtomin_time.dev_attr.attr, + NULL +}; + +static const struct attribute_group adxl380_event_attribute_group = { + .attrs = adxl380_event_attributes, +}; + +static int adxl380_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct adxl380_state *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static int adxl380_set_watermark(struct iio_dev *indio_dev, unsigned int val) +{ + struct adxl380_state *st = iio_priv(indio_dev); + + st->watermark = min(val, ADXL380_FIFO_SAMPLES); + + return 0; +} + +static const struct iio_info adxl380_info = { + .read_raw = adxl380_read_raw, + .read_avail = &adxl380_read_avail, + .write_raw = adxl380_write_raw, + .write_raw_get_fmt = adxl380_write_raw_get_fmt, + .read_event_config = adxl380_read_event_config, + .write_event_config = adxl380_write_event_config, + .read_event_value = adxl380_read_event_value, + .write_event_value = adxl380_write_event_value, + .event_attrs = &adxl380_event_attribute_group, + .debugfs_reg_access = &adxl380_reg_access, + .hwfifo_set_watermark = adxl380_set_watermark, +}; + +static const struct iio_event_spec adxl380_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_PERIOD), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_PERIOD), + }, + { + .type = IIO_EV_TYPE_GESTURE, + .dir = IIO_EV_DIR_SINGLETAP, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_RESET_TIMEOUT), + }, + { + .type = IIO_EV_TYPE_GESTURE, + .dir = IIO_EV_DIR_DOUBLETAP, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_RESET_TIMEOUT) | + BIT(IIO_EV_INFO_TAP2_MIN_DELAY), + }, +}; + +#define ADXL380_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + .event_spec = adxl380_events, \ + .num_event_specs = ARRAY_SIZE(adxl380_events) \ +} + +static const struct iio_chan_spec adxl380_channels[] = { + ADXL380_ACCEL_CHANNEL(0, ADXL380_X_DATA_H_REG, X), + ADXL380_ACCEL_CHANNEL(1, ADXL380_Y_DATA_H_REG, Y), + ADXL380_ACCEL_CHANNEL(2, ADXL380_Z_DATA_H_REG, Z), + { + .type = IIO_TEMP, + .address = ADXL380_T_DATA_H_REG, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 3, + .scan_type = { + .sign = 's', + .realbits = 12, + .storagebits = 16, + .shift = 4, + .endianness = IIO_BE, + }, + }, +}; + +static int adxl380_config_irq(struct iio_dev *indio_dev) +{ + struct adxl380_state *st = iio_priv(indio_dev); + unsigned long irq_flag; + u32 irq_type; + u8 polarity; + int ret; + + st->irq = fwnode_irq_get_byname(dev_fwnode(st->dev), "INT0"); + if (st->irq > 0) { + st->int_map[0] = ADXL380_INT0_MAP0_REG; + st->int_map[1] = ADXL380_INT0_MAP1_REG; + } else { + st->irq = fwnode_irq_get_byname(dev_fwnode(st->dev), "INT1"); + if (st->irq > 0) + return dev_err_probe(st->dev, -ENODEV, + "no interrupt name specified"); + st->int_map[0] = ADXL380_INT1_MAP0_REG; + st->int_map[1] = ADXL380_INT1_MAP1_REG; + } + + irq_type = irq_get_trigger_type(st->irq); + if (irq_type == IRQ_TYPE_LEVEL_HIGH) { + polarity = 0; + irq_flag = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; + } else if (irq_type == IRQ_TYPE_LEVEL_LOW) { + polarity = 1; + irq_flag = IRQF_TRIGGER_LOW | IRQF_ONESHOT; + } else { + return dev_err_probe(st->dev, -EINVAL, + "Invalid interrupt 0x%x. Only level interrupts supported\n", + irq_type); + } + + ret = regmap_update_bits(st->regmap, ADXL380_INT0_REG, + ADXL380_INT0_POL_MSK, + FIELD_PREP(ADXL380_INT0_POL_MSK, polarity)); + if (ret) + return ret; + + return devm_request_threaded_irq(st->dev, st->irq, NULL, + adxl380_irq_handler, irq_flag, + indio_dev->name, indio_dev); +} + +static int adxl380_setup(struct iio_dev *indio_dev) +{ + unsigned int reg_val; + u16 part_id, chip_id; + int ret, i; + struct adxl380_state *st = iio_priv(indio_dev); + + ret = regmap_read(st->regmap, ADXL380_DEVID_AD_REG, ®_val); + if (ret) + return ret; + + if (reg_val != ADXL380_DEVID_AD_VAL) + dev_warn(st->dev, "Unknown chip id %x\n", reg_val); + + ret = regmap_bulk_read(st->regmap, ADLX380_PART_ID_REG, + &st->transf_buf, 2); + if (ret) + return ret; + + part_id = get_unaligned_be16(st->transf_buf); + part_id >>= 4; + + if (part_id != ADXL380_ID_VAL) + dev_warn(st->dev, "Unknown part id %x\n", part_id); + + ret = regmap_read(st->regmap, ADXL380_MISC_0_REG, ®_val); + if (ret) + return ret; + + /* Bit to differentiate between ADXL380/382. */ + if (reg_val & ADXL380_XL382_MSK) + chip_id = ADXL382_ID_VAL; + else + chip_id = ADXL380_ID_VAL; + + if (chip_id != st->chip_info->chip_id) + dev_warn(st->dev, "Unknown chip id %x\n", chip_id); + + ret = regmap_write(st->regmap, ADXL380_RESET_REG, ADXL380_RESET_CODE); + if (ret) + return ret; + + /* + * A latency of approximately 0.5 ms is required after soft reset. + * Stated in the register REG_RESET description. + */ + fsleep(500); + + for (i = 0; i < indio_dev->num_channels; i++) { + ret = regmap_update_bits(st->regmap, ADXL380_DIG_EN_REG, + ADXL380_CHAN_EN_MSK(i), + 1 << (4 + i)); + if (ret) + return ret; + } + + ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG, + ADXL380_FIFO_MODE_MSK, + FIELD_PREP(ADXL380_FIFO_MODE_MSK, ADXL380_FIFO_STREAMED)); + if (ret) + return ret; + + /* Select all 3 axis for act/inact detection. */ + ret = regmap_update_bits(st->regmap, ADXL380_SNSR_AXIS_EN_REG, + ADXL380_ACT_INACT_AXIS_EN_MSK, + FIELD_PREP(ADXL380_ACT_INACT_AXIS_EN_MSK, + ADXL380_ACT_INACT_AXIS_EN_MSK)); + if (ret) + return ret; + + ret = adxl380_config_irq(indio_dev); + if (ret) + return ret; + + ret = adxl380_fill_lpf_tbl(st); + if (ret) + return ret; + + ret = adxl380_fill_hpf_tbl(st); + if (ret) + return ret; + + return adxl380_set_measure_en(st, true); +} + +int adxl380_probe(struct device *dev, struct regmap *regmap, + const struct adxl380_chip_info *chip_info) +{ + struct iio_dev *indio_dev; + struct adxl380_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->dev = dev; + st->regmap = regmap; + st->chip_info = chip_info; + + mutex_init(&st->lock); + + indio_dev->channels = adxl380_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl380_channels); + indio_dev->name = chip_info->name; + indio_dev->info = &adxl380_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_regulator_get_enable(dev, "vddio"); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to get vddio regulator\n"); + + ret = devm_regulator_get_enable(st->dev, "vsupply"); + if (ret) + return dev_err_probe(st->dev, ret, + "Failed to get vsupply regulator\n"); + + ret = adxl380_setup(indio_dev); + if (ret) + return ret; + + ret = devm_iio_kfifo_buffer_setup_ext(st->dev, indio_dev, + &adxl380_buffer_ops, + adxl380_fifo_attributes); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(adxl380_probe, "IIO_ADXL380"); + +MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>"); +MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl380.h b/drivers/iio/accel/adxl380.h new file mode 100644 index 000000000000..a683625d897a --- /dev/null +++ b/drivers/iio/accel/adxl380.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * ADXL380 3-Axis Digital Accelerometer + * + * Copyright 2024 Analog Devices Inc. + */ + +#ifndef _ADXL380_H_ +#define _ADXL380_H_ + +struct adxl380_chip_info { + const char *name; + const int scale_tbl[3][2]; + const int samp_freq_tbl[3]; + const int temp_offset; + const u16 chip_id; +}; + +extern const struct adxl380_chip_info adxl380_chip_info; +extern const struct adxl380_chip_info adxl382_chip_info; + +int adxl380_probe(struct device *dev, struct regmap *regmap, + const struct adxl380_chip_info *chip_info); +bool adxl380_readable_noinc_reg(struct device *dev, unsigned int reg); + +#endif /* _ADXL380_H_ */ diff --git a/drivers/iio/accel/adxl380_i2c.c b/drivers/iio/accel/adxl380_i2c.c new file mode 100644 index 000000000000..b4f86f972361 --- /dev/null +++ b/drivers/iio/accel/adxl380_i2c.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ADXL380 3-Axis Digital Accelerometer I2C driver + * + * Copyright 2024 Analog Devices Inc. + */ + +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include "adxl380.h" + +static const struct regmap_config adxl380_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .readable_noinc_reg = adxl380_readable_noinc_reg, +}; + +static int adxl380_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + const struct adxl380_chip_info *chip_data; + + chip_data = i2c_get_match_data(client); + + regmap = devm_regmap_init_i2c(client, &adxl380_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return adxl380_probe(&client->dev, regmap, chip_data); +} + +static const struct i2c_device_id adxl380_i2c_id[] = { + { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, + { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adxl380_i2c_id); + +static const struct of_device_id adxl380_of_match[] = { + { .compatible = "adi,adxl380", .data = &adxl380_chip_info }, + { .compatible = "adi,adxl382", .data = &adxl382_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, adxl380_of_match); + +static struct i2c_driver adxl380_i2c_driver = { + .driver = { + .name = "adxl380_i2c", + .of_match_table = adxl380_of_match, + }, + .probe = adxl380_i2c_probe, + .id_table = adxl380_i2c_id, +}; + +module_i2c_driver(adxl380_i2c_driver); + +MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>"); +MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer I2C driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_ADXL380"); diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c new file mode 100644 index 000000000000..6edd0d211ffa --- /dev/null +++ b/drivers/iio/accel/adxl380_spi.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ADXL380 3-Axis Digital Accelerometer SPI driver + * + * Copyright 2024 Analog Devices Inc. + */ + +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include "adxl380.h" + +static const struct regmap_config adxl380_spi_regmap_config = { + .reg_bits = 7, + .pad_bits = 1, + .val_bits = 8, + .read_flag_mask = BIT(0), + .readable_noinc_reg = adxl380_readable_noinc_reg, +}; + +static int adxl380_spi_probe(struct spi_device *spi) +{ + const struct adxl380_chip_info *chip_data; + struct regmap *regmap; + + chip_data = spi_get_device_match_data(spi); + + regmap = devm_regmap_init_spi(spi, &adxl380_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return adxl380_probe(&spi->dev, regmap, chip_data); +} + +static const struct spi_device_id adxl380_spi_id[] = { + { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, + { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, adxl380_spi_id); + +static const struct of_device_id adxl380_of_match[] = { + { .compatible = "adi,adxl380", .data = &adxl380_chip_info }, + { .compatible = "adi,adxl382", .data = &adxl382_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, adxl380_of_match); + +static struct spi_driver adxl380_spi_driver = { + .driver = { + .name = "adxl380_spi", + .of_match_table = adxl380_of_match, + }, + .probe = adxl380_spi_probe, + .id_table = adxl380_spi_id, +}; + +module_spi_driver(adxl380_spi_driver); + +MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>"); +MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer SPI driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_ADXL380"); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 6581772cb0c4..93a868678722 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -21,6 +21,7 @@ #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/types.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> @@ -144,7 +145,7 @@ struct bma180_data { /* Ensure timestamp is naturally aligned */ struct { s16 chan[4]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; }; @@ -539,14 +540,13 @@ static int bma180_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&data->mutex); ret = bma180_get_data_reg(data, chan->scan_index); mutex_unlock(&data->mutex); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; if (chan->scan_type.sign == 's') { @@ -876,8 +876,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + iio_for_each_active_channel(indio_dev, bit) { ret = bma180_get_data_reg(data, bit); if (ret < 0) { mutex_unlock(&data->mutex); @@ -888,7 +887,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) mutex_unlock(&data->mutex); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), time_ns); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index fcbd695e4654..38f7498431ee 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/types.h> #include <linux/spi/spi.h> #include <linux/iio/buffer.h> @@ -65,7 +66,7 @@ struct bma220_data { struct { s8 chans[3]; /* Ensure timestamp is naturally aligned. */ - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; u8 tx_buf[2] __aligned(IIO_DMA_MINALIGN); }; @@ -102,8 +103,8 @@ static irqreturn_t bma220_trigger_handler(int irq, void *p) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: mutex_unlock(&data->lock); iio_trigger_notify_done(indio_dev->trig); @@ -306,12 +307,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); static const struct spi_device_id bma220_spi_id[] = { {"bma220", 0}, - {} + { } }; static const struct acpi_device_id bma220_acpi_id[] = { {"BMA0220", 0}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bma220_spi_id); diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index e90e2f01550a..85e23badf733 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -13,6 +13,7 @@ #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/module.h> @@ -21,7 +22,7 @@ #include <linux/regulator/consumer.h> #include <linux/slab.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -114,7 +115,7 @@ struct bma400_data { struct { __le16 buff[3]; u8 temperature; - s64 ts __aligned(8); + aligned_s64 ts; } buffer __aligned(IIO_DMA_MINALIGN); __le16 status; __be16 duration; @@ -189,11 +190,11 @@ const struct regmap_config bma400_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = BMA400_CMD_REG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .writeable_reg = bma400_is_writable_reg, .volatile_reg = bma400_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bma400_regmap_config, IIO_BMA400); +EXPORT_SYMBOL_NS(bma400_regmap_config, "IIO_BMA400"); static const struct iio_mount_matrix * bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev, @@ -795,21 +796,19 @@ static int bma400_enable_steps(struct bma400_data *data, int val) static int bma400_get_steps_reg(struct bma400_data *data, int *val) { - u8 *steps_raw; int ret; - steps_raw = kmalloc(BMA400_STEP_RAW_LEN, GFP_KERNEL); + u8 *steps_raw __free(kfree) = kmalloc(BMA400_STEP_RAW_LEN, GFP_KERNEL); if (!steps_raw) return -ENOMEM; ret = regmap_bulk_read(data->regmap, BMA400_STEP_CNT0_REG, steps_raw, BMA400_STEP_RAW_LEN); - if (ret) { - kfree(steps_raw); + if (ret) return ret; - } + *val = get_unaligned_le24(steps_raw); - kfree(steps_raw); + return IIO_VAL_INT; } @@ -1219,7 +1218,8 @@ static int bma400_activity_event_en(struct bma400_data *data, static int bma400_tap_event_en(struct bma400_data *data, enum iio_event_direction dir, int state) { - unsigned int mask, field_value; + unsigned int mask; + unsigned int field_value = 0; int ret; /* @@ -1293,7 +1293,7 @@ static int bma400_disable_adv_interrupt(struct bma400_data *data) static int bma400_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { struct bma400_data *data = iio_priv(indio_dev); int ret; @@ -1591,8 +1591,9 @@ static irqreturn_t bma400_trigger_handler(int irq, void *p) data->buffer.temperature = temp; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); mutex_unlock(&data->mutex); iio_trigger_notify_done(indio_dev->trig); @@ -1763,7 +1764,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, int irq, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS(bma400_probe, IIO_BMA400); +EXPORT_SYMBOL_NS(bma400_probe, "IIO_BMA400"); MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>"); MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>"); diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index adf4e3fd2e1d..24a390c3ae66 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -28,7 +28,7 @@ static int bma400_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bma400_i2c_ids[] = { - { "bma400", 0 }, + { "bma400" }, { } }; MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids); @@ -53,4 +53,4 @@ module_i2c_driver(bma400_i2c_driver); MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>"); MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (I2C)"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BMA400); +MODULE_IMPORT_NS("IIO_BMA400"); diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c index ec13c044b304..d386f643515b 100644 --- a/drivers/iio/accel/bma400_spi.c +++ b/drivers/iio/accel/bma400_spi.c @@ -53,7 +53,7 @@ static int bma400_regmap_spi_write(void *context, const void *data, return spi_write(spi, data, count); } -static struct regmap_bus bma400_regmap_bus = { +static const struct regmap_bus bma400_regmap_bus = { .read = bma400_regmap_spi_read, .write = bma400_regmap_spi_write, .read_flag_mask = BIT(7), @@ -112,4 +112,4 @@ module_spi_driver(bma400_spi_driver); MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>"); MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (SPI)"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BMA400); +MODULE_IMPORT_NS("IIO_BMA400"); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 110591804b4c..744a034bb8b5 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -10,9 +10,9 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/acpi.h> -#include <linux/of_irq.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> @@ -203,7 +203,7 @@ const struct regmap_config bmc150_regmap_conf = { .val_bits = 8, .max_register = 0x3f, }; -EXPORT_SYMBOL_NS_GPL(bmc150_regmap_conf, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_regmap_conf, "IIO_BMC150"); static int bmc150_accel_set_mode(struct bmc150_accel_data *data, enum bmc150_power_modes mode, @@ -386,13 +386,9 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev, struct iio_mount_matrix *orientation) { - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct acpi_device *adev = ACPI_COMPANION(dev); - char *name, *alt_name, *label, *str; - union acpi_object *obj, *elements; - acpi_status status; - int i, j, val[3]; + acpi_handle handle = ACPI_HANDLE(dev); + char *name, *alt_name, *label; if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) { alt_name = "ROMK"; @@ -402,52 +398,16 @@ static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev, label = "accel-display"; } - if (acpi_has_method(adev->handle, "ROTM")) { + if (acpi_has_method(handle, "ROTM")) { name = "ROTM"; - } else if (acpi_has_method(adev->handle, alt_name)) { + } else if (acpi_has_method(handle, alt_name)) { name = alt_name; indio_dev->label = label; } else { return false; } - status = acpi_evaluate_object(adev->handle, name, NULL, &buffer); - if (ACPI_FAILURE(status)) { - dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status); - return false; - } - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) - goto unknown_format; - - elements = obj->package.elements; - for (i = 0; i < 3; i++) { - if (elements[i].type != ACPI_TYPE_STRING) - goto unknown_format; - - str = elements[i].string.pointer; - if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) - goto unknown_format; - - for (j = 0; j < 3; j++) { - switch (val[j]) { - case -1: str = "-1"; break; - case 0: str = "0"; break; - case 1: str = "1"; break; - default: goto unknown_format; - } - orientation->rotation[i * 3 + j] = str; - } - } - - kfree(buffer.pointer); - return true; - -unknown_format: - dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n"); - kfree(buffer.pointer); - return false; + return iio_read_acpi_mount_matrix(dev, orientation, name); } static bool bmc150_apply_dual250e_acpi_orientation(struct device *dev, @@ -554,7 +514,7 @@ static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev, */ irq_info = bmc150_accel_interrupts_int1; if (data->type == BOSCH_BMC156 || - irq == of_irq_get_byname(dev->of_node, "INT2")) + irq == fwnode_irq_get_byname(dev_fwnode(dev), "INT2")) irq_info = bmc150_accel_interrupts_int2; for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++) @@ -844,7 +804,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int state) + bool state) { struct bmc150_accel_data *data = iio_priv(indio_dev); int ret; @@ -1047,8 +1007,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, int j, bit; j = 0; - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) + iio_for_each_active_channel(indio_dev, bit) memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit], sizeof(data->scan.channels[0])); @@ -1801,7 +1760,7 @@ err_disable_regulators: return ret; } -EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_probe, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_probe, "IIO_BMC150"); void bmc150_accel_core_remove(struct device *dev) { @@ -1824,7 +1783,7 @@ void bmc150_accel_core_remove(struct device *dev) regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); } -EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, "IIO_BMC150"); #ifdef CONFIG_PM_SLEEP static int bmc150_accel_suspend(struct device *dev) @@ -1899,7 +1858,7 @@ const struct dev_pm_ops bmc150_accel_pm_ops = { SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, bmc150_accel_runtime_resume, NULL) }; -EXPORT_SYMBOL_NS_GPL(bmc150_accel_pm_ops, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_pm_ops, "IIO_BMC150"); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index 1c2e40369839..b4604f441553 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -240,7 +240,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { {"BOSC0200"}, {"BSBA0150"}, {"DUAL250E"}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); @@ -255,7 +255,7 @@ static const struct i2c_device_id bmc150_accel_id[] = { {"bmc150_accel"}, {"bmc156_accel", BOSCH_BMC156}, {"bmi055_accel"}, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); @@ -271,7 +271,7 @@ static const struct of_device_id bmc150_accel_of_match[] = { { .compatible = "bosch,bmc150_accel" }, { .compatible = "bosch,bmc156_accel" }, { .compatible = "bosch,bmi055_accel" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, bmc150_accel_of_match); @@ -291,4 +291,4 @@ module_i2c_driver(bmc150_accel_driver); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMC150 I2C accelerometer driver"); -MODULE_IMPORT_NS(IIO_BMC150); +MODULE_IMPORT_NS("IIO_BMC150"); diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index a6b9f599eb7b..26ce50b37716 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -48,7 +48,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { {"BMC150A"}, {"BMI055A"}, {"BSBA0150"}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); @@ -62,7 +62,7 @@ static const struct spi_device_id bmc150_accel_id[] = { {"bmc150_accel"}, {"bmc156_accel", BOSCH_BMC156}, {"bmi055_accel"}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bmc150_accel_id); @@ -81,4 +81,4 @@ module_spi_driver(bmc150_accel_driver); MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMC150 SPI accelerometer driver"); -MODULE_IMPORT_NS(IIO_BMC150); +MODULE_IMPORT_NS("IIO_BMC150"); diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h index 7775c5edaeef..7a7baf52e595 100644 --- a/drivers/iio/accel/bmc150-accel.h +++ b/drivers/iio/accel/bmc150-accel.h @@ -6,6 +6,7 @@ #include <linux/iio/iio.h> #include <linux/mutex.h> #include <linux/regulator/consumer.h> +#include <linux/types.h> #include <linux/workqueue.h> struct regmap; @@ -69,7 +70,7 @@ struct bmc150_accel_data { */ struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; u8 bw_bits; u32 slope_dur; diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c index 4d989708e6c3..dea126f993c1 100644 --- a/drivers/iio/accel/bmi088-accel-core.c +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -18,7 +18,7 @@ #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "bmi088-accel.h" @@ -114,11 +114,6 @@ enum bmi088_odr_modes { BMI088_ACCEL_MODE_ODR_1600 = 0xc, }; -struct bmi088_scale_info { - int scale; - u8 reg_range; -}; - struct bmi088_accel_chip_info { const char *name; u8 chip_id; @@ -150,9 +145,9 @@ const struct regmap_config bmi088_regmap_conf = { .val_bits = 8, .max_register = 0x7E, .volatile_table = &bmi088_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; -EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf, IIO_BMI088); +EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf, "IIO_BMI088"); static int bmi088_accel_power_up(struct bmi088_accel_data *data) { @@ -318,12 +313,13 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev, if (ret) return ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) + if (!iio_device_claim_direct(indio_dev)) { + ret = -EBUSY; goto out_read_raw_pm_put; + } ret = bmi088_accel_get_axis(data, chan, val); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (!ret) ret = IIO_VAL_INT; @@ -592,7 +588,7 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, return ret; } -EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe, IIO_BMI088); +EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe, "IIO_BMI088"); void bmi088_accel_core_remove(struct device *dev) @@ -606,7 +602,7 @@ void bmi088_accel_core_remove(struct device *dev) pm_runtime_set_suspended(dev); bmi088_accel_power_down(data); } -EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove, IIO_BMI088); +EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove, "IIO_BMI088"); static int bmi088_accel_runtime_suspend(struct device *dev) { diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c index 17e9156bbe89..310f863029bb 100644 --- a/drivers/iio/accel/bmi088-accel-i2c.c +++ b/drivers/iio/accel/bmi088-accel-i2c.c @@ -40,7 +40,7 @@ static const struct of_device_id bmi088_of_match[] = { { .compatible = "bosch,bmi085-accel" }, { .compatible = "bosch,bmi088-accel" }, { .compatible = "bosch,bmi090l-accel" }, - {} + { } }; MODULE_DEVICE_TABLE(of, bmi088_of_match); @@ -48,7 +48,7 @@ static const struct i2c_device_id bmi088_accel_id[] = { { "bmi085-accel", BOSCH_BMI085 }, { "bmi088-accel", BOSCH_BMI088 }, { "bmi090l-accel", BOSCH_BMI090L }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, bmi088_accel_id); @@ -67,4 +67,4 @@ module_i2c_driver(bmi088_accel_driver); MODULE_AUTHOR("Jun Yan <jerrysteve1101@gmail.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("BMI088 accelerometer driver (I2C)"); -MODULE_IMPORT_NS(IIO_BMI088); +MODULE_IMPORT_NS("IIO_BMI088"); diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c index 7b419a7b2478..44cb50c76cb1 100644 --- a/drivers/iio/accel/bmi088-accel-spi.c +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -36,7 +36,7 @@ static int bmi088_regmap_spi_read(void *context, const void *reg, return spi_write_then_read(spi, addr, sizeof(addr), val, val_size); } -static struct regmap_bus bmi088_regmap_bus = { +static const struct regmap_bus bmi088_regmap_bus = { .write = bmi088_regmap_spi_write, .read = bmi088_regmap_spi_read, }; @@ -67,7 +67,7 @@ static const struct of_device_id bmi088_of_match[] = { { .compatible = "bosch,bmi085-accel" }, { .compatible = "bosch,bmi088-accel" }, { .compatible = "bosch,bmi090l-accel" }, - {} + { } }; MODULE_DEVICE_TABLE(of, bmi088_of_match); @@ -75,7 +75,7 @@ static const struct spi_device_id bmi088_accel_id[] = { {"bmi085-accel", BOSCH_BMI085}, {"bmi088-accel", BOSCH_BMI088}, {"bmi090l-accel", BOSCH_BMI090L}, - {} + { } }; MODULE_DEVICE_TABLE(spi, bmi088_accel_id); @@ -94,4 +94,4 @@ module_spi_driver(bmi088_accel_driver); MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMI088 accelerometer driver (SPI)"); -MODULE_IMPORT_NS(IIO_BMI088); +MODULE_IMPORT_NS("IIO_BMI088"); diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index 0f403342b1fc..f7e4dc02b34d 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -62,7 +62,7 @@ static int cros_ec_accel_legacy_read_cmd(struct iio_dev *indio_dev, return ret; } - for_each_set_bit(i, &scan_mask, indio_dev->masklength) { + for_each_set_bit(i, &scan_mask, iio_get_masklength(indio_dev)) { *data = st->resp->dump.sensor[sensor_num].data[i] * st->sign[i]; data++; diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index 992286828844..c2dd123b9021 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -157,7 +157,7 @@ static const struct da280_match_data da280_match_data = { "da280", 3 }; static const struct acpi_device_id da280_acpi_match[] = { { "NSA2513", (kernel_ulong_t)&da217_match_data }, { "MIRAACC", (kernel_ulong_t)&da280_match_data }, - {} + { } }; MODULE_DEVICE_TABLE(acpi, da280_acpi_match); @@ -165,7 +165,7 @@ static const struct i2c_device_id da280_i2c_id[] = { { "da217", (kernel_ulong_t)&da217_match_data }, { "da226", (kernel_ulong_t)&da226_match_data }, { "da280", (kernel_ulong_t)&da280_match_data }, - {} + { } }; MODULE_DEVICE_TABLE(i2c, da280_i2c_id); diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index 8f919920ced5..e1df7b009d89 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -268,8 +268,8 @@ static int da311_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); static const struct i2c_device_id da311_i2c_id[] = { - {"da311", 0}, - {} + { "da311" }, + { } }; MODULE_DEVICE_TABLE(i2c, da311_i2c_id); diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index 2e719d60fff8..fb14894c66f9 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -201,9 +201,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume); static const struct i2c_device_id dmard06_id[] = { - { "dmard05", 0 }, - { "dmard06", 0 }, - { "dmard07", 0 }, + { "dmard05" }, + { "dmard06" }, + { "dmard07" }, { } }; MODULE_DEVICE_TABLE(i2c, dmard06_id); diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index fa98623de579..4ec70ca6910d 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -5,7 +5,7 @@ * Copyright (c) 2016, Jelle van der Waa <jelle@vdwaa.nl> */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -125,8 +125,8 @@ static int dmard09_probe(struct i2c_client *client) } static const struct i2c_device_id dmard09_id[] = { - { "dmard09", 0 }, - { }, + { "dmard09" }, + { } }; MODULE_DEVICE_TABLE(i2c, dmard09_id); diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 7745b6ffd1ad..71cd1928baa6 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -231,8 +231,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume); static const struct i2c_device_id dmard10_i2c_id[] = { - {"dmard10", 0}, - {} + { "dmard10" }, + { } }; MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index be8a15cb945f..b10a30960e1e 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -15,11 +15,15 @@ #include <linux/bits.h> #include <linux/bitfield.h> #include <linux/i2c.h> +#include <linux/irq.h> #include <linux/module.h> -#include <linux/of_irq.h> +#include <linux/mod_devicetable.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/regmap.h> +#include <linux/types.h> +#include <linux/units.h> #include <linux/iio/buffer.h> #include <linux/iio/events.h> @@ -126,6 +130,8 @@ #define FXLS8962AF_DEVICE_ID 0x62 #define FXLS8964AF_DEVICE_ID 0x84 +#define FXLS8974CF_DEVICE_ID 0x86 +#define FXLS8967AF_DEVICE_ID 0x87 /* Raw temp channel offset */ #define FXLS8962AF_TEMP_CENTER_VAL 25 @@ -161,7 +167,7 @@ struct fxls8962af_data { const struct fxls8962af_chip_info *chip_info; struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ struct iio_mount_matrix orientation; @@ -177,7 +183,7 @@ const struct regmap_config fxls8962af_i2c_regmap_conf = { .val_bits = 8, .max_register = FXLS8962AF_MAX_REG, }; -EXPORT_SYMBOL_NS_GPL(fxls8962af_i2c_regmap_conf, IIO_FXLS8962AF); +EXPORT_SYMBOL_NS_GPL(fxls8962af_i2c_regmap_conf, "IIO_FXLS8962AF"); const struct regmap_config fxls8962af_spi_regmap_conf = { .reg_bits = 8, @@ -185,7 +191,7 @@ const struct regmap_config fxls8962af_spi_regmap_conf = { .val_bits = 8, .max_register = FXLS8962AF_MAX_REG, }; -EXPORT_SYMBOL_NS_GPL(fxls8962af_spi_regmap_conf, IIO_FXLS8962AF); +EXPORT_SYMBOL_NS_GPL(fxls8962af_spi_regmap_conf, "IIO_FXLS8962AF"); enum { fxls8962af_idx_x, @@ -226,8 +232,8 @@ static int fxls8962af_power_off(struct fxls8962af_data *data) static int fxls8962af_standby(struct fxls8962af_data *data) { - return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, - FXLS8962AF_SENS_CONFIG1_ACTIVE, 0); + return regmap_clear_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_ACTIVE); } static int fxls8962af_active(struct fxls8962af_data *data) @@ -434,8 +440,16 @@ static int fxls8962af_read_raw(struct iio_dev *indio_dev, *val = FXLS8962AF_TEMP_CENTER_VAL; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = 0; - return fxls8962af_read_full_scale(data, val2); + switch (chan->type) { + case IIO_TEMP: + *val = MILLIDEGREE_PER_DEGREE; + return IIO_VAL_INT; + case IIO_ACCEL: + *val = 0; + return fxls8962af_read_full_scale(data, val2); + default: + return -EINVAL; + } case IIO_CHAN_INFO_SAMP_FREQ: return fxls8962af_read_samp_freq(data, val, val2); default: @@ -455,22 +469,20 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev, if (val != 0) return -EINVAL; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = fxls8962af_set_full_scale(data, val2); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = fxls8962af_set_samp_freq(data, val, val2); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); return ret; default: return -EINVAL; @@ -614,7 +626,7 @@ static int fxls8962af_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { struct fxls8962af_data *data = iio_priv(indio_dev); u8 enable_event, enable_bits; @@ -678,14 +690,13 @@ fxls8962af_write_event_config(struct iio_dev *indio_dev, fxls8962af_active(data); ret = fxls8962af_power_on(data); } else { - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; /* Not in buffered mode so disable power */ ret = fxls8962af_power_off(data); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); } return ret; @@ -734,9 +745,11 @@ static const struct iio_event_spec fxls8962af_event[] = { .type = IIO_TEMP, \ .address = FXLS8962AF_TEMP_OUT, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_OFFSET),\ .scan_index = -1, \ .scan_type = { \ + .sign = 's', \ .realbits = 8, \ .storagebits = 8, \ }, \ @@ -763,6 +776,18 @@ static const struct fxls8962af_chip_info fxls_chip_info_table[] = { .channels = fxls8962af_channels, .num_channels = ARRAY_SIZE(fxls8962af_channels), }, + [fxls8967af] = { + .chip_id = FXLS8967AF_DEVICE_ID, + .name = "fxls8967af", + .channels = fxls8962af_channels, + .num_channels = ARRAY_SIZE(fxls8962af_channels), + }, + [fxls8974cf] = { + .chip_id = FXLS8974CF_DEVICE_ID, + .name = "fxls8974cf", + .channels = fxls8962af_channels, + .num_channels = ARRAY_SIZE(fxls8962af_channels), + }, }; static const struct iio_info fxls8962af_info = { @@ -783,9 +808,8 @@ static int fxls8962af_reset(struct fxls8962af_data *data) unsigned int reg; int ret; - ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, - FXLS8962AF_SENS_CONFIG1_RST, - FXLS8962AF_SENS_CONFIG1_RST); + ret = regmap_set_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_RST); if (ret) return ret; @@ -828,9 +852,8 @@ static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev) fxls8962af_standby(data); /* Enable buffer interrupt */ - ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, - FXLS8962AF_INT_EN_BUF_EN, - FXLS8962AF_INT_EN_BUF_EN); + ret = regmap_set_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN); if (ret) return ret; @@ -849,11 +872,13 @@ static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev) fxls8962af_standby(data); /* Disable buffer interrupt */ - ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, - FXLS8962AF_INT_EN_BUF_EN, 0); + ret = regmap_clear_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN); if (ret) return ret; + synchronize_irq(data->irq); + ret = __fxls8962af_fifo_set_mode(data, false); if (data->enable_event) @@ -966,14 +991,13 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev) int j, bit; j = 0; - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + iio_for_each_active_channel(indio_dev, bit) { memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit], sizeof(data->scan.channels[0])); } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - tstamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, + sizeof(data->scan), tstamp); tstamp += sample_period; } @@ -1062,12 +1086,12 @@ static void fxls8962af_pm_disable(void *dev_ptr) fxls8962af_standby(iio_priv(indio_dev)); } -static void fxls8962af_get_irq(struct device_node *of_node, +static void fxls8962af_get_irq(struct device *dev, enum fxls8962af_int_pin *pin) { int irq; - irq = of_irq_get_byname(of_node, "INT2"); + irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); if (irq > 0) { *pin = FXLS8962AF_PIN_INT2; return; @@ -1086,7 +1110,7 @@ static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq) u8 int_pin_sel; int ret; - fxls8962af_get_irq(dev->of_node, &int_pin); + fxls8962af_get_irq(dev, &int_pin); switch (int_pin) { case FXLS8962AF_PIN_INT1: int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1; @@ -1104,8 +1128,7 @@ static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq) if (ret) return ret; - irq_type = irqd_get_trigger_type(irq_get_irq_data(irq)); - + irq_type = irq_get_trigger_type(irq); switch (irq_type) { case IRQF_TRIGGER_HIGH: case IRQF_TRIGGER_RISING: @@ -1216,12 +1239,15 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) if (ret) return ret; - if (device_property_read_bool(dev, "wakeup-source")) - device_init_wakeup(dev, true); + if (device_property_read_bool(dev, "wakeup-source")) { + ret = devm_device_init_wakeup(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to init wakeup\n"); + } return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF); +EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, "IIO_FXLS8962AF"); static int fxls8962af_runtime_suspend(struct device *dev) { diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index 160124673308..106198a12474 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -30,14 +30,16 @@ static int fxls8962af_probe(struct i2c_client *client) static const struct i2c_device_id fxls8962af_id[] = { { "fxls8962af", fxls8962af }, { "fxls8964af", fxls8964af }, - {} + { "fxls8967af", fxls8967af }, + { "fxls8974cf", fxls8974cf }, + { } }; MODULE_DEVICE_TABLE(i2c, fxls8962af_id); static const struct of_device_id fxls8962af_of_match[] = { { .compatible = "nxp,fxls8962af" }, { .compatible = "nxp,fxls8964af" }, - {} + { } }; MODULE_DEVICE_TABLE(of, fxls8962af_of_match); @@ -55,4 +57,4 @@ module_i2c_driver(fxls8962af_driver); MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>"); MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_FXLS8962AF); +MODULE_IMPORT_NS("IIO_FXLS8962AF"); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c index a0d192211839..bdafd1f615d9 100644 --- a/drivers/iio/accel/fxls8962af-spi.c +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -30,14 +30,14 @@ static int fxls8962af_probe(struct spi_device *spi) static const struct of_device_id fxls8962af_spi_of_match[] = { { .compatible = "nxp,fxls8962af" }, { .compatible = "nxp,fxls8964af" }, - {} + { } }; MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match); static const struct spi_device_id fxls8962af_spi_id_table[] = { { "fxls8962af", fxls8962af }, { "fxls8964af", fxls8964af }, - {} + { } }; MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table); @@ -55,4 +55,4 @@ module_spi_driver(fxls8962af_driver); MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>"); MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_FXLS8962AF); +MODULE_IMPORT_NS("IIO_FXLS8962AF"); diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h index 6eaa2803b26f..1c9adfc8c0dc 100644 --- a/drivers/iio/accel/fxls8962af.h +++ b/drivers/iio/accel/fxls8962af.h @@ -11,6 +11,8 @@ struct device; enum { fxls8962af, fxls8964af, + fxls8967af, + fxls8974cf, }; int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 9b7a73a4c48a..2ff591b3458f 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -28,7 +28,7 @@ struct accel_3d_state { /* Ensure timestamp is naturally aligned */ struct { u32 accel_val[3]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -228,7 +228,7 @@ static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data, int len, int64_t timestamp) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp); + iio_push_to_buffers_with_ts(indio_dev, data, len, timestamp); } /* Callback handler to send event after all samples are received and captured */ @@ -328,6 +328,7 @@ static int accel_3d_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_accel_3d_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret = 0; const char *name; struct iio_dev *indio_dev; @@ -335,8 +336,6 @@ static int hid_accel_3d_probe(struct platform_device *pdev) const struct iio_chan_spec *channel_spec; int channel_size; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct accel_3d_state)); if (indio_dev == NULL) @@ -424,7 +423,7 @@ error_remove_trigger: /* Function to deinitialize the processing for usage id */ static void hid_accel_3d_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct accel_3d_state *accel_state = iio_priv(indio_dev); @@ -441,7 +440,7 @@ static const struct platform_device_id hid_accel_3d_ids[] = { { /* gravity sensor */ .name = "HID-SENSOR-20007b", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids); @@ -452,11 +451,11 @@ static struct platform_driver hid_accel_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_accel_3d_probe, - .remove_new = hid_accel_3d_remove, + .remove = hid_accel_3d_remove, }; module_platform_driver(hid_accel_3d_platform_driver); MODULE_DESCRIPTION("HID Sensor Accel 3D"); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index 8a1d4fc28ddd..42388636ca31 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -38,7 +38,9 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) static const struct i2c_device_id kx022a_i2c_id[] = { { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, + { .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info }, { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, + { .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); @@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); static const struct of_device_id kx022a_of_match[] = { { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, + { .compatible = "kionix,kx134-1211", .data = &kx134_chip_info }, { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, + { .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); @@ -65,4 +69,4 @@ module_i2c_driver(kx022a_i2c_driver); MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver"); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_KX022A); +MODULE_IMPORT_NS("IIO_KX022A"); diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c index f798b964d0b5..e30d21083dc8 100644 --- a/drivers/iio/accel/kionix-kx022a-spi.c +++ b/drivers/iio/accel/kionix-kx022a-spi.c @@ -38,7 +38,9 @@ static int kx022a_spi_probe(struct spi_device *spi) static const struct spi_device_id kx022a_id[] = { { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, + { .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info }, { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, + { .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, kx022a_id); @@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(spi, kx022a_id); static const struct of_device_id kx022a_of_match[] = { { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, + { .compatible = "kionix,kx134-1211", .data = &kx134_chip_info }, { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, + { .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); @@ -65,4 +69,4 @@ module_spi_driver(kx022a_spi_driver); MODULE_DESCRIPTION("ROHM/Kionix kx022A accelerometer driver"); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_KX022A); +MODULE_IMPORT_NS("IIO_KX022A"); diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 53d59a04ae15..07dcf5f0599f 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -5,6 +5,7 @@ * ROHM/KIONIX accelerometer driver */ +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/interrupt.h> @@ -16,6 +17,7 @@ #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/string_choices.h> +#include <linux/types.h> #include <linux/units.h> #include <linux/iio/iio.h> @@ -147,7 +149,7 @@ static const struct regmap_config kx022a_regmap_config = { .rd_noinc_table = &kx022a_nir_regs, .precious_table = &kx022a_precious_regs, .max_register = KX022A_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* Regmap configs kx132 */ @@ -258,7 +260,7 @@ static const struct regmap_config kx132_regmap_config = { .rd_noinc_table = &kx132_nir_regs, .precious_table = &kx132_precious_regs, .max_register = KX132_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; struct kx022a_data { @@ -292,7 +294,7 @@ struct kx022a_data { __le16 buffer[8] __aligned(IIO_DMA_MINALIGN); struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; }; @@ -406,11 +408,21 @@ static const int kx022a_scale_table[][2] = { { 0, 4788403 }, }; +/* KX134ACR-LBZ ranges are (+/-) 8, 16, 32, 64 G */ +static const int kx134acr_lbz_scale_table[][2] = { + { 0, 2394202 }, + { 0, 4788403 }, + { 0, 9576807 }, + { 0, 19153613 }, +}; + static int kx022a_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask) { + struct kx022a_data *data = iio_priv(indio_dev); + switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: *vals = (const int *)kx022a_accel_samp_freq_table; @@ -419,9 +431,8 @@ static int kx022a_read_avail(struct iio_dev *indio_dev, *type = IIO_VAL_INT_PLUS_MICRO; return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SCALE: - *vals = (const int *)kx022a_scale_table; - *length = ARRAY_SIZE(kx022a_scale_table) * - ARRAY_SIZE(kx022a_scale_table[0]); + *vals = (const int *)data->chip_info->scale_table; + *length = data->chip_info->scale_table_size; *type = IIO_VAL_INT_PLUS_NANO; return IIO_AVAIL_LIST; default: @@ -437,17 +448,17 @@ static void kx022a_reg2freq(unsigned int val, int *val1, int *val2) *val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1]; } -static void kx022a_reg2scale(unsigned int val, unsigned int *val1, - unsigned int *val2) +static void kx022a_reg2scale(struct kx022a_data *data, unsigned int val, + unsigned int *val1, unsigned int *val2) { val &= KX022A_MASK_GSEL; val >>= KX022A_GSEL_SHIFT; - *val1 = kx022a_scale_table[val][0]; - *val2 = kx022a_scale_table[val][1]; + *val1 = data->chip_info->scale_table[val][0]; + *val2 = data->chip_info->scale_table[val][1]; } -static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on) +static int __kx022a_turn_on_off(struct kx022a_data *data, bool on) { int ret; @@ -468,7 +479,7 @@ static int kx022a_turn_off_lock(struct kx022a_data *data) int ret; mutex_lock(&data->mutex); - ret = kx022a_turn_on_off_unlocked(data, false); + ret = __kx022a_turn_on_off(data, false); if (ret) mutex_unlock(&data->mutex); @@ -479,7 +490,7 @@ static int kx022a_turn_on_unlock(struct kx022a_data *data) { int ret; - ret = kx022a_turn_on_off_unlocked(data, true); + ret = __kx022a_turn_on_off(data, true); mutex_unlock(&data->mutex); return ret; @@ -499,26 +510,13 @@ static int kx022a_write_raw_get_fmt(struct iio_dev *idev, } } -static int kx022a_write_raw(struct iio_dev *idev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) +static int __kx022a_write_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct kx022a_data *data = iio_priv(idev); int ret, n; - /* - * We should not allow changing scale or frequency when FIFO is running - * as it will mess the timestamp/scale for samples existing in the - * buffer. If this turns out to be an issue we can later change logic - * to internally flush the fifo before reconfiguring so the samples in - * fifo keep matching the freq/scale settings. (Such setup could cause - * issues if users trust the watermark to be reached within known - * time-limit). - */ - ret = iio_device_claim_direct_mode(idev); - if (ret) - return ret; - switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: n = ARRAY_SIZE(kx022a_accel_samp_freq_table); @@ -527,48 +525,64 @@ static int kx022a_write_raw(struct iio_dev *idev, if (val == kx022a_accel_samp_freq_table[n][0] && val2 == kx022a_accel_samp_freq_table[n][1]) break; - if (n < 0) { - ret = -EINVAL; - goto unlock_out; - } + if (n < 0) + return -EINVAL; + ret = kx022a_turn_off_lock(data); if (ret) - break; + return ret; ret = regmap_update_bits(data->regmap, data->chip_info->odcntl, KX022A_MASK_ODR, n); data->odr_ns = kx022a_odrs[n]; kx022a_turn_on_unlock(data); - break; + return ret; case IIO_CHAN_INFO_SCALE: - n = ARRAY_SIZE(kx022a_scale_table); + n = data->chip_info->scale_table_size / 2; while (n-- > 0) - if (val == kx022a_scale_table[n][0] && - val2 == kx022a_scale_table[n][1]) + if (val == data->chip_info->scale_table[n][0] && + val2 == data->chip_info->scale_table[n][1]) break; - if (n < 0) { - ret = -EINVAL; - goto unlock_out; - } + if (n < 0) + return -EINVAL; ret = kx022a_turn_off_lock(data); if (ret) - break; + return ret; ret = regmap_update_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_GSEL, n << KX022A_GSEL_SHIFT); kx022a_turn_on_unlock(data); - break; + return ret; default: - ret = -EINVAL; - break; + return -EINVAL; } +} + +static int kx022a_write_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + /* + * We should not allow changing scale or frequency when FIFO is running + * as it will mess the timestamp/scale for samples existing in the + * buffer. If this turns out to be an issue we can later change logic + * to internally flush the fifo before reconfiguring so the samples in + * fifo keep matching the freq/scale settings. (Such setup could cause + * issues if users trust the watermark to be reached within known + * time-limit). + */ + if (!iio_device_claim_direct(idev)) + return -EBUSY; -unlock_out: - iio_device_release_direct_mode(idev); + ret = __kx022a_write_raw(idev, chan, val, val2, mask); + + iio_device_release_direct(idev); return ret; } @@ -594,7 +608,7 @@ static int kx022a_get_axis(struct kx022a_data *data, if (ret) return ret; - *val = le16_to_cpu(data->buffer[0]); + *val = (s16)le16_to_cpu(data->buffer[0]); return IIO_VAL_INT; } @@ -609,15 +623,14 @@ static int kx022a_read_raw(struct iio_dev *idev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(idev); - if (ret) - return ret; + if (!iio_device_claim_direct(idev)) + return -EBUSY; mutex_lock(&data->mutex); ret = kx022a_get_axis(data, chan, val); mutex_unlock(&data->mutex); - iio_device_release_direct_mode(idev); + iio_device_release_direct(idev); return ret; @@ -641,7 +654,7 @@ static int kx022a_read_raw(struct iio_dev *idev, if (ret < 0) return ret; - kx022a_reg2scale(regval, val, val2); + kx022a_reg2scale(data, regval, val, val2); return IIO_VAL_INT_PLUS_NANO; } @@ -911,18 +924,19 @@ static int kx022a_fifo_disable(struct kx022a_data *data) { int ret = 0; - ret = kx022a_turn_off_lock(data); + guard(mutex)(&data->mutex); + ret = __kx022a_turn_on_off(data, false); if (ret) return ret; ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI); if (ret) - goto unlock_out; + return ret; ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BUF_EN); if (ret) - goto unlock_out; + return ret; data->state &= ~KX022A_STATE_FIFO; @@ -930,12 +944,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data) kfree(data->fifo_buffer); - return kx022a_turn_on_unlock(data); - -unlock_out: - mutex_unlock(&data->mutex); - - return ret; + return __kx022a_turn_on_off(data, true); } static int kx022a_buffer_predisable(struct iio_dev *idev) @@ -958,33 +967,29 @@ static int kx022a_fifo_enable(struct kx022a_data *data) if (!data->fifo_buffer) return -ENOMEM; - ret = kx022a_turn_off_lock(data); + guard(mutex)(&data->mutex); + ret = __kx022a_turn_on_off(data, false); if (ret) return ret; /* Update watermark to HW */ ret = kx022a_fifo_set_wmi(data); if (ret) - goto unlock_out; + return ret; /* Enable buffer */ ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BUF_EN); if (ret) - goto unlock_out; + return ret; data->state |= KX022A_STATE_FIFO; ret = regmap_set_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI); if (ret) - goto unlock_out; - - return kx022a_turn_on_unlock(data); - -unlock_out: - mutex_unlock(&data->mutex); + return ret; - return ret; + return __kx022a_turn_on_off(data, true); } static int kx022a_buffer_postenable(struct iio_dev *idev) @@ -1052,7 +1057,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private) struct kx022a_data *data = iio_priv(idev); irqreturn_t ret = IRQ_NONE; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); if (data->trigger_enabled) { iio_trigger_poll_nested(data->trig); @@ -1067,8 +1072,6 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private) ret = IRQ_HANDLED; } - mutex_unlock(&data->mutex); - return ret; } @@ -1078,32 +1081,26 @@ static int kx022a_trigger_set_state(struct iio_trigger *trig, struct kx022a_data *data = iio_trigger_get_drvdata(trig); int ret = 0; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); if (data->trigger_enabled == state) - goto unlock_out; + return 0; if (data->state & KX022A_STATE_FIFO) { dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); - ret = -EBUSY; - goto unlock_out; + return -EBUSY; } - ret = kx022a_turn_on_off_unlocked(data, false); + ret = __kx022a_turn_on_off(data, false); if (ret) - goto unlock_out; + return ret; data->trigger_enabled = state; ret = kx022a_set_drdy_irq(data, state); if (ret) - goto unlock_out; - - ret = kx022a_turn_on_off_unlocked(data, true); - -unlock_out: - mutex_unlock(&data->mutex); + return ret; - return ret; + return __kx022a_turn_on_off(data, true); } static const struct iio_trigger_ops kx022a_trigger_ops = { @@ -1120,10 +1117,15 @@ static int kx022a_chip_init(struct kx022a_data *data) return ret; /* - * I've seen I2C read failures if we poll too fast after the sensor - * reset. Slight delay gives I2C block the time to recover. + * According to the power-on procedure documents, there is (at least) + * 2ms delay required after the software reset. This should be same for + * all, KX022ACR-Z, KX132-1211, KX132ACR-LBZ and KX134ACR-LBZ. + * + * https://fscdn.rohm.com/kionix/en/document/AN010_KX022ACR-Z_Power-on_Procedure_E.pdf + * https://fscdn.rohm.com/kionix/en/document/TN027-Power-On-Procedure.pdf + * https://fscdn.rohm.com/kionix/en/document/AN011_KX134ACR-LBZ_Power-on_Procedure_E.pdf */ - msleep(1); + msleep(2); ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val, !(val & KX022A_MASK_SRST), @@ -1157,6 +1159,9 @@ const struct kx022a_chip_info kx022a_chip_info = { .regmap_config = &kx022a_regmap_config, .channels = kx022a_channels, .num_channels = ARRAY_SIZE(kx022a_channels), + .scale_table = kx022a_scale_table, + .scale_table_size = ARRAY_SIZE(kx022a_scale_table) * + ARRAY_SIZE(kx022a_scale_table[0]), .fifo_length = KX022A_FIFO_LENGTH, .who = KX022A_REG_WHO, .id = KX022A_ID, @@ -1175,13 +1180,16 @@ const struct kx022a_chip_info kx022a_chip_info = { .xout_l = KX022A_REG_XOUT_L, .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, }; -EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, "IIO_KX022A"); const struct kx022a_chip_info kx132_chip_info = { .name = "kx132-1211", .regmap_config = &kx132_regmap_config, .channels = kx132_channels, .num_channels = ARRAY_SIZE(kx132_channels), + .scale_table = kx022a_scale_table, + .scale_table_size = ARRAY_SIZE(kx022a_scale_table) * + ARRAY_SIZE(kx022a_scale_table[0]), .fifo_length = KX132_FIFO_LENGTH, .who = KX132_REG_WHO, .id = KX132_ID, @@ -1201,7 +1209,36 @@ const struct kx022a_chip_info kx132_chip_info = { .xout_l = KX132_REG_XOUT_L, .get_fifo_bytes_available = kx132_get_fifo_bytes_available, }; -EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx132_chip_info, "IIO_KX022A"); + +const struct kx022a_chip_info kx134_chip_info = { + .name = "kx134-1211", + .regmap_config = &kx132_regmap_config, + .channels = kx132_channels, + .num_channels = ARRAY_SIZE(kx132_channels), + .scale_table = kx134acr_lbz_scale_table, + .scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) * + ARRAY_SIZE(kx134acr_lbz_scale_table[0]), + .fifo_length = KX132_FIFO_LENGTH, + .who = KX132_REG_WHO, + .id = KX134_1211_ID, + .cntl = KX132_REG_CNTL, + .cntl2 = KX132_REG_CNTL2, + .odcntl = KX132_REG_ODCNTL, + .buf_cntl1 = KX132_REG_BUF_CNTL1, + .buf_cntl2 = KX132_REG_BUF_CNTL2, + .buf_clear = KX132_REG_BUF_CLEAR, + .buf_status1 = KX132_REG_BUF_STATUS_1, + .buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL, + .buf_read = KX132_REG_BUF_READ, + .inc1 = KX132_REG_INC1, + .inc4 = KX132_REG_INC4, + .inc5 = KX132_REG_INC5, + .inc6 = KX132_REG_INC6, + .xout_l = KX132_REG_XOUT_L, + .get_fifo_bytes_available = kx132_get_fifo_bytes_available, +}; +EXPORT_SYMBOL_NS_GPL(kx134_chip_info, "IIO_KX022A"); /* * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is @@ -1215,6 +1252,9 @@ const struct kx022a_chip_info kx132acr_chip_info = { .regmap_config = &kx022a_regmap_config, .channels = kx022a_channels, .num_channels = ARRAY_SIZE(kx022a_channels), + .scale_table = kx022a_scale_table, + .scale_table_size = ARRAY_SIZE(kx022a_scale_table) * + ARRAY_SIZE(kx022a_scale_table[0]), .fifo_length = KX022A_FIFO_LENGTH, .who = KX022A_REG_WHO, .id = KX132ACR_LBZ_ID, @@ -1233,7 +1273,35 @@ const struct kx022a_chip_info kx132acr_chip_info = { .xout_l = KX022A_REG_XOUT_L, .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, }; -EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, "IIO_KX022A"); + +const struct kx022a_chip_info kx134acr_chip_info = { + .name = "kx134acr-lbz", + .regmap_config = &kx022a_regmap_config, + .channels = kx022a_channels, + .num_channels = ARRAY_SIZE(kx022a_channels), + .scale_table = kx134acr_lbz_scale_table, + .scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) * + ARRAY_SIZE(kx134acr_lbz_scale_table[0]), + .fifo_length = KX022A_FIFO_LENGTH, + .who = KX022A_REG_WHO, + .id = KX134ACR_LBZ_ID, + .cntl = KX022A_REG_CNTL, + .cntl2 = KX022A_REG_CNTL2, + .odcntl = KX022A_REG_ODCNTL, + .buf_cntl1 = KX022A_REG_BUF_CNTL1, + .buf_cntl2 = KX022A_REG_BUF_CNTL2, + .buf_clear = KX022A_REG_BUF_CLEAR, + .buf_status1 = KX022A_REG_BUF_STATUS_1, + .buf_read = KX022A_REG_BUF_READ, + .inc1 = KX022A_REG_INC1, + .inc4 = KX022A_REG_INC4, + .inc5 = KX022A_REG_INC5, + .inc6 = KX022A_REG_INC6, + .xout_l = KX022A_REG_XOUT_L, + .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, +}; +EXPORT_SYMBOL_NS_GPL(kx134acr_chip_info, "IIO_KX022A"); int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) { @@ -1371,7 +1439,7 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi return ret; } -EXPORT_SYMBOL_NS_GPL(kx022a_probe_internal, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx022a_probe_internal, "IIO_KX022A"); MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver"); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h index 7060438ad88c..0ed54f584223 100644 --- a/drivers/iio/accel/kionix-kx022a.h +++ b/drivers/iio/accel/kionix-kx022a.h @@ -14,6 +14,7 @@ #define KX022A_REG_WHO 0x0f #define KX022A_ID 0xc8 #define KX132ACR_LBZ_ID 0xd8 +#define KX134ACR_LBZ_ID 0xcc #define KX022A_REG_CNTL2 0x19 #define KX022A_MASK_SRST BIT(7) @@ -77,6 +78,7 @@ #define KX132_REG_WHO 0x13 #define KX132_ID 0x3d +#define KX134_1211_ID 0x46 #define KX132_FIFO_LENGTH 86 @@ -135,6 +137,14 @@ struct kx022a_data; * * @name: name of the device * @regmap_config: pointer to register map configuration + * @scale_table: An array of tables of scaling factors for + * a supported acceleration measurement range. + * Each table containing a single scaling + * factor consisting of two integers. The first + * value in a table is the integer part, and + * the second value is the fractional part as + * parts per billion. + * @scale_table_size: Amount of values in tables. * @channels: pointer to iio_chan_spec array * @num_channels: number of iio_chan_spec channels * @fifo_length: number of 16-bit samples in a full buffer @@ -161,6 +171,8 @@ struct kx022a_data; struct kx022a_chip_info { const char *name; const struct regmap_config *regmap_config; + const int (*scale_table)[2]; + const int scale_table_size; const struct iio_chan_spec *channels; unsigned int num_channels; unsigned int fifo_length; @@ -187,6 +199,8 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi extern const struct kx022a_chip_info kx022a_chip_info; extern const struct kx022a_chip_info kx132_chip_info; +extern const struct kx022a_chip_info kx134_chip_info; extern const struct kx022a_chip_info kx132acr_chip_info; +extern const struct kx022a_chip_info kx134acr_chip_info; #endif diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 126e8bdd6d0e..910d7b5716e1 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -4,13 +4,15 @@ * Copyright (c) 2014, Intel Corporation. */ -#include <linux/module.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/bitops.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/types.h> #include <linux/acpi.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -168,13 +170,73 @@ #define KXCJK1013_DEFAULT_WAKE_THRES 1 -enum kx_chipset { - KXCJK1013, - KXCJ91008, - KXTJ21009, - KXTF9, - KX0231025, - KX_MAX_CHIPS /* this must be last */ +/* Refer to section 4 of the specification */ +struct kx_odr_start_up_time { + int odr_bits; + int usec; +}; + +/* KXCJK-1013 */ +static const struct kx_odr_start_up_time kxcjk1013_odr_start_up_times[] = { + { 0x08, 100000 }, + { 0x09, 100000 }, + { 0x0A, 100000 }, + { 0x0B, 100000 }, + { 0x00, 80000 }, + { 0x01, 41000 }, + { 0x02, 21000 }, + { 0x03, 11000 }, + { 0x04, 6400 }, + { 0x05, 3900 }, + { 0x06, 2700 }, + { 0x07, 2100 }, + { } +}; + +/* KXCTJ2-1009 */ +static const struct kx_odr_start_up_time kxtj21009_odr_start_up_times[] = { + { 0x08, 1240000 }, + { 0x09, 621000 }, + { 0x0A, 309000 }, + { 0x0B, 151000 }, + { 0x00, 80000 }, + { 0x01, 41000 }, + { 0x02, 21000 }, + { 0x03, 11000 }, + { 0x04, 6000 }, + { 0x05, 4000 }, + { 0x06, 3000 }, + { 0x07, 2000 }, + { } +}; + +/* KXTF9 */ +static const struct kx_odr_start_up_time kxtf9_odr_start_up_times[] = { + { 0x01, 81000 }, + { 0x02, 41000 }, + { 0x03, 21000 }, + { 0x04, 11000 }, + { 0x05, 5100 }, + { 0x06, 2700 }, + { } +}; + +/* KX023-1025 */ +static const struct kx_odr_start_up_time kx0231025_odr_start_up_times[] = { + /* First 4 are not in datasheet, taken from KXCTJ2-1009 */ + { 0x08, 1240000 }, + { 0x09, 621000 }, + { 0x0A, 309000 }, + { 0x0B, 151000 }, + { 0x00, 81000 }, + { 0x01, 40000 }, + { 0x02, 22000 }, + { 0x03, 12000 }, + { 0x04, 7000 }, + { 0x05, 4400 }, + { 0x06, 3000 }, + { 0x07, 3000 }, + { } }; enum kx_acpi_type { @@ -233,6 +295,55 @@ static const struct kx_chipset_regs kx0231025_regs = { .wake_thres = KX023_REG_ATH, }; +struct kx_chipset_info { + const struct kx_chipset_regs *regs; + const struct kx_odr_start_up_time *times; + enum kx_acpi_type acpi_type; +}; + +static const struct kx_chipset_info kxcjk1013_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), +}; + +static const struct kx_chipset_info kxcj91008_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), +}; + +static const struct kx_chipset_info kxcj91008_kiox010a_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), + .acpi_type = ACPI_KIOX010A, +}; + +static const struct kx_chipset_info kxcj91008_kiox020a_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), + .acpi_type = ACPI_GENERIC, +}; + +static const struct kx_chipset_info kxcj91008_smo8500_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), + .acpi_type = ACPI_SMO8500, +}; + +static const struct kx_chipset_info kxtj21009_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxtj21009_odr_start_up_times), +}; + +static const struct kx_chipset_info kxtf9_info = { + .regs = &kxtf9_regs, + .times = pm_ptr(kxtf9_odr_start_up_times), +}; + +static const struct kx_chipset_info kx0231025_info = { + .regs = &kx0231025_regs, + .times = pm_ptr(kx0231025_odr_start_up_times), +}; + enum kxcjk1013_axis { AXIS_X, AXIS_Y, @@ -249,7 +360,7 @@ struct kxcjk1013_data { /* Ensure timestamp naturally aligned */ struct { s16 chans[AXIS_MAX]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; u8 odr_bits; u8 range; @@ -260,9 +371,7 @@ struct kxcjk1013_data { int ev_enable_state; bool motion_trigger_on; int64_t timestamp; - enum kx_chipset chipset; - enum kx_acpi_type acpi_type; - const struct kx_chipset_regs *regs; + const struct kx_chipset_info *info; }; enum kxcjk1013_mode { @@ -313,83 +422,6 @@ static const struct kx_odr_map kxtf9_samp_freq_table[] = { static const char *const kxtf9_samp_freq_avail = "25 50 100 200 400 800"; -/* Refer to section 4 of the specification */ -static __maybe_unused const struct { - int odr_bits; - int usec; -} odr_start_up_times[KX_MAX_CHIPS][12] = { - /* KXCJK-1013 */ - { - {0x08, 100000}, - {0x09, 100000}, - {0x0A, 100000}, - {0x0B, 100000}, - {0, 80000}, - {0x01, 41000}, - {0x02, 21000}, - {0x03, 11000}, - {0x04, 6400}, - {0x05, 3900}, - {0x06, 2700}, - {0x07, 2100}, - }, - /* KXCJ9-1008 */ - { - {0x08, 100000}, - {0x09, 100000}, - {0x0A, 100000}, - {0x0B, 100000}, - {0, 80000}, - {0x01, 41000}, - {0x02, 21000}, - {0x03, 11000}, - {0x04, 6400}, - {0x05, 3900}, - {0x06, 2700}, - {0x07, 2100}, - }, - /* KXCTJ2-1009 */ - { - {0x08, 1240000}, - {0x09, 621000}, - {0x0A, 309000}, - {0x0B, 151000}, - {0, 80000}, - {0x01, 41000}, - {0x02, 21000}, - {0x03, 11000}, - {0x04, 6000}, - {0x05, 4000}, - {0x06, 3000}, - {0x07, 2000}, - }, - /* KXTF9 */ - { - {0x01, 81000}, - {0x02, 41000}, - {0x03, 21000}, - {0x04, 11000}, - {0x05, 5100}, - {0x06, 2700}, - }, - /* KX023-1025 */ - { - /* First 4 are not in datasheet, taken from KXCTJ2-1009 */ - {0x08, 1240000}, - {0x09, 621000}, - {0x0A, 309000}, - {0x0B, 151000}, - {0, 81000}, - {0x01, 40000}, - {0x02, 22000}, - {0x03, 12000}, - {0x04, 7000}, - {0x05, 4400}, - {0x06, 3000}, - {0x07, 3000}, - }, -}; - static const struct { u16 scale; u8 gsel_0; @@ -423,30 +455,15 @@ static int kiox010a_dsm(struct device *dev, int fn_index) return 0; } -static const struct acpi_device_id kx_acpi_match[] = { - {"KXCJ1013", KXCJK1013}, - {"KXCJ1008", KXCJ91008}, - {"KXCJ9000", KXCJ91008}, - {"KIOX0008", KXCJ91008}, - {"KIOX0009", KXTJ21009}, - {"KIOX000A", KXCJ91008}, - {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */ - {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */ - {"KXTJ1009", KXTJ21009}, - {"KXJ2109", KXTJ21009}, - {"SMO8500", KXCJ91008}, - { } -}; -MODULE_DEVICE_TABLE(acpi, kx_acpi_match); - #endif static int kxcjk1013_set_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode mode) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -457,7 +474,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, else ret |= KXCJK1013_REG_CTRL1_BIT_PC1; - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -469,9 +486,10 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, static int kxcjk1013_get_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode *mode) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -487,9 +505,10 @@ static int kxcjk1013_get_mode(struct kxcjk1013_data *data, static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -500,7 +519,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3); ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4); - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -513,10 +532,11 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) static int kxcjk1013_chip_init(struct kxcjk1013_data *data) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; #ifdef CONFIG_ACPI - if (data->acpi_type == ACPI_KIOX010A) { + if (data->info->acpi_type == ACPI_KIOX010A) { /* Make sure the kbd and touchpad on 2-in-1s using 2 KXCJ91008-s work */ kiox010a_dsm(&data->client->dev, KIOX010A_SET_LAPTOP_MODE); } @@ -534,7 +554,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -543,7 +563,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) /* Set 12 bit mode */ ret |= KXCJK1013_REG_CTRL1_BIT_RES; - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl\n"); return ret; @@ -554,7 +574,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->data_ctrl); + ret = i2c_smbus_read_byte_data(data->client, regs->data_ctrl); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); return ret; @@ -563,7 +583,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) data->odr_bits = ret; /* Set up INT polarity */ - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -574,14 +594,14 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA; - ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; } /* On KX023, route all used interrupts to INT1 for now */ - if (data->chipset == KX0231025 && data->client->irq > 0) { + if (data->info == &kx0231025_info && data->client->irq > 0) { ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4, KX023_REG_INC4_DRDY1 | KX023_REG_INC4_WUFI1); @@ -600,20 +620,17 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return 0; } -#ifdef CONFIG_PM static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) { - int i; - int idx = data->chipset; + const struct kx_odr_start_up_time *times; - for (i = 0; i < ARRAY_SIZE(odr_start_up_times[idx]); ++i) { - if (odr_start_up_times[idx][i].odr_bits == data->odr_bits) - return odr_start_up_times[idx][i].usec; + for (times = data->info->times; times->usec; times++) { + if (times->odr_bits == data->odr_bits) + return times->usec; } return KXCJK1013_MAX_STARTUP_TIME_US; } -#endif static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) { @@ -636,98 +653,19 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) return 0; } -#ifdef CONFIG_ACPI -static bool kxj_acpi_orientation(struct device *dev, - struct iio_mount_matrix *orientation) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_device *adev = ACPI_COMPANION(dev); - char *str; - union acpi_object *obj, *elements; - acpi_status status; - int i, j, val[3]; - bool ret = false; - - if (!acpi_has_method(adev->handle, "ROTM")) - return false; - - status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer); - if (ACPI_FAILURE(status)) { - dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status); - return false; - } - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) { - dev_err(dev, "Unknown ACPI mount matrix package format\n"); - goto out_free_buffer; - } - - elements = obj->package.elements; - for (i = 0; i < 3; i++) { - if (elements[i].type != ACPI_TYPE_STRING) { - dev_err(dev, "Unknown ACPI mount matrix element format\n"); - goto out_free_buffer; - } - - str = elements[i].string.pointer; - if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) { - dev_err(dev, "Incorrect ACPI mount matrix string format\n"); - goto out_free_buffer; - } - - for (j = 0; j < 3; j++) { - switch (val[j]) { - case -1: str = "-1"; break; - case 0: str = "0"; break; - case 1: str = "1"; break; - default: - dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]); - goto out_free_buffer; - } - orientation->rotation[i * 3 + j] = str; - } - } - - ret = true; - -out_free_buffer: - kfree(buffer.pointer); - return ret; -} - -static bool kxj1009_apply_acpi_orientation(struct device *dev, - struct iio_mount_matrix *orientation) -{ - struct acpi_device *adev = ACPI_COMPANION(dev); - - if (adev && acpi_dev_hid_uid_match(adev, "KIOX000A", NULL)) - return kxj_acpi_orientation(dev, orientation); - - return false; -} -#else -static bool kxj1009_apply_acpi_orientation(struct device *dev, - struct iio_mount_matrix *orientation) -{ - return false; -} -#endif - static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_timer, - data->wake_dur); + ret = i2c_smbus_write_byte_data(data->client, regs->wake_timer, data->wake_dur); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_wake_timer\n"); return ret; } - ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_thres, - data->wake_thres); + ret = i2c_smbus_write_byte_data(data->client, regs->wake_thres, data->wake_thres); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_wake_thres\n"); return ret; @@ -736,9 +674,10 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) return 0; } -static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, - bool status) +static int kxcjk1013_setup_interrupt(struct kxcjk1013_data *data, + bool status, bool is_new_data) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; enum kxcjk1013_mode store_mode; @@ -751,69 +690,13 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, if (ret < 0) return ret; - ret = kxcjk1013_chip_update_thresholds(data); - if (ret < 0) - return ret; - - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); - return ret; - } - - if (status) - ret |= KXCJK1013_REG_INT_CTRL1_BIT_IEN; - else - ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN; - - ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); - return ret; - } - - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); - return ret; - } - - if (status) - ret |= KXCJK1013_REG_CTRL1_BIT_WUFE; - else - ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; - - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); - return ret; - } - - if (store_mode == OPERATION) { - ret = kxcjk1013_set_mode(data, OPERATION); + if (is_new_data == true) { + ret = kxcjk1013_chip_update_thresholds(data); if (ret < 0) return ret; } - return 0; -} - -static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, - bool status) -{ - int ret; - enum kxcjk1013_mode store_mode; - - ret = kxcjk1013_get_mode(data, &store_mode); - if (ret < 0) - return ret; - - /* This is requirement by spec to change state to STANDBY */ - ret = kxcjk1013_set_mode(data, STANDBY); - if (ret < 0) - return ret; - - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -824,24 +707,31 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN; - ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; } - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; } - if (status) - ret |= KXCJK1013_REG_CTRL1_BIT_DRDY; - else - ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; + if (is_new_data) { + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_DRDY; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; + } else { + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_WUFE; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; + } - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -888,6 +778,7 @@ static int kxcjk1013_convert_odr_value(const struct kx_odr_map *map, static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; enum kxcjk1013_mode store_mode; const struct kx_odr_map *odr_setting; @@ -896,7 +787,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) if (ret < 0) return ret; - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) odr_setting = kxcjk1013_find_odr_value(kxtf9_samp_freq_table, ARRAY_SIZE(kxtf9_samp_freq_table), val, val2); @@ -913,7 +804,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) if (ret < 0) return ret; - ret = i2c_smbus_write_byte_data(data->client, data->regs->data_ctrl, + ret = i2c_smbus_write_byte_data(data->client, regs->data_ctrl, odr_setting->odr_bits); if (ret < 0) { dev_err(&data->client->dev, "Error writing data_ctrl\n"); @@ -922,7 +813,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) data->odr_bits = odr_setting->odr_bits; - ret = i2c_smbus_write_byte_data(data->client, data->regs->wuf_ctrl, + ret = i2c_smbus_write_byte_data(data->client, regs->wuf_ctrl, odr_setting->wuf_bits); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl2\n"); @@ -940,7 +831,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) static int kxcjk1013_get_odr(struct kxcjk1013_data *data, int *val, int *val2) { - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) return kxcjk1013_convert_odr_value(kxtf9_samp_freq_table, ARRAY_SIZE(kxtf9_samp_freq_table), data->odr_bits, val, val2); @@ -1140,7 +1031,7 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int state) + bool state) { struct kxcjk1013_data *data = iio_priv(indio_dev); int ret; @@ -1171,7 +1062,7 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev, return ret; } - ret = kxcjk1013_setup_any_motion_interrupt(data, state); + ret = kxcjk1013_setup_interrupt(data, state, false); if (ret < 0) { kxcjk1013_set_power_state(data, false); data->ev_enable_state = 0; @@ -1207,7 +1098,7 @@ static ssize_t kxcjk1013_get_samp_freq_avail(struct device *dev, struct kxcjk1013_data *data = iio_priv(indio_dev); const char *str; - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) str = kxtf9_samp_freq_avail; else str = kxcjk1013_samp_freq_avail; @@ -1284,7 +1175,7 @@ static const struct iio_buffer_setup_ops kxcjk1013_buffer_setup_ops = { .postdisable = kxcjk1013_buffer_postdisable, }; -static const struct iio_info kxcjk1013_info = { +static const struct iio_info kxcjk1013_iio_info = { .attrs = &kxcjk1013_attrs_group, .read_raw = kxcjk1013_read_raw, .write_raw = kxcjk1013_write_raw, @@ -1312,8 +1203,8 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - data->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + data->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -1324,9 +1215,10 @@ static void kxcjk1013_trig_reen(struct iio_trigger *trig) { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct kxcjk1013_data *data = iio_priv(indio_dev); + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel); + ret = i2c_smbus_read_byte_data(data->client, regs->int_rel); if (ret < 0) dev_err(&data->client->dev, "Error reading reg_int_rel\n"); } @@ -1351,10 +1243,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, mutex_unlock(&data->mutex); return ret; } - if (data->motion_trig == trig) - ret = kxcjk1013_setup_any_motion_interrupt(data, state); - else - ret = kxcjk1013_setup_new_data_interrupt(data, state); + ret = kxcjk1013_setup_interrupt(data, state, data->motion_trig != trig); if (ret < 0) { kxcjk1013_set_power_state(data, false); mutex_unlock(&data->mutex); @@ -1378,8 +1267,9 @@ static const struct iio_trigger_ops kxcjk1013_trigger_ops = { static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev) { struct kxcjk1013_data *data = iio_priv(indio_dev); + const struct kx_chipset_regs *regs = data->info->regs; - int ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src2); + int ret = i2c_smbus_read_byte_data(data->client, regs->int_src2); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_src2\n"); return; @@ -1444,16 +1334,17 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct kxcjk1013_data *data = iio_priv(indio_dev); + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src1); + ret = i2c_smbus_read_byte_data(data->client, regs->int_src1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_src1\n"); goto ack_intr; } if (ret & KXCJK1013_REG_INT_SRC1_BIT_WUFS) { - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, @@ -1469,7 +1360,7 @@ ack_intr: if (data->dready_trigger_on) return IRQ_HANDLED; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel); + ret = i2c_smbus_read_byte_data(data->client, regs->int_rel); if (ret < 0) dev_err(&data->client->dev, "Error reading reg_int_rel\n"); @@ -1494,31 +1385,6 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } -static const char *kxcjk1013_match_acpi_device(struct device *dev, - enum kx_chipset *chipset, - enum kx_acpi_type *acpi_type, - const char **label) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - if (strcmp(id->id, "SMO8500") == 0) { - *acpi_type = ACPI_SMO8500; - } else if (strcmp(id->id, "KIOX010A") == 0) { - *acpi_type = ACPI_KIOX010A; - *label = "accel-display"; - } else if (strcmp(id->id, "KIOX020A") == 0) { - *label = "accel-base"; - } - - *chipset = (enum kx_chipset)id->driver_data; - - return dev_name(dev); -} - static int kxcjk1013_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -1526,6 +1392,7 @@ static int kxcjk1013_probe(struct i2c_client *client) struct kxcjk1013_data *data; struct iio_dev *indio_dev; struct kxcjk_1013_platform_data *pdata; + const void *ddata = NULL; const char *name; int ret; @@ -1544,7 +1411,7 @@ static int kxcjk1013_probe(struct i2c_client *client) } else { data->active_high_intr = true; /* default polarity */ - if (!kxj1009_apply_acpi_orientation(&client->dev, &data->orientation)) { + if (!iio_read_acpi_mount_matrix(&client->dev, &data->orientation, "ROTM")) { ret = iio_read_mount_matrix(&client->dev, &data->orientation); if (ret) return ret; @@ -1566,31 +1433,18 @@ static int kxcjk1013_probe(struct i2c_client *client) msleep(20); if (id) { - data->chipset = (enum kx_chipset)(id->driver_data); name = id->name; - } else if (ACPI_HANDLE(&client->dev)) { - name = kxcjk1013_match_acpi_device(&client->dev, - &data->chipset, - &data->acpi_type, - &indio_dev->label); - } else - return -ENODEV; - - switch (data->chipset) { - case KXCJK1013: - case KXCJ91008: - case KXTJ21009: - data->regs = &kxcjk1013_regs; - break; - case KXTF9: - data->regs = &kxtf9_regs; - break; - case KX0231025: - data->regs = &kx0231025_regs; - break; - default: - return -EINVAL; + data->info = (const struct kx_chipset_info *)(id->driver_data); + } else { + name = iio_get_acpi_device_name_and_data(&client->dev, &ddata); + data->info = ddata; + if (data->info == &kxcj91008_kiox010a_info) + indio_dev->label = "accel-display"; + else if (data->info == &kxcj91008_kiox020a_info) + indio_dev->label = "accel-base"; } + if (!name) + return -ENODEV; ret = kxcjk1013_chip_init(data); if (ret < 0) @@ -1603,9 +1457,9 @@ static int kxcjk1013_probe(struct i2c_client *client) indio_dev->available_scan_masks = kxcjk1013_scan_masks; indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &kxcjk1013_info; + indio_dev->info = &kxcjk1013_iio_info; - if (client->irq > 0 && data->acpi_type != ACPI_SMO8500) { + if (client->irq > 0 && data->info->acpi_type != ACPI_SMO8500) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, @@ -1713,7 +1567,6 @@ static void kxcjk1013_remove(struct i2c_client *client) mutex_unlock(&data->mutex); } -#ifdef CONFIG_PM_SLEEP static int kxcjk1013_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1741,9 +1594,7 @@ static int kxcjk1013_resume(struct device *dev) return ret; } -#endif -#ifdef CONFIG_PM static int kxcjk1013_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1777,42 +1628,56 @@ static int kxcjk1013_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops kxcjk1013_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume) - SET_RUNTIME_PM_OPS(kxcjk1013_runtime_suspend, - kxcjk1013_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume) + RUNTIME_PM_OPS(kxcjk1013_runtime_suspend, kxcjk1013_runtime_resume, NULL) }; static const struct i2c_device_id kxcjk1013_id[] = { - {"kxcjk1013", KXCJK1013}, - {"kxcj91008", KXCJ91008}, - {"kxtj21009", KXTJ21009}, - {"kxtf9", KXTF9}, - {"kx023-1025", KX0231025}, - {"SMO8500", KXCJ91008}, - {} + { "kxcjk1013", (kernel_ulong_t)&kxcjk1013_info }, + { "kxcj91008", (kernel_ulong_t)&kxcj91008_info }, + { "kxtj21009", (kernel_ulong_t)&kxtj21009_info }, + { "kxtf9", (kernel_ulong_t)&kxtf9_info }, + { "kx023-1025", (kernel_ulong_t)&kx0231025_info }, + { } }; - MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); static const struct of_device_id kxcjk1013_of_match[] = { - { .compatible = "kionix,kxcjk1013", }, - { .compatible = "kionix,kxcj91008", }, - { .compatible = "kionix,kxtj21009", }, - { .compatible = "kionix,kxtf9", }, - { .compatible = "kionix,kx023-1025", }, + { .compatible = "kionix,kxcjk1013", &kxcjk1013_info }, + { .compatible = "kionix,kxcj91008", &kxcj91008_info }, + { .compatible = "kionix,kxtj21009", &kxtj21009_info }, + { .compatible = "kionix,kxtf9", &kxtf9_info }, + { .compatible = "kionix,kx023-1025", &kx0231025_info }, { } }; MODULE_DEVICE_TABLE(of, kxcjk1013_of_match); +static const struct acpi_device_id kx_acpi_match[] = { + { "KIOX0008", (kernel_ulong_t)&kxcj91008_info }, + { "KIOX0009", (kernel_ulong_t)&kxtj21009_info }, + { "KIOX000A", (kernel_ulong_t)&kxcj91008_info }, + /* KXCJ91008 in the display of a yoga 2-in-1 */ + { "KIOX010A", (kernel_ulong_t)&kxcj91008_kiox010a_info }, + /* KXCJ91008 in the base of a yoga 2-in-1 */ + { "KIOX020A", (kernel_ulong_t)&kxcj91008_kiox020a_info }, + { "KXCJ1008", (kernel_ulong_t)&kxcj91008_info }, + { "KXCJ1013", (kernel_ulong_t)&kxcjk1013_info }, + { "KXCJ9000", (kernel_ulong_t)&kxcj91008_info }, + { "KXJ2109", (kernel_ulong_t)&kxtj21009_info }, + { "KXTJ1009", (kernel_ulong_t)&kxtj21009_info }, + { "SMO8500", (kernel_ulong_t)&kxcj91008_smo8500_info }, + { } +}; +MODULE_DEVICE_TABLE(acpi, kx_acpi_match); + static struct i2c_driver kxcjk1013_driver = { .driver = { .name = KXCJK1013_DRV_NAME, - .acpi_match_table = ACPI_PTR(kx_acpi_match), + .acpi_match_table = kx_acpi_match, .of_match_table = kxcjk1013_of_match, - .pm = &kxcjk1013_pm_ops, + .pm = pm_ptr(&kxcjk1013_pm_ops), }, .probe = kxcjk1013_probe, .remove = kxcjk1013_remove, diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 3bc9ee1f9db3..1fa88b99149e 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -38,13 +38,13 @@ static void kxsd9_i2c_remove(struct i2c_client *client) static const struct of_device_id kxsd9_of_match[] = { { .compatible = "kionix,kxsd9", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, kxsd9_of_match); static const struct i2c_device_id kxsd9_i2c_id[] = { - {"kxsd9", 0}, - { }, + { "kxsd9" }, + { } }; MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id); @@ -62,4 +62,4 @@ module_i2c_driver(kxsd9_i2c_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("KXSD9 accelerometer I2C interface"); -MODULE_IMPORT_NS(IIO_KXSD9); +MODULE_IMPORT_NS("IIO_KXSD9"); diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index 4414670dfb43..cbb6c6412665 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -38,7 +38,7 @@ static void kxsd9_spi_remove(struct spi_device *spi) static const struct spi_device_id kxsd9_spi_id[] = { {"kxsd9", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(spi, kxsd9_spi_id); @@ -63,4 +63,4 @@ module_spi_driver(kxsd9_spi_driver); MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_KXSD9); +MODULE_IMPORT_NS("IIO_KXSD9"); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index ba99649fe195..cfc31265cdd0 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -15,6 +15,7 @@ #include <linux/kernel.h> #include <linux/sysfs.h> #include <linux/slab.h> +#include <linux/types.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/bitops.h> @@ -215,7 +216,7 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p) */ struct { __be16 chan[4]; - s64 ts __aligned(8); + aligned_s64 ts; } hw_values; int ret; @@ -228,9 +229,8 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p) goto out; } - iio_push_to_buffers_with_timestamp(indio_dev, - &hw_values, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &hw_values, sizeof(hw_values), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -272,7 +272,7 @@ kxsd9_get_mount_matrix(const struct iio_dev *indio_dev, static const struct iio_chan_spec_ext_info kxsd9_ext_info[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kxsd9_get_mount_matrix), - { }, + { } }; #define KXSD9_ACCEL_CHAN(axis, index) \ @@ -370,10 +370,7 @@ static int kxsd9_power_down(struct kxsd9_state *st) * make sure we conserve power even if there are others users on the * regulators. */ - ret = regmap_update_bits(st->map, - KXSD9_REG_CTRL_B, - KXSD9_CTRL_B_ENABLE, - 0); + ret = regmap_clear_bits(st->map, KXSD9_REG_CTRL_B, KXSD9_CTRL_B_ENABLE); if (ret) return ret; @@ -476,7 +473,7 @@ err_power_down: return ret; } -EXPORT_SYMBOL_NS(kxsd9_common_probe, IIO_KXSD9); +EXPORT_SYMBOL_NS(kxsd9_common_probe, "IIO_KXSD9"); void kxsd9_common_remove(struct device *dev) { @@ -490,7 +487,7 @@ void kxsd9_common_remove(struct device *dev) pm_runtime_disable(dev); kxsd9_power_down(st); } -EXPORT_SYMBOL_NS(kxsd9_common_remove, IIO_KXSD9); +EXPORT_SYMBOL_NS(kxsd9_common_remove, "IIO_KXSD9"); static int kxsd9_runtime_suspend(struct device *dev) { diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index 6b87c2c9945c..e2853090fa6e 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -22,20 +22,37 @@ #define MC3230_MODE_OPCON_STANDBY 0x03 #define MC3230_REG_CHIP_ID 0x18 -#define MC3230_CHIP_ID 0x01 - #define MC3230_REG_PRODUCT_CODE 0x3b -#define MC3230_PRODUCT_CODE 0x19 /* * The accelerometer has one measurement range: * * -1.5g - +1.5g (8-bit, signed) * - * scale = (1.5 + 1.5) * 9.81 / (2^8 - 1) = 0.115411765 */ -static const int mc3230_nscale = 115411765; +struct mc3230_chip_info { + const char *name; + const u8 chip_id; + const u8 product_code; + const int scale; +}; + +static const struct mc3230_chip_info mc3230_chip_info = { + .name = "mc3230", + .chip_id = 0x01, + .product_code = 0x19, + /* (1.5 + 1.5) * 9.81 / (2^8 - 1) = 0.115411765 */ + .scale = 115411765, +}; + +static const struct mc3230_chip_info mc3510c_chip_info = { + .name = "mc3510c", + .chip_id = 0x23, + .product_code = 0x10, + /* Was obtained empirically */ + .scale = 625000000, +}; #define MC3230_CHANNEL(reg, axis) { \ .type = IIO_ACCEL, \ @@ -44,18 +61,35 @@ static const int mc3230_nscale = 115411765; .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = mc3230_ext_info, \ +} + +struct mc3230_data { + const struct mc3230_chip_info *chip_info; + struct i2c_client *client; + struct iio_mount_matrix orientation; +}; + +static const struct iio_mount_matrix * +mc3230_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mc3230_data *data = iio_priv(indio_dev); + + return &data->orientation; } +static const struct iio_chan_spec_ext_info mc3230_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, mc3230_get_mount_matrix), + { } +}; + static const struct iio_chan_spec mc3230_channels[] = { MC3230_CHANNEL(MC3230_REG_XOUT, X), MC3230_CHANNEL(MC3230_REG_YOUT, Y), MC3230_CHANNEL(MC3230_REG_ZOUT, Z), }; -struct mc3230_data { - struct i2c_client *client; -}; - static int mc3230_set_opcon(struct mc3230_data *data, int opcon) { int ret; @@ -95,7 +129,7 @@ static int mc3230_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = mc3230_nscale; + *val2 = data->chip_info->scale; return IIO_VAL_INT_PLUS_NANO; default: return -EINVAL; @@ -111,15 +145,28 @@ static int mc3230_probe(struct i2c_client *client) int ret; struct iio_dev *indio_dev; struct mc3230_data *data; + const struct mc3230_chip_info *chip_info; + + chip_info = i2c_get_match_data(client); + if (chip_info == NULL) { + dev_err(&client->dev, "failed to get match data"); + return -ENODATA; + } /* First check chip-id and product-id */ ret = i2c_smbus_read_byte_data(client, MC3230_REG_CHIP_ID); - if (ret != MC3230_CHIP_ID) - return (ret < 0) ? ret : -ENODEV; + if (ret != chip_info->chip_id) { + dev_info(&client->dev, + "chip id check fail: 0x%x != 0x%x !\n", + ret, chip_info->chip_id); + } ret = i2c_smbus_read_byte_data(client, MC3230_REG_PRODUCT_CODE); - if (ret != MC3230_PRODUCT_CODE) - return (ret < 0) ? ret : -ENODEV; + if (ret != chip_info->product_code) { + dev_info(&client->dev, + "product code check fail: 0x%x != 0x%x !\n", + ret, chip_info->product_code); + } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) { @@ -128,11 +175,12 @@ static int mc3230_probe(struct i2c_client *client) } data = iio_priv(indio_dev); + data->chip_info = chip_info; data->client = client; i2c_set_clientdata(client, indio_dev); indio_dev->info = &mc3230_info; - indio_dev->name = "mc3230"; + indio_dev->name = chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = mc3230_channels; indio_dev->num_channels = ARRAY_SIZE(mc3230_channels); @@ -141,6 +189,10 @@ static int mc3230_probe(struct i2c_client *client) if (ret < 0) return ret; + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "device_register failed\n"); @@ -180,14 +232,23 @@ static int mc3230_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume); static const struct i2c_device_id mc3230_i2c_id[] = { - {"mc3230", 0}, - {} + { "mc3230", (kernel_ulong_t)&mc3230_chip_info }, + { "mc3510c", (kernel_ulong_t)&mc3510c_chip_info }, + { } }; MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id); +static const struct of_device_id mc3230_of_match[] = { + { .compatible = "mcube,mc3230", &mc3230_chip_info }, + { .compatible = "mcube,mc3510c", &mc3510c_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, mc3230_of_match); + static struct i2c_driver mc3230_driver = { .driver = { .name = "mc3230", + .of_match_table = mc3230_of_match, .pm = pm_sleep_ptr(&mc3230_pm_ops), }, .probe = mc3230_probe, diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index a34195b3215d..a2b5bdf14dde 100644 --- a/drivers/iio/accel/mma7455_core.c +++ b/drivers/iio/accel/mma7455_core.c @@ -19,6 +19,7 @@ #include <linux/iio/triggered_buffer.h> #include <linux/module.h> #include <linux/regmap.h> +#include <linux/types.h> #include "mma7455.h" @@ -58,7 +59,7 @@ struct mma7455_data { */ struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; }; @@ -102,8 +103,9 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p) if (ret) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &mma7455->scan, + sizeof(mma7455->scan), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); @@ -238,7 +240,7 @@ const struct regmap_config mma7455_core_regmap = { .val_bits = 8, .max_register = MMA7455_REG_TW, }; -EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, IIO_MMA7455); +EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, "IIO_MMA7455"); int mma7455_core_probe(struct device *dev, struct regmap *regmap, const char *name) @@ -293,7 +295,7 @@ int mma7455_core_probe(struct device *dev, struct regmap *regmap, return 0; } -EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, IIO_MMA7455); +EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, "IIO_MMA7455"); void mma7455_core_remove(struct device *dev) { @@ -306,7 +308,7 @@ void mma7455_core_remove(struct device *dev) regmap_write(mma7455->regmap, MMA7455_REG_MCTL, MMA7455_MCTL_MODE_STANDBY); } -EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, IIO_MMA7455); +EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, "IIO_MMA7455"); MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver"); diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index 14f7850a22f0..2ff8eb1f9ce9 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -32,8 +32,8 @@ static void mma7455_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id mma7455_i2c_ids[] = { - { "mma7455", 0 }, - { "mma7456", 0 }, + { "mma7455" }, + { "mma7456" }, { } }; MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids); @@ -59,4 +59,4 @@ module_i2c_driver(mma7455_i2c_driver); MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); MODULE_DESCRIPTION("Freescale MMA7455L I2C accelerometer driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MMA7455); +MODULE_IMPORT_NS("IIO_MMA7455"); diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c index fcdde2e8a84b..aca02e83f789 100644 --- a/drivers/iio/accel/mma7455_spi.c +++ b/drivers/iio/accel/mma7455_spi.c @@ -47,4 +47,4 @@ module_spi_driver(mma7455_spi_driver); MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); MODULE_DESCRIPTION("Freescale MMA7455L SPI accelerometer driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MMA7455); +MODULE_IMPORT_NS("IIO_MMA7455"); diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index 260cbceaa151..d0a16f227903 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -38,21 +38,6 @@ static const int mma7660_nscale = 467142857; -#define MMA7660_CHANNEL(reg, axis) { \ - .type = IIO_ACCEL, \ - .address = reg, \ - .modified = 1, \ - .channel2 = IIO_MOD_##axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ -} - -static const struct iio_chan_spec mma7660_channels[] = { - MMA7660_CHANNEL(MMA7660_REG_XOUT, X), - MMA7660_CHANNEL(MMA7660_REG_YOUT, Y), - MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z), -}; - enum mma7660_mode { MMA7660_MODE_STANDBY, MMA7660_MODE_ACTIVE @@ -62,6 +47,21 @@ struct mma7660_data { struct i2c_client *client; struct mutex lock; enum mma7660_mode mode; + struct iio_mount_matrix orientation; +}; + +static const struct iio_mount_matrix * +mma7660_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mma7660_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info mma7660_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, mma7660_get_mount_matrix), + { } }; static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL); @@ -75,6 +75,22 @@ static const struct attribute_group mma7660_attribute_group = { .attrs = mma7660_attributes }; +#define MMA7660_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = mma7660_ext_info, \ +} + +static const struct iio_chan_spec mma7660_channels[] = { + MMA7660_CHANNEL(MMA7660_REG_XOUT, X), + MMA7660_CHANNEL(MMA7660_REG_YOUT, Y), + MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z), +}; + static int mma7660_set_mode(struct mma7660_data *data, enum mma7660_mode mode) { @@ -187,6 +203,10 @@ static int mma7660_probe(struct i2c_client *client) mutex_init(&data->lock); data->mode = MMA7660_MODE_STANDBY; + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; + indio_dev->info = &mma7660_info; indio_dev->name = MMA7660_DRIVER_NAME; indio_dev->modes = INDIO_DIRECT_MODE; @@ -241,8 +261,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume); static const struct i2c_device_id mma7660_i2c_id[] = { - {"mma7660", 0}, - {} + { "mma7660" }, + { } }; MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); @@ -254,7 +274,7 @@ MODULE_DEVICE_TABLE(of, mma7660_of_match); static const struct acpi_device_id mma7660_acpi_id[] = { {"MMA7660", 0}, - {} + { } }; MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d3fd0318e47b..aba444a980d9 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -19,6 +19,8 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/property.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -28,10 +30,9 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/events.h> #include <linux/delay.h> -#include <linux/of.h> -#include <linux/of_irq.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/types.h> #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) @@ -115,7 +116,7 @@ struct mma8452_data { /* Ensure correct alignment of time stamp when present */ struct { __be16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } buffer; }; @@ -496,14 +497,13 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&data->lock); ret = mma8452_read(data, buffer); mutex_unlock(&data->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -706,55 +706,45 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg); } -static int mma8452_write_raw(struct iio_dev *indio_dev, +static int __mma8452_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct mma8452_data *data = iio_priv(indio_dev); - int i, ret; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + int i, j, ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_samp_freq_index(data, val, val2); - if (i < 0) { - ret = i; - break; - } + if (i < 0) + return i; + data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; data->sleep_val = mma8452_calculate_sleep(data); - ret = mma8452_change_config(data, MMA8452_CTRL_REG1, - data->ctrl_reg1); - break; + return mma8452_change_config(data, MMA8452_CTRL_REG1, + data->ctrl_reg1); + case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); - if (i < 0) { - ret = i; - break; - } + if (i < 0) + return i; data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; - ret = mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); - break; + return mma8452_change_config(data, MMA8452_DATA_CFG, + data->data_cfg); + case IIO_CHAN_INFO_CALIBBIAS: - if (val < -128 || val > 127) { - ret = -EINVAL; - break; - } + if (val < -128 || val > 127) + return -EINVAL; - ret = mma8452_change_config(data, - MMA8452_OFF_X + chan->scan_index, - val); - break; + return mma8452_change_config(data, + MMA8452_OFF_X + chan->scan_index, + val); case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (val == 0 && val2 == 0) { @@ -763,29 +753,38 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; ret = mma8452_set_hp_filter_frequency(data, val, val2); if (ret < 0) - break; + return ret; } - ret = mma8452_change_config(data, MMA8452_DATA_CFG, + return mma8452_change_config(data, MMA8452_DATA_CFG, data->data_cfg); - break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = mma8452_get_odr_index(data); + j = mma8452_get_odr_index(data); for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) { - if (mma8452_os_ratio[i][ret] == val) { - ret = mma8452_set_power_mode(data, i); - break; - } + if (mma8452_os_ratio[i][j] == val) + return mma8452_set_power_mode(data, i); } - break; + + return -EINVAL; + default: - ret = -EINVAL; - break; + return -EINVAL; } +} + +static int mma8452_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - iio_device_release_direct_mode(indio_dev); + ret = __mma8452_write_raw(indio_dev, chan, val, val2, mask); + iio_device_release_direct(indio_dev); return ret; } @@ -973,7 +972,7 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int state) + bool state) { struct mma8452_data *data = iio_priv(indio_dev); int val, ret; @@ -1104,8 +1103,9 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) if (ret < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); @@ -1642,7 +1642,7 @@ static int mma8452_probe(struct i2c_client *client) if (client->irq) { int irq2; - irq2 = of_irq_get_byname(client->dev.of_node, "INT2"); + irq2 = fwnode_irq_get_byname(dev_fwnode(&client->dev), "INT2"); if (irq2 == client->irq) { dev_dbg(&client->dev, "using interrupt line INT2\n"); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 083c08f65baf..b89bad9e6fe6 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -4,11 +4,11 @@ * Copyright (c) 2014, Intel Corporation. */ -#include <linux/module.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/slab.h> -#include <linux/acpi.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/iio/iio.h> @@ -45,7 +45,7 @@ enum mma9551_tilt_axis { struct mma9551_data { struct i2c_client *client; struct mutex mutex; - int event_enabled[3]; + bool event_enabled[3]; int irqs[MMA9551_GPIO_COUNT]; }; @@ -162,7 +162,7 @@ static int mma9551_read_event_config(struct iio_dev *indio_dev, static int mma9551_config_incli_event(struct iio_dev *indio_dev, enum iio_modifier axis, - int state) + bool state) { struct mma9551_data *data = iio_priv(indio_dev); enum mma9551_tilt_axis mma_axis; @@ -174,7 +174,7 @@ static int mma9551_config_incli_event(struct iio_dev *indio_dev, if (data->event_enabled[mma_axis] == state) return 0; - if (state == 0) { + if (!state) { ret = mma9551_gpio_config(data->client, (enum mma9551_gpio_pin)mma_axis, MMA9551_APPID_NONE, 0, 0); @@ -225,7 +225,7 @@ static int mma9551_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int state) + bool state) { struct mma9551_data *data = iio_priv(indio_dev); int ret; @@ -435,17 +435,6 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev) return 0; } -static const char *mma9551_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - return dev_name(dev); -} - static int mma9551_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -464,8 +453,8 @@ static int mma9551_probe(struct i2c_client *client) if (id) name = id->name; - else if (ACPI_HANDLE(&client->dev)) - name = mma9551_match_acpi_device(&client->dev); + else + name = iio_get_acpi_device_name(&client->dev); ret = mma9551_init(data); if (ret < 0) @@ -589,14 +578,14 @@ static const struct dev_pm_ops mma9551_pm_ops = { static const struct acpi_device_id mma9551_acpi_match[] = { {"MMA9551", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match); static const struct i2c_device_id mma9551_id[] = { - {"mma9551", 0}, - {} + { "mma9551" }, + { } }; MODULE_DEVICE_TABLE(i2c, mma9551_id); @@ -618,4 +607,4 @@ MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver"); -MODULE_IMPORT_NS(IIO_MMA9551); +MODULE_IMPORT_NS("IIO_MMA9551"); diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index b898f865fb87..3e7d9b79ed0e 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -219,7 +219,7 @@ int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, reg, NULL, 0, val, 1); } -EXPORT_SYMBOL_NS(mma9551_read_config_byte, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_config_byte, "IIO_MMA9551"); /** * mma9551_write_config_byte() - write 1 configuration byte @@ -244,7 +244,7 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, &val, 1, NULL, 0); } -EXPORT_SYMBOL_NS(mma9551_write_config_byte, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_write_config_byte, "IIO_MMA9551"); /** * mma9551_read_status_byte() - read 1 status byte @@ -269,7 +269,7 @@ int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, reg, NULL, 0, val, 1); } -EXPORT_SYMBOL_NS(mma9551_read_status_byte, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_status_byte, "IIO_MMA9551"); /** * mma9551_read_config_word() - read 1 config word @@ -303,7 +303,7 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_config_word, "IIO_MMA9551"); /** * mma9551_write_config_word() - write 1 config word @@ -330,7 +330,7 @@ int mma9551_write_config_word(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, (u8 *)&v, 2, NULL, 0); } -EXPORT_SYMBOL_NS(mma9551_write_config_word, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_write_config_word, "IIO_MMA9551"); /** * mma9551_read_status_word() - read 1 status word @@ -364,7 +364,7 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_status_word, "IIO_MMA9551"); /** * mma9551_read_config_words() - read multiple config words @@ -403,7 +403,7 @@ int mma9551_read_config_words(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_config_words, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_config_words, "IIO_MMA9551"); /** * mma9551_read_status_words() - read multiple status words @@ -442,7 +442,7 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_status_words, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_status_words, "IIO_MMA9551"); /** * mma9551_write_config_words() - write multiple config words @@ -477,7 +477,7 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, (u8 *)be_buf, len * sizeof(u16), NULL, 0); } -EXPORT_SYMBOL_NS(mma9551_write_config_words, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_write_config_words, "IIO_MMA9551"); /** * mma9551_update_config_bits() - update bits in register @@ -513,7 +513,7 @@ int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, return mma9551_write_config_byte(client, app_id, reg, tmp); } -EXPORT_SYMBOL_NS(mma9551_update_config_bits, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_update_config_bits, "IIO_MMA9551"); /** * mma9551_gpio_config() - configure gpio @@ -592,7 +592,7 @@ int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin, return ret; } -EXPORT_SYMBOL_NS(mma9551_gpio_config, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_gpio_config, "IIO_MMA9551"); /** * mma9551_read_version() - read device version information @@ -622,7 +622,7 @@ int mma9551_read_version(struct i2c_client *client) return 0; } -EXPORT_SYMBOL_NS(mma9551_read_version, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_version, "IIO_MMA9551"); /** * mma9551_set_device_state() - sets HW power mode @@ -652,7 +652,7 @@ int mma9551_set_device_state(struct i2c_client *client, bool enable) MMA9551_SLEEP_CFG_FLEEN : MMA9551_SLEEP_CFG_SNCEN); } -EXPORT_SYMBOL_NS(mma9551_set_device_state, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_set_device_state, "IIO_MMA9551"); /** * mma9551_set_power_state() - sets runtime PM state @@ -686,7 +686,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on) return 0; } -EXPORT_SYMBOL_NS(mma9551_set_power_state, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_set_power_state, "IIO_MMA9551"); /** * mma9551_sleep() - sleep @@ -705,7 +705,7 @@ void mma9551_sleep(int freq) else msleep_interruptible(sleep_val); } -EXPORT_SYMBOL_NS(mma9551_sleep, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_sleep, "IIO_MMA9551"); /** * mma9551_read_accel_chan() - read accelerometer channel @@ -761,7 +761,7 @@ out_poweroff: mma9551_set_power_state(client, false); return ret; } -EXPORT_SYMBOL_NS(mma9551_read_accel_chan, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_accel_chan, "IIO_MMA9551"); /** * mma9551_read_accel_scale() - read accelerometer scale @@ -779,7 +779,7 @@ int mma9551_read_accel_scale(int *val, int *val2) return IIO_VAL_INT_PLUS_MICRO; } -EXPORT_SYMBOL_NS(mma9551_read_accel_scale, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_accel_scale, "IIO_MMA9551"); /** * mma9551_app_reset() - reset application @@ -798,7 +798,7 @@ int mma9551_app_reset(struct i2c_client *client, u32 app_mask) MMA9551_RSC_OFFSET(app_mask), MMA9551_RSC_VAL(app_mask)); } -EXPORT_SYMBOL_NS(mma9551_app_reset, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_app_reset, "IIO_MMA9551"); MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 3cbd0fd4e624..1bbe660b254f 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -4,11 +4,11 @@ * Copyright (c) 2014, Intel Corporation. */ -#include <linux/module.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/slab.h> -#include <linux/acpi.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/events.h> @@ -725,7 +725,8 @@ static int mma9553_read_event_config(struct iio_dev *indio_dev, static int mma9553_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, + bool state) { struct mma9553_data *data = iio_priv(indio_dev); struct mma9553_event *event; @@ -918,7 +919,7 @@ static const struct iio_enum mma9553_calibgender_enum = { static const struct iio_chan_spec_ext_info mma9553_ext_info[] = { IIO_ENUM("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum), IIO_ENUM_AVAILABLE("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum), - {}, + { } }; #define MMA9553_PEDOMETER_CHANNEL(_type, _mask) { \ @@ -1030,9 +1031,9 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) { data->stepcnt = stepcnt; iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD, - IIO_EV_DIR_NONE, - IIO_EV_TYPE_CHANGE, 0, 0, 0), + IIO_UNMOD_EVENT_CODE(IIO_STEPS, 0, + IIO_EV_TYPE_CHANGE, + IIO_EV_DIR_NONE), data->timestamp); } @@ -1041,20 +1042,18 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) /* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */ if (ev_prev_activity && ev_prev_activity->enabled) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - ev_prev_activity->info->mod, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, 0, 0, - 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + ev_prev_activity->info->mod, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), data->timestamp); if (ev_activity && ev_activity->enabled) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - ev_activity->info->mod, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, 0, 0, - 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + ev_activity->info->mod, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), data->timestamp); } mutex_unlock(&data->mutex); @@ -1062,17 +1061,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) return IRQ_HANDLED; } -static const char *mma9553_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - return dev_name(dev); -} - static int mma9553_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -1091,9 +1079,9 @@ static int mma9553_probe(struct i2c_client *client) if (id) name = id->name; - else if (ACPI_HANDLE(&client->dev)) - name = mma9553_match_acpi_device(&client->dev); else + name = iio_get_acpi_device_name(&client->dev); + if (!name) return -ENOSYS; mutex_init(&data->mutex); @@ -1228,14 +1216,14 @@ static const struct dev_pm_ops mma9553_pm_ops = { static const struct acpi_device_id mma9553_acpi_match[] = { {"MMA9553", 0}, - {}, + { } }; MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match); static const struct i2c_device_id mma9553_id[] = { - {"mma9553", 0}, - {}, + { "mma9553" }, + { } }; MODULE_DEVICE_TABLE(i2c, mma9553_id); @@ -1256,4 +1244,4 @@ module_i2c_driver(mma9553_driver); MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MMA9553L pedometer platform driver"); -MODULE_IMPORT_NS(IIO_MMA9551); +MODULE_IMPORT_NS("IIO_MMA9551"); diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index b8ddbfd98f11..c31c53abc3d0 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -34,6 +34,7 @@ #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/string_choices.h> +#include <linux/types.h> #include <linux/units.h> #include <linux/iio/buffer.h> @@ -331,7 +332,7 @@ static const struct regmap_config msa311_regmap_config = { .wr_table = &msa311_writeable_table, .rd_table = &msa311_readable_table, .volatile_table = &msa311_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #define MSA311_GENMASK(field) ({ \ @@ -593,23 +594,24 @@ static int msa311_read_raw_data(struct iio_dev *indio_dev, __le16 axis; int err; - err = pm_runtime_resume_and_get(dev); - if (err) - return err; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - err = iio_device_claim_direct_mode(indio_dev); - if (err) + err = pm_runtime_resume_and_get(dev); + if (err) { + iio_device_release_direct(indio_dev); return err; + } mutex_lock(&msa311->lock); err = msa311_get_axis(msa311, chan, &axis); mutex_unlock(&msa311->lock); - iio_device_release_direct_mode(indio_dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + iio_device_release_direct(indio_dev); + if (err) { dev_err(dev, "can't get axis %s (%pe)\n", chan->datasheet_name, ERR_PTR(err)); @@ -755,18 +757,19 @@ static int msa311_write_samp_freq(struct iio_dev *indio_dev, int val, int val2) unsigned int odr; int err; - err = pm_runtime_resume_and_get(dev); - if (err) - return err; - /* * Sampling frequency changing is prohibited when buffer mode is * enabled, because sometimes MSA311 chip returns outliers during * frequency values growing up in the read operation moment. */ - err = iio_device_claim_direct_mode(indio_dev); - if (err) + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + err = pm_runtime_resume_and_get(dev); + if (err) { + iio_device_release_direct(indio_dev); return err; + } err = -EINVAL; for (odr = 0; odr < ARRAY_SIZE(msa311_odr_table); odr++) @@ -778,11 +781,11 @@ static int msa311_write_samp_freq(struct iio_dev *indio_dev, int val, int val2) break; } - iio_device_release_direct_mode(indio_dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + iio_device_release_direct(indio_dev); + if (err) dev_err(dev, "can't update frequency (%pe)\n", ERR_PTR(err)); @@ -893,15 +896,14 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p) __le16 axis; struct { __le16 channels[MSA311_SI_Z + 1]; - s64 ts __aligned(8); + aligned_s64 ts; } buf; memset(&buf, 0, sizeof(buf)); mutex_lock(&msa311->lock); - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + iio_for_each_active_channel(indio_dev, bit) { chan = &msa311_channels[bit]; err = msa311_get_axis(msa311, chan, &axis); @@ -917,8 +919,8 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p) mutex_unlock(&msa311->lock); - iio_push_to_buffers_with_timestamp(indio_dev, &buf, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &buf, sizeof(buf), + iio_get_time_ns(indio_dev)); notify_done: iio_trigger_notify_done(indio_dev->trig); @@ -1034,10 +1036,10 @@ static int msa311_chip_init(struct msa311_priv *msa311) "failed to unmap map0/map1 interrupts\n"); /* Disable all axes by default */ - err = regmap_update_bits(msa311->regs, MSA311_ODR_REG, - MSA311_GENMASK(F_X_AXIS_DIS) | - MSA311_GENMASK(F_Y_AXIS_DIS) | - MSA311_GENMASK(F_Z_AXIS_DIS), 0); + err = regmap_clear_bits(msa311->regs, MSA311_ODR_REG, + MSA311_GENMASK(F_X_AXIS_DIS) | + MSA311_GENMASK(F_Y_AXIS_DIS) | + MSA311_GENMASK(F_Z_AXIS_DIS)); if (err) return dev_err_probe(dev, err, "can't enable all axes\n"); diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 61839be501c2..1075c8ce0e37 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -5,11 +5,13 @@ * Copyright (c) 2014, Intel Corporation. */ +#include <linux/delay.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/mod_devicetable.h> #include <linux/regmap.h> +#include <linux/types.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> #include <linux/iio/buffer.h> @@ -27,11 +29,16 @@ #define MXC4005_REG_ZOUT_UPPER 0x07 #define MXC4005_REG_ZOUT_LOWER 0x08 +#define MXC4005_REG_INT_MASK0 0x0A + #define MXC4005_REG_INT_MASK1 0x0B #define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01 +#define MXC4005_REG_INT_CLR0 0x00 + #define MXC4005_REG_INT_CLR1 0x01 #define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 +#define MXC4005_REG_INT_CLR1_SW_RST 0x10 #define MXC4005_REG_CONTROL 0x0D #define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) @@ -39,6 +46,9 @@ #define MXC4005_REG_DEVICE_ID 0x0E +/* Datasheet does not specify a reset time, this is a conservative guess */ +#define MXC4005_RESET_TIME_US 2000 + enum mxc4005_axis { AXIS_X, AXIS_Y, @@ -56,12 +66,15 @@ struct mxc4005_data { struct mutex mutex; struct regmap *regmap; struct iio_trigger *dready_trig; + struct iio_mount_matrix orientation; /* Ensure timestamp is naturally aligned */ struct { __be16 chans[3]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; bool trigger_enabled; + unsigned int control; + unsigned int int_mask1; }; /* @@ -113,7 +126,9 @@ static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg) static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MXC4005_REG_INT_CLR0: case MXC4005_REG_INT_CLR1: + case MXC4005_REG_INT_MASK0: case MXC4005_REG_INT_MASK1: case MXC4005_REG_CONTROL: return true; @@ -259,6 +274,20 @@ static int mxc4005_write_raw(struct iio_dev *indio_dev, } } +static const struct iio_mount_matrix * +mxc4005_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mxc4005_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info mxc4005_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mxc4005_get_mount_matrix), + { } +}; + static const struct iio_info mxc4005_info = { .read_raw = mxc4005_read_raw, .write_raw = mxc4005_write_raw, @@ -285,6 +314,7 @@ static const unsigned long mxc4005_scan_masks[] = { .shift = 4, \ .endianness = IIO_BE, \ }, \ + .ext_info = mxc4005_ext_info, \ } static const struct iio_chan_spec mxc4005_channels[] = { @@ -305,8 +335,8 @@ static irqreturn_t mxc4005_trigger_handler(int irq, void *private) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -330,23 +360,20 @@ static int mxc4005_set_trigger_state(struct iio_trigger *trig, { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct mxc4005_data *data = iio_priv(indio_dev); + unsigned int val; int ret; mutex_lock(&data->mutex); - if (state) { - ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, - MXC4005_REG_INT_MASK1_BIT_DRDYE); - } else { - ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, - ~MXC4005_REG_INT_MASK1_BIT_DRDYE); - } + val = state ? MXC4005_REG_INT_MASK1_BIT_DRDYE : 0; + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, val); if (ret < 0) { mutex_unlock(&data->mutex); dev_err(data->dev, "failed to update reg_int_mask1"); return ret; } + data->int_mask1 = val; data->trigger_enabled = state; mutex_unlock(&data->mutex); @@ -382,6 +409,21 @@ static int mxc4005_chip_init(struct mxc4005_data *data) dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg); + ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, + MXC4005_REG_INT_CLR1_SW_RST); + if (ret < 0) + return dev_err_probe(data->dev, ret, "resetting chip\n"); + + fsleep(MXC4005_RESET_TIME_US); + + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0); + if (ret < 0) + return dev_err_probe(data->dev, ret, "writing INT_MASK0\n"); + + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, 0); + if (ret < 0) + return dev_err_probe(data->dev, ret, "writing INT_MASK1\n"); + return 0; } @@ -415,6 +457,12 @@ static int mxc4005_probe(struct i2c_client *client) mutex_init(&data->mutex); + if (!iio_read_acpi_mount_matrix(&client->dev, &data->orientation, "ROTM")) { + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; + } + indio_dev->channels = mxc4005_channels; indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); indio_dev->available_scan_masks = mxc4005_scan_masks; @@ -469,25 +517,77 @@ static int mxc4005_probe(struct i2c_client *client) return devm_iio_device_register(&client->dev, indio_dev); } +static int mxc4005_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + /* Save control to restore it on resume */ + ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &data->control); + if (ret < 0) + dev_err(data->dev, "failed to read reg_control\n"); + + return ret; +} + +static int mxc4005_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, + MXC4005_REG_INT_CLR1_SW_RST); + if (ret) { + dev_err(data->dev, "failed to reset chip: %d\n", ret); + return ret; + } + + fsleep(MXC4005_RESET_TIME_US); + + ret = regmap_write(data->regmap, MXC4005_REG_CONTROL, data->control); + if (ret) { + dev_err(data->dev, "failed to restore control register\n"); + return ret; + } + + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0); + if (ret) { + dev_err(data->dev, "failed to restore interrupt 0 mask\n"); + return ret; + } + + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, data->int_mask1); + if (ret) { + dev_err(data->dev, "failed to restore interrupt 1 mask\n"); + return ret; + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(mxc4005_pm_ops, mxc4005_suspend, mxc4005_resume); + static const struct acpi_device_id mxc4005_acpi_match[] = { {"MXC4005", 0}, {"MXC6655", 0}, {"MDA6655", 0}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); static const struct of_device_id mxc4005_of_match[] = { { .compatible = "memsic,mxc4005", }, { .compatible = "memsic,mxc6655", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, mxc4005_of_match); static const struct i2c_device_id mxc4005_id[] = { - {"mxc4005", 0}, - {"mxc6655", 0}, - { }, + { "mxc4005" }, + { "mxc6655" }, + { } }; MODULE_DEVICE_TABLE(i2c, mxc4005_id); @@ -496,6 +596,7 @@ static struct i2c_driver mxc4005_driver = { .name = MXC4005_DRV_NAME, .acpi_match_table = mxc4005_acpi_match, .of_match_table = mxc4005_of_match, + .pm = pm_sleep_ptr(&mxc4005_pm_ops), }, .probe = mxc4005_probe, .id_table = mxc4005_id, diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index ac228128c4f9..a8abda7b2a63 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -172,8 +172,8 @@ static const struct acpi_device_id mxc6255_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match); static const struct i2c_device_id mxc6255_id[] = { - {"mxc6225", 0}, - {"mxc6255", 0}, + { "mxc6225" }, + { "mxc6255" }, { } }; MODULE_DEVICE_TABLE(i2c, mxc6255_id); diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 87c54e41f6cc..aabe4491efd7 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -1158,7 +1158,7 @@ error_ret: return ret; } -static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) +static int sca3000_freefall_set_state(struct iio_dev *indio_dev, bool state) { struct sca3000_state *st = iio_priv(indio_dev); int ret; @@ -1181,7 +1181,7 @@ static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) } static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, - int state) + bool state) { struct sca3000_state *st = iio_priv(indio_dev); int ret, ctrlval; @@ -1253,7 +1253,7 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int state) + bool state) { struct sca3000_state *st = iio_priv(indio_dev); int ret; @@ -1541,7 +1541,7 @@ static const struct spi_device_id sca3000_id[] = { {"sca3000_e02", e02}, {"sca3000_e04", e04}, {"sca3000_e05", e05}, - {} + { } }; MODULE_DEVICE_TABLE(spi, sca3000_id); diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c index 306482b70fad..67416a406e2f 100644 --- a/drivers/iio/accel/sca3300.c +++ b/drivers/iio/accel/sca3300.c @@ -12,7 +12,7 @@ #include <linux/module.h> #include <linux/spi/spi.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> @@ -58,15 +58,6 @@ enum sca3300_scan_indexes { SCA3300_SCAN_MAX }; -/* - * Buffer size max case: - * Three accel channels, two bytes per channel. - * Temperature channel, two bytes. - * Three incli channels, two bytes per channel. - * Timestamp channel, eight bytes. - */ -#define SCA3300_MAX_BUFFER_SIZE (ALIGN(sizeof(s16) * SCA3300_SCAN_MAX, sizeof(s64)) + sizeof(s64)) - #define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \ .type = IIO_ACCEL, \ .address = reg, \ @@ -193,9 +184,6 @@ struct sca3300_chip_info { * @spi: SPI device structure * @lock: Data buffer lock * @chip: Sensor chip specific information - * @buffer: Triggered buffer: - * -SCA3300: 4 channel 16-bit data + 64-bit timestamp - * -SCL3300: 7 channel 16-bit data + 64-bit timestamp * @txbuf: Transmit buffer * @rxbuf: Receive buffer */ @@ -203,7 +191,6 @@ struct sca3300_data { struct spi_device *spi; struct mutex lock; const struct sca3300_chip_info *chip; - u8 buffer[SCA3300_MAX_BUFFER_SIZE] __aligned(sizeof(s64)); u8 txbuf[4] __aligned(IIO_DMA_MINALIGN); u8 rxbuf[4]; }; @@ -492,10 +479,9 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct sca3300_data *data = iio_priv(indio_dev); int bit, ret, val, i = 0; - s16 *channels = (s16 *)data->buffer; + IIO_DECLARE_BUFFER_WITH_TS(s16, channels, SCA3300_SCAN_MAX); - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + iio_for_each_active_channel(indio_dev, bit) { ret = sca3300_read_reg(data, indio_dev->channels[bit].address, &val); if (ret) { dev_err_ratelimited(&data->spi->dev, @@ -506,8 +492,8 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p) channels[i++] = val; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, channels, sizeof(channels), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -675,14 +661,14 @@ static int sca3300_probe(struct spi_device *spi) static const struct of_device_id sca3300_dt_ids[] = { { .compatible = "murata,sca3300"}, { .compatible = "murata,scl3300"}, - {} + { } }; MODULE_DEVICE_TABLE(of, sca3300_dt_ids); static const struct spi_device_id sca3300_ids[] = { { "sca3300" }, { "scl3300" }, - {} + { } }; MODULE_DEVICE_TABLE(spi, sca3300_ids); diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c index 7ca9d0d543e0..3e572af2ec03 100644 --- a/drivers/iio/accel/ssp_accel_sensor.c +++ b/drivers/iio/accel/ssp_accel_sensor.c @@ -141,4 +141,4 @@ module_platform_driver(ssp_accel_driver); MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>"); MODULE_DESCRIPTION("Samsung sensorhub accelerometers driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_SSP_SENSORS); +MODULE_IMPORT_NS("IIO_SSP_SENSORS"); diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index e7525615712b..2659f536cef6 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -35,6 +35,7 @@ #define LIS3DHH_ACCEL_DEV_NAME "lis3dhh" #define LIS3DE_ACCEL_DEV_NAME "lis3de" #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" +#define LIS2DS12_ACCEL_DEV_NAME "lis2ds12" #define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" #define LIS302DL_ACCEL_DEV_NAME "lis302dl" #define LSM303C_ACCEL_DEV_NAME "lsm303c_accel" diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index d2104e14e255..a7961c610ed2 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -926,6 +926,87 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .bootime = 2, }, { + .wai = 0x43, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LIS2DS12_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_16bit_channels, + .odr = { + .addr = 0x20, + .mask = 0xf0, + .odr_avl = { + { .hz = 10, .value = 0x01, }, + { .hz = 50, .value = 0x02, }, + { .hz = 100, .value = 0x03, }, + { .hz = 200, .value = 0x04, }, + { .hz = 400, .value = 0x05, }, + { .hz = 800, .value = 0x06, }, + }, + }, + .pw = { + .addr = 0x20, + .mask = 0xf0, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = 0x20, + .mask = 0x0c, + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(61), + }, + [1] = { + .num = ST_ACCEL_FS_AVL_4G, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(122), + }, + [2] = { + .num = ST_ACCEL_FS_AVL_8G, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(244), + }, + [3] = { + .num = ST_ACCEL_FS_AVL_16G, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(488), + }, + }, + }, + .bdu = { + .addr = 0x20, + .mask = 0x01, + }, + .drdy_irq = { + .int1 = { + .addr = 0x23, + .mask = 0x01, + }, + .int2 = { + .addr = 0x24, + .mask = 0x01, + }, + .addr_ihl = 0x22, + .mask_ihl = 0x02, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x01, + }, + }, + .sim = { + .addr = 0x21, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, + { .wai = 0x41, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { @@ -1272,6 +1353,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev) union acpi_object *ont; union acpi_object *elements; acpi_status status; + struct device *parent = indio_dev->dev.parent; int ret = -EINVAL; unsigned int val; int i, j; @@ -1290,7 +1372,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev) }; - adev = ACPI_COMPANION(indio_dev->dev.parent); + adev = ACPI_COMPANION(parent); if (!adev) return -ENXIO; @@ -1299,8 +1381,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev) if (status == AE_NOT_FOUND) { return -ENXIO; } else if (ACPI_FAILURE(status)) { - dev_warn(&indio_dev->dev, "failed to execute _ONT: %d\n", - status); + dev_warn(parent, "failed to execute _ONT: %d\n", status); return status; } @@ -1376,12 +1457,12 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev) } ret = 0; - dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n"); + dev_info(parent, "computed mount matrix from ACPI\n"); out: kfree(buffer.pointer); if (ret) - dev_dbg(&indio_dev->dev, + dev_dbg(parent, "failed to apply ACPI orientation data: %d\n", ret); return ret; @@ -1409,7 +1490,7 @@ const struct st_sensor_settings *st_accel_get_settings(const char *name) return &st_accel_sensors_settings[index]; } -EXPORT_SYMBOL_NS(st_accel_get_settings, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_accel_get_settings, "IIO_ST_SENSORS"); int st_accel_common_probe(struct iio_dev *indio_dev) { @@ -1463,9 +1544,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL_NS(st_accel_common_probe, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_accel_common_probe, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics accelerometers driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index fd3749871121..f24449500533 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -103,6 +103,10 @@ static const struct of_device_id st_accel_of_match[] = { .data = LIS2DE12_ACCEL_DEV_NAME, }, { + .compatible = "st,lis2ds12", + .data = LIS2DS12_ACCEL_DEV_NAME, + }, + { .compatible = "st,lis2hh12", .data = LIS2HH12_ACCEL_DEV_NAME, }, @@ -122,14 +126,14 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,iis328dq", .data = IIS328DQ_ACCEL_DEV_NAME, }, - {}, + { } }; MODULE_DEVICE_TABLE(of, st_accel_of_match); static const struct acpi_device_id st_accel_acpi_match[] = { {"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME}, {"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); @@ -154,12 +158,13 @@ static const struct i2c_device_id st_accel_id_table[] = { { LIS2DW12_ACCEL_DEV_NAME }, { LIS3DE_ACCEL_DEV_NAME }, { LIS2DE12_ACCEL_DEV_NAME }, + { LIS2DS12_ACCEL_DEV_NAME }, { LIS2HH12_ACCEL_DEV_NAME }, { LIS302DL_ACCEL_DEV_NAME }, { LSM303C_ACCEL_DEV_NAME }, { SC7A20_ACCEL_DEV_NAME }, { IIS328DQ_ACCEL_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); @@ -211,4 +216,4 @@ module_i2c_driver(st_accel_driver); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index f72a24f45322..d8ec0555f42a 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -65,6 +65,10 @@ static const struct of_device_id st_accel_of_match[] = { .data = LIS2DH12_ACCEL_DEV_NAME, }, { + .compatible = "st,lis2ds12", + .data = LIS2DS12_ACCEL_DEV_NAME, + }, + { .compatible = "st,lis3l02dq", .data = LIS3L02DQ_ACCEL_DEV_NAME, }, @@ -104,7 +108,7 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,iis328dq", .data = IIS328DQ_ACCEL_DEV_NAME, }, - {} + { } }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -151,6 +155,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM330_ACCEL_DEV_NAME }, { LSM303AGR_ACCEL_DEV_NAME }, { LIS2DH12_ACCEL_DEV_NAME }, + { LIS2DS12_ACCEL_DEV_NAME }, { LIS3L02DQ_ACCEL_DEV_NAME }, { LNG2DM_ACCEL_DEV_NAME }, { H3LIS331DL_ACCEL_DEV_NAME }, @@ -162,7 +167,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LIS302DL_ACCEL_DEV_NAME }, { LSM303C_ACCEL_DEV_NAME }, { IIS328DQ_ACCEL_DEV_NAME }, - {}, + { } }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); @@ -179,4 +184,4 @@ module_spi_driver(st_accel_driver); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics accelerometers spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index ef0ae7672253..dfac2e44191f 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/types.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -105,7 +106,7 @@ struct stk8312_data { /* Ensure timestamp is naturally aligned */ struct { s8 chans[3]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; }; @@ -448,8 +449,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) goto err; } } else { - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + iio_for_each_active_channel(indio_dev, bit) { ret = stk8312_read_accel(data, bit); if (ret < 0) { mutex_unlock(&data->lock); @@ -460,8 +460,8 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -633,9 +633,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, static const struct i2c_device_id stk8312_i2c_id[] = { /* Deprecated in favour of lowercase form */ - { "STK8312", 0 }, - { "stk8312", 0 }, - {} + { "STK8312" }, + { "stk8312" }, + { } }; MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 668edc88c89d..05d4fd540eb2 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mod_devicetable.h> +#include <linux/types.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -94,7 +95,7 @@ struct stk8ba50_data { /* Ensure timestamp is naturally aligned */ struct { s16 chans[3]; - s64 timetamp __aligned(8); + aligned_s64 timetamp; } scan; }; @@ -330,8 +331,7 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p) goto err; } } else { - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + iio_for_each_active_channel(indio_dev, bit) { ret = stk8ba50_read_accel(data, stk8ba50_channel_table[bit]); if (ret < 0) @@ -340,8 +340,8 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p) data->scan.chans[i++] = ret; } } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + pf->timestamp); err: mutex_unlock(&data->lock); iio_trigger_notify_done(indio_dev->trig); @@ -525,14 +525,14 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume); static const struct i2c_device_id stk8ba50_i2c_id[] = { - {"stk8ba50", 0}, - {} + { "stk8ba50" }, + { } }; MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); static const struct acpi_device_id stk8ba50_acpi_id[] = { {"STK8BA50", 0}, - {} + { } }; MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id); |