diff options
Diffstat (limited to 'drivers/iio')
137 files changed, 7503 insertions, 2151 deletions
diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index eabaefa92f19..7ccd2f653b9b 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -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, diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index e790a66d86c7..705375f3b56e 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -1073,7 +1073,7 @@ 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) + bool state) { enum adxl367_activity_type act; diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index ef8dd557877b..5b9eb364760a 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -940,7 +940,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); diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c index ccb2f59bd835..a1460120d9da 100644 --- a/drivers/iio/accel/adxl380.c +++ b/drivers/iio/accel/adxl380.c @@ -1386,7 +1386,7 @@ 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, - int state) + bool state) { struct adxl380_state *st = iio_priv(indio_dev); enum adxl380_axis axis; diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 2445a0f7bc2b..128db14ba726 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; }; diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index fcbd695e4654..009e6243c6cb 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> diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index e4fe36768216..906d2577be2d 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -115,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; @@ -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; diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 0f32c1e92b4d..158579350d59 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -804,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; 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/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 37f33c29fb4b..f07fba17048e 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -22,6 +22,7 @@ #include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/regmap.h> +#include <linux/types.h> #include <linux/iio/buffer.h> #include <linux/iio/events.h> @@ -163,7 +164,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; @@ -616,7 +617,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; diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index b6a828a6df93..53261e1d5d1f 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -16,6 +16,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> @@ -292,7 +293,7 @@ struct kx022a_data { __le16 buffer[8] __aligned(IIO_DMA_MINALIGN); struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; }; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index b76df8816323..f2496cad8ec2 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,14 +170,73 @@ #define KXCJK1013_DEFAULT_WAKE_THRES 1 -enum kx_chipset { - KXCJK1013, - KXCJ91008, - KXTJ21009, - KXTF9, - KX0221020, - 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 { @@ -234,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, @@ -250,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; @@ -261,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 { @@ -314,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; @@ -424,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; @@ -458,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; @@ -470,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; @@ -488,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; @@ -501,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; @@ -514,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); } @@ -535,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; @@ -544,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; @@ -555,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; @@ -564,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; @@ -575,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 and KX022, route all used interrupts to INT1 for now */ - if ((data->chipset == KX0231025 || data->chipset == KX0221020) && data->client->irq > 0) { + /* On KX023, route all used interrupts to INT1 for now */ + 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); @@ -601,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) { @@ -639,18 +655,17 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) 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; @@ -662,6 +677,7 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, bool status) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; enum kxcjk1013_mode store_mode; @@ -678,7 +694,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, 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; @@ -689,13 +705,13 @@ static int kxcjk1013_setup_any_motion_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; @@ -706,7 +722,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, 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; @@ -724,6 +740,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, bool status) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; enum kxcjk1013_mode store_mode; @@ -736,7 +753,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, 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; @@ -747,13 +764,13 @@ 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; @@ -764,7 +781,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; - 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; @@ -811,6 +828,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; @@ -819,7 +837,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); @@ -836,7 +854,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"); @@ -845,7 +863,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"); @@ -863,7 +881,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); @@ -1063,7 +1081,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; @@ -1130,7 +1148,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; @@ -1207,7 +1225,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, @@ -1247,9 +1265,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"); } @@ -1301,8 +1320,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; @@ -1367,16 +1387,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, @@ -1392,7 +1413,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"); @@ -1417,31 +1438,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); @@ -1449,6 +1445,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; @@ -1489,32 +1486,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 KX0221020: - 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) @@ -1527,9 +1510,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, @@ -1637,7 +1620,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)); @@ -1665,9 +1647,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)); @@ -1701,44 +1681,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}, - {"kx022-1020", KX0221020}, - {"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,kx022-1020", }, - { .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.c b/drivers/iio/accel/kxsd9.c index 70dfd6e354db..6d2b0a22e550 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; diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index a34195b3215d..50f7ac1845c6 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; }; diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 62e6369e2269..962d289065ab 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -32,6 +32,7 @@ #include <linux/delay.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; }; @@ -973,7 +974,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; diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index fa1799b0b0df..6d73eec95126 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) diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 86543f34ef17..8536743a6886 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; @@ -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); diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 57025354c7cd..e7fb860f3233 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> @@ -893,7 +894,7 @@ 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)); diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index fc54a2a4693c..cb5c4e354fc0 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -11,6 +11,7 @@ #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> @@ -69,7 +70,7 @@ struct mxc4005_data { /* Ensure timestamp is naturally aligned */ struct { __be16 chans[3]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; bool trigger_enabled; unsigned int control; diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 87c54e41f6cc..3fb0f386c3db 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; diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index abead190254b..471c154c3631 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; }; diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index a32a77324e92..cab592a68622 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; }; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 179d83aafd8a..849c90203071 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -226,9 +226,11 @@ config AD7606_IFACE_PARALLEL tristate "Analog Devices AD7606 ADC driver with parallel interface support" depends on HAS_IOPORT select AD7606 + select IIO_BACKEND help Say yes here to build parallel interface support for Analog Devices: ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). + It also support iio_backended devices for AD7606B. To compile this driver as a module, choose M here: the module will be called ad7606_par. @@ -285,6 +287,18 @@ config AD7768_1 To compile this driver as a module, choose M here: the module will be called ad7768-1. +config AD7779 + tristate "Analog Devices AD7779 ADC driver" + depends on SPI + select CRC8 + select IIO_BUFFER + help + Say yes here to build support for Analog Devices AD777X family + (AD7770, AD7771, AD7779) analog to digital converter (ADC). + + To compile this driver as a module, choose M here: the module will be + called ad7779. + config AD7780 tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI @@ -1606,7 +1620,6 @@ config TWL4030_MADC config TWL6030_GPADC tristate "TWL6030 GPADC (General Purpose A/D Converter) Support" depends on TWL4030_CORE - default n help Say yes here if you want support for the TWL6030/TWL6032 General Purpose A/D Converter. This will add support for battery type diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 1df8f311c183..ee19afba62b7 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_AD7606) += ad7606.o obj-$(CONFIG_AD7625) += ad7625.o obj-$(CONFIG_AD7766) += ad7766.o obj-$(CONFIG_AD7768_1) += ad7768-1.o +obj-$(CONFIG_AD7779) += ad7779.o obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c index fc9c9807f89d..b3b82535f5c1 100644 --- a/drivers/iio/adc/ad4000.c +++ b/drivers/iio/adc/ad4000.c @@ -639,7 +639,9 @@ static int ad4000_probe(struct spi_device *spi) indio_dev->name = chip->dev_name; indio_dev->num_channels = 1; - devm_mutex_init(dev, &st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; st->gain_milli = 1000; if (chip->has_hardware_gain) { diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index d6876259ad14..eb0a059b4b0e 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -150,7 +150,8 @@ static int ad7091r_read_event_config(struct iio_dev *indio_dev, static int ad7091r_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 ad7091r_state *st = iio_priv(indio_dev); diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 7042ddfdfc03..955e9eff0099 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -1394,6 +1394,9 @@ static int ad7192_probe(struct spi_device *spi) st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI; st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = st->chip_info->info; diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index 35aa39fe4bde..f9f32737db80 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -822,17 +822,15 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <= AD7280A_CELL_VOLTAGE_6_REG) { if (val >= st->cell_threshhigh) { - u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, - 0, 0, 0); + u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING); iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); } else if (val <= st->cell_threshlow) { - u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, - 0, 0, 0); + u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING); iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); } diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index 4c7f887adbbf..60e12faa3207 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -269,7 +269,7 @@ static int ad7291_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) { int ret = 0; struct ad7291_chip_info *chip = iio_priv(indio_dev); diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index fb728570debe..4f32cb22f140 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -13,6 +13,8 @@ * ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf * ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf * ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf + * adaq4370-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4370-4.pdf + * adaq4380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4380-4.pdf */ #include <linux/align.h> @@ -22,11 +24,14 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/kernel.h> +#include <linux/math.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/spi/spi.h> +#include <linux/units.h> +#include <linux/util_macros.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> @@ -36,6 +41,8 @@ #define MAX_NUM_CHANNELS 8 /* 2.5V internal reference voltage */ #define AD7380_INTERNAL_REF_MV 2500 +/* 3.3V internal reference voltage for ADAQ */ +#define ADAQ4380_INTERNAL_REF_MV 3300 /* reading and writing registers is more reliable at lower than max speed */ #define AD7380_REG_WR_SPEED_HZ 10000000 @@ -77,6 +84,13 @@ #define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */ #define T_POWERUP_US 5000 /* Power up */ +/* + * AD738x support several SDO lines to increase throughput, but driver currently + * supports only 1 SDO line (standard SPI transaction) + */ +#define AD7380_NUM_SDO_LINES 1 +#define AD7380_DEFAULT_GAIN_MILLI 1000 + struct ad7380_timing_specs { const unsigned int t_csh_ns; /* CS minimum high time */ }; @@ -86,10 +100,12 @@ struct ad7380_chip_info { const struct iio_chan_spec *channels; unsigned int num_channels; unsigned int num_simult_channels; + bool has_hardware_gain; bool has_mux; const char * const *supplies; unsigned int num_supplies; bool external_ref_only; + bool adaq_internal_ref_only; const char * const *vcm_supplies; unsigned int num_vcm_supplies; const unsigned long *available_scan_masks; @@ -181,11 +197,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = { }, }; -#define AD7380_CHANNEL(index, bits, diff, sign) { \ +#define _AD7380_CHANNEL(index, bits, diff, sign, gain) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + ((gain) ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \ ((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + .info_mask_shared_by_type = ((gain) ? 0 : BIT(IIO_CHAN_INFO_SCALE)) | \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .info_mask_shared_by_type_available = \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ @@ -199,6 +216,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = { .num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits##_##sign), \ } +#define AD7380_CHANNEL(index, bits, diff, sign) \ + _AD7380_CHANNEL(index, bits, diff, sign, false) + +#define ADAQ4380_CHANNEL(index, bits, diff, sign) \ + _AD7380_CHANNEL(index, bits, diff, sign, true) + #define DEFINE_AD7380_2_CHANNEL(name, bits, diff, sign) \ static const struct iio_chan_spec name[] = { \ AD7380_CHANNEL(0, bits, diff, sign), \ @@ -215,6 +238,15 @@ static const struct iio_chan_spec name[] = { \ IIO_CHAN_SOFT_TIMESTAMP(4), \ } +#define DEFINE_ADAQ4380_4_CHANNEL(name, bits, diff, sign) \ +static const struct iio_chan_spec name[] = { \ + ADAQ4380_CHANNEL(0, bits, diff, sign), \ + ADAQ4380_CHANNEL(1, bits, diff, sign), \ + ADAQ4380_CHANNEL(2, bits, diff, sign), \ + ADAQ4380_CHANNEL(3, bits, diff, sign), \ + IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + #define DEFINE_AD7380_8_CHANNEL(name, bits, diff, sign) \ static const struct iio_chan_spec name[] = { \ AD7380_CHANNEL(0, bits, diff, sign), \ @@ -233,6 +265,7 @@ DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1, s); DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1, s); DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1, s); DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1, s); +DEFINE_ADAQ4380_4_CHANNEL(adaq4380_4_channels, 16, 1, s); /* pseudo differential */ DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0, s); DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0, s); @@ -251,6 +284,10 @@ static const char * const ad7380_supplies[] = { "vcc", "vlogic", }; +static const char * const adaq4380_supplies[] = { + "ldo", "vcc", "vlogic", "vs-p", "vs-n", "refin", +}; + static const char * const ad7380_2_channel_vcm_supplies[] = { "aina", "ainb", }; @@ -341,6 +378,11 @@ static const int ad7380_oversampling_ratios[] = { 1, 2, 4, 8, 16, 32, }; +/* Gains stored as fractions of 1000 so they can be expressed by integers. */ +static const int ad7380_gains[] = { + 300, 600, 1000, 1600, +}; + static const struct ad7380_chip_info ad7380_chip_info = { .name = "ad7380", .channels = ad7380_channels, @@ -510,6 +552,32 @@ static const struct ad7380_chip_info ad7388_4_chip_info = { .timing_specs = &ad7380_4_timing, }; +static const struct ad7380_chip_info adaq4370_4_chip_info = { + .name = "adaq4370-4", + .channels = adaq4380_4_channels, + .num_channels = ARRAY_SIZE(adaq4380_4_channels), + .num_simult_channels = 4, + .supplies = adaq4380_supplies, + .num_supplies = ARRAY_SIZE(adaq4380_supplies), + .adaq_internal_ref_only = true, + .has_hardware_gain = true, + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + +static const struct ad7380_chip_info adaq4380_4_chip_info = { + .name = "adaq4380-4", + .channels = adaq4380_4_channels, + .num_channels = ARRAY_SIZE(adaq4380_4_channels), + .num_simult_channels = 4, + .supplies = adaq4380_supplies, + .num_supplies = ARRAY_SIZE(adaq4380_supplies), + .adaq_internal_ref_only = true, + .has_hardware_gain = true, + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + struct ad7380_state { const struct ad7380_chip_info *chip_info; struct spi_device *spi; @@ -520,6 +588,7 @@ struct ad7380_state { bool seq; unsigned int vref_mv; unsigned int vcm_mv[MAX_NUM_CHANNELS]; + unsigned int gain_milli[MAX_NUM_CHANNELS]; /* xfers, message an buffer for reading sample data */ struct spi_transfer normal_xfer[2]; struct spi_message normal_msg; @@ -649,7 +718,8 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch) if (st->oversampling_ratio > 1) xfer.delay.value = T_CONVERT_0_NS + - T_CONVERT_X_NS * (st->oversampling_ratio - 1); + T_CONVERT_X_NS * (st->oversampling_ratio - 1) * + st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; return spi_sync_transfer(st->spi, &xfer, 1); } @@ -672,7 +742,8 @@ static void ad7380_update_xfers(struct ad7380_state *st, */ if (st->oversampling_ratio > 1) t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS * - (st->oversampling_ratio - 1); + (st->oversampling_ratio - 1) * + st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; if (st->seq) { xfer[0].delay.value = xfer[1].delay.value = t_convert; @@ -868,8 +939,15 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, * * (2 × VREF) / 2^N, for differential chips * * VREF / 2^N, for pseudo-differential chips * where N is the ADC resolution (i.e realbits) + * + * The gain is stored as a fraction of 1000 and, as we need to + * divide vref_mv by the gain, we invert the gain/1000 fraction. */ - *val = st->vref_mv; + if (st->chip_info->has_hardware_gain) + *val = mult_frac(st->vref_mv, MILLI, + st->gain_milli[chan->scan_index]); + else + *val = st->vref_mv; *val2 = scan_type->realbits - chan->differential; return IIO_VAL_FRACTIONAL_LOG2; @@ -1021,17 +1099,19 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en) /* SPI 1-wire mode */ return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2, AD7380_CONFIG2_SDO, - FIELD_PREP(AD7380_CONFIG2_SDO, 1)); + FIELD_PREP(AD7380_CONFIG2_SDO, + AD7380_NUM_SDO_LINES)); } static int ad7380_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct ad7380_state *st; bool external_ref_en; int ret, i; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1039,21 +1119,32 @@ static int ad7380_probe(struct spi_device *spi) st->spi = spi; st->chip_info = spi_get_device_match_data(spi); if (!st->chip_info) - return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n"); + return dev_err_probe(dev, -EINVAL, "missing match data\n"); - ret = devm_regulator_bulk_get_enable(&spi->dev, st->chip_info->num_supplies, + ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies, st->chip_info->supplies); if (ret) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to enable power supplies\n"); fsleep(T_POWERUP_US); - if (st->chip_info->external_ref_only) { - ret = devm_regulator_get_enable_read_voltage(&spi->dev, - "refin"); + if (st->chip_info->adaq_internal_ref_only) { + /* + * ADAQ chips use fixed internal reference but still + * require a specific reference supply to power it. + * "refin" is already enabled with other power supplies + * in bulk_get_enable(). + */ + + st->vref_mv = ADAQ4380_INTERNAL_REF_MV; + + /* these chips don't have a register bit for this */ + external_ref_en = false; + } else if (st->chip_info->external_ref_only) { + ret = devm_regulator_get_enable_read_voltage(dev, "refin"); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to get refin regulator\n"); st->vref_mv = ret / 1000; @@ -1065,10 +1156,9 @@ static int ad7380_probe(struct spi_device *spi) * If there is no REFIO supply, then it means that we are using * the internal reference, otherwise REFIO is reference voltage. */ - ret = devm_regulator_get_enable_read_voltage(&spi->dev, - "refio"); + ret = devm_regulator_get_enable_read_voltage(dev, "refio"); if (ret < 0 && ret != -ENODEV) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to get refio regulator\n"); external_ref_en = ret != -ENODEV; @@ -1076,7 +1166,7 @@ static int ad7380_probe(struct spi_device *spi) } if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv)) - return dev_err_probe(&spi->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "invalid number of VCM supplies\n"); /* @@ -1086,18 +1176,54 @@ static int ad7380_probe(struct spi_device *spi) for (i = 0; i < st->chip_info->num_vcm_supplies; i++) { const char *vcm = st->chip_info->vcm_supplies[i]; - ret = devm_regulator_get_enable_read_voltage(&spi->dev, vcm); + ret = devm_regulator_get_enable_read_voltage(dev, vcm); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to get %s regulator\n", vcm); st->vcm_mv[i] = ret / 1000; } - st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config); + for (i = 0; i < MAX_NUM_CHANNELS; i++) + st->gain_milli[i] = AD7380_DEFAULT_GAIN_MILLI; + + if (st->chip_info->has_hardware_gain) { + device_for_each_child_node_scoped(dev, node) { + unsigned int channel, gain; + int gain_idx; + + ret = fwnode_property_read_u32(node, "reg", &channel); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read reg property\n"); + + if (channel >= st->chip_info->num_channels - 1) + return dev_err_probe(dev, -EINVAL, + "Invalid channel number %i\n", + channel); + + ret = fwnode_property_read_u32(node, "adi,gain-milli", + &gain); + if (ret && ret != -EINVAL) + return dev_err_probe(dev, ret, + "Failed to read gain for channel %i\n", + channel); + if (ret != -EINVAL) { + /* + * Match gain value from dt to one of supported + * gains + */ + gain_idx = find_closest(gain, ad7380_gains, + ARRAY_SIZE(ad7380_gains)); + st->gain_milli[channel] = ad7380_gains[gain_idx]; + } + } + } + + st->regmap = devm_regmap_init(dev, NULL, st, &ad7380_regmap_config); if (IS_ERR(st->regmap)) - return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + return dev_err_probe(dev, PTR_ERR(st->regmap), "failed to allocate register map\n"); /* @@ -1148,7 +1274,7 @@ static int ad7380_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->available_scan_masks = st->chip_info->available_scan_masks; - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, ad7380_trigger_handler, &ad7380_buffer_setup_ops); @@ -1159,7 +1285,7 @@ static int ad7380_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad7380_of_match_table[] = { @@ -1177,6 +1303,8 @@ static const struct of_device_id ad7380_of_match_table[] = { { .compatible = "adi,ad7386-4", .data = &ad7386_4_chip_info }, { .compatible = "adi,ad7387-4", .data = &ad7387_4_chip_info }, { .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info }, + { .compatible = "adi,adaq4370-4", .data = &adaq4370_4_chip_info }, + { .compatible = "adi,adaq4380-4", .data = &adaq4380_4_chip_info }, { } }; @@ -1195,6 +1323,8 @@ static const struct spi_device_id ad7380_id_table[] = { { "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info }, { "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info }, { "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info }, + { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info }, + { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7380_id_table); diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 71362eafe838..8b2046baaa3e 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -13,12 +13,15 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/property.h> +#include <linux/pwm.h> #include <linux/regulator/consumer.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/sysfs.h> +#include <linux/units.h> #include <linux/util_macros.h> +#include <linux/iio/backend.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -30,42 +33,52 @@ /* * Scales are computed as 5000/32768 and 10000/32768 respectively, - * so that when applied to the raw values they provide mV values + * so that when applied to the raw values they provide mV values. + * The scale arrays are kept as IIO_VAL_INT_PLUS_MICRO, so index + * X is the integer part and X + 1 is the fractional part. */ -static const unsigned int ad7606_16bit_hw_scale_avail[2] = { - 152588, 305176 +static const unsigned int ad7606_16bit_hw_scale_avail[2][2] = { + { 0, 152588 }, { 0, 305176 } }; -static const unsigned int ad7606_18bit_hw_scale_avail[2] = { - 38147, 76294 +static const unsigned int ad7606_18bit_hw_scale_avail[2][2] = { + { 0, 38147 }, { 0, 76294 } }; -static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3] = { - 76294, 152588, 190735, +static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3][2] = { + { 0, 76294 }, { 0, 152588 }, { 0, 190735 } }; -static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5] = { - 76294, 152588, 190735, 305176, 381470 +static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5][2] = { + { 0, 76294 }, { 0, 152588 }, { 0, 190735 }, { 0, 305176 }, { 0, 381470 } }; -static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4] = { - 152588, 305176, 381470, 610352 +static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4][2] = { + { 0, 152588 }, { 0, 305176 }, { 0, 381470 }, { 0, 610352 } }; -static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3] = { - 19073, 38147, 47684 +static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3][2] = { + { 0, 19073 }, { 0, 38147 }, { 0, 47684 } }; -static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5] = { - 19073, 38147, 47684, 76294, 95367 +static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5][2] = { + { 0, 19073 }, { 0, 38147 }, { 0, 47684 }, { 0, 76294 }, { 0, 95367 } }; -static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4] = { - 38147, 76294, 95367, 152588 +static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4][2] = { + { 0, 38147 }, { 0, 76294 }, { 0, 95367 }, { 0, 152588 } }; -static const unsigned int ad7606_16bit_sw_scale_avail[3] = { - 76293, 152588, 305176 +static const unsigned int ad7606_16bit_sw_scale_avail[3][2] = { + { 0, 76293 }, { 0, 152588 }, { 0, 305176 } +}; + +static const unsigned int ad7607_hw_scale_avail[2][2] = { + { 0, 610352 }, { 1, 220703 } +}; + +static const unsigned int ad7609_hw_scale_avail[2][2] = { + { 0, 152588 }, { 0, 305176 } }; static const unsigned int ad7606_oversampling_avail[7] = { @@ -76,6 +89,227 @@ static const unsigned int ad7616_oversampling_avail[8] = { 1, 2, 4, 8, 16, 32, 64, 128, }; +static const struct iio_chan_spec ad7605_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(4), + AD7605_CHANNEL(0), + AD7605_CHANNEL(1), + AD7605_CHANNEL(2), + AD7605_CHANNEL(3), +}; + +static const struct iio_chan_spec ad7606_channels_16bit[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 16), + AD7606_CHANNEL(1, 16), + AD7606_CHANNEL(2, 16), + AD7606_CHANNEL(3, 16), + AD7606_CHANNEL(4, 16), + AD7606_CHANNEL(5, 16), + AD7606_CHANNEL(6, 16), + AD7606_CHANNEL(7, 16), +}; + +static const struct iio_chan_spec ad7606_channels_18bit[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 18), + AD7606_CHANNEL(1, 18), + AD7606_CHANNEL(2, 18), + AD7606_CHANNEL(3, 18), + AD7606_CHANNEL(4, 18), + AD7606_CHANNEL(5, 18), + AD7606_CHANNEL(6, 18), + AD7606_CHANNEL(7, 18), +}; + +static const struct iio_chan_spec ad7607_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 14), + AD7606_CHANNEL(1, 14), + AD7606_CHANNEL(2, 14), + AD7606_CHANNEL(3, 14), + AD7606_CHANNEL(4, 14), + AD7606_CHANNEL(5, 14), + AD7606_CHANNEL(6, 14), + AD7606_CHANNEL(7, 14), +}; + +static const struct iio_chan_spec ad7608_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 18), + AD7606_CHANNEL(1, 18), + AD7606_CHANNEL(2, 18), + AD7606_CHANNEL(3, 18), + AD7606_CHANNEL(4, 18), + AD7606_CHANNEL(5, 18), + AD7606_CHANNEL(6, 18), + AD7606_CHANNEL(7, 18), +}; + +/* + * The current assumption that this driver makes for AD7616, is that it's + * working in Hardware Mode with Serial, Burst and Sequencer modes activated. + * To activate them, following pins must be pulled high: + * -SER/PAR + * -SEQEN + * And following pins must be pulled low: + * -WR/BURST + * -DB4/SER1W + */ +static const struct iio_chan_spec ad7616_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(16), + AD7606_CHANNEL(0, 16), + AD7606_CHANNEL(1, 16), + AD7606_CHANNEL(2, 16), + AD7606_CHANNEL(3, 16), + AD7606_CHANNEL(4, 16), + AD7606_CHANNEL(5, 16), + AD7606_CHANNEL(6, 16), + AD7606_CHANNEL(7, 16), + AD7606_CHANNEL(8, 16), + AD7606_CHANNEL(9, 16), + AD7606_CHANNEL(10, 16), + AD7606_CHANNEL(11, 16), + AD7606_CHANNEL(12, 16), + AD7606_CHANNEL(13, 16), + AD7606_CHANNEL(14, 16), + AD7606_CHANNEL(15, 16), +}; + +static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7607_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7608_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7609_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); + +const struct ad7606_chip_info ad7605_4_info = { + .channels = ad7605_channels, + .name = "ad7605-4", + .num_adc_channels = 4, + .num_channels = 5, + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7605_4_info, IIO_AD7606); + +const struct ad7606_chip_info ad7606_8_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606-8", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606_8_info, IIO_AD7606); + +const struct ad7606_chip_info ad7606_6_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606-6", + .num_adc_channels = 6, + .num_channels = 7, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606_6_info, IIO_AD7606); + +const struct ad7606_chip_info ad7606_4_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606-4", + .num_adc_channels = 4, + .num_channels = 5, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606_4_info, IIO_AD7606); + +const struct ad7606_chip_info ad7606b_info = { + .channels = ad7606_channels_16bit, + .max_samplerate = 800 * KILO, + .name = "ad7606b", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606b_info, IIO_AD7606); + +const struct ad7606_chip_info ad7606c_16_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606c16", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606c_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, IIO_AD7606); + +const struct ad7606_chip_info ad7607_info = { + .channels = ad7607_channels, + .name = "ad7607", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7607_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7607_info, IIO_AD7606); + +const struct ad7606_chip_info ad7608_info = { + .channels = ad7608_channels, + .name = "ad7608", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7608_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7608_info, IIO_AD7606); + +const struct ad7606_chip_info ad7609_info = { + .channels = ad7608_channels, + .name = "ad7609", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7609_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7609_info, IIO_AD7606); + +const struct ad7606_chip_info ad7606c_18_info = { + .channels = ad7606_channels_18bit, + .name = "ad7606c18", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606c_18bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, IIO_AD7606); + +const struct ad7606_chip_info ad7616_info = { + .channels = ad7616_channels, + .init_delay_ms = 15, + .name = "ad7616", + .num_adc_channels = 16, + .num_channels = 17, + .oversampling_avail = ad7616_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), + .os_req_reset = true, + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7616_info, IIO_AD7606); + int ad7606_reset(struct ad7606_state *st) { if (st->gpio_reset) { @@ -278,6 +512,39 @@ static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, return 0; } +static int ad7607_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + + cs->range = 0; + cs->scale_avail = ad7607_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail); + return 0; +} + +static int ad7608_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + + cs->range = 0; + cs->scale_avail = ad7606_18bit_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail); + return 0; +} + +static int ad7609_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + + cs->range = 0; + cs->scale_avail = ad7609_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail); + return 0; +} + static int ad7606_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, @@ -299,9 +566,83 @@ static int ad7606_reg_access(struct iio_dev *indio_dev, } } +static int ad7606_pwm_set_high(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + int ret; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + cnvst_pwm_state.enabled = true; + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period; + + ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); + + return ret; +} + +static int ad7606_pwm_set_low(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + int ret; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + cnvst_pwm_state.enabled = true; + cnvst_pwm_state.duty_cycle = 0; + + ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); + + return ret; +} + +static int ad7606_pwm_set_swing(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + cnvst_pwm_state.enabled = true; + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2; + + return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); +} + +static bool ad7606_pwm_is_swinging(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + + return cnvst_pwm_state.duty_cycle != cnvst_pwm_state.period && + cnvst_pwm_state.duty_cycle != 0; +} + +static int ad7606_set_sampling_freq(struct ad7606_state *st, unsigned long freq) +{ + struct pwm_state cnvst_pwm_state; + bool is_swinging = ad7606_pwm_is_swinging(st); + bool is_high; + + if (freq == 0) + return -EINVAL; + + /* Retrieve the previous state. */ + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + is_high = cnvst_pwm_state.duty_cycle == cnvst_pwm_state.period; + + cnvst_pwm_state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq); + cnvst_pwm_state.polarity = PWM_POLARITY_NORMAL; + if (is_high) + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period; + else if (is_swinging) + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2; + else + cnvst_pwm_state.duty_cycle = 0; + + return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); +} + static int ad7606_read_samples(struct ad7606_state *st) { - unsigned int num = st->chip_info->num_channels - 1; + unsigned int num = st->chip_info->num_adc_channels; return st->bops->read_block(st->dev, num, &st->data); } @@ -333,16 +674,33 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch, int *val) { struct ad7606_state *st = iio_priv(indio_dev); - unsigned int storagebits = st->chip_info->channels[1].scan_type.storagebits; + unsigned int realbits = st->chip_info->channels[1].scan_type.realbits; const struct iio_chan_spec *chan; int ret; - gpiod_set_value(st->gpio_convst, 1); - ret = wait_for_completion_timeout(&st->completion, - msecs_to_jiffies(1000)); - if (!ret) { - ret = -ETIMEDOUT; - goto error_ret; + if (st->gpio_convst) { + gpiod_set_value(st->gpio_convst, 1); + } else { + ret = ad7606_pwm_set_high(st); + if (ret < 0) + return ret; + } + + /* + * If no backend, wait for the interruption on busy pin, otherwise just add + * a delay to leave time for the data to be available. For now, the latter + * will not happen because IIO_CHAN_INFO_RAW is not supported for the backend. + * TODO: Add support for reading a single value when the backend is used. + */ + if (!st->back) { + ret = wait_for_completion_timeout(&st->completion, + msecs_to_jiffies(1000)); + if (!ret) { + ret = -ETIMEDOUT; + goto error_ret; + } + } else { + fsleep(1); } ret = ad7606_read_samples(st); @@ -351,18 +709,23 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch, chan = &indio_dev->channels[ch + 1]; if (chan->scan_type.sign == 'u') { - if (storagebits > 16) + if (realbits > 16) *val = st->data.buf32[ch]; else *val = st->data.buf16[ch]; } else { - if (storagebits > 16) - *val = sign_extend32(st->data.buf32[ch], 17); + if (realbits > 16) + *val = sign_extend32(st->data.buf32[ch], realbits - 1); else - *val = sign_extend32(st->data.buf16[ch], 15); + *val = sign_extend32(st->data.buf16[ch], realbits - 1); } error_ret: + if (!st->gpio_convst) { + ret = ad7606_pwm_set_low(st); + if (ret < 0) + return ret; + } gpiod_set_value(st->gpio_convst, 0); return ret; @@ -377,6 +740,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, int ret, ch = 0; struct ad7606_state *st = iio_priv(indio_dev); struct ad7606_chan_scale *cs; + struct pwm_state cnvst_pwm_state; switch (m) { case IIO_CHAN_INFO_RAW: @@ -391,31 +755,24 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, if (st->sw_mode_en) ch = chan->address; cs = &st->chan_scales[ch]; - *val = 0; - *val2 = cs->scale_avail[cs->range]; + *val = cs->scale_avail[cs->range][0]; + *val2 = cs->scale_avail[cs->range][1]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + /* + * TODO: return the real frequency intead of the requested one once + * pwm_get_state_hw comes upstream. + */ + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + *val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period); + return IIO_VAL_INT; } return -EINVAL; } -static ssize_t ad7606_show_avail(char *buf, const unsigned int *vals, - unsigned int n, bool micros) -{ - size_t len = 0; - int i; - - for (i = 0; i < n; i++) { - len += scnprintf(buf + len, PAGE_SIZE - len, - micros ? "0.%06u " : "%u ", vals[i]); - } - buf[len - 1] = '\n'; - - return len; -} - static ssize_t in_voltage_scale_available_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -423,8 +780,16 @@ static ssize_t in_voltage_scale_available_show(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); struct ad7606_chan_scale *cs = &st->chan_scales[0]; + const unsigned int (*vals)[2] = cs->scale_avail; + unsigned int i; + size_t len = 0; - return ad7606_show_avail(buf, cs->scale_avail, cs->num_scales, true); + for (i = 0; i < cs->num_scales; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ", + vals[i][0], vals[i][1]); + buf[len - 1] = '\n'; + + return len; } static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); @@ -462,6 +827,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7606_state *st = iio_priv(indio_dev); + unsigned int scale_avail_uv[AD760X_MAX_SCALES]; struct ad7606_chan_scale *cs; int i, ret, ch = 0; @@ -472,7 +838,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, if (st->sw_mode_en) ch = chan->address; cs = &st->chan_scales[ch]; - i = find_closest(val2, cs->scale_avail, cs->num_scales); + for (i = 0; i < cs->num_scales; i++) { + scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO + + cs->scale_avail[i][1]; + } + val = (val * MICRO) + val2; + i = find_closest(val, scale_avail_uv, cs->num_scales); ret = st->write_scale(indio_dev, ch, i + cs->reg_offset); if (ret < 0) return ret; @@ -487,8 +858,13 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, ret = st->write_os(indio_dev, i); if (ret < 0) return ret; + st->oversampling = st->oversampling_avail[i]; return 0; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val < 0 && val2 != 0) + return -EINVAL; + return ad7606_set_sampling_freq(st, val); default: return -EINVAL; } @@ -500,9 +876,15 @@ static ssize_t ad7606_oversampling_ratio_avail(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); + const unsigned int *vals = st->oversampling_avail; + unsigned int i; + size_t len = 0; - return ad7606_show_avail(buf, st->oversampling_avail, - st->num_os_ratios, false); + for (i = 0; i < st->num_os_ratios; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u ", vals[i]); + buf[len - 1] = '\n'; + + return len; } static IIO_DEVICE_ATTR(oversampling_ratio_available, 0444, @@ -536,134 +918,13 @@ static const struct attribute_group ad7606_attribute_group_range = { .attrs = ad7606_attributes_range, }; -static const struct iio_chan_spec ad7605_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(4), - AD7605_CHANNEL(0), - AD7605_CHANNEL(1), - AD7605_CHANNEL(2), - AD7605_CHANNEL(3), -}; - -static const struct iio_chan_spec ad7606_channels_16bit[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0, 16), - AD7606_CHANNEL(1, 16), - AD7606_CHANNEL(2, 16), - AD7606_CHANNEL(3, 16), - AD7606_CHANNEL(4, 16), - AD7606_CHANNEL(5, 16), - AD7606_CHANNEL(6, 16), - AD7606_CHANNEL(7, 16), -}; - -static const struct iio_chan_spec ad7606_channels_18bit[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0, 18), - AD7606_CHANNEL(1, 18), - AD7606_CHANNEL(2, 18), - AD7606_CHANNEL(3, 18), - AD7606_CHANNEL(4, 18), - AD7606_CHANNEL(5, 18), - AD7606_CHANNEL(6, 18), - AD7606_CHANNEL(7, 18), -}; - -/* - * The current assumption that this driver makes for AD7616, is that it's - * working in Hardware Mode with Serial, Burst and Sequencer modes activated. - * To activate them, following pins must be pulled high: - * -SER/PAR - * -SEQEN - * And following pins must be pulled low: - * -WR/BURST - * -DB4/SER1W - */ -static const struct iio_chan_spec ad7616_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(16), - AD7606_CHANNEL(0, 16), - AD7606_CHANNEL(1, 16), - AD7606_CHANNEL(2, 16), - AD7606_CHANNEL(3, 16), - AD7606_CHANNEL(4, 16), - AD7606_CHANNEL(5, 16), - AD7606_CHANNEL(6, 16), - AD7606_CHANNEL(7, 16), - AD7606_CHANNEL(8, 16), - AD7606_CHANNEL(9, 16), - AD7606_CHANNEL(10, 16), - AD7606_CHANNEL(11, 16), - AD7606_CHANNEL(12, 16), - AD7606_CHANNEL(13, 16), - AD7606_CHANNEL(14, 16), - AD7606_CHANNEL(15, 16), -}; - -static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { - /* More devices added in future */ - [ID_AD7605_4] = { - .channels = ad7605_channels, - .num_channels = 5, - .scale_setup_cb = ad7606_16bit_chan_scale_setup, - }, - [ID_AD7606_8] = { - .channels = ad7606_channels_16bit, - .num_channels = 9, - .scale_setup_cb = ad7606_16bit_chan_scale_setup, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606_6] = { - .channels = ad7606_channels_16bit, - .num_channels = 7, - .scale_setup_cb = ad7606_16bit_chan_scale_setup, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606_4] = { - .channels = ad7606_channels_16bit, - .num_channels = 5, - .scale_setup_cb = ad7606_16bit_chan_scale_setup, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606B] = { - .channels = ad7606_channels_16bit, - .num_channels = 9, - .scale_setup_cb = ad7606_16bit_chan_scale_setup, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606C_16] = { - .channels = ad7606_channels_16bit, - .num_channels = 9, - .scale_setup_cb = ad7606c_16bit_chan_scale_setup, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606C_18] = { - .channels = ad7606_channels_18bit, - .num_channels = 9, - .scale_setup_cb = ad7606c_18bit_chan_scale_setup, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7616] = { - .channels = ad7616_channels, - .num_channels = 17, - .scale_setup_cb = ad7606_16bit_chan_scale_setup, - .oversampling_avail = ad7616_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), - .os_req_reset = true, - .init_delay_ms = 15, - }, -}; - static int ad7606_request_gpios(struct ad7606_state *st) { struct device *dev = st->dev; - st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start", - GPIOD_OUT_LOW); + st->gpio_convst = devm_gpiod_get_optional(dev, "adi,conversion-start", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_convst)) return PTR_ERR(st->gpio_convst); @@ -705,14 +966,24 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) { struct iio_dev *indio_dev = dev_id; struct ad7606_state *st = iio_priv(indio_dev); + int ret; if (iio_buffer_enabled(indio_dev)) { - gpiod_set_value(st->gpio_convst, 0); + if (st->gpio_convst) { + gpiod_set_value(st->gpio_convst, 0); + } else { + ret = ad7606_pwm_set_low(st); + if (ret < 0) { + dev_err(st->dev, "PWM set low failed"); + goto done; + } + } iio_trigger_poll_nested(st->trig); } else { complete(&st->completion); } +done: return IRQ_HANDLED; }; @@ -767,8 +1038,8 @@ static int ad7606_read_avail(struct iio_dev *indio_dev, ch = chan->address; cs = &st->chan_scales[ch]; - *vals = cs->scale_avail_show; - *length = cs->num_scales * 2; + *vals = (int *)cs->scale_avail; + *length = cs->num_scales; *type = IIO_VAL_INT_PLUS_MICRO; return IIO_AVAIL_LIST; @@ -776,14 +1047,50 @@ static int ad7606_read_avail(struct iio_dev *indio_dev, return -EINVAL; } +static int ad7606_backend_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_pwm_set_swing(st); +} + +static int ad7606_backend_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_pwm_set_low(st); +} + +static int ad7606_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + /* + * The update scan mode is only for iio backend compatible drivers. + * If the specific update_scan_mode is not defined in the bus ops, + * just do nothing and return 0. + */ + if (!st->bops->update_scan_mode) + return 0; + + return st->bops->update_scan_mode(indio_dev, scan_mask); +} + static const struct iio_buffer_setup_ops ad7606_buffer_ops = { .postenable = &ad7606_buffer_postenable, .predisable = &ad7606_buffer_predisable, }; +static const struct iio_buffer_setup_ops ad7606_backend_buffer_ops = { + .postenable = &ad7606_backend_buffer_postenable, + .predisable = &ad7606_backend_buffer_predisable, +}; + static const struct iio_info ad7606_info_no_os_or_range = { .read_raw = &ad7606_read_raw, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_info ad7606_info_os_and_range = { @@ -791,6 +1098,7 @@ static const struct iio_info ad7606_info_os_and_range = { .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os_and_range, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_info ad7606_info_sw_mode = { @@ -799,6 +1107,7 @@ static const struct iio_info ad7606_info_sw_mode = { .read_avail = &ad7606_read_avail, .debugfs_reg_access = &ad7606_reg_access, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_info ad7606_info_os = { @@ -806,6 +1115,7 @@ static const struct iio_info ad7606_info_os = { .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_info ad7606_info_range = { @@ -813,13 +1123,14 @@ static const struct iio_info ad7606_info_range = { .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_range, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_trigger_ops ad7606_trigger_ops = { .validate_device = iio_trigger_validate_own_device, }; -static int ad7606_sw_mode_setup(struct iio_dev *indio_dev, unsigned int id) +static int ad7606_sw_mode_setup(struct iio_dev *indio_dev) { struct ad7606_state *st = iio_priv(indio_dev); @@ -851,31 +1162,21 @@ static int ad7606_chan_scales_setup(struct iio_dev *indio_dev) indio_dev->channels = chans; for (ch = 0; ch < num_channels; ch++) { - struct ad7606_chan_scale *cs; - int i; - ret = st->chip_info->scale_setup_cb(st, &chans[ch + 1], ch); if (ret) return ret; - - cs = &st->chan_scales[ch]; - - if (cs->num_scales * 2 > AD760X_MAX_SCALE_SHOW) - return dev_err_probe(st->dev, -ERANGE, - "Driver error: scale range too big"); - - /* Generate a scale_avail list for showing to userspace */ - for (i = 0; i < cs->num_scales; i++) { - cs->scale_avail_show[i * 2] = 0; - cs->scale_avail_show[i * 2 + 1] = cs->scale_avail[i]; - } } return 0; } +static void ad7606_pwm_disable(void *data) +{ + pwm_disable(data); +} + int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - const char *name, unsigned int id, + const struct ad7606_chip_info *chip_info, const struct ad7606_bus_ops *bops) { struct ad7606_state *st; @@ -900,7 +1201,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, return dev_err_probe(dev, ret, "Failed to enable specified AVcc supply\n"); - st->chip_info = &ad7606_chip_info_tbl[id]; + st->chip_info = chip_info; if (st->chip_info->oversampling_num) { st->oversampling_avail = st->chip_info->oversampling_avail; @@ -923,12 +1224,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, indio_dev->info = &ad7606_info_no_os_or_range; } indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = name; + indio_dev->name = chip_info->name; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; - init_completion(&st->completion); - ret = ad7606_reset(st); if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); @@ -942,7 +1241,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; - ret = ad7606_sw_mode_setup(indio_dev, id); + ret = ad7606_sw_mode_setup(indio_dev); if (ret) return ret; @@ -950,34 +1249,82 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, if (ret) return ret; - st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", - indio_dev->name, - iio_device_id(indio_dev)); - if (!st->trig) - return -ENOMEM; + /* If convst pin is not defined, setup PWM. */ + if (!st->gpio_convst) { + st->cnvst_pwm = devm_pwm_get(dev, NULL); + if (IS_ERR(st->cnvst_pwm)) + return PTR_ERR(st->cnvst_pwm); - st->trig->ops = &ad7606_trigger_ops; - iio_trigger_set_drvdata(st->trig, indio_dev); - ret = devm_iio_trigger_register(dev, st->trig); - if (ret) - return ret; + /* The PWM is initialized at 1MHz to have a fast enough GPIO emulation. */ + ret = ad7606_set_sampling_freq(st, 1 * MEGA); + if (ret) + return ret; - indio_dev->trig = iio_trigger_get(st->trig); + ret = ad7606_pwm_set_low(st); + if (ret) + return ret; - ret = devm_request_threaded_irq(dev, irq, - NULL, - &ad7606_interrupt, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - name, indio_dev); - if (ret) - return ret; + /* + * PWM is not disabled when sampling stops, but instead its duty cycle is set + * to 0% to be sure we have a "low" state. After we unload the driver, let's + * disable the PWM. + */ + ret = devm_add_action_or_reset(dev, ad7606_pwm_disable, + st->cnvst_pwm); + if (ret) + return ret; + } - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - &iio_pollfunc_store_time, - &ad7606_trigger_handler, - &ad7606_buffer_ops); - if (ret) - return ret; + if (st->bops->iio_backend_config) { + /* + * If there is a backend, the PWM should not overpass the maximum sampling + * frequency the chip supports. + */ + ret = ad7606_set_sampling_freq(st, + chip_info->max_samplerate ? : 2 * KILO); + if (ret) + return ret; + + ret = st->bops->iio_backend_config(dev, indio_dev); + if (ret) + return ret; + + indio_dev->setup_ops = &ad7606_backend_buffer_ops; + } else { + + /* Reserve the PWM use only for backend (force gpio_convst definition) */ + if (!st->gpio_convst) + return dev_err_probe(dev, -EINVAL, + "No backend, connect convst to a GPIO"); + + init_completion(&st->completion); + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7606_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + ret = devm_request_threaded_irq(dev, irq, NULL, &ad7606_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + chip_info->name, indio_dev); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &ad7606_trigger_handler, + &ad7606_buffer_ops); + if (ret) + return ret; + } return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index fc05a4afa3b8..998814a92b82 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -61,6 +61,12 @@ #define AD7616_CHANNEL(num) AD7606_SW_CHANNEL(num, 16) +#define AD7606_BI_CHANNEL(num) \ + AD760X_CHANNEL(num, 0, \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 16) + struct ad7606_state; typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st, @@ -69,7 +75,10 @@ typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st, /** * struct ad7606_chip_info - chip specific information * @channels: channel specification + * @max_samplerate: maximum supported samplerate + * @name device name * @num_channels: number of channels + * @num_adc_channels the number of channels the ADC actually inputs. * @scale_setup_cb: callback to setup the scales for each channel * @oversampling_avail pointer to the array which stores the available * oversampling ratios. @@ -80,6 +89,9 @@ typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st, */ struct ad7606_chip_info { const struct iio_chan_spec *channels; + unsigned int max_samplerate; + const char *name; + unsigned int num_adc_channels; unsigned int num_channels; ad7606_scale_setup_cb_t scale_setup_cb; const unsigned int *oversampling_avail; @@ -91,8 +103,6 @@ struct ad7606_chip_info { /** * struct ad7606_chan_scale - channel scale configuration * @scale_avail pointer to the array which stores the available scales - * @scale_avail_show a duplicate of 'scale_avail' which is readily formatted - * such that it can be read via the 'read_avail' hook * @num_scales number of elements stored in the scale_avail array * @range voltage range selection, selects which scale to apply * @reg_offset offset for the register value, to be applied when @@ -100,9 +110,7 @@ struct ad7606_chip_info { */ struct ad7606_chan_scale { #define AD760X_MAX_SCALES 16 -#define AD760X_MAX_SCALE_SHOW (AD760X_MAX_SCALES * 2) - const unsigned int *scale_avail; - int scale_avail_show[AD760X_MAX_SCALE_SHOW]; + const unsigned int (*scale_avail)[2]; unsigned int num_scales; unsigned int range; unsigned int reg_offset; @@ -115,6 +123,7 @@ struct ad7606_chan_scale { * @bops bus operations (SPI or parallel) * @chan_scales scale configuration for channels * @oversampling oversampling selection + * @cnvst_pwm pointer to the PWM device connected to the cnvst pin * @base_address address from where to read data in parallel operation * @sw_mode_en software mode enabled * @oversampling_avail pointer to the array which stores the available @@ -142,10 +151,12 @@ struct ad7606_state { const struct ad7606_bus_ops *bops; struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS]; unsigned int oversampling; + struct pwm_device *cnvst_pwm; void __iomem *base_address; bool sw_mode_en; const unsigned int *oversampling_avail; unsigned int num_os_ratios; + struct iio_backend *back; int (*write_scale)(struct iio_dev *indio_dev, int ch, int val); int (*write_os)(struct iio_dev *indio_dev, int val); @@ -174,16 +185,21 @@ struct ad7606_state { /** * struct ad7606_bus_ops - driver bus operations + * @iio_backend_config function pointer for configuring the iio_backend for + * the compatibles that use it * @read_block function pointer for reading blocks of data * @sw_mode_config: pointer to a function which configured the device * for software mode * @reg_read function pointer for reading spi register * @reg_write function pointer for writing spi register * @write_mask function pointer for write spi register with mask + * @update_scan_mode function pointer for handling the calls to iio_info's update_scan + * mode when enabling/disabling channels. * @rd_wr_cmd pointer to the function which calculates the spi address */ struct ad7606_bus_ops { /* more methods added in future? */ + int (*iio_backend_config)(struct device *dev, struct iio_dev *indio_dev); int (*read_block)(struct device *dev, int num, void *data); int (*sw_mode_config)(struct iio_dev *indio_dev); int (*reg_read)(struct ad7606_state *st, unsigned int addr); @@ -194,25 +210,37 @@ struct ad7606_bus_ops { unsigned int addr, unsigned long mask, unsigned int val); + int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask); u16 (*rd_wr_cmd)(int addr, char isWriteOp); }; +/** + * struct ad7606_bus_info - agregate ad7606_chip_info and ad7606_bus_ops + * @chip_info entry in the table of chips that describes this device + * @bops bus operations (SPI or parallel) + */ +struct ad7606_bus_info { + const struct ad7606_chip_info *chip_info; + const struct ad7606_bus_ops *bops; +}; + int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - const char *name, unsigned int id, + const struct ad7606_chip_info *info, const struct ad7606_bus_ops *bops); int ad7606_reset(struct ad7606_state *st); -enum ad7606_supported_device_ids { - ID_AD7605_4, - ID_AD7606_8, - ID_AD7606_6, - ID_AD7606_4, - ID_AD7606B, - ID_AD7606C_16, - ID_AD7606C_18, - ID_AD7616, -}; +extern const struct ad7606_chip_info ad7605_4_info; +extern const struct ad7606_chip_info ad7606_8_info; +extern const struct ad7606_chip_info ad7606_6_info; +extern const struct ad7606_chip_info ad7606_4_info; +extern const struct ad7606_chip_info ad7606b_info; +extern const struct ad7606_chip_info ad7606c_16_info; +extern const struct ad7606_chip_info ad7606c_18_info; +extern const struct ad7606_chip_info ad7607_info; +extern const struct ad7606_chip_info ad7608_info; +extern const struct ad7606_chip_info ad7609_info; +extern const struct ad7606_chip_info ad7616_info; #ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops ad7606_pm_ops; diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index d651639c45eb..a25182a3daa7 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -2,7 +2,8 @@ /* * AD7606 Parallel Interface ADC driver * - * Copyright 2011 Analog Devices Inc. + * Copyright 2011 - 2024 Analog Devices Inc. + * Copyright 2024 BayLibre SAS. */ #include <linux/err.h> @@ -11,11 +12,85 @@ #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/types.h> +#include <linux/iio/backend.h> #include <linux/iio/iio.h> + #include "ad7606.h" +static const struct iio_chan_spec ad7606b_bi_channels[] = { + AD7606_BI_CHANNEL(0), + AD7606_BI_CHANNEL(1), + AD7606_BI_CHANNEL(2), + AD7606_BI_CHANNEL(3), + AD7606_BI_CHANNEL(4), + AD7606_BI_CHANNEL(5), + AD7606_BI_CHANNEL(6), + AD7606_BI_CHANNEL(7), +}; + +static int ad7606_bi_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int c, ret; + + for (c = 0; c < indio_dev->num_channels; c++) { + if (test_bit(c, scan_mask)) + ret = iio_backend_chan_enable(st->back, c); + else + ret = iio_backend_chan_disable(st->back, c); + if (ret) + return ret; + } + + return 0; +} + +static int ad7606_bi_setup_iio_backend(struct device *dev, struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int ret, c; + struct iio_backend_data_fmt data = { + .sign_extend = true, + .enable = true, + }; + + st->back = devm_iio_backend_get(dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + /* If the device is iio_backend powered the PWM is mandatory */ + if (!st->cnvst_pwm) + return dev_err_probe(st->dev, -EINVAL, + "A PWM is mandatory when using backend.\n"); + + ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return ret; + + ret = devm_iio_backend_enable(dev, st->back); + if (ret) + return ret; + + for (c = 0; c < indio_dev->num_channels; c++) { + ret = iio_backend_data_format_set(st->back, c, &data); + if (ret) + return ret; + } + + indio_dev->channels = ad7606b_bi_channels; + indio_dev->num_channels = 8; + + return 0; +} + +static const struct ad7606_bus_ops ad7606_bi_bops = { + .iio_backend_config = ad7606_bi_setup_iio_backend, + .update_scan_mode = ad7606_bi_update_scan_mode, +}; + static int ad7606_par16_read_block(struct device *dev, int count, void *buf) { @@ -89,12 +164,32 @@ static const struct ad7606_bus_ops ad7606_par8_bops = { static int ad7606_par_probe(struct platform_device *pdev) { - const struct platform_device_id *id = platform_get_device_id(pdev); + const struct ad7606_chip_info *chip_info; + const struct platform_device_id *id; struct resource *res; void __iomem *addr; resource_size_t remap_size; int irq; + /* + * If a firmware node is available (ACPI or DT), platform_device_id is null + * and we must use get_match_data. + */ + if (dev_fwnode(&pdev->dev)) { + chip_info = device_get_match_data(&pdev->dev); + if (device_property_present(&pdev->dev, "io-backends")) + /* + * If a backend is available ,call the core probe with backend + * bops, otherwise use the former bops. + */ + return ad7606_probe(&pdev->dev, 0, NULL, + chip_info, + &ad7606_bi_bops); + } else { + id = platform_get_device_id(pdev); + chip_info = (const struct ad7606_chip_info *)id->driver_data; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -105,26 +200,33 @@ static int ad7606_par_probe(struct platform_device *pdev) remap_size = resource_size(res); - return ad7606_probe(&pdev->dev, irq, addr, - id->name, id->driver_data, + return ad7606_probe(&pdev->dev, irq, addr, chip_info, remap_size > 1 ? &ad7606_par16_bops : &ad7606_par8_bops); } static const struct platform_device_id ad7606_driver_ids[] = { - { .name = "ad7605-4", .driver_data = ID_AD7605_4, }, - { .name = "ad7606-4", .driver_data = ID_AD7606_4, }, - { .name = "ad7606-6", .driver_data = ID_AD7606_6, }, - { .name = "ad7606-8", .driver_data = ID_AD7606_8, }, + { .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_info, }, + { .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_info, }, + { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_info, }, + { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_info, }, + { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_info, }, + { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_info, }, + { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_info, }, + { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_info, }, { } }; MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); static const struct of_device_id ad7606_of_match[] = { - { .compatible = "adi,ad7605-4" }, - { .compatible = "adi,ad7606-4" }, - { .compatible = "adi,ad7606-6" }, - { .compatible = "adi,ad7606-8" }, + { .compatible = "adi,ad7605-4", .data = &ad7605_4_info }, + { .compatible = "adi,ad7606-4", .data = &ad7606_4_info }, + { .compatible = "adi,ad7606-6", .data = &ad7606_6_info }, + { .compatible = "adi,ad7606-8", .data = &ad7606_8_info }, + { .compatible = "adi,ad7606b", .data = &ad7606b_info }, + { .compatible = "adi,ad7607", .data = &ad7607_info }, + { .compatible = "adi,ad7608", .data = &ad7608_info }, + { .compatible = "adi,ad7609", .data = &ad7609_info }, { } }; MODULE_DEVICE_TABLE(of, ad7606_of_match); @@ -144,3 +246,4 @@ MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(IIO_AD7606); +MODULE_IMPORT_NS(IIO_BACKEND); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index d12e55123888..0662300cde8d 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -132,6 +132,19 @@ static int ad7606_spi_read_block(struct device *dev, return 0; } +static int ad7606_spi_read_block14to16(struct device *dev, + int count, void *buf) +{ + struct spi_device *spi = to_spi_device(dev); + struct spi_transfer xfer = { + .bits_per_word = 14, + .len = count * sizeof(u16), + .rx_buf = buf, + }; + + return spi_sync_transfer(spi, &xfer, 1); +} + static int ad7606_spi_read_block18to32(struct device *dev, int count, void *buf) { @@ -325,6 +338,14 @@ static const struct ad7606_bus_ops ad7606_spi_bops = { .read_block = ad7606_spi_read_block, }; +static const struct ad7606_bus_ops ad7607_spi_bops = { + .read_block = ad7606_spi_read_block14to16, +}; + +static const struct ad7606_bus_ops ad7608_spi_bops = { + .read_block = ad7606_spi_read_block18to32, +}; + static const struct ad7606_bus_ops ad7616_spi_bops = { .read_block = ad7606_spi_read_block, .reg_read = ad7606_spi_reg_read, @@ -334,7 +355,7 @@ static const struct ad7606_bus_ops ad7616_spi_bops = { .sw_mode_config = ad7616_sw_mode_config, }; -static const struct ad7606_bus_ops ad7606B_spi_bops = { +static const struct ad7606_bus_ops ad7606b_spi_bops = { .read_block = ad7606_spi_read_block, .reg_read = ad7606_spi_reg_read, .reg_write = ad7606_spi_reg_write, @@ -352,54 +373,97 @@ static const struct ad7606_bus_ops ad7606c_18_spi_bops = { .sw_mode_config = ad7606c_18_sw_mode_config, }; +static const struct ad7606_bus_info ad7605_4_bus_info = { + .chip_info = &ad7605_4_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606_8_bus_info = { + .chip_info = &ad7606_8_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606_6_bus_info = { + .chip_info = &ad7606_6_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606_4_bus_info = { + .chip_info = &ad7606_4_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606b_bus_info = { + .chip_info = &ad7606b_info, + .bops = &ad7606b_spi_bops, +}; + +static const struct ad7606_bus_info ad7606c_16_bus_info = { + .chip_info = &ad7606c_16_info, + .bops = &ad7606b_spi_bops, +}; + +static const struct ad7606_bus_info ad7606c_18_bus_info = { + .chip_info = &ad7606c_18_info, + .bops = &ad7606c_18_spi_bops, +}; + +static const struct ad7606_bus_info ad7607_bus_info = { + .chip_info = &ad7607_info, + .bops = &ad7607_spi_bops, +}; + +static const struct ad7606_bus_info ad7608_bus_info = { + .chip_info = &ad7608_info, + .bops = &ad7608_spi_bops, +}; + +static const struct ad7606_bus_info ad7609_bus_info = { + .chip_info = &ad7609_info, + .bops = &ad7608_spi_bops, +}; + +static const struct ad7606_bus_info ad7616_bus_info = { + .chip_info = &ad7616_info, + .bops = &ad7616_spi_bops, +}; + static int ad7606_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); - const struct ad7606_bus_ops *bops; - - switch (id->driver_data) { - case ID_AD7616: - bops = &ad7616_spi_bops; - break; - case ID_AD7606B: - case ID_AD7606C_16: - bops = &ad7606B_spi_bops; - break; - case ID_AD7606C_18: - bops = &ad7606c_18_spi_bops; - break; - default: - bops = &ad7606_spi_bops; - break; - } + const struct ad7606_bus_info *bus_info = spi_get_device_match_data(spi); return ad7606_probe(&spi->dev, spi->irq, NULL, - id->name, id->driver_data, - bops); + bus_info->chip_info, bus_info->bops); } static const struct spi_device_id ad7606_id_table[] = { - { "ad7605-4", ID_AD7605_4 }, - { "ad7606-4", ID_AD7606_4 }, - { "ad7606-6", ID_AD7606_6 }, - { "ad7606-8", ID_AD7606_8 }, - { "ad7606b", ID_AD7606B }, - { "ad7606c-16", ID_AD7606C_16 }, - { "ad7606c-18", ID_AD7606C_18 }, - { "ad7616", ID_AD7616 }, + { "ad7605-4", (kernel_ulong_t)&ad7605_4_bus_info }, + { "ad7606-4", (kernel_ulong_t)&ad7606_4_bus_info }, + { "ad7606-6", (kernel_ulong_t)&ad7606_6_bus_info }, + { "ad7606-8", (kernel_ulong_t)&ad7606_8_bus_info }, + { "ad7606b", (kernel_ulong_t)&ad7606b_bus_info }, + { "ad7606c-16", (kernel_ulong_t)&ad7606c_16_bus_info }, + { "ad7606c-18", (kernel_ulong_t)&ad7606c_18_bus_info }, + { "ad7607", (kernel_ulong_t)&ad7607_bus_info }, + { "ad7608", (kernel_ulong_t)&ad7608_bus_info }, + { "ad7609", (kernel_ulong_t)&ad7609_bus_info }, + { "ad7616", (kernel_ulong_t)&ad7616_bus_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7606_id_table); static const struct of_device_id ad7606_of_match[] = { - { .compatible = "adi,ad7605-4" }, - { .compatible = "adi,ad7606-4" }, - { .compatible = "adi,ad7606-6" }, - { .compatible = "adi,ad7606-8" }, - { .compatible = "adi,ad7606b" }, - { .compatible = "adi,ad7606c-16" }, - { .compatible = "adi,ad7606c-18" }, - { .compatible = "adi,ad7616" }, + { .compatible = "adi,ad7605-4", .data = &ad7605_4_bus_info }, + { .compatible = "adi,ad7606-4", .data = &ad7606_4_bus_info }, + { .compatible = "adi,ad7606-6", .data = &ad7606_6_bus_info }, + { .compatible = "adi,ad7606-8", .data = &ad7606_8_bus_info }, + { .compatible = "adi,ad7606b", .data = &ad7606b_bus_info }, + { .compatible = "adi,ad7606c-16", .data = &ad7606c_16_bus_info }, + { .compatible = "adi,ad7606c-18", .data = &ad7606c_18_bus_info }, + { .compatible = "adi,ad7607", .data = &ad7607_bus_info }, + { .compatible = "adi,ad7608", .data = &ad7608_bus_info }, + { .compatible = "adi,ad7609", .data = &ad7609_bus_info }, + { .compatible = "adi,ad7616", .data = &ad7616_bus_info }, { } }; MODULE_DEVICE_TABLE(of, ad7606_of_match); diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c new file mode 100644 index 000000000000..2537dab69a35 --- /dev/null +++ b/drivers/iio/adc/ad7779.c @@ -0,0 +1,914 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AD7770, AD7771, AD7779 ADC + * + * Copyright 2023-2024 Analog Devices Inc. + */ + +#include <linux/bitfield.h> +#include <linux/bitmap.h> +#include <linux/clk.h> +#include <linux/crc8.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/unaligned.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> + +#define AD7779_SPI_READ_CMD BIT(7) + +#define AD7779_DISABLE_SD BIT(7) + +#define AD7779_REG_CH_DISABLE 0x08 +#define AD7779_REG_CH_SYNC_OFFSET(ch) (0x09 + (ch)) +#define AD7779_REG_CH_CONFIG(ch) (0x00 + (ch)) +#define AD7779_REG_GENERAL_USER_CONFIG_1 0x11 +#define AD7779_REG_GENERAL_USER_CONFIG_2 0x12 +#define AD7779_REG_GENERAL_USER_CONFIG_3 0x13 +#define AD7779_REG_DOUT_FORMAT 0x14 +#define AD7779_REG_ADC_MUX_CONFIG 0x15 +#define AD7779_REG_GPIO_CONFIG 0x17 +#define AD7779_REG_BUFFER_CONFIG_1 0x19 +#define AD7779_REG_GLOBAL_MUX_CONFIG 0x16 +#define AD7779_REG_BUFFER_CONFIG_2 0x1A +#define AD7779_REG_GPIO_DATA 0x18 +#define AD7779_REG_CH_OFFSET_UPPER_BYTE(ch) (0x1C + (ch) * 6) +#define AD7779_REG_CH_OFFSET_LOWER_BYTE(ch) (0x1E + (ch) * 6) +#define AD7779_REG_CH_GAIN_UPPER_BYTE(ch) (0x1F + (ch) * 6) +#define AD7779_REG_CH_OFFSET_MID_BYTE(ch) (0x1D + (ch) * 6) +#define AD7779_REG_CH_GAIN_MID_BYTE(ch) (0x20 + (ch) * 6) +#define AD7779_REG_CH_ERR_REG(ch) (0x4C + (ch)) +#define AD7779_REG_CH0_1_SAT_ERR 0x54 +#define AD7779_REG_CH_GAIN_LOWER_BYTE(ch) (0x21 + (ch) * 6) +#define AD7779_REG_CH2_3_SAT_ERR 0x55 +#define AD7779_REG_CH4_5_SAT_ERR 0x56 +#define AD7779_REG_CH6_7_SAT_ERR 0x57 +#define AD7779_REG_CHX_ERR_REG_EN 0x58 +#define AD7779_REG_GEN_ERR_REG_1 0x59 +#define AD7779_REG_GEN_ERR_REG_1_EN 0x5A +#define AD7779_REG_GEN_ERR_REG_2 0x5B +#define AD7779_REG_GEN_ERR_REG_2_EN 0x5C +#define AD7779_REG_STATUS_REG_1 0x5D +#define AD7779_REG_STATUS_REG_2 0x5E +#define AD7779_REG_STATUS_REG_3 0x5F +#define AD7779_REG_SRC_N_MSB 0x60 +#define AD7779_REG_SRC_N_LSB 0x61 +#define AD7779_REG_SRC_IF_MSB 0x62 +#define AD7779_REG_SRC_IF_LSB 0x63 +#define AD7779_REG_SRC_UPDATE 0x64 + +#define AD7779_FILTER_MSK BIT(6) +#define AD7779_MOD_POWERMODE_MSK BIT(6) +#define AD7779_MOD_PDB_REFOUT_MSK BIT(4) +#define AD7779_MOD_SPI_EN_MSK BIT(4) +#define AD7779_USRMOD_INIT_MSK GENMASK(6, 4) + +/* AD7779_REG_DOUT_FORMAT */ +#define AD7779_DOUT_FORMAT_MSK GENMASK(7, 6) +#define AD7779_DOUT_HEADER_FORMAT BIT(5) +#define AD7779_DCLK_CLK_DIV_MSK GENMASK(3, 1) + +#define AD7779_REFMUX_CTRL_MSK GENMASK(7, 6) +#define AD7779_SPI_CRC_EN_MSK BIT(0) + +#define AD7779_MAXCLK_LOWPOWER (4096 * HZ_PER_KHZ) +#define AD7779_NUM_CHANNELS 8 +#define AD7779_RESET_BUF_SIZE 8 +#define AD7779_CHAN_DATA_SIZE 4 + +#define AD7779_LOWPOWER_DIV 512 +#define AD7779_HIGHPOWER_DIV 2048 + +#define AD7779_SINC3_MAXFREQ (16 * HZ_PER_KHZ) +#define AD7779_SINC5_MAXFREQ (128 * HZ_PER_KHZ) + +#define AD7779_DEFAULT_SAMPLING_FREQ (8 * HZ_PER_KHZ) +#define AD7779_DEFAULT_SAMPLING_2LINE (4 * HZ_PER_KHZ) +#define AD7779_DEFAULT_SAMPLING_1LINE (2 * HZ_PER_KHZ) + +#define AD7779_SPIMODE_MAX_SAMP_FREQ (16 * HZ_PER_KHZ) + +#define GAIN_REL 0x555555 +#define AD7779_FREQ_MSB_MSK GENMASK(15, 8) +#define AD7779_FREQ_LSB_MSK GENMASK(7, 0) +#define AD7779_UPPER GENMASK(23, 16) +#define AD7779_MID GENMASK(15, 8) +#define AD7779_LOWER GENMASK(7, 0) + +#define AD7779_REG_MSK GENMASK(6, 0) + +#define AD7779_CRC8_POLY 0x07 +DECLARE_CRC8_TABLE(ad7779_crc8_table); + +enum ad7779_filter { + AD7779_SINC3, + AD7779_SINC5, +}; + +enum ad7779_variant { + ad7770, + ad7771, + ad7779, +}; + +enum ad7779_power_mode { + AD7779_LOW_POWER, + AD7779_HIGH_POWER, +}; + +struct ad7779_chip_info { + const char *name; + struct iio_chan_spec const *channels; +}; + +struct ad7779_state { + struct spi_device *spi; + const struct ad7779_chip_info *chip_info; + struct clk *mclk; + struct iio_trigger *trig; + struct completion completion; + unsigned int sampling_freq; + enum ad7779_filter filter_enabled; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + struct { + u32 chans[8]; + aligned_s64 timestamp; + } data __aligned(IIO_DMA_MINALIGN); + u32 spidata_tx[8]; + u8 reg_rx_buf[3]; + u8 reg_tx_buf[3]; + u8 reset_buf[8]; +}; + +static const char * const ad7779_filter_type[] = { + [AD7779_SINC3] = "sinc3", + [AD7779_SINC5] = "sinc5", +}; + +static const char * const ad7779_power_supplies[] = { + "avdd1", "avdd2", "avdd4", +}; + +static int ad7779_spi_read(struct ad7779_state *st, u8 reg, u8 *rbuf) +{ + int ret; + u8 crc_buf[2]; + u8 exp_crc; + struct spi_transfer t = { + .tx_buf = st->reg_tx_buf, + .rx_buf = st->reg_rx_buf, + }; + + st->reg_tx_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg); + st->reg_tx_buf[1] = 0; + + if (reg == AD7779_REG_GEN_ERR_REG_1_EN) { + t.len = 2; + } else { + t.len = 3; + st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf, + t.len - 1, 0); + } + + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) + return ret; + + crc_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg); + crc_buf[1] = st->reg_rx_buf[1]; + exp_crc = crc8(ad7779_crc8_table, crc_buf, ARRAY_SIZE(crc_buf), 0); + if (reg != AD7779_REG_GEN_ERR_REG_1_EN && exp_crc != st->reg_rx_buf[2]) { + dev_err(&st->spi->dev, "Bad CRC %x, expected %x", + st->reg_rx_buf[2], exp_crc); + return -EINVAL; + } + *rbuf = st->reg_rx_buf[1]; + + return 0; +} + +static int ad7779_spi_write(struct ad7779_state *st, u8 reg, u8 val) +{ + u8 length = 3; + + st->reg_tx_buf[0] = FIELD_GET(AD7779_REG_MSK, reg); + st->reg_tx_buf[1] = val; + if (reg == AD7779_REG_GEN_ERR_REG_1_EN) + length = 2; + else + st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf, + length - 1, 0); + + return spi_write(st->spi, st->reg_tx_buf, length); +} + +static int ad7779_spi_write_mask(struct ad7779_state *st, u8 reg, u8 mask, + u8 val) +{ + int ret; + u8 regval, data; + + ret = ad7779_spi_read(st, reg, &data); + if (ret) + return ret; + + regval = (data & ~mask) | (val & mask); + + if (regval == data) + return 0; + + return ad7779_spi_write(st, reg, regval); +} + +static int ad7779_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ad7779_state *st = iio_priv(indio_dev); + u8 rval; + int ret; + + if (readval) { + ret = ad7779_spi_read(st, reg, &rval); + *readval = rval; + return ret; + } + + return ad7779_spi_write(st, reg, writeval); +} + +static int ad7779_set_sampling_frequency(struct ad7779_state *st, + unsigned int sampling_freq) +{ + int ret; + unsigned int dec; + unsigned int frac; + unsigned int div; + unsigned int decimal; + unsigned int freq_khz; + + if (st->filter_enabled == AD7779_SINC3 && + sampling_freq > AD7779_SINC3_MAXFREQ) + return -EINVAL; + + if (st->filter_enabled == AD7779_SINC5 && + sampling_freq > AD7779_SINC5_MAXFREQ) + return -EINVAL; + + if (sampling_freq > AD7779_SPIMODE_MAX_SAMP_FREQ) + return -EINVAL; + + div = AD7779_HIGHPOWER_DIV; + + freq_khz = sampling_freq / HZ_PER_KHZ; + dec = div / freq_khz; + frac = div % freq_khz; + + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB, + FIELD_GET(AD7779_FREQ_MSB_MSK, dec)); + if (ret) + return ret; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB, + FIELD_GET(AD7779_FREQ_LSB_MSK, dec)); + if (ret) + return ret; + + if (frac) { + /* + * In order to obtain the first three decimals of the decimation + * the initial number is multiplied with 10^3 prior to the + * division, then the original division result is subtracted and + * the number is divided by 10^3. + */ + decimal = ((mult_frac(div, KILO, freq_khz) - dec * KILO) << 16) + / KILO; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB, + FIELD_GET(AD7779_FREQ_MSB_MSK, decimal)); + if (ret) + return ret; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB, + FIELD_GET(AD7779_FREQ_LSB_MSK, decimal)); + if (ret) + return ret; + } else { + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB, + FIELD_GET(AD7779_FREQ_MSB_MSK, 0x0)); + if (ret) + return ret; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB, + FIELD_GET(AD7779_FREQ_LSB_MSK, 0x0)); + if (ret) + return ret; + } + ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, BIT(0)); + if (ret) + return ret; + + /* SRC update settling time */ + fsleep(15); + + ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, 0x0); + if (ret) + return ret; + + /* SRC update settling time */ + fsleep(15); + + st->sampling_freq = sampling_freq; + + return 0; +} + +static int ad7779_get_filter(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) +{ + struct ad7779_state *st = iio_priv(indio_dev); + u8 temp; + int ret; + + ret = ad7779_spi_read(st, AD7779_REG_GENERAL_USER_CONFIG_2, &temp); + if (ret) + return ret; + + return FIELD_GET(AD7779_FILTER_MSK, temp); +} + +static int ad7779_set_filter(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + unsigned int mode) +{ + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + + ret = ad7779_spi_write_mask(st, + AD7779_REG_GENERAL_USER_CONFIG_2, + AD7779_FILTER_MSK, + FIELD_PREP(AD7779_FILTER_MSK, mode)); + if (ret) + return ret; + + ret = ad7779_set_sampling_frequency(st, st->sampling_freq); + if (ret) + return ret; + + st->filter_enabled = mode; + + return 0; +} + +static int ad7779_get_calibscale(struct ad7779_state *st, int channel) +{ + int ret; + u8 calibscale[3]; + + ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel), + &calibscale[0]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_MID_BYTE(channel), + &calibscale[1]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel), + &calibscale[2]); + if (ret) + return ret; + + return get_unaligned_be24(calibscale); +} + +static int ad7779_set_calibscale(struct ad7779_state *st, int channel, int val) +{ + int ret; + unsigned int gain; + u8 gain_bytes[3]; + + /* + * The gain value is relative to 0x555555, which represents a gain of 1 + */ + gain = DIV_ROUND_CLOSEST_ULL((u64)val * 5592405LL, MEGA); + put_unaligned_be24(gain, gain_bytes); + ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel), + gain_bytes[0]); + if (ret) + return ret; + + ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_MID_BYTE(channel), + gain_bytes[1]); + if (ret) + return ret; + + return ad7779_spi_write(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel), + gain_bytes[2]); +} + +static int ad7779_get_calibbias(struct ad7779_state *st, int channel) +{ + int ret; + u8 calibbias[3]; + + ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel), + &calibbias[0]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel), + &calibbias[1]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel), + &calibbias[2]); + if (ret) + return ret; + + return get_unaligned_be24(calibbias); +} + +static int ad7779_set_calibbias(struct ad7779_state *st, int channel, int val) +{ + int ret; + u8 calibbias[3]; + + put_unaligned_be24(val, calibbias); + ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel), + calibbias[0]); + if (ret) + return ret; + + ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel), + calibbias[1]); + if (ret) + return ret; + + return ad7779_spi_write(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel), + calibbias[2]); +} + +static int ad7779_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + ret = ad7779_get_calibscale(st, chan->channel); + if (ret < 0) + return ret; + *val = ret; + *val2 = GAIN_REL; + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_CALIBBIAS: + ret = ad7779_get_calibbias(st, chan->channel); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->sampling_freq; + if (*val < 0) + return -EINVAL; + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + unreachable(); +} + +static int ad7779_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct ad7779_state *st = iio_priv(indio_dev); + + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + return ad7779_set_calibscale(st, chan->channel, val2); + case IIO_CHAN_INFO_CALIBBIAS: + return ad7779_set_calibbias(st, chan->channel, val); + case IIO_CHAN_INFO_SAMP_FREQ: + return ad7779_set_sampling_frequency(st, val); + default: + return -EINVAL; + } + } + unreachable(); +} + +static int ad7779_buffer_preenable(struct iio_dev *indio_dev) +{ + int ret; + struct ad7779_state *st = iio_priv(indio_dev); + + ret = ad7779_spi_write_mask(st, + AD7779_REG_GENERAL_USER_CONFIG_3, + AD7779_MOD_SPI_EN_MSK, + FIELD_PREP(AD7779_MOD_SPI_EN_MSK, 1)); + if (ret) + return ret; + + /* + * DRDY output cannot be disabled at device level therefore we mask + * the irq at host end. + */ + enable_irq(st->spi->irq); + + return 0; +} + +static int ad7779_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad7779_state *st = iio_priv(indio_dev); + + disable_irq(st->spi->irq); + + return ad7779_spi_write(st, AD7779_REG_GENERAL_USER_CONFIG_3, + AD7779_DISABLE_SD); +} + +static irqreturn_t ad7779_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + struct spi_transfer t = { + .rx_buf = st->data.chans, + .tx_buf = st->spidata_tx, + .len = AD7779_NUM_CHANNELS * AD7779_CHAN_DATA_SIZE, + }; + + st->spidata_tx[0] = AD7779_SPI_READ_CMD; + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) { + dev_err(&st->spi->dev, "SPI transfer error in IRQ handler"); + goto exit_handler; + } + + iio_push_to_buffers_with_timestamp(indio_dev, &st->data, pf->timestamp); + +exit_handler: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int ad7779_reset(struct iio_dev *indio_dev, struct gpio_desc *reset_gpio) +{ + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + struct spi_transfer t = { + .tx_buf = st->reset_buf, + .len = 8, + }; + + if (reset_gpio) { + gpiod_set_value(reset_gpio, 1); + /* Delay for reset to occur is 225 microseconds */ + fsleep(230); + ret = 0; + } else { + memset(st->reset_buf, 0xff, sizeof(st->reset_buf)); + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) + return ret; + } + + /* Delay for reset to occur is 225 microseconds */ + fsleep(230); + + return ret; +} + +static const struct iio_info ad7779_info = { + .read_raw = ad7779_read_raw, + .write_raw = ad7779_write_raw, + .debugfs_reg_access = &ad7779_reg_access, +}; + +static const struct iio_enum ad7779_filter_enum = { + .items = ad7779_filter_type, + .num_items = ARRAY_SIZE(ad7779_filter_type), + .get = ad7779_get_filter, + .set = ad7779_set_filter, +}; + +static const struct iio_chan_spec_ext_info ad7779_ext_filter[] = { + IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7779_filter_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, + &ad7779_filter_enum), + { } +}; + +#define AD777x_CHAN_S(index, _ext_info) \ + { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .address = (index), \ + .indexed = 1, \ + .channel = (index), \ + .scan_index = (index), \ + .ext_info = (_ext_info), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 24, \ + .storagebits = 32, \ + .endianness = IIO_BE, \ + }, \ + } + +#define AD777x_CHAN_NO_FILTER_S(index) \ + AD777x_CHAN_S(index, NULL) + +#define AD777x_CHAN_FILTER_S(index) \ + AD777x_CHAN_S(index, ad7779_ext_filter) +static const struct iio_chan_spec ad7779_channels[] = { + AD777x_CHAN_NO_FILTER_S(0), + AD777x_CHAN_NO_FILTER_S(1), + AD777x_CHAN_NO_FILTER_S(2), + AD777x_CHAN_NO_FILTER_S(3), + AD777x_CHAN_NO_FILTER_S(4), + AD777x_CHAN_NO_FILTER_S(5), + AD777x_CHAN_NO_FILTER_S(6), + AD777x_CHAN_NO_FILTER_S(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_chan_spec ad7779_channels_filter[] = { + AD777x_CHAN_FILTER_S(0), + AD777x_CHAN_FILTER_S(1), + AD777x_CHAN_FILTER_S(2), + AD777x_CHAN_FILTER_S(3), + AD777x_CHAN_FILTER_S(4), + AD777x_CHAN_FILTER_S(5), + AD777x_CHAN_FILTER_S(6), + AD777x_CHAN_FILTER_S(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_buffer_setup_ops ad7779_buffer_setup_ops = { + .preenable = ad7779_buffer_preenable, + .postdisable = ad7779_buffer_postdisable, +}; + +static const struct iio_trigger_ops ad7779_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static int ad7779_conf(struct ad7779_state *st, struct gpio_desc *start_gpio) +{ + int ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_GEN_ERR_REG_1_EN, + AD7779_SPI_CRC_EN_MSK, + FIELD_PREP(AD7779_SPI_CRC_EN_MSK, 1)); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1, + AD7779_USRMOD_INIT_MSK, + FIELD_PREP(AD7779_USRMOD_INIT_MSK, 5)); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT, + AD7779_DCLK_CLK_DIV_MSK, + FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 1)); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_ADC_MUX_CONFIG, + AD7779_REFMUX_CTRL_MSK, + FIELD_PREP(AD7779_REFMUX_CTRL_MSK, 1)); + if (ret) + return ret; + + ret = ad7779_set_sampling_frequency(st, AD7779_DEFAULT_SAMPLING_FREQ); + if (ret) + return ret; + + gpiod_set_value(start_gpio, 0); + /* Start setup time */ + fsleep(15); + gpiod_set_value(start_gpio, 1); + /* Start setup time */ + fsleep(15); + gpiod_set_value(start_gpio, 0); + /* Start setup time */ + fsleep(15); + + return 0; +} + +static int ad7779_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad7779_state *st; + struct gpio_desc *reset_gpio, *start_gpio; + struct device *dev = &spi->dev; + int ret = -EINVAL; + + if (!spi->irq) + return dev_err_probe(dev, ret, "DRDY irq not present\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(ad7779_power_supplies), + ad7779_power_supplies); + if (ret) + return dev_err_probe(dev, ret, + "failed to get and enable supplies\n"); + + st->mclk = devm_clk_get_enabled(dev, "mclk"); + if (IS_ERR(st->mclk)) + return PTR_ERR(st->mclk); + + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + + start_gpio = devm_gpiod_get(dev, "start", GPIOD_OUT_HIGH); + if (IS_ERR(start_gpio)) + return PTR_ERR(start_gpio); + + crc8_populate_msb(ad7779_crc8_table, AD7779_CRC8_POLY); + st->spi = spi; + + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + + ret = ad7779_reset(indio_dev, reset_gpio); + if (ret) + return ret; + + ret = ad7779_conf(st, start_gpio); + if (ret) + return ret; + + indio_dev->name = st->chip_info->name; + indio_dev->info = &ad7779_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = ARRAY_SIZE(ad7779_channels); + + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7779_trigger_ops; + + iio_trigger_set_drvdata(st->trig, st); + + ret = devm_request_irq(dev, spi->irq, iio_trigger_generic_data_rdy_poll, + IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name, + st->trig); + if (ret) + return dev_err_probe(dev, ret, "request IRQ %d failed\n", + st->spi->irq); + + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + init_completion(&st->completion); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &ad7779_trigger_handler, + &ad7779_buffer_setup_ops); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT, + AD7779_DCLK_CLK_DIV_MSK, + FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7)); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static int ad7779_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7779_state *st = iio_priv(indio_dev); + + return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1, + AD7779_MOD_POWERMODE_MSK, + FIELD_PREP(AD7779_MOD_POWERMODE_MSK, + AD7779_LOW_POWER)); +} + +static int ad7779_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7779_state *st = iio_priv(indio_dev); + + return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1, + AD7779_MOD_POWERMODE_MSK, + FIELD_PREP(AD7779_MOD_POWERMODE_MSK, + AD7779_HIGH_POWER)); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ad7779_pm_ops, ad7779_suspend, ad7779_resume); + +static const struct ad7779_chip_info ad7770_chip_info = { + .name = "ad7770", + .channels = ad7779_channels, +}; + +static const struct ad7779_chip_info ad7771_chip_info = { + .name = "ad7771", + .channels = ad7779_channels_filter, +}; + +static const struct ad7779_chip_info ad7779_chip_info = { + .name = "ad7779", + .channels = ad7779_channels, +}; + +static const struct spi_device_id ad7779_id[] = { + { + .name = "ad7770", + .driver_data = (kernel_ulong_t)&ad7770_chip_info, + }, + { + .name = "ad7771", + .driver_data = (kernel_ulong_t)&ad7771_chip_info, + }, + { + .name = "ad7779", + .driver_data = (kernel_ulong_t)&ad7779_chip_info, + }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad7779_id); + +static const struct of_device_id ad7779_of_table[] = { + { + .compatible = "adi,ad7770", + .data = &ad7770_chip_info, + }, + { + .compatible = "adi,ad7771", + .data = &ad7771_chip_info, + }, + { + .compatible = "adi,ad7779", + .data = &ad7779_chip_info, + }, + { } +}; +MODULE_DEVICE_TABLE(of, ad7779_of_table); + +static struct spi_driver ad7779_driver = { + .driver = { + .name = "ad7779", + .pm = pm_sleep_ptr(&ad7779_pm_ops), + .of_match_table = ad7779_of_table, + }, + .probe = ad7779_probe, + .id_table = ad7779_id, +}; +module_spi_driver(ad7779_driver); + +MODULE_AUTHOR("Ramona Alexandra Nechita <ramona.nechita@analog.com>"); +MODULE_DESCRIPTION("Analog Devices AD7779 ADC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 0f107e3fc2c8..aa44b4e2542b 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -406,7 +406,7 @@ static int ad799x_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 ad799x_state *st = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index fb635a756440..689e34f06987 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -132,7 +132,7 @@ static int hi8435_read_event_config(struct iio_dev *idev, static int hi8435_write_event_config(struct iio_dev *idev, 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 hi8435_priv *priv = iio_priv(idev); int ret; diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 8da2d8d7a9c6..9a0baea08ab6 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -944,7 +944,7 @@ error_ret: static int max1363_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 max1363_state *st = iio_priv(indio_dev); diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c index a96fae546bc1..b0f6727cfe38 100644 --- a/drivers/iio/adc/pac1921.c +++ b/drivers/iio/adc/pac1921.c @@ -699,7 +699,8 @@ static int pac1921_read_event_config(struct iio_dev *indio_dev, static int pac1921_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 pac1921_priv *priv = iio_priv(indio_dev); u8 ovf_bit; @@ -1170,7 +1171,9 @@ static int pac1921_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(priv->regmap), "Cannot initialize register map\n"); - devm_mutex_init(dev, &priv->lock); + ret = devm_mutex_init(dev, &priv->lock); + if (ret) + return ret; priv->dv_gain = PAC1921_DEFAULT_DV_GAIN; priv->di_gain = PAC1921_DEFAULT_DI_GAIN; diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index 7ef249d83286..20802b7f49ea 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -1507,7 +1507,7 @@ static int pac1934_probe(struct i2c_client *client) indio_dev->name = pac1934_chip_config[ret].name; } - if (acpi_match_device(dev->driver->acpi_match_table, dev)) + if (is_acpi_device_node(dev_fwnode(dev))) ret = pac1934_acpi_parse_channel_config(client, info); else /* diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 67d567ee21b4..d283ee8fb1d2 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -676,7 +676,7 @@ static int palmas_gpadc_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 palmas_gpadc *adc = iio_priv(indio_dev); int adc_chan = chan->channel; diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 052d2124b215..47fe8e16aee4 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -806,7 +806,7 @@ static int ads1015_disable_event_config(struct ads1015_data *data, static int ads1015_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 ads1015_data *data = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index ebc583b07e0c..76dd0343f5f7 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -905,7 +905,7 @@ static int ams_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 ams *ams = iio_priv(indio_dev); unsigned int alarm; diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c index 90f62377c34d..c188d3dcab48 100644 --- a/drivers/iio/adc/xilinx-xadc-events.c +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -121,7 +121,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev, int xadc_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) { unsigned int alarm = xadc_get_alarm_mask(chan); struct xadc *xadc = iio_priv(indio_dev); diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index 3036f4d613ff..b4d9d4683117 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -25,7 +25,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir); int xadc_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); int xadc_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, diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index e50c896a0766..daea2bde7acf 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -6,9 +6,11 @@ #include <linux/unaligned.h> #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/crc8.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> @@ -59,7 +61,7 @@ struct ad74413r_state { unsigned int num_gpo_gpios; unsigned int num_comparator_gpios; u32 sense_resistor_ohms; - + int refin_reg_uv; /* * Synchronize consecutive operations when doing a one-shot * conversion and when updating the ADC samples SPI message. @@ -68,11 +70,9 @@ struct ad74413r_state { const struct ad74413r_chip_info *chip_info; struct spi_device *spi; - struct regulator *refin_reg; struct regmap *regmap; struct device *dev; struct iio_trigger *trig; - struct gpio_desc *reset_gpio; size_t adc_active_channels; struct spi_message adc_samples_msg; @@ -407,12 +407,16 @@ static int ad74413r_gpio_set_comp_config(struct gpio_chip *chip, static int ad74413r_reset(struct ad74413r_state *st) { + struct gpio_desc *reset_gpio; int ret; - if (st->reset_gpio) { - gpiod_set_value_cansleep(st->reset_gpio, 1); + reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + + if (reset_gpio) { fsleep(50); - gpiod_set_value_cansleep(st->reset_gpio, 0); + gpiod_set_value_cansleep(reset_gpio, 0); return 0; } @@ -660,7 +664,7 @@ static int ad74413r_get_output_voltage_scale(struct ad74413r_state *st, static int ad74413r_get_output_current_scale(struct ad74413r_state *st, int *val, int *val2) { - *val = regulator_get_voltage(st->refin_reg); + *val = st->refin_reg_uv; *val2 = st->sense_resistor_ohms * AD74413R_DAC_CODE_MAX * 1000; return IIO_VAL_FRACTIONAL; @@ -861,19 +865,12 @@ static int ad74413r_get_single_adc_result(struct iio_dev *indio_dev, unsigned int channel, int *val) { struct ad74413r_state *st = iio_priv(indio_dev); - int ret; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - mutex_lock(&st->lock); - ret = _ad74413r_get_single_adc_result(st, channel, val); - mutex_unlock(&st->lock); - - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + guard(mutex)(&st->lock); + return _ad74413r_get_single_adc_result(st, channel, val); + } + unreachable(); } static void ad74413r_adc_to_resistance_result(int adc_result, int *val) @@ -895,7 +892,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, unsigned int channel; int ret = -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); spi_message_init(&st->adc_samples_msg); st->adc_active_channels = 0; @@ -903,11 +900,11 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, for_each_clear_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) { ret = ad74413r_set_adc_channel_enable(st, channel, false); if (ret) - goto out; + return ret; } if (*active_scan_mask == 0) - goto out; + return ret; /* * The read select register is used to select which register's value @@ -925,7 +922,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, for_each_set_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) { ret = ad74413r_set_adc_channel_enable(st, channel, true); if (ret) - goto out; + return ret; st->adc_active_channels++; @@ -956,11 +953,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, xfer->cs_change = 0; spi_message_add_tail(xfer, &st->adc_samples_msg); - -out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static int ad74413r_buffer_postenable(struct iio_dev *indio_dev) @@ -1347,11 +1340,6 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st) return 0; } -static void ad74413r_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int ad74413r_probe(struct spi_device *spi) { struct ad74413r_state *st; @@ -1370,7 +1358,10 @@ static int ad74413r_probe(struct spi_device *spi) if (!st->chip_info) return -EINVAL; - mutex_init(&st->lock); + ret = devm_mutex_init(st->dev, &st->lock); + if (ret) + return ret; + init_completion(&st->adc_data_completion); st->regmap = devm_regmap_init(st->dev, NULL, st, @@ -1378,23 +1369,11 @@ static int ad74413r_probe(struct spi_device *spi) if (IS_ERR(st->regmap)) return PTR_ERR(st->regmap); - st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(st->reset_gpio)) - return PTR_ERR(st->reset_gpio); - - st->refin_reg = devm_regulator_get(st->dev, "refin"); - if (IS_ERR(st->refin_reg)) - return dev_err_probe(st->dev, PTR_ERR(st->refin_reg), - "Failed to get refin regulator\n"); - - ret = regulator_enable(st->refin_reg); - if (ret) - return ret; - - ret = devm_add_action_or_reset(st->dev, ad74413r_regulator_disable, - st->refin_reg); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(st->dev, "refin"); + if (ret < 0) + return dev_err_probe(st->dev, ret, + "Failed to get refin regulator voltage\n"); + st->refin_reg_uv = ret; st->sense_resistor_ohms = 100000000; device_property_read_u32(st->dev, "shunt-resistor-micro-ohms", diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index 4c03b9e834b8..e64a41bae32c 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -232,7 +232,7 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, static int ad7150_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 ad7150_chip_info *chip = iio_priv(indio_dev); int ret = 0; diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index 6c87223f58d9..330fe0af946f 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -50,6 +50,8 @@ config BME680 select REGMAP select BME680_I2C if I2C select BME680_SPI if SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for Bosch Sensortec BME680 sensor with temperature, pressure, humidity and gas sensing capability. diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h index b2c547ac8d34..00ab89b3138b 100644 --- a/drivers/iio/chemical/bme680.h +++ b/drivers/iio/chemical/bme680.h @@ -2,6 +2,8 @@ #ifndef BME680_H_ #define BME680_H_ +#include <linux/regmap.h> + #define BME680_REG_CHIP_ID 0xD0 #define BME680_CHIP_ID_VAL 0x61 #define BME680_REG_SOFT_RESET 0xE0 @@ -25,8 +27,6 @@ #define BME680_OSRS_TEMP_MASK GENMASK(7, 5) #define BME680_OSRS_PRESS_MASK GENMASK(4, 2) #define BME680_MODE_MASK GENMASK(1, 0) -#define BME680_MODE_FORCED 1 -#define BME680_MODE_SLEEP 0 #define BME680_REG_CONFIG 0x75 #define BME680_FILTER_MASK GENMASK(4, 2) @@ -42,6 +42,7 @@ #define BME680_RHRANGE_MASK GENMASK(5, 4) #define BME680_REG_RES_HEAT_VAL 0x00 #define BME680_RSERROR_MASK GENMASK(7, 4) +#define BME680_REG_IDAC_HEAT_0 0x50 #define BME680_REG_RES_HEAT_0 0x5A #define BME680_REG_GAS_WAIT_0 0x64 #define BME680_ADC_GAS_RES GENMASK(15, 6) @@ -63,7 +64,11 @@ #define BME680_MEAS_TRIM_MASK GENMASK(24, 4) -#define BME680_STARTUP_TIME_US 5000 +/* Datasheet Section 1.1, Table 1 */ +#define BME680_STARTUP_TIME_US 2000 + +#define BME680_NUM_CHANNELS 4 +#define BME680_NUM_BULK_READ_REGS 15 /* Calibration Parameters */ #define BME680_T2_LSB_REG 0x8A diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index 0b96534c6867..9783953e64e0 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -16,8 +16,11 @@ #include <linux/module.h> #include <linux/regmap.h> +#include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include <linux/unaligned.h> @@ -95,6 +98,19 @@ struct bme680_calib { s8 range_sw_err; }; +/* values of CTRL_MEAS register */ +enum bme680_op_mode { + BME680_MODE_SLEEP = 0, + BME680_MODE_FORCED = 1, +}; + +enum bme680_scan { + BME680_TEMP, + BME680_PRESS, + BME680_HUMID, + BME680_GAS, +}; + struct bme680_data { struct regmap *regmap; struct bme680_calib bme680; @@ -102,11 +118,17 @@ struct bme680_data { u8 oversampling_temp; u8 oversampling_press; u8 oversampling_humid; + u8 preheat_curr_mA; u16 heater_dur; u16 heater_temp; + struct { + s32 chan[4]; + aligned_s64 ts; + } scan; + union { - u8 buf[3]; + u8 buf[BME680_NUM_BULK_READ_REGS]; unsigned int check; __be16 be16; u8 bme680_cal_buf_1[BME680_CALIB_RANGE_1_LEN]; @@ -138,22 +160,66 @@ EXPORT_SYMBOL_NS(bme680_regmap_config, IIO_BME680); static const struct iio_chan_spec bme680_channels[] = { { .type = IIO_TEMP, + /* PROCESSED maintained for ABI backwards compatibility */ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, }, { .type = IIO_PRESSURE, + /* PROCESSED maintained for ABI backwards compatibility */ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, }, { .type = IIO_HUMIDITYRELATIVE, + /* PROCESSED maintained for ABI backwards compatibility */ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 2, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, }, { .type = IIO_RESISTANCE, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = 3, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(4), + { + .type = IIO_CURRENT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .output = 1, + .scan_index = -1, }, }; @@ -224,7 +290,7 @@ static int bme680_read_calib(struct bme680_data *data, calib->res_heat_val = data->bme680_cal_buf_3[RES_HEAT_VAL]; calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK, - data->bme680_cal_buf_3[RES_HEAT_RANGE]); + data->bme680_cal_buf_3[RES_HEAT_RANGE]); calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK, data->bme680_cal_buf_3[RANGE_SW_ERR]); @@ -438,19 +504,19 @@ static u32 bme680_compensate_gas(struct bme680_data *data, u16 gas_res_adc, u32 calc_gas_res; /* Look up table for the possible gas range values */ - static const u32 lookupTable[16] = {2147483647u, 2147483647u, - 2147483647u, 2147483647u, 2147483647u, - 2126008810u, 2147483647u, 2130303777u, - 2147483647u, 2147483647u, 2143188679u, - 2136746228u, 2147483647u, 2126008810u, - 2147483647u, 2147483647u}; - - var1 = ((1340 + (5 * (s64) calib->range_sw_err)) * - ((s64) lookupTable[gas_range])) >> 16; + static const u32 lookup_table[16] = { + 2147483647u, 2147483647u, 2147483647u, 2147483647u, + 2147483647u, 2126008810u, 2147483647u, 2130303777u, + 2147483647u, 2147483647u, 2143188679u, 2136746228u, + 2147483647u, 2126008810u, 2147483647u, 2147483647u + }; + + var1 = ((1340LL + (5 * calib->range_sw_err)) * + (lookup_table[gas_range])) >> 16; var2 = ((gas_res_adc << 15) - 16777216) + var1; var3 = ((125000 << (15 - gas_range)) * var1) >> 9; var3 += (var2 >> 1); - calc_gas_res = div64_s64(var3, (s64) var2); + calc_gas_res = div64_s64(var3, (s64)var2); return calc_gas_res; } @@ -468,7 +534,7 @@ static u8 bme680_calc_heater_res(struct bme680_data *data, u16 temp) if (temp > 400) /* Cap temperature */ temp = 400; - var1 = (((s32) BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256; + var1 = (((s32)BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256; var2 = (calib->par_gh1 + 784) * (((((calib->par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10); @@ -502,23 +568,22 @@ static u8 bme680_calc_heater_dur(u16 dur) return durval; } -static int bme680_set_mode(struct bme680_data *data, bool mode) +/* Taken from datasheet, section 5.3.3 */ +static u8 bme680_calc_heater_preheat_current(u8 curr) +{ + return 8 * curr - 1; +} + +static int bme680_set_mode(struct bme680_data *data, enum bme680_op_mode mode) { struct device *dev = regmap_get_device(data->regmap); int ret; - if (mode) { - ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS, - BME680_MODE_MASK, BME680_MODE_FORCED); - if (ret < 0) - dev_err(dev, "failed to set forced mode\n"); - - } else { - ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS, - BME680_MODE_MASK, BME680_MODE_SLEEP); - if (ret < 0) - dev_err(dev, "failed to set sleep mode\n"); - + ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS, + BME680_MODE_MASK, mode); + if (ret < 0) { + dev_err(dev, "failed to set ctrl_meas register\n"); + return ret; } return ret; @@ -546,7 +611,7 @@ static int bme680_wait_for_eoc(struct bme680_data *data) data->oversampling_humid) * 1936) + (477 * 4) + (477 * 5) + 1000 + (data->heater_dur * 1000); - usleep_range(wait_eoc_us, wait_eoc_us + 100); + fsleep(wait_eoc_us); ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &data->check); if (ret) { @@ -571,9 +636,8 @@ static int bme680_chip_config(struct bme680_data *data) int ret; u8 osrs; - osrs = FIELD_PREP( - BME680_OSRS_HUMIDITY_MASK, - bme680_oversampling_to_reg(data->oversampling_humid)); + osrs = FIELD_PREP(BME680_OSRS_HUMIDITY_MASK, + bme680_oversampling_to_reg(data->oversampling_humid)); /* * Highly recommended to set oversampling of humidity before * temperature/pressure oversampling. @@ -587,8 +651,7 @@ static int bme680_chip_config(struct bme680_data *data) /* IIR filter settings */ ret = regmap_update_bits(data->regmap, BME680_REG_CONFIG, - BME680_FILTER_MASK, - BME680_FILTER_COEFF_VAL); + BME680_FILTER_MASK, BME680_FILTER_COEFF_VAL); if (ret < 0) { dev_err(dev, "failed to write config register\n"); return ret; @@ -609,14 +672,27 @@ static int bme680_chip_config(struct bme680_data *data) return 0; } +static int bme680_preheat_curr_config(struct bme680_data *data, u8 val) +{ + struct device *dev = regmap_get_device(data->regmap); + u8 heatr_curr; + int ret; + + heatr_curr = bme680_calc_heater_preheat_current(val); + ret = regmap_write(data->regmap, BME680_REG_IDAC_HEAT_0, heatr_curr); + if (ret < 0) + dev_err(dev, "failed to write idac_heat_0 register\n"); + + return ret; +} + static int bme680_gas_config(struct bme680_data *data) { struct device *dev = regmap_get_device(data->regmap); int ret; u8 heatr_res, heatr_dur; - /* Go to sleep */ - ret = bme680_set_mode(data, false); + ret = bme680_set_mode(data, BME680_MODE_SLEEP); if (ret < 0) return ret; @@ -638,6 +714,10 @@ static int bme680_gas_config(struct bme680_data *data) return ret; } + ret = bme680_preheat_curr_config(data, data->preheat_curr_mA); + if (ret) + return ret; + /* Enable the gas sensor and select heater profile set-point 0 */ ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1, BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK, @@ -649,23 +729,20 @@ static int bme680_gas_config(struct bme680_data *data) return ret; } -static int bme680_read_temp(struct bme680_data *data, int *val) +static int bme680_read_temp(struct bme680_data *data, s16 *comp_temp) { int ret; u32 adc_temp; - s16 comp_temp; ret = bme680_read_temp_adc(data, &adc_temp); if (ret) return ret; - comp_temp = bme680_compensate_temp(data, adc_temp); - *val = comp_temp * 10; /* Centidegrees to millidegrees */ - return IIO_VAL_INT; + *comp_temp = bme680_compensate_temp(data, adc_temp); + return 0; } -static int bme680_read_press(struct bme680_data *data, - int *val, int *val2) +static int bme680_read_press(struct bme680_data *data, u32 *comp_press) { int ret; u32 adc_press; @@ -679,16 +756,14 @@ static int bme680_read_press(struct bme680_data *data, if (ret) return ret; - *val = bme680_compensate_press(data, adc_press, t_fine); - *val2 = 1000; - return IIO_VAL_FRACTIONAL; + *comp_press = bme680_compensate_press(data, adc_press, t_fine); + return 0; } -static int bme680_read_humid(struct bme680_data *data, - int *val, int *val2) +static int bme680_read_humid(struct bme680_data *data, u32 *comp_humidity) { int ret; - u32 adc_humidity, comp_humidity; + u32 adc_humidity; s32 t_fine; ret = bme680_get_t_fine(data, &t_fine); @@ -699,15 +774,11 @@ static int bme680_read_humid(struct bme680_data *data, if (ret) return ret; - comp_humidity = bme680_compensate_humid(data, adc_humidity, t_fine); - - *val = comp_humidity; - *val2 = 1000; - return IIO_VAL_FRACTIONAL; + *comp_humidity = bme680_compensate_humid(data, adc_humidity, t_fine); + return 0; } -static int bme680_read_gas(struct bme680_data *data, - int *val) +static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res) { struct device *dev = regmap_get_device(data->regmap); int ret; @@ -742,9 +813,8 @@ static int bme680_read_gas(struct bme680_data *data, } gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val); - - *val = bme680_compensate_gas(data, adc_gas_res, gas_range); - return IIO_VAL_INT; + *comp_gas_res = bme680_compensate_gas(data, adc_gas_res, gas_range); + return 0; } static int bme680_read_raw(struct iio_dev *indio_dev, @@ -752,12 +822,12 @@ static int bme680_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct bme680_data *data = iio_priv(indio_dev); - int ret; + int chan_val, ret; + s16 temp_chan_val; guard(mutex)(&data->lock); - /* set forced mode to trigger measurement */ - ret = bme680_set_mode(data, true); + ret = bme680_set_mode(data, BME680_MODE_FORCED); if (ret < 0) return ret; @@ -769,13 +839,77 @@ static int bme680_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_TEMP: - return bme680_read_temp(data, val); + ret = bme680_read_temp(data, &temp_chan_val); + if (ret) + return ret; + + *val = temp_chan_val * 10; + return IIO_VAL_INT; case IIO_PRESSURE: - return bme680_read_press(data, val, val2); + ret = bme680_read_press(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; case IIO_HUMIDITYRELATIVE: - return bme680_read_humid(data, val, val2); + ret = bme680_read_humid(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; case IIO_RESISTANCE: - return bme680_read_gas(data, val); + ret = bme680_read_gas(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + ret = bme680_read_temp(data, (s16 *)&chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + case IIO_PRESSURE: + ret = bme680_read_press(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + case IIO_HUMIDITYRELATIVE: + ret = bme680_read_humid(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + *val = 10; + return IIO_VAL_INT; + case IIO_PRESSURE: + *val = 1; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + case IIO_HUMIDITYRELATIVE: + *val = 1; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -836,6 +970,15 @@ static int bme680_write_raw(struct iio_dev *indio_dev, return bme680_chip_config(data); } + case IIO_CHAN_INFO_PROCESSED: + { + switch (chan->type) { + case IIO_CURRENT: + return bme680_preheat_curr_config(data, (u8)val); + default: + return -EINVAL; + } + } default: return -EINVAL; } @@ -861,6 +1004,86 @@ static const struct iio_info bme680_info = { .attrs = &bme680_attribute_group, }; +static const unsigned long bme680_avail_scan_masks[] = { + BIT(BME680_GAS) | BIT(BME680_HUMID) | BIT(BME680_PRESS) | BIT(BME680_TEMP), + 0 +}; + +static irqreturn_t bme680_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bme680_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + u32 adc_temp, adc_press, adc_humid; + u16 adc_gas_res, gas_regs_val; + u8 gas_range; + s32 t_fine; + int ret; + + guard(mutex)(&data->lock); + + ret = bme680_set_mode(data, BME680_MODE_FORCED); + if (ret < 0) + goto out; + + ret = bme680_wait_for_eoc(data); + if (ret) + goto out; + + ret = regmap_bulk_read(data->regmap, BME680_REG_MEAS_STAT_0, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(dev, "failed to burst read sensor data\n"); + goto out; + } + if (data->buf[0] & BME680_GAS_MEAS_BIT) { + dev_err(dev, "gas measurement incomplete\n"); + goto out; + } + + /* Temperature calculations */ + adc_temp = FIELD_GET(BME680_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[5])); + if (adc_temp == BME680_MEAS_SKIPPED) { + dev_err(dev, "reading temperature skipped\n"); + goto out; + } + data->scan.chan[0] = bme680_compensate_temp(data, adc_temp); + t_fine = bme680_calc_t_fine(data, adc_temp); + + /* Pressure calculations */ + adc_press = FIELD_GET(BME680_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[2])); + if (adc_press == BME680_MEAS_SKIPPED) { + dev_err(dev, "reading pressure skipped\n"); + goto out; + } + data->scan.chan[1] = bme680_compensate_press(data, adc_press, t_fine); + + /* Humidity calculations */ + adc_humid = get_unaligned_be16(&data->buf[8]); + if (adc_humid == BME680_MEAS_SKIPPED) { + dev_err(dev, "reading humidity skipped\n"); + goto out; + } + data->scan.chan[2] = bme680_compensate_humid(data, adc_humid, t_fine); + + /* Gas calculations */ + gas_regs_val = get_unaligned_be16(&data->buf[13]); + adc_gas_res = FIELD_GET(BME680_ADC_GAS_RES, gas_regs_val); + if ((gas_regs_val & BME680_GAS_STAB_BIT) == 0) { + dev_err(dev, "heater failed to reach the target temperature\n"); + goto out; + } + gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val); + data->scan.chan[3] = bme680_compensate_gas(data, adc_gas_res, gas_range); + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + iio_get_time_ns(indio_dev)); +out: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + int bme680_core_probe(struct device *dev, struct regmap *regmap, const char *name) { @@ -879,6 +1102,7 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, indio_dev->name = name; indio_dev->channels = bme680_channels; indio_dev->num_channels = ARRAY_SIZE(bme680_channels); + indio_dev->available_scan_masks = bme680_avail_scan_masks; indio_dev->info = &bme680_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -888,13 +1112,13 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, data->oversampling_temp = 8; /* 8X oversampling rate */ data->heater_temp = 320; /* degree Celsius */ data->heater_dur = 150; /* milliseconds */ + data->preheat_curr_mA = 0; - ret = regmap_write(regmap, BME680_REG_SOFT_RESET, - BME680_CMD_SOFTRESET); + ret = regmap_write(regmap, BME680_REG_SOFT_RESET, BME680_CMD_SOFTRESET); if (ret < 0) return dev_err_probe(dev, ret, "Failed to reset chip\n"); - usleep_range(BME680_STARTUP_TIME_US, BME680_STARTUP_TIME_US + 1000); + fsleep(BME680_STARTUP_TIME_US); ret = regmap_read(regmap, BME680_REG_CHIP_ID, &data->check); if (ret < 0) @@ -922,6 +1146,14 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, return dev_err_probe(dev, ret, "failed to set gas config data\n"); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + bme680_trigger_handler, + NULL); + if (ret) + return dev_err_probe(dev, ret, + "iio triggered buffer setup failed\n"); + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS_GPL(bme680_core_probe, IIO_BME680); diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 8395a2f4950d..5d01ba4edbf3 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -6,9 +6,28 @@ menu "Digital to analog converters" +config AD3552R_HS + tristate "Analog Devices AD3552R DAC High Speed driver" + select AD3552R_LIB + select IIO_BACKEND + help + Say yes here to build support for Analog Devices AD3552R + Digital to Analog Converter High Speed driver. + + The driver requires the assistance of an IP core to operate, + since data is streamed into target device via DMA, sent over a + QSPI + DDR (Double Data Rate) bus. + + To compile this driver as a module, choose M here: the + module will be called ad3552r-hs. + +config AD3552R_LIB + tristate + config AD3552R tristate "Analog Devices AD3552R DAC driver" depends on SPI_MASTER + select AD3552R_LIB select IIO_BUFFER select IIO_TRIGGERED_BUFFER help diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 621d553bd6e3..414c152be779 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -4,6 +4,8 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o +obj-$(CONFIG_AD3552R_LIB) += ad3552r-common.o obj-$(CONFIG_AD3552R) += ad3552r.o obj-$(CONFIG_AD5360) += ad5360.o obj-$(CONFIG_AD5380) += ad5380.o diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c new file mode 100644 index 000000000000..2dfeca3656d2 --- /dev/null +++ b/drivers/iio/dac/ad3552r-common.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2010-2024 Analog Devices Inc. +// Copyright (c) 2024 Baylibre, SAS + +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> + +#include "ad3552r.h" + +const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = { + [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, + [AD3552R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, + [AD3552R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, + [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }, + [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = { -10000, 10000 } +}; +EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, IIO_AD3552R); + +const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = { + [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, + [AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 }, + [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, + [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, + [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 }, + [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 } +}; +EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, IIO_AD3552R); + +/* Gain * AD3552R_GAIN_SCALE */ +static const s32 gains_scaling_table[] = { + [AD3552R_CH_GAIN_SCALING_1] = 1000, + [AD3552R_CH_GAIN_SCALING_0_5] = 500, + [AD3552R_CH_GAIN_SCALING_0_25] = 250, + [AD3552R_CH_GAIN_SCALING_0_125] = 125 +}; + +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs) +{ + return FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1) | + FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p) | + FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n) | + FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs(goffs)) | + FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, goffs < 0); +} +EXPORT_SYMBOL_NS_GPL(ad3552r_calc_custom_gain, IIO_AD3552R); + +static void ad3552r_get_custom_range(struct ad3552r_ch_data *ch_data, + s32 *v_min, s32 *v_max) +{ + s64 vref, tmp, common, offset, gn, gp; + /* + * From datasheet formula (In Volts): + * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03] + * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03] + * Calculus are converted to milivolts + */ + vref = 2500; + /* 2.5 * 1.03 * 1000 (To mV) */ + common = 2575 * ch_data->rfb; + offset = ch_data->gain_offset; + + gn = gains_scaling_table[ch_data->n]; + tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_max = vref + tmp; + + gp = gains_scaling_table[ch_data->p]; + tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_min = vref - tmp; +} + +void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data, + const struct ad3552r_model_data *model_data) +{ + s32 idx, v_max, v_min, span, rem; + s64 tmp; + + if (ch_data->range_override) { + ad3552r_get_custom_range(ch_data, &v_min, &v_max); + } else { + /* Normal range */ + idx = ch_data->range; + v_min = model_data->ranges_table[idx][0]; + v_max = model_data->ranges_table[idx][1]; + } + + /* + * From datasheet formula: + * Vout = Span * (D / 65536) + Vmin + * Converted to scale and offset: + * Scale = Span / 65536 + * Offset = 65536 * Vmin / Span + * + * Reminders are in micros in order to be printed as + * IIO_VAL_INT_PLUS_MICRO + */ + span = v_max - v_min; + ch_data->scale_int = div_s64_rem(span, 65536, &rem); + /* Do operations in microvolts */ + ch_data->scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, 65536); + + ch_data->offset_int = div_s64_rem(v_min * 65536, span, &rem); + tmp = (s64)rem * 1000000; + ch_data->offset_dec = div_s64(tmp, span); +} +EXPORT_SYMBOL_NS_GPL(ad3552r_calc_gain_and_offset, IIO_AD3552R); + +int ad3552r_get_ref_voltage(struct device *dev, u32 *val) +{ + int voltage; + int delta = 100000; + + voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (voltage < 0 && voltage != -ENODEV) + return dev_err_probe(dev, voltage, + "Error getting vref voltage\n"); + + if (voltage == -ENODEV) { + if (device_property_read_bool(dev, "adi,vref-out-en")) + *val = AD3552R_INTERNAL_VREF_PIN_2P5V; + else + *val = AD3552R_INTERNAL_VREF_PIN_FLOATING; + + return 0; + } + + if (voltage > 2500000 + delta || voltage < 2500000 - delta) { + dev_warn(dev, "vref-supply must be 2.5V"); + return -EINVAL; + } + + *val = AD3552R_EXTERNAL_VREF_PIN_INPUT; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_ref_voltage, IIO_AD3552R); + +int ad3552r_get_drive_strength(struct device *dev, u32 *val) +{ + int err; + u32 drive_strength; + + err = device_property_read_u32(dev, "adi,sdo-drive-strength", + &drive_strength); + if (err) + return err; + + if (drive_strength > 3) { + dev_err_probe(dev, -EINVAL, + "adi,sdo-drive-strength must be less than 4\n"); + return -EINVAL; + } + + *val = drive_strength; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_drive_strength, IIO_AD3552R); + +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child, + u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs) +{ + int err; + u32 val; + struct fwnode_handle *gain_child __free(fwnode_handle) = + fwnode_get_named_child_node(child, + "custom-output-range-config"); + + if (!gain_child) + return dev_err_probe(dev, -EINVAL, + "custom-output-range-config mandatory\n"); + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-scaling-p mandatory\n"); + *gs_p = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-scaling-n property mandatory\n"); + *gs_n = val; + + err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); + if (err) + return dev_err_probe(dev, err, + "adi,rfb-ohms mandatory\n"); + *rfb = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-offset mandatory\n"); + *goffs = val; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_custom_gain, IIO_AD3552R); + +static int ad3552r_find_range(const struct ad3552r_model_data *model_info, + s32 *vals) +{ + int i; + + for (i = 0; i < model_info->num_ranges; i++) + if (vals[0] == model_info->ranges_table[i][0] * 1000 && + vals[1] == model_info->ranges_table[i][1] * 1000) + return i; + + return -EINVAL; +} + +int ad3552r_get_output_range(struct device *dev, + const struct ad3552r_model_data *model_info, + struct fwnode_handle *child, u32 *val) +{ + int ret; + s32 vals[2]; + + /* This property is optional, so returning -ENOENT if missing */ + if (!fwnode_property_present(child, "adi,output-range-microvolt")) + return -ENOENT; + + ret = fwnode_property_read_u32_array(child, + "adi,output-range-microvolt", + vals, 2); + if (ret) + return dev_err_probe(dev, ret, + "invalid adi,output-range-microvolt\n"); + + ret = ad3552r_find_range(model_info, vals); + if (ret < 0) + return dev_err_probe(dev, ret, + "invalid adi,output-range-microvolt value\n"); + + *val = ret; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_output_range, IIO_AD3552R); + +MODULE_DESCRIPTION("ad3552r common functions"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c new file mode 100644 index 000000000000..d5c704adf5bf --- /dev/null +++ b/drivers/iio/dac/ad3552r-hs.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD3552R + * Digital to Analog converter driver, High Speed version + * + * Copyright 2024 Analog Devices Inc. + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/backend.h> +#include <linux/iio/buffer.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/units.h> + +#include "ad3552r.h" +#include "ad3552r-hs.h" + +struct ad3552r_hs_state { + const struct ad3552r_model_data *model_data; + struct gpio_desc *reset_gpio; + struct device *dev; + struct iio_backend *back; + bool single_channel; + struct ad3552r_ch_data ch_data[AD3552R_MAX_CH]; + struct ad3552r_hs_platform_data *data; +}; + +static int ad3552r_qspi_update_reg_bits(struct ad3552r_hs_state *st, + u32 reg, u32 mask, u32 val, + size_t xfer_size) +{ + u32 rval; + int ret; + + ret = st->data->bus_reg_read(st->back, reg, &rval, xfer_size); + if (ret) + return ret; + + rval = (rval & ~mask) | val; + + return st->data->bus_reg_write(st->back, reg, rval, xfer_size); +} + +static int ad3552r_hs_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + int ret; + int ch = chan->channel; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + /* + * Using 4 lanes (QSPI), then using 2 as DDR mode is + * considered always on (considering buffering mode always). + */ + *val = DIV_ROUND_CLOSEST(st->data->bus_sample_data_clock_hz * + 4 * 2, chan->scan_type.realbits); + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_RAW: + ret = st->data->bus_reg_read(st->back, + AD3552R_REG_ADDR_CH_DAC_16B(chan->channel), + val, 2); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = st->ch_data[ch].scale_int; + *val2 = st->ch_data[ch].scale_dec; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = st->ch_data[ch].offset_int; + *val2 = st->ch_data[ch].offset_dec; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int ad3552r_hs_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + return st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_CH_DAC_16B(chan->channel), + val, 2); + } + unreachable(); + default: + return -EINVAL; + } +} + +static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + struct iio_backend_data_fmt fmt = { + .type = IIO_BACKEND_DATA_UNSIGNED + }; + int loop_len, val, ret; + + switch (*indio_dev->active_scan_mask) { + case AD3552R_CH0_ACTIVE: + st->single_channel = true; + loop_len = 2; + val = AD3552R_REG_ADDR_CH_DAC_16B(0); + break; + case AD3552R_CH1_ACTIVE: + st->single_channel = true; + loop_len = 2; + val = AD3552R_REG_ADDR_CH_DAC_16B(1); + break; + case AD3552R_CH0_ACTIVE | AD3552R_CH1_ACTIVE: + st->single_channel = false; + loop_len = 4; + val = AD3552R_REG_ADDR_CH_DAC_16B(1); + break; + default: + return -EINVAL; + } + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE, + loop_len, 1); + if (ret) + return ret; + + /* Inform DAC chip to switch into DDR mode */ + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + AD3552R_MASK_SPI_CONFIG_DDR, 1); + if (ret) + return ret; + + /* Inform DAC IP to go for DDR mode from now on */ + ret = iio_backend_ddr_enable(st->back); + if (ret) { + dev_err(st->dev, "could not set DDR mode, not streaming"); + goto exit_err; + } + + ret = iio_backend_data_transfer_addr(st->back, val); + if (ret) + goto exit_err; + + ret = iio_backend_data_format_set(st->back, 0, &fmt); + if (ret) + goto exit_err; + + ret = iio_backend_data_stream_enable(st->back); + if (ret) + goto exit_err; + + return 0; + +exit_err: + ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + 0, 1); + + iio_backend_ddr_disable(st->back); + + return ret; +} + +static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_backend_data_stream_disable(st->back); + if (ret) + return ret; + + /* Inform DAC to set in SDR mode */ + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + 0, 1); + if (ret) + return ret; + + ret = iio_backend_ddr_disable(st->back); + if (ret) + return ret; + + return 0; +} + +static inline int ad3552r_hs_set_output_range(struct ad3552r_hs_state *st, + int ch, unsigned int mode) +{ + int val; + + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH0_RANGE, mode); + else + val = FIELD_PREP(AD3552R_MASK_CH1_RANGE, mode); + + return ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch), + val, 1); +} + +static int ad3552r_hs_reset(struct ad3552r_hs_state *st) +{ + int ret; + + st->reset_gpio = devm_gpiod_get_optional(st->dev, + "reset", GPIOD_OUT_HIGH); + if (IS_ERR(st->reset_gpio)) + return PTR_ERR(st->reset_gpio); + + if (st->reset_gpio) { + fsleep(10); + gpiod_set_value_cansleep(st->reset_gpio, 0); + } else { + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_SOFTWARE_RESET, + AD3552R_MASK_SOFTWARE_RESET, 1); + if (ret) + return ret; + } + msleep(100); + + return 0; +} + +static int ad3552r_hs_scratch_pad_test(struct ad3552r_hs_state *st) +{ + int ret, val; + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + AD3552R_SCRATCH_PAD_TEST_VAL1, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + &val, 1); + if (ret) + return ret; + + if (val != AD3552R_SCRATCH_PAD_TEST_VAL1) + return dev_err_probe(st->dev, -EIO, + "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n", + AD3552R_SCRATCH_PAD_TEST_VAL1, val); + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + AD3552R_SCRATCH_PAD_TEST_VAL2, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + &val, 1); + if (ret) + return ret; + + if (val != AD3552R_SCRATCH_PAD_TEST_VAL2) + return dev_err_probe(st->dev, -EIO, + "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n", + AD3552R_SCRATCH_PAD_TEST_VAL2, val); + + return 0; +} + +static int ad3552r_hs_setup_custom_gain(struct ad3552r_hs_state *st, + int ch, u16 gain, u16 offset) +{ + int ret; + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_OFFSET(ch), + offset, 1); + if (ret) + return ret; + + return st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_GAIN(ch), + gain, 1); +} + +static int ad3552r_hs_setup(struct ad3552r_hs_state *st) +{ + u16 id; + u16 gain = 0, offset = 0; + u32 ch, val, range; + int ret; + + ret = ad3552r_hs_reset(st); + if (ret) + return ret; + + ret = iio_backend_ddr_disable(st->back); + if (ret) + return ret; + + ret = ad3552r_hs_scratch_pad_test(st); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L, + &val, 1); + if (ret) + return ret; + + id = val; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H, + &val, 1); + if (ret) + return ret; + + id |= val << 8; + if (id != st->model_data->chip_id) + dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n", + AD3552R_ID, id); + + ret = st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + 0, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_TRANSFER_REGISTER, + FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE, + AD3552R_QUAD_SPI) | + AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1); + if (ret) + return ret; + + ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL); + if (ret) + return ret; + + ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL); + if (ret) + return ret; + + ret = ad3552r_get_ref_voltage(st->dev, &val); + if (ret < 0) + return ret; + + val = ret; + + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + AD3552R_MASK_REFERENCE_VOLTAGE_SEL, + val, 1); + if (ret) + return ret; + + ret = ad3552r_get_drive_strength(st->dev, &val); + if (!ret) { + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SDO_DRIVE_STRENGTH, + val, 1); + if (ret) + return ret; + } + + device_for_each_child_node_scoped(st->dev, child) { + ret = fwnode_property_read_u32(child, "reg", &ch); + if (ret) + return dev_err_probe(st->dev, ret, + "reg property missing\n"); + + ret = ad3552r_get_output_range(st->dev, st->model_data, child, + &range); + if (ret && ret != -ENOENT) + return ret; + if (ret == -ENOENT) { + ret = ad3552r_get_custom_gain(st->dev, child, + &st->ch_data[ch].p, + &st->ch_data[ch].n, + &st->ch_data[ch].rfb, + &st->ch_data[ch].gain_offset); + if (ret) + return ret; + + gain = ad3552r_calc_custom_gain(st->ch_data[ch].p, + st->ch_data[ch].n, + st->ch_data[ch].gain_offset); + offset = abs(st->ch_data[ch].gain_offset); + + st->ch_data[ch].range_override = 1; + + ret = ad3552r_hs_setup_custom_gain(st, ch, gain, + offset); + if (ret) + return ret; + } else { + st->ch_data[ch].range = range; + + ret = ad3552r_hs_set_output_range(st, ch, range); + if (ret) + return ret; + } + + ad3552r_calc_gain_and_offset(&st->ch_data[ch], st->model_data); + } + + return 0; +} + +static const struct iio_buffer_setup_ops ad3552r_hs_buffer_setup_ops = { + .postenable = ad3552r_hs_buffer_postenable, + .predisable = ad3552r_hs_buffer_predisable, +}; + +#define AD3552R_CHANNEL(ch) { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .output = 1, \ + .indexed = 1, \ + .channel = (ch), \ + .scan_index = (ch), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + } \ +} + +static const struct iio_chan_spec ad3552r_hs_channels[] = { + AD3552R_CHANNEL(0), + AD3552R_CHANNEL(1), +}; + +static const struct iio_info ad3552r_hs_info = { + .read_raw = &ad3552r_hs_read_raw, + .write_raw = &ad3552r_hs_write_raw, +}; + +static int ad3552r_hs_probe(struct platform_device *pdev) +{ + struct ad3552r_hs_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->dev = &pdev->dev; + + st->data = dev_get_platdata(st->dev); + if (!st->data) + return dev_err_probe(st->dev, -ENODEV, "No platform data !"); + + st->back = devm_iio_backend_get(&pdev->dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + ret = devm_iio_backend_enable(&pdev->dev, st->back); + if (ret) + return ret; + + st->model_data = device_get_match_data(&pdev->dev); + if (!st->model_data) + return -ENODEV; + + indio_dev->name = "ad3552r"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->setup_ops = &ad3552r_hs_buffer_setup_ops; + indio_dev->channels = ad3552r_hs_channels; + indio_dev->num_channels = ARRAY_SIZE(ad3552r_hs_channels); + indio_dev->info = &ad3552r_hs_info; + + ret = devm_iio_backend_request_buffer(&pdev->dev, st->back, indio_dev); + if (ret) + return ret; + + ret = ad3552r_hs_setup(st); + if (ret) + return ret; + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct ad3552r_model_data ad3552r_model_data = { + .model_name = "ad3552r", + .chip_id = AD3552R_ID, + .num_hw_channels = 2, + .ranges_table = ad3552r_ch_ranges, + .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges), +}; + +static const struct of_device_id ad3552r_hs_of_id[] = { + { .compatible = "adi,ad3552r", .data = &ad3552r_model_data }, + { } +}; +MODULE_DEVICE_TABLE(of, ad3552r_hs_of_id); + +static struct platform_driver ad3552r_hs_driver = { + .driver = { + .name = "ad3552r-hs", + .of_match_table = ad3552r_hs_of_id, + }, + .probe = ad3552r_hs_probe, +}; +module_platform_driver(ad3552r_hs_driver); + +MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>"); +MODULE_AUTHOR("Angelo Dureghello <adueghello@baylibre.com>"); +MODULE_DESCRIPTION("AD3552R Driver - High Speed version"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS(IIO_AD3552R); diff --git a/drivers/iio/dac/ad3552r-hs.h b/drivers/iio/dac/ad3552r-hs.h new file mode 100644 index 000000000000..724261d38dea --- /dev/null +++ b/drivers/iio/dac/ad3552r-hs.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Analog Devices Inc. + * Copyright (c) 2024 Baylibre, SAS + */ +#ifndef __LINUX_PLATFORM_DATA_AD3552R_HS_H__ +#define __LINUX_PLATFORM_DATA_AD3552R_HS_H__ + +struct iio_backend; + +struct ad3552r_hs_platform_data { + int (*bus_reg_read)(struct iio_backend *back, u32 reg, u32 *val, + size_t data_size); + int (*bus_reg_write)(struct iio_backend *back, u32 reg, u32 val, + size_t data_size); + u32 bus_sample_data_clock_hz; +}; + +#endif /* __LINUX_PLATFORM_DATA_AD3552R_HS_H__ */ diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index 7d61b2fe6624..92688d958f4f 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -6,271 +6,15 @@ * Copyright 2021 Analog Devices Inc. */ #include <linux/unaligned.h> +#include <linux/bitfield.h> #include <linux/device.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/iopoll.h> #include <linux/kernel.h> -#include <linux/regulator/consumer.h> #include <linux/spi/spi.h> -/* Register addresses */ -/* Primary address space */ -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00 -#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0)) -#define AD3552R_MASK_ADDR_ASCENSION BIT(5) -#define AD3552R_MASK_SDO_ACTIVE BIT(4) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01 -#define AD3552R_MASK_SINGLE_INST BIT(7) -#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3) -#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02 -#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n)) -#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2) -#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0) -#define AD3552R_REG_ADDR_CHIP_TYPE 0x03 -#define AD3552R_MASK_CLASS GENMASK(7, 0) -#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04 -#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05 -#define AD3552R_REG_ADDR_CHIP_GRADE 0x06 -#define AD3552R_MASK_GRADE GENMASK(7, 4) -#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0) -#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A -#define AD3552R_REG_ADDR_SPI_REVISION 0x0B -#define AD3552R_REG_ADDR_VENDOR_L 0x0C -#define AD3552R_REG_ADDR_VENDOR_H 0x0D -#define AD3552R_REG_ADDR_STREAM_MODE 0x0E -#define AD3552R_MASK_LENGTH GENMASK(7, 0) -#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F -#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6) -#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10 -#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\ - GENMASK(1, 0)) -#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5) -#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11 -#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7) -#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5) -#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3) -#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2) -#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1) -#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14 -#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6) -#define AD3552R_MASK_MEM_CRC_EN BIT(4) -#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2) -#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1) -#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0) -#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15 -#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6) -#define AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN BIT(5) -#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3) -#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2) -#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0) -#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16 -#define AD3552R_MASK_REF_RANGE_ALARM BIT(6) -#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5) -#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4) -#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3) -#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2) -#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1) -#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0) -#define AD3552R_REG_ADDR_ERR_STATUS 0x17 -#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6) -#define AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5) -#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4) -#define AD3552R_MASK_RESET_STATUS BIT(0) -#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18 -#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch)) -#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch) -#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19 -#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? GENMASK(7, 4) :\ - GENMASK(3, 0)) -#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2) -#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0) -#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2) -#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7) -#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5) -#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3) -#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2) -#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(0) -/* - * Secondary region - * For multibyte registers specify the highest address because the access is - * done in descending order - */ -#define AD3552R_SECONDARY_REGION_START 0x28 -#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28 -#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - ch) * 2) -#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E -#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F -#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31 -#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32 -#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - ch) * 2) -/* 3 bytes registers */ -#define AD3552R_REG_START_24B 0x37 -#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37 -#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - ch) * 3) -#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40 -#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41 -#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44 -#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45 -#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3) - -/* Useful defines */ -#define AD3552R_MAX_CH 2 -#define AD3552R_MASK_CH(ch) BIT(ch) -#define AD3552R_MASK_ALL_CH GENMASK(1, 0) -#define AD3552R_MAX_REG_SIZE 3 -#define AD3552R_READ_BIT BIT(7) -#define AD3552R_ADDR_MASK GENMASK(6, 0) -#define AD3552R_MASK_DAC_12B 0xFFF0 -#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8 -#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34 -#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2 -#define AD3552R_GAIN_SCALE 1000 -#define AD3552R_LDAC_PULSE_US 100 - -enum ad3552r_ch_vref_select { - /* Internal source with Vref I/O floating */ - AD3552R_INTERNAL_VREF_PIN_FLOATING, - /* Internal source with Vref I/O at 2.5V */ - AD3552R_INTERNAL_VREF_PIN_2P5V, - /* External source with Vref I/O as input */ - AD3552R_EXTERNAL_VREF_PIN_INPUT -}; - -enum ad3552r_id { - AD3541R_ID = 0x400b, - AD3542R_ID = 0x4009, - AD3551R_ID = 0x400a, - AD3552R_ID = 0x4008, -}; - -enum ad3552r_ch_output_range { - /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ - AD3552R_CH_OUTPUT_RANGE_0__2P5V, - /* Range from 0 V to 5 V. Requires Rfb1x connection */ - AD3552R_CH_OUTPUT_RANGE_0__5V, - /* Range from 0 V to 10 V. Requires Rfb2x connection */ - AD3552R_CH_OUTPUT_RANGE_0__10V, - /* Range from -5 V to 5 V. Requires Rfb2x connection */ - AD3552R_CH_OUTPUT_RANGE_NEG_5__5V, - /* Range from -10 V to 10 V. Requires Rfb4x connection */ - AD3552R_CH_OUTPUT_RANGE_NEG_10__10V, -}; - -static const s32 ad3552r_ch_ranges[][2] = { - [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, - [AD3552R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, - [AD3552R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, - [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000}, - [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = {-10000, 10000} -}; - -enum ad3542r_ch_output_range { - /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__2P5V, - /* Range from 0 V to 3 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__3V, - /* Range from 0 V to 5 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__5V, - /* Range from 0 V to 10 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_0__10V, - /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, - /* Range from -5 V to 5 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, -}; - -static const s32 ad3542r_ch_ranges[][2] = { - [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, - [AD3542R_CH_OUTPUT_RANGE_0__3V] = {0, 3000}, - [AD3542R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, - [AD3542R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, - [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = {-2500, 7500}, - [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000} -}; - -enum ad3552r_ch_gain_scaling { - /* Gain scaling of 1 */ - AD3552R_CH_GAIN_SCALING_1, - /* Gain scaling of 0.5 */ - AD3552R_CH_GAIN_SCALING_0_5, - /* Gain scaling of 0.25 */ - AD3552R_CH_GAIN_SCALING_0_25, - /* Gain scaling of 0.125 */ - AD3552R_CH_GAIN_SCALING_0_125, -}; - -/* Gain * AD3552R_GAIN_SCALE */ -static const s32 gains_scaling_table[] = { - [AD3552R_CH_GAIN_SCALING_1] = 1000, - [AD3552R_CH_GAIN_SCALING_0_5] = 500, - [AD3552R_CH_GAIN_SCALING_0_25] = 250, - [AD3552R_CH_GAIN_SCALING_0_125] = 125 -}; - -enum ad3552r_dev_attributes { - /* - Direct register values */ - /* From 0-3 */ - AD3552R_SDO_DRIVE_STRENGTH, - /* - * 0 -> Internal Vref, vref_io pin floating (default) - * 1 -> Internal Vref, vref_io driven by internal vref - * 2 or 3 -> External Vref - */ - AD3552R_VREF_SELECT, - /* Read registers in ascending order if set. Else descending */ - AD3552R_ADDR_ASCENSION, -}; - -enum ad3552r_ch_attributes { - /* DAC powerdown */ - AD3552R_CH_DAC_POWERDOWN, - /* DAC amplifier powerdown */ - AD3552R_CH_AMPLIFIER_POWERDOWN, - /* Select the output range. Select from enum ad3552r_ch_output_range */ - AD3552R_CH_OUTPUT_RANGE_SEL, - /* - * Over-rider the range selector in order to manually set the output - * voltage range - */ - AD3552R_CH_RANGE_OVERRIDE, - /* Manually set the offset voltage */ - AD3552R_CH_GAIN_OFFSET, - /* Sets the polarity of the offset. */ - AD3552R_CH_GAIN_OFFSET_POLARITY, - /* PDAC gain scaling */ - AD3552R_CH_GAIN_SCALING_P, - /* NDAC gain scaling */ - AD3552R_CH_GAIN_SCALING_N, - /* Rfb value */ - AD3552R_CH_RFB, - /* Channel select. When set allow Input -> DAC and Mask -> DAC */ - AD3552R_CH_SELECT, -}; - -struct ad3552r_ch_data { - s32 scale_int; - s32 scale_dec; - s32 offset_int; - s32 offset_dec; - s16 gain_offset; - u16 rfb; - u8 n; - u8 p; - u8 range; - bool range_override; -}; - -struct ad3552r_model_data { - const char *model_name; - enum ad3552r_id chip_id; - unsigned int num_hw_channels; - const s32 (*ranges_table)[2]; - int num_ranges; - bool requires_output_range; -}; +#include "ad3552r.h" struct ad3552r_desc { const struct ad3552r_model_data *model_data; @@ -285,45 +29,6 @@ struct ad3552r_desc { unsigned int num_ch; }; -static const u16 addr_mask_map[][2] = { - [AD3552R_ADDR_ASCENSION] = { - AD3552R_REG_ADDR_INTERFACE_CONFIG_A, - AD3552R_MASK_ADDR_ASCENSION - }, - [AD3552R_SDO_DRIVE_STRENGTH] = { - AD3552R_REG_ADDR_INTERFACE_CONFIG_D, - AD3552R_MASK_SDO_DRIVE_STRENGTH - }, - [AD3552R_VREF_SELECT] = { - AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, - AD3552R_MASK_REFERENCE_VOLTAGE_SEL - }, -}; - -/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */ -static const u16 addr_mask_map_ch[][3] = { - [AD3552R_CH_DAC_POWERDOWN] = { - AD3552R_REG_ADDR_POWERDOWN_CONFIG, - AD3552R_MASK_CH_DAC_POWERDOWN(0), - AD3552R_MASK_CH_DAC_POWERDOWN(1) - }, - [AD3552R_CH_AMPLIFIER_POWERDOWN] = { - AD3552R_REG_ADDR_POWERDOWN_CONFIG, - AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), - AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1) - }, - [AD3552R_CH_OUTPUT_RANGE_SEL] = { - AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, - AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), - AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1) - }, - [AD3552R_CH_SELECT] = { - AD3552R_REG_ADDR_CH_SELECT_16B, - AD3552R_MASK_CH(0), - AD3552R_MASK_CH(1) - } -}; - static u8 _ad3552r_reg_len(u8 addr) { switch (addr) { @@ -399,11 +104,6 @@ static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val) return 0; } -static u16 ad3552r_field_prep(u16 val, u16 mask) -{ - return (val << __ffs(mask)) & mask; -} - /* Update field of a register, shift val if needed */ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask, u16 val) @@ -416,21 +116,11 @@ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask, return ret; reg &= ~mask; - reg |= ad3552r_field_prep(val, mask); + reg |= val; return ad3552r_write_reg(dac, addr, reg); } -static int ad3552r_set_ch_value(struct ad3552r_desc *dac, - enum ad3552r_ch_attributes attr, - u8 ch, - u16 val) -{ - /* Update register related to attributes in chip */ - return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0], - addr_mask_map_ch[attr][ch + 1], val); -} - #define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \ .type = IIO_VOLTAGE, \ .output = true, \ @@ -510,8 +200,14 @@ static int ad3552r_write_raw(struct iio_dev *indio_dev, val); break; case IIO_CHAN_INFO_ENABLE: - err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN, - chan->channel, !val); + if (chan->channel == 0) + val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(0), !val); + else + val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(1), !val); + + err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_DAC_POWERDOWN(chan->channel), + val); break; default: err = -EINVAL; @@ -715,83 +411,9 @@ static int ad3552r_reset(struct ad3552r_desc *dac) } return ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_ADDR_ASCENSION][0], - addr_mask_map[AD3552R_ADDR_ASCENSION][1], - val); -} - -static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min, - s32 *v_max) -{ - s64 vref, tmp, common, offset, gn, gp; - /* - * From datasheet formula (In Volts): - * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03] - * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03] - * Calculus are converted to milivolts - */ - vref = 2500; - /* 2.5 * 1.03 * 1000 (To mV) */ - common = 2575 * dac->ch_data[i].rfb; - offset = dac->ch_data[i].gain_offset; - - gn = gains_scaling_table[dac->ch_data[i].n]; - tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common; - tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); - *v_max = vref + tmp; - - gp = gains_scaling_table[dac->ch_data[i].p]; - tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common; - tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); - *v_min = vref - tmp; -} - -static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch) -{ - s32 idx, v_max, v_min, span, rem; - s64 tmp; - - if (dac->ch_data[ch].range_override) { - ad3552r_get_custom_range(dac, ch, &v_min, &v_max); - } else { - /* Normal range */ - idx = dac->ch_data[ch].range; - v_min = dac->model_data->ranges_table[idx][0]; - v_max = dac->model_data->ranges_table[idx][1]; - } - - /* - * From datasheet formula: - * Vout = Span * (D / 65536) + Vmin - * Converted to scale and offset: - * Scale = Span / 65536 - * Offset = 65536 * Vmin / Span - * - * Reminders are in micros in order to be printed as - * IIO_VAL_INT_PLUS_MICRO - */ - span = v_max - v_min; - dac->ch_data[ch].scale_int = div_s64_rem(span, 65536, &rem); - /* Do operations in microvolts */ - dac->ch_data[ch].scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, - 65536); - - dac->ch_data[ch].offset_int = div_s64_rem(v_min * 65536, span, &rem); - tmp = (s64)rem * 1000000; - dac->ch_data[ch].offset_dec = div_s64(tmp, span); -} - -static int ad3552r_find_range(const struct ad3552r_model_data *model_data, - s32 *vals) -{ - int i; - - for (i = 0; i < model_data->num_ranges; i++) - if (vals[0] == model_data->ranges_table[i][0] * 1000 && - vals[1] == model_data->ranges_table[i][1] * 1000) - return i; - - return -EINVAL; + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_ADDR_ASCENSION, + FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val)); } static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, @@ -799,57 +421,30 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, u32 ch) { struct device *dev = &dac->spi->dev; - u32 val; int err; u8 addr; - u16 reg = 0, offset; - - struct fwnode_handle *gain_child __free(fwnode_handle) - = fwnode_get_named_child_node(child, - "custom-output-range-config"); - if (!gain_child) - return dev_err_probe(dev, -EINVAL, - "mandatory custom-output-range-config property missing\n"); - - dac->ch_data[ch].range_override = 1; - reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE); - - err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-scaling-p property missing\n"); - reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P); - dac->ch_data[ch].p = val; - - err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-scaling-n property missing\n"); - reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N); - dac->ch_data[ch].n = val; - - err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,rfb-ohms property missing\n"); - dac->ch_data[ch].rfb = val; + u16 reg; - err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); + err = ad3552r_get_custom_gain(dev, child, + &dac->ch_data[ch].p, + &dac->ch_data[ch].n, + &dac->ch_data[ch].rfb, + &dac->ch_data[ch].gain_offset); if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-offset property missing\n"); - dac->ch_data[ch].gain_offset = val; + return err; - offset = abs((s32)val); - reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8); + dac->ch_data[ch].range_override = 1; - reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY); addr = AD3552R_REG_ADDR_CH_GAIN(ch); err = ad3552r_write_reg(dac, addr, - offset & AD3552R_MASK_CH_OFFSET_BITS_0_7); + abs((s32)dac->ch_data[ch].gain_offset) & + AD3552R_MASK_CH_OFFSET_BITS_0_7); if (err) return dev_err_probe(dev, err, "Error writing register\n"); + reg = ad3552r_calc_custom_gain(dac->ch_data[ch].p, dac->ch_data[ch].n, + dac->ch_data[ch].gain_offset); + err = ad3552r_write_reg(dac, addr, reg); if (err) return dev_err_probe(dev, err, "Error writing register\n"); @@ -860,49 +455,31 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, static int ad3552r_configure_device(struct ad3552r_desc *dac) { struct device *dev = &dac->spi->dev; - int err, cnt = 0, voltage, delta = 100000; - u32 vals[2], val, ch; + int err, cnt = 0; + u32 val, ch; dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH); if (IS_ERR(dac->gpio_ldac)) return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac), "Error getting gpio ldac"); - voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); - if (voltage < 0 && voltage != -ENODEV) - return dev_err_probe(dev, voltage, "Error getting vref voltage\n"); - - if (voltage == -ENODEV) { - if (device_property_read_bool(dev, "adi,vref-out-en")) - val = AD3552R_INTERNAL_VREF_PIN_2P5V; - else - val = AD3552R_INTERNAL_VREF_PIN_FLOATING; - } else { - if (voltage > 2500000 + delta || voltage < 2500000 - delta) { - dev_warn(dev, "vref-supply must be 2.5V"); - return -EINVAL; - } - val = AD3552R_EXTERNAL_VREF_PIN_INPUT; - } + err = ad3552r_get_ref_voltage(dev, &val); + if (err < 0) + return err; err = ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_VREF_SELECT][0], - addr_mask_map[AD3552R_VREF_SELECT][1], - val); + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + AD3552R_MASK_REFERENCE_VOLTAGE_SEL, + FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val)); if (err) return err; - err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val); + err = ad3552r_get_drive_strength(dev, &val); if (!err) { - if (val > 3) { - dev_err(dev, "adi,sdo-drive-strength must be less than 4\n"); - return -EINVAL; - } - err = ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0], - addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1], - val); + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SDO_DRIVE_STRENGTH, + FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val)); if (err) return err; } @@ -923,24 +500,21 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) "reg must be less than %d\n", dac->model_data->num_hw_channels); - if (fwnode_property_present(child, "adi,output-range-microvolt")) { - err = fwnode_property_read_u32_array(child, - "adi,output-range-microvolt", - vals, - 2); - if (err) - return dev_err_probe(dev, err, - "adi,output-range-microvolt property could not be parsed\n"); - - err = ad3552r_find_range(dac->model_data, vals); - if (err < 0) - return dev_err_probe(dev, err, - "Invalid adi,output-range-microvolt value\n"); - - val = err; - err = ad3552r_set_ch_value(dac, - AD3552R_CH_OUTPUT_RANGE_SEL, - ch, val); + err = ad3552r_get_output_range(dev, dac->model_data, + child, &val); + if (err && err != -ENOENT) + return err; + + if (!err) { + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val); + else + val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), val); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch), + val); if (err) return err; @@ -955,10 +529,17 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return err; } - ad3552r_calc_gain_and_offset(dac, ch); + ad3552r_calc_gain_and_offset(&dac->ch_data[ch], dac->model_data); dac->enabled_ch |= BIT(ch); - err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1); + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH(0), 1); + else + val = FIELD_PREP(AD3552R_MASK_CH(1), 1); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_CH_SELECT_16B, + AD3552R_MASK_CH(ch), val); if (err < 0) return err; @@ -970,8 +551,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) /* Disable unused channels */ for_each_clear_bit(ch, &dac->enabled_ch, dac->model_data->num_hw_channels) { - err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN, - ch, 1); + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), 1); + else + val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1), 1); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch), + val); if (err) return err; } @@ -1140,3 +728,4 @@ module_spi_driver(ad3552r_driver); MODULE_AUTHOR("Mihail Chindris <mihail.chindris@analog.com>"); MODULE_DESCRIPTION("Analog Device AD3552R DAC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD3552R); diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h new file mode 100644 index 000000000000..fd5a3dfd1d1c --- /dev/null +++ b/drivers/iio/dac/ad3552r.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * AD3552R Digital <-> Analog converters common header + * + * Copyright 2021-2024 Analog Devices Inc. + * Author: Angelo Dureghello <adureghello@baylibre.com> + */ + +#ifndef __DRIVERS_IIO_DAC_AD3552R_H__ +#define __DRIVERS_IIO_DAC_AD3552R_H__ + +/* Register addresses */ +/* Primary address space */ +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00 +#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0)) +#define AD3552R_MASK_ADDR_ASCENSION BIT(5) +#define AD3552R_MASK_SDO_ACTIVE BIT(4) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01 +#define AD3552R_MASK_SINGLE_INST BIT(7) +#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3) +#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02 +#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n)) +#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2) +#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0) +#define AD3552R_REG_ADDR_CHIP_TYPE 0x03 +#define AD3552R_MASK_CLASS GENMASK(7, 0) +#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04 +#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05 +#define AD3552R_REG_ADDR_CHIP_GRADE 0x06 +#define AD3552R_MASK_GRADE GENMASK(7, 4) +#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0) +#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A +#define AD3552R_REG_ADDR_SPI_REVISION 0x0B +#define AD3552R_REG_ADDR_VENDOR_L 0x0C +#define AD3552R_REG_ADDR_VENDOR_H 0x0D +#define AD3552R_REG_ADDR_STREAM_MODE 0x0E +#define AD3552R_MASK_LENGTH GENMASK(7, 0) +#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F +#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6) +#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10 +#define AD3552R_MASK_CRC_ENABLE \ + (GENMASK(7, 6) | GENMASK(1, 0)) +#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5) +#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11 +#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7) +#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5) +#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14 +#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6) +#define AD3552R_MASK_MEM_CRC_EN BIT(4) +#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2) +#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1) +#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0) +#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15 +#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6) +#define AD3552R_MASK_SAMPLE_HOLD_DIFF_USER_EN BIT(5) +#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3) +#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2) +#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0) +#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16 +#define AD3552R_MASK_REF_RANGE_ALARM BIT(6) +#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4) +#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0) +#define AD3552R_REG_ADDR_ERR_STATUS 0x17 +#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6) +#define AD3552R_MASK_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4) +#define AD3552R_MASK_RESET_STATUS BIT(0) +#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18 +#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch)) +#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch) +#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19 +#define AD3552R_MASK_CH0_RANGE GENMASK(2, 0) +#define AD3552R_MASK_CH1_RANGE GENMASK(6, 4) +#define AD3552R_MASK_CH_OUTPUT_RANGE GENMASK(7, 0) +#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) \ + ((ch) ? GENMASK(7, 4) : GENMASK(3, 0)) +#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2) +#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0) +#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2) +#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7) +#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5) +#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3) +#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2) +#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(8) +/* + * Secondary region + * For multibyte registers specify the highest address because the access is + * done in descending order + */ +#define AD3552R_SECONDARY_REGION_START 0x28 +#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28 +#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - (ch)) * 2) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E +#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31 +#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32 +#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - (ch)) * 2) +/* 3 bytes registers */ +#define AD3552R_REG_START_24B 0x37 +#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37 +#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - (ch)) * 3) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40 +#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41 +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44 +#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45 +#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - (ch)) * 3) + +#define AD3552R_MAX_CH 2 +#define AD3552R_MASK_CH(ch) BIT(ch) +#define AD3552R_MASK_ALL_CH GENMASK(1, 0) +#define AD3552R_MAX_REG_SIZE 3 +#define AD3552R_READ_BIT BIT(7) +#define AD3552R_ADDR_MASK GENMASK(6, 0) +#define AD3552R_MASK_DAC_12B GENMASK(15, 4) +#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8 +#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34 +#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2 +#define AD3552R_GAIN_SCALE 1000 +#define AD3552R_LDAC_PULSE_US 100 + +#define AD3552R_CH0_ACTIVE BIT(0) +#define AD3552R_CH1_ACTIVE BIT(1) + +#define AD3552R_MAX_RANGES 5 +#define AD3542R_MAX_RANGES 6 +#define AD3552R_QUAD_SPI 2 + +extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2]; +extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2]; + +enum ad3552r_id { + AD3541R_ID = 0x400b, + AD3542R_ID = 0x4009, + AD3551R_ID = 0x400a, + AD3552R_ID = 0x4008, +}; + +struct ad3552r_model_data { + const char *model_name; + enum ad3552r_id chip_id; + unsigned int num_hw_channels; + const s32 (*ranges_table)[2]; + int num_ranges; + bool requires_output_range; +}; + +struct ad3552r_ch_data { + s32 scale_int; + s32 scale_dec; + s32 offset_int; + s32 offset_dec; + s16 gain_offset; + u16 rfb; + u8 n; + u8 p; + u8 range; + bool range_override; +}; + +enum ad3552r_ch_gain_scaling { + /* Gain scaling of 1 */ + AD3552R_CH_GAIN_SCALING_1, + /* Gain scaling of 0.5 */ + AD3552R_CH_GAIN_SCALING_0_5, + /* Gain scaling of 0.25 */ + AD3552R_CH_GAIN_SCALING_0_25, + /* Gain scaling of 0.125 */ + AD3552R_CH_GAIN_SCALING_0_125, +}; + +enum ad3552r_ch_vref_select { + /* Internal source with Vref I/O floating */ + AD3552R_INTERNAL_VREF_PIN_FLOATING, + /* Internal source with Vref I/O at 2.5V */ + AD3552R_INTERNAL_VREF_PIN_2P5V, + /* External source with Vref I/O as input */ + AD3552R_EXTERNAL_VREF_PIN_INPUT +}; + +enum ad3542r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 3 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__3V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_0__10V, + /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, +}; + +enum ad3552r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_0__10V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_5__5V, + /* Range from -10 V to 10 V. Requires Rfb4x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_10__10V, +}; + +int ad3552r_get_output_range(struct device *dev, + const struct ad3552r_model_data *model_info, + struct fwnode_handle *child, u32 *val); +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child, + u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs); +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs); +int ad3552r_get_ref_voltage(struct device *dev, u32 *val); +int ad3552r_get_drive_strength(struct device *dev, u32 *val); +void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data, + const struct ad3552r_model_data *model_data); + +#endif /* __DRIVERS_IIO_DAC_AD3552R_H__ */ diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 2e3e33f92bc0..392a1c7aee03 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -47,7 +47,6 @@ struct ad5380_chip_info { * struct ad5380_state - driver instance specific data * @regmap: regmap instance used by the device * @chip_info: chip model specific constants, available modes etc - * @vref_reg: vref supply regulator * @vref: actual reference voltage used in uA * @pwr_down: whether the chip is currently in power down mode * @lock: lock to protect the data buffer during regmap ops @@ -55,7 +54,6 @@ struct ad5380_chip_info { struct ad5380_state { struct regmap *regmap; const struct ad5380_chip_info *chip_info; - struct regulator *vref_reg; int vref; bool pwr_down; struct mutex lock; @@ -341,14 +339,14 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = { }, }; -static int ad5380_alloc_channels(struct iio_dev *indio_dev) +static int ad5380_alloc_channels(struct device *dev, struct iio_dev *indio_dev) { struct ad5380_state *st = iio_priv(indio_dev); struct iio_chan_spec *channels; unsigned int i; - channels = kcalloc(st->chip_info->num_channels, - sizeof(struct iio_chan_spec), GFP_KERNEL); + channels = devm_kcalloc(dev, st->chip_info->num_channels, + sizeof(struct iio_chan_spec), GFP_KERNEL); if (!channels) return -ENOMEM; @@ -379,7 +377,6 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, } st = iio_priv(indio_dev); - dev_set_drvdata(dev, indio_dev); st->chip_info = &ad5380_chip_info_tbl[type]; st->regmap = regmap; @@ -391,68 +388,32 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, mutex_init(&st->lock); - ret = ad5380_alloc_channels(indio_dev); - if (ret) { - dev_err(dev, "Failed to allocate channel spec: %d\n", ret); - return ret; - } + ret = ad5380_alloc_channels(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to allocate channel spec\n"); if (st->chip_info->int_vref == 2500) ctrl |= AD5380_CTRL_INT_VREF_2V5; - st->vref_reg = devm_regulator_get(dev, "vref"); - if (!IS_ERR(st->vref_reg)) { - ret = regulator_enable(st->vref_reg); - if (ret) { - dev_err(dev, "Failed to enable vref regulators: %d\n", - ret); - goto error_free_reg; - } - - ret = regulator_get_voltage(st->vref_reg); - if (ret < 0) - goto error_disable_reg; - - st->vref = ret / 1000; - } else { + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get vref voltage\n"); + if (ret == -ENODEV) { st->vref = st->chip_info->int_vref; ctrl |= AD5380_CTRL_INT_VREF_EN; + } else { + st->vref = ret / 1000; } ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl); - if (ret) { - dev_err(dev, "Failed to write to device: %d\n", ret); - goto error_disable_reg; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to write to device\n"); - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(dev, "Failed to register iio device: %d\n", ret); - goto error_disable_reg; - } + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to register iio device\n"); return 0; - -error_disable_reg: - if (!IS_ERR(st->vref_reg)) - regulator_disable(st->vref_reg); -error_free_reg: - kfree(indio_dev->channels); - - return ret; -} - -static void ad5380_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5380_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - kfree(indio_dev->channels); - - if (!IS_ERR(st->vref_reg)) - regulator_disable(st->vref_reg); } static bool ad5380_reg_false(struct device *dev, unsigned int reg) @@ -486,11 +447,6 @@ static int ad5380_spi_probe(struct spi_device *spi) return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name); } -static void ad5380_spi_remove(struct spi_device *spi) -{ - ad5380_remove(&spi->dev); -} - static const struct spi_device_id ad5380_spi_ids[] = { { "ad5380-3", ID_AD5380_3 }, { "ad5380-5", ID_AD5380_5 }, @@ -517,7 +473,6 @@ static struct spi_driver ad5380_spi_driver = { .name = "ad5380", }, .probe = ad5380_spi_probe, - .remove = ad5380_spi_remove, .id_table = ad5380_spi_ids, }; @@ -559,11 +514,6 @@ static int ad5380_i2c_probe(struct i2c_client *i2c) return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name); } -static void ad5380_i2c_remove(struct i2c_client *i2c) -{ - ad5380_remove(&i2c->dev); -} - static const struct i2c_device_id ad5380_i2c_ids[] = { { "ad5380-3", ID_AD5380_3 }, { "ad5380-5", ID_AD5380_5 }, @@ -590,7 +540,6 @@ static struct i2c_driver ad5380_i2c_driver = { .name = "ad5380", }, .probe = ad5380_i2c_probe, - .remove = ad5380_i2c_remove, .id_table = ad5380_i2c_ids, }; diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 7644acfd879e..1462ee640b16 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -384,7 +384,7 @@ static int ad5421_write_raw(struct iio_dev *indio_dev, static int ad5421_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 ad5421_state *st = iio_priv(indio_dev); unsigned int mask; diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 708629efc157..6ad99f97eed5 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -32,7 +32,6 @@ * struct ad5446_state - driver instance specific data * @dev: this device * @chip_info: chip model specific constants, available modes etc - * @reg: supply regulator * @vref_mv: actual reference voltage used * @cached_val: store/retrieve values during power down * @pwr_down_mode: power down mode (1k, 100k or tristate) @@ -43,7 +42,6 @@ struct ad5446_state { struct device *dev; const struct ad5446_chip_info *chip_info; - struct regulator *reg; unsigned short vref_mv; unsigned cached_val; unsigned pwr_down_mode; @@ -226,32 +224,15 @@ static int ad5446_probe(struct device *dev, const char *name, { struct ad5446_state *st; struct iio_dev *indio_dev; - struct regulator *reg; - int ret, voltage_uv = 0; - - reg = devm_regulator_get(dev, "vcc"); - if (!IS_ERR(reg)) { - ret = regulator_enable(reg); - if (ret) - return ret; - - ret = regulator_get_voltage(reg); - if (ret < 0) - goto error_disable_reg; - - voltage_uv = ret; - } + int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_disable_reg; - } + if (!indio_dev) + return -ENOMEM; + st = iio_priv(indio_dev); st->chip_info = chip_info; - dev_set_drvdata(dev, indio_dev); - st->reg = reg; st->dev = dev; indio_dev->name = name; @@ -264,33 +245,19 @@ static int ad5446_probe(struct device *dev, const char *name, st->pwr_down_mode = MODE_PWRDWN_1k; - if (st->chip_info->int_vref_mv) - st->vref_mv = st->chip_info->int_vref_mv; - else if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - dev_warn(dev, "reference voltage unspecified\n"); - - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg; - - return 0; - -error_disable_reg: - if (!IS_ERR(reg)) - regulator_disable(reg); - return ret; -} - -static void ad5446_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(indio_dev); + ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); + if (ret < 0 && ret != -ENODEV) + return ret; + if (ret == -ENODEV) { + if (chip_info->int_vref_mv) + st->vref_mv = chip_info->int_vref_mv; + else + dev_warn(dev, "reference voltage unspecified\n"); + } else { + st->vref_mv = ret / 1000; + } - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + return devm_iio_device_register(dev, indio_dev); } #if IS_ENABLED(CONFIG_SPI_MASTER) @@ -491,18 +458,12 @@ static int ad5446_spi_probe(struct spi_device *spi) &ad5446_spi_chip_info[id->driver_data]); } -static void ad5446_spi_remove(struct spi_device *spi) -{ - ad5446_remove(&spi->dev); -} - static struct spi_driver ad5446_spi_driver = { .driver = { .name = "ad5446", .of_match_table = ad5446_of_ids, }, .probe = ad5446_spi_probe, - .remove = ad5446_spi_remove, .id_table = ad5446_spi_ids, }; @@ -575,11 +536,6 @@ static int ad5446_i2c_probe(struct i2c_client *i2c) &ad5446_i2c_chip_info[id->driver_data]); } -static void ad5446_i2c_remove(struct i2c_client *i2c) -{ - ad5446_remove(&i2c->dev); -} - static const struct i2c_device_id ad5446_i2c_ids[] = { {"ad5301", ID_AD5602}, {"ad5311", ID_AD5612}, @@ -596,7 +552,6 @@ static struct i2c_driver ad5446_i2c_driver = { .name = "ad5446", }, .probe = ad5446_i2c_probe, - .remove = ad5446_i2c_remove, .id_table = ad5446_i2c_ids, }; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 305cd58cd257..ff0765c8af47 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -273,35 +273,26 @@ static int ad5504_probe(struct spi_device *spi) const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev); struct iio_dev *indio_dev; struct ad5504_state *st; - struct regulator *reg; - int ret, voltage_uv = 0; + int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; - reg = devm_regulator_get(&spi->dev, "vcc"); - if (!IS_ERR(reg)) { - ret = regulator_enable(reg); - if (ret) - return ret; - ret = regulator_get_voltage(reg); - if (ret < 0) - goto error_disable_reg; + st = iio_priv(indio_dev); - voltage_uv = ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); + if (ret < 0 && ret != -ENODEV) + return ret; + if (ret == -ENODEV) { + if (pdata->vref_mv) + st->vref_mv = pdata->vref_mv; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); + } else { + st->vref_mv = ret / 1000; } - spi_set_drvdata(spi, indio_dev); - st = iio_priv(indio_dev); - if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else if (pdata) - st->vref_mv = pdata->vref_mv; - else - dev_warn(&spi->dev, "reference voltage unspecified\n"); - - st->reg = reg; st->spi = spi; indio_dev->name = spi_get_device_id(st->spi)->name; indio_dev->info = &ad5504_info; @@ -320,31 +311,10 @@ static int ad5504_probe(struct spi_device *spi) spi_get_device_id(st->spi)->name, indio_dev); if (ret) - goto error_disable_reg; + return ret; } - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg; - - return 0; - -error_disable_reg: - if (!IS_ERR(reg)) - regulator_disable(reg); - - return ret; -} - -static void ad5504_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5504_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad5504_id[] = { @@ -359,7 +329,6 @@ static struct spi_driver ad5504_driver = { .name = "ad5504", }, .probe = ad5504_probe, - .remove = ad5504_remove, .id_table = ad5504_id, }; module_spi_driver(ad5504_driver); diff --git a/drivers/iio/dac/ad5624r.h b/drivers/iio/dac/ad5624r.h index 13964f3a22a4..14a439b06eb6 100644 --- a/drivers/iio/dac/ad5624r.h +++ b/drivers/iio/dac/ad5624r.h @@ -54,7 +54,6 @@ struct ad5624r_chip_info { struct ad5624r_state { struct spi_device *us; const struct ad5624r_chip_info *chip_info; - struct regulator *reg; unsigned short vref_mv; unsigned pwr_down_mask; unsigned pwr_down_mode; diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 9304d0499bae..2fd38ac8f698 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -223,50 +223,26 @@ static int ad5624r_probe(struct spi_device *spi) { struct ad5624r_state *st; struct iio_dev *indio_dev; - int ret, voltage_uv = 0; + bool external_vref; + int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - goto error_disable_reg; - - voltage_uv = ret; - } else { - if (PTR_ERR(st->reg) != -ENODEV) - return PTR_ERR(st->reg); + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret == -ENODEV) /* Backwards compatibility. This naming is not correct */ - st->reg = devm_regulator_get_optional(&spi->dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - goto error_disable_reg; - - voltage_uv = ret; - } - } + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); + if (ret < 0 && ret != -ENODEV) + return ret; + + external_vref = ret != -ENODEV; + st->vref_mv = external_vref ? ret / 1000 : st->chip_info->int_vref_mv; - spi_set_drvdata(spi, indio_dev); st->chip_info = &ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - st->vref_mv = st->chip_info->int_vref_mv; - st->us = spi; indio_dev->name = spi_get_device_id(spi)->name; @@ -276,31 +252,11 @@ static int ad5624r_probe(struct spi_device *spi) indio_dev->num_channels = AD5624R_DAC_CHANNELS; ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, - !!voltage_uv, 16); - if (ret) - goto error_disable_reg; - - ret = iio_device_register(indio_dev); + external_vref, 16); if (ret) - goto error_disable_reg; - - return 0; - -error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - - return ret; -} - -static void ad5624r_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5624r_state *st = iio_priv(indio_dev); + return ret; - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad5624r_id[] = { @@ -319,7 +275,6 @@ static struct spi_driver ad5624r_driver = { .name = "ad5624r", }, .probe = ad5624r_probe, - .remove = ad5624r_remove, .id_table = ad5624r_id, }; module_spi_driver(ad5624r_driver); diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c index 6aa1a068adb0..0aa5ba7f4654 100644 --- a/drivers/iio/dac/ad5761.c +++ b/drivers/iio/dac/ad5761.c @@ -53,7 +53,6 @@ enum ad5761_supported_device_ids { /** * struct ad5761_state - driver instance specific data * @spi: spi_device - * @vref_reg: reference voltage regulator * @use_intref: true when the internal voltage reference is used * @vref: actual voltage reference in mVolts * @range: output range mode used @@ -62,7 +61,6 @@ enum ad5761_supported_device_ids { */ struct ad5761_state { struct spi_device *spi; - struct regulator *vref_reg; struct mutex lock; bool use_intref; @@ -287,63 +285,6 @@ static const struct ad5761_chip_info ad5761_chip_infos[] = { }, }; -static int ad5761_get_vref(struct ad5761_state *st, - const struct ad5761_chip_info *chip_info) -{ - int ret; - - st->vref_reg = devm_regulator_get_optional(&st->spi->dev, "vref"); - if (PTR_ERR(st->vref_reg) == -ENODEV) { - /* Use Internal regulator */ - if (!chip_info->int_vref) { - dev_err(&st->spi->dev, - "Voltage reference not found\n"); - return -EIO; - } - - st->use_intref = true; - st->vref = chip_info->int_vref; - return 0; - } - - if (IS_ERR(st->vref_reg)) { - dev_err(&st->spi->dev, - "Error getting voltage reference regulator\n"); - return PTR_ERR(st->vref_reg); - } - - ret = regulator_enable(st->vref_reg); - if (ret) { - dev_err(&st->spi->dev, - "Failed to enable voltage reference\n"); - return ret; - } - - ret = regulator_get_voltage(st->vref_reg); - if (ret < 0) { - dev_err(&st->spi->dev, - "Failed to get voltage reference value\n"); - goto disable_regulator_vref; - } - - if (ret < 2000000 || ret > 3000000) { - dev_warn(&st->spi->dev, - "Invalid external voltage ref. value %d uV\n", ret); - ret = -EIO; - goto disable_regulator_vref; - } - - st->vref = ret / 1000; - st->use_intref = false; - - return 0; - -disable_regulator_vref: - regulator_disable(st->vref_reg); - st->vref_reg = NULL; - return ret; -} - static int ad5761_probe(struct spi_device *spi) { struct iio_dev *iio_dev; @@ -361,11 +302,28 @@ static int ad5761_probe(struct spi_device *spi) st = iio_priv(iio_dev); st->spi = spi; - spi_set_drvdata(spi, iio_dev); - ret = ad5761_get_vref(st, chip_info); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(&spi->dev, ret, + "Failed to get voltage reference value\n"); + if (ret == -ENODEV) { + /* Use Internal regulator */ + if (!chip_info->int_vref) + return dev_err_probe(&spi->dev, -EIO, + "Voltage reference not found\n"); + + st->use_intref = true; + st->vref = chip_info->int_vref; + } else { + if (ret < 2000000 || ret > 3000000) + return dev_err_probe(&spi->dev, -EIO, + "Invalid external voltage ref. value %d uV\n", + ret); + + st->use_intref = false; + st->vref = ret / 1000; + } if (pdata) voltage_range = pdata->voltage_range; @@ -374,35 +332,15 @@ static int ad5761_probe(struct spi_device *spi) ret = ad5761_spi_set_range(st, voltage_range); if (ret) - goto disable_regulator_err; + return ret; iio_dev->info = &ad5761_info; iio_dev->modes = INDIO_DIRECT_MODE; iio_dev->channels = &chip_info->channel; iio_dev->num_channels = 1; iio_dev->name = spi_get_device_id(st->spi)->name; - ret = iio_device_register(iio_dev); - if (ret) - goto disable_regulator_err; - - return 0; - -disable_regulator_err: - if (!IS_ERR_OR_NULL(st->vref_reg)) - regulator_disable(st->vref_reg); - - return ret; -} - -static void ad5761_remove(struct spi_device *spi) -{ - struct iio_dev *iio_dev = spi_get_drvdata(spi); - struct ad5761_state *st = iio_priv(iio_dev); - - iio_device_unregister(iio_dev); - if (!IS_ERR_OR_NULL(st->vref_reg)) - regulator_disable(st->vref_reg); + return devm_iio_device_register(&spi->dev, iio_dev); } static const struct spi_device_id ad5761_id[] = { @@ -419,7 +357,6 @@ static struct spi_driver ad5761_driver = { .name = "ad5761", }, .probe = ad5761_probe, - .remove = ad5761_remove, .id_table = ad5761_id, }; module_spi_driver(ad5761_driver); diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index 7d7f5110d66a..25cf11d0471b 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -122,7 +122,6 @@ struct ad5770r_out_range { * struct ad5770r_state - driver instance specific data * @spi: spi_device * @regmap: regmap - * @vref_reg: fixed regulator for reference configuration * @gpio_reset: gpio descriptor * @output_mode: array contains channels output ranges * @vref: reference value @@ -134,7 +133,6 @@ struct ad5770r_out_range { struct ad5770r_state { struct spi_device *spi; struct regmap *regmap; - struct regulator *vref_reg; struct gpio_desc *gpio_reset; struct ad5770r_out_range output_mode[AD5770R_MAX_CHANNELS]; int vref; @@ -591,13 +589,6 @@ static int ad5770r_init(struct ad5770r_state *st) return ret; } -static void ad5770r_disable_regulator(void *data) -{ - struct ad5770r_state *st = data; - - regulator_disable(st->vref_reg); -} - static int ad5770r_probe(struct spi_device *spi) { struct ad5770r_state *st; @@ -622,34 +613,12 @@ static int ad5770r_probe(struct spi_device *spi) } st->regmap = regmap; - st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->vref_reg)) { - ret = regulator_enable(st->vref_reg); - if (ret) { - dev_err(&spi->dev, - "Failed to enable vref regulators: %d\n", ret); - return ret; - } + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(&spi->dev, ret, "Failed to get vref voltage\n"); - ret = devm_add_action_or_reset(&spi->dev, - ad5770r_disable_regulator, - st); - if (ret < 0) - return ret; - - ret = regulator_get_voltage(st->vref_reg); - if (ret < 0) - return ret; - - st->vref = ret / 1000; - } else { - if (PTR_ERR(st->vref_reg) == -ENODEV) { - st->vref = AD5770R_LOW_VREF_mV; - st->internal_ref = true; - } else { - return PTR_ERR(st->vref_reg); - } - } + st->internal_ref = ret == -ENODEV; + st->vref = st->internal_ref ? AD5770R_LOW_VREF_mV : ret / 1000; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad5770r_info; diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 553431bf0232..57374f78f6b8 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -9,6 +9,7 @@ #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/device.h> +#include <linux/delay.h> #include <linux/kernel.h> #include <linux/spi/spi.h> #include <linux/slab.h> @@ -61,11 +62,14 @@ /** * struct ad5791_chip_info - chip specific information + * @name: name of the dac chip + * @channel: channel specification * @get_lin_comp: function pointer to the device specific function */ - struct ad5791_chip_info { - int (*get_lin_comp) (unsigned int span); + const char *name; + const struct iio_chan_spec channel; + int (*get_lin_comp)(unsigned int span); }; /** @@ -73,6 +77,9 @@ struct ad5791_chip_info { * @spi: spi_device * @reg_vdd: positive supply regulator * @reg_vss: negative supply regulator + * @gpio_reset: reset gpio + * @gpio_clear: clear gpio + * @gpio_ldac: load dac gpio * @chip_info: chip model specific constants * @vref_mv: actual reference voltage used * @vref_neg_mv: voltage of the negative supply @@ -85,6 +92,9 @@ struct ad5791_state { struct spi_device *spi; struct regulator *reg_vdd; struct regulator *reg_vss; + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_clear; + struct gpio_desc *gpio_ldac; const struct ad5791_chip_info *chip_info; unsigned short vref_mv; unsigned int vref_neg_mv; @@ -98,13 +108,6 @@ struct ad5791_state { } data[3] __aligned(IIO_DMA_MINALIGN); }; -enum ad5791_supported_device_ids { - ID_AD5760, - ID_AD5780, - ID_AD5781, - ID_AD5791, -}; - static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val) { st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE | @@ -228,20 +231,6 @@ static int ad5780_get_lin_comp(unsigned int span) else return AD5780_LINCOMP_10_20; } -static const struct ad5791_chip_info ad5791_chip_info_tbl[] = { - [ID_AD5760] = { - .get_lin_comp = ad5780_get_lin_comp, - }, - [ID_AD5780] = { - .get_lin_comp = ad5780_get_lin_comp, - }, - [ID_AD5781] = { - .get_lin_comp = ad5791_get_lin_comp, - }, - [ID_AD5791] = { - .get_lin_comp = ad5791_get_lin_comp, - }, -}; static int ad5791_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -289,30 +278,34 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { { }, }; -#define AD5791_CHAN(bits, _shift) { \ - .type = IIO_VOLTAGE, \ - .output = 1, \ - .indexed = 1, \ - .address = AD5791_ADDR_DAC0, \ - .channel = 0, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .scan_type = { \ - .sign = 'u', \ - .realbits = (bits), \ - .storagebits = 24, \ - .shift = (_shift), \ - }, \ - .ext_info = ad5791_ext_info, \ +#define AD5791_DEFINE_CHIP_INFO(_name, bits, _shift, _lin_comp) \ +static const struct ad5791_chip_info _name##_chip_info = { \ + .name = #_name, \ + .get_lin_comp = &(_lin_comp), \ + .channel = { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .address = AD5791_ADDR_DAC0, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 24, \ + .shift = (_shift), \ + }, \ + .ext_info = ad5791_ext_info, \ + }, \ } -static const struct iio_chan_spec ad5791_channels[] = { - [ID_AD5760] = AD5791_CHAN(16, 4), - [ID_AD5780] = AD5791_CHAN(18, 2), - [ID_AD5781] = AD5791_CHAN(18, 2), - [ID_AD5791] = AD5791_CHAN(20, 0) -}; +AD5791_DEFINE_CHIP_INFO(ad5760, 16, 4, ad5780_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5780, 18, 2, ad5780_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5781, 18, 2, ad5791_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5790, 20, 0, ad5791_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5791, 20, 0, ad5791_get_lin_comp); static int ad5791_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -351,31 +344,21 @@ static int ad5791_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg_vdd = devm_regulator_get(&spi->dev, "vdd"); - if (!IS_ERR(st->reg_vdd)) { - ret = regulator_enable(st->reg_vdd); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg_vdd); - if (ret < 0) - goto error_disable_reg_pos; - - pos_voltage_uv = ret; - } - st->reg_vss = devm_regulator_get(&spi->dev, "vss"); - if (!IS_ERR(st->reg_vss)) { - ret = regulator_enable(st->reg_vss); - if (ret) - goto error_disable_reg_pos; + st->gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); - ret = regulator_get_voltage(st->reg_vss); - if (ret < 0) - goto error_disable_reg_neg; + st->gpio_clear = devm_gpiod_get_optional(&spi->dev, "clear", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_clear)) + return PTR_ERR(st->gpio_clear); - neg_voltage_uv = ret; - } + st->gpio_ldac = devm_gpiod_get_optional(&spi->dev, "ldac", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_ldac)) + return PTR_ERR(st->gpio_ldac); st->pwr_down = true; st->spi = spi; @@ -386,7 +369,17 @@ static int ad5791_probe(struct spi_device *spi) use_rbuf_gain2 = device_property_read_bool(&spi->dev, "adi,rbuf-gain2-en"); - if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) { + pos_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vdd"); + if (pos_voltage_uv < 0 && pos_voltage_uv != -ENODEV) + return dev_err_probe(&spi->dev, pos_voltage_uv, + "failed to get vdd voltage\n"); + + neg_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vss"); + if (neg_voltage_uv < 0 && neg_voltage_uv != -ENODEV) + return dev_err_probe(&spi->dev, neg_voltage_uv, + "failed to get vss voltage\n"); + + if (neg_voltage_uv >= 0 && pos_voltage_uv >= 0) { st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000; st->vref_neg_mv = neg_voltage_uv / 1000; } else if (pdata) { @@ -396,13 +389,18 @@ static int ad5791_probe(struct spi_device *spi) dev_warn(&spi->dev, "reference voltage unspecified\n"); } - ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); - if (ret) - goto error_disable_reg_neg; - - st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi) - ->driver_data]; + if (st->gpio_reset) { + fsleep(20); + gpiod_set_value_cansleep(st->gpio_reset, 0); + } else { + ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); + if (ret) + return dev_err_probe(&spi->dev, ret, "fail to reset\n"); + } + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return dev_err_probe(&spi->dev, -EINVAL, "no chip info\n"); st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv)) | (use_rbuf_gain2 ? 0 : AD5791_CTRL_RBUF) | @@ -411,59 +409,42 @@ static int ad5791_probe(struct spi_device *spi) ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); if (ret) - goto error_disable_reg_neg; + return dev_err_probe(&spi->dev, ret, "fail to write ctrl register\n"); - spi_set_drvdata(spi, indio_dev); indio_dev->info = &ad5791_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels - = &ad5791_channels[spi_get_device_id(spi)->driver_data]; + indio_dev->channels = &st->chip_info->channel; indio_dev->num_channels = 1; - indio_dev->name = spi_get_device_id(st->spi)->name; - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg_neg; - - return 0; - -error_disable_reg_neg: - if (!IS_ERR(st->reg_vss)) - regulator_disable(st->reg_vss); -error_disable_reg_pos: - if (!IS_ERR(st->reg_vdd)) - regulator_disable(st->reg_vdd); - return ret; + indio_dev->name = st->chip_info->name; + return devm_iio_device_register(&spi->dev, indio_dev); } -static void ad5791_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5791_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg_vdd)) - regulator_disable(st->reg_vdd); - - if (!IS_ERR(st->reg_vss)) - regulator_disable(st->reg_vss); -} +static const struct of_device_id ad5791_of_match[] = { + { .compatible = "adi,ad5760", .data = &ad5760_chip_info }, + { .compatible = "adi,ad5780", .data = &ad5780_chip_info }, + { .compatible = "adi,ad5781", .data = &ad5781_chip_info }, + { .compatible = "adi,ad5790", .data = &ad5790_chip_info }, + { .compatible = "adi,ad5791", .data = &ad5791_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5791_of_match); static const struct spi_device_id ad5791_id[] = { - {"ad5760", ID_AD5760}, - {"ad5780", ID_AD5780}, - {"ad5781", ID_AD5781}, - {"ad5790", ID_AD5791}, - {"ad5791", ID_AD5791}, - {} + { "ad5760", (kernel_ulong_t)&ad5760_chip_info }, + { "ad5780", (kernel_ulong_t)&ad5780_chip_info }, + { "ad5781", (kernel_ulong_t)&ad5781_chip_info }, + { "ad5790", (kernel_ulong_t)&ad5790_chip_info }, + { "ad5791", (kernel_ulong_t)&ad5791_chip_info }, + { } }; MODULE_DEVICE_TABLE(spi, ad5791_id); static struct spi_driver ad5791_driver = { .driver = { .name = "ad5791", + .of_match_table = ad5791_of_match, }, .probe = ad5791_probe, - .remove = ad5791_remove, .id_table = ad5791_id, }; module_spi_driver(ad5791_driver); diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c index dc8c76ba573d..f235394589df 100644 --- a/drivers/iio/dac/ad8460.c +++ b/drivers/iio/dac/ad8460.c @@ -573,7 +573,7 @@ static int ad8460_read_event_value(struct iio_dev *indio_dev, static int ad8460_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 val) + enum iio_event_direction dir, bool val) { struct ad8460_state *state = iio_priv(indio_dev); int fault; @@ -924,17 +924,24 @@ static int ad8460_probe(struct spi_device *spi) } static const struct of_device_id ad8460_of_match[] = { - { .compatible = "adi, ad8460" }, + { .compatible = "adi,ad8460" }, { } }; MODULE_DEVICE_TABLE(of, ad8460_of_match); +static const struct spi_device_id ad8460_spi_match[] = { + { .name = "ad8460" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad8460_spi_match); + static struct spi_driver ad8460_driver = { .driver = { .name = "ad8460", .of_match_table = ad8460_of_match, }, .probe = ad8460_probe, + .id_table = ad8460_spi_match, }; module_spi_driver(ad8460_driver); diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 04193a98616e..dd1919441b6d 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -29,6 +29,8 @@ #include <linux/iio/buffer.h> #include <linux/iio/iio.h> +#include "ad3552r-hs.h" + /* * Register definitions: * https://wiki.analog.com/resources/fpga/docs/axi_dac_ip#register_map @@ -46,9 +48,28 @@ #define AXI_DAC_CNTRL_1_REG 0x0044 #define AXI_DAC_CNTRL_1_SYNC BIT(0) #define AXI_DAC_CNTRL_2_REG 0x0048 +#define AXI_DAC_CNTRL_2_SDR_DDR_N BIT(16) +#define AXI_DAC_CNTRL_2_SYMB_8B BIT(14) #define ADI_DAC_CNTRL_2_R1_MODE BIT(5) +#define AXI_DAC_CNTRL_2_UNSIGNED_DATA BIT(4) +#define AXI_DAC_STATUS_1_REG 0x0054 +#define AXI_DAC_STATUS_2_REG 0x0058 #define AXI_DAC_DRP_STATUS_REG 0x0074 #define AXI_DAC_DRP_STATUS_DRP_LOCKED BIT(17) +#define AXI_DAC_CUSTOM_RD_REG 0x0080 +#define AXI_DAC_CUSTOM_WR_REG 0x0084 +#define AXI_DAC_CUSTOM_WR_DATA_8 GENMASK(23, 16) +#define AXI_DAC_CUSTOM_WR_DATA_16 GENMASK(23, 8) +#define AXI_DAC_UI_STATUS_REG 0x0088 +#define AXI_DAC_UI_STATUS_IF_BUSY BIT(4) +#define AXI_DAC_CUSTOM_CTRL_REG 0x008C +#define AXI_DAC_CUSTOM_CTRL_ADDRESS GENMASK(31, 24) +#define AXI_DAC_CUSTOM_CTRL_SYNCED_TRANSFER BIT(2) +#define AXI_DAC_CUSTOM_CTRL_STREAM BIT(1) +#define AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA BIT(0) + +#define AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE (AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA | \ + AXI_DAC_CUSTOM_CTRL_STREAM) /* DAC Channel controls */ #define AXI_DAC_CHAN_CNTRL_1_REG(c) (0x0400 + (c) * 0x40) @@ -63,12 +84,22 @@ #define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40) #define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0) +#define AXI_DAC_RD_ADDR(x) (BIT(7) | (x)) + /* 360 degrees in rad */ #define AXI_DAC_2_PI_MEGA 6283190 enum { AXI_DAC_DATA_INTERNAL_TONE, AXI_DAC_DATA_DMA = 2, + AXI_DAC_DATA_INTERNAL_RAMP_16BIT = 11, +}; + +struct axi_dac_info { + unsigned int version; + const struct iio_backend_info *backend_info; + bool has_dac_clk; + bool has_child_nodes; }; struct axi_dac_state { @@ -79,9 +110,11 @@ struct axi_dac_state { * data/variables. */ struct mutex lock; + const struct axi_dac_info *info; u64 dac_clk; u32 reg_config; bool int_tone; + int dac_clk_rate; }; static int axi_dac_enable(struct iio_backend *back) @@ -471,6 +504,11 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan, AXI_DAC_CHAN_CNTRL_7_REG(chan), AXI_DAC_CHAN_CNTRL_7_DATA_SEL, AXI_DAC_DATA_DMA); + case IIO_BACKEND_INTERNAL_RAMP_16BIT: + return regmap_update_bits(st->regmap, + AXI_DAC_CHAN_CNTRL_7_REG(chan), + AXI_DAC_CHAN_CNTRL_7_DATA_SEL, + AXI_DAC_DATA_INTERNAL_RAMP_16BIT); default: return -EINVAL; } @@ -528,6 +566,184 @@ static int axi_dac_reg_access(struct iio_backend *back, unsigned int reg, return regmap_write(st->regmap, reg, writeval); } +static int axi_dac_ddr_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SDR_DDR_N); +} + +static int axi_dac_ddr_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SDR_DDR_N); +} + +static int axi_dac_data_stream_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_set_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE); +} + +static int axi_dac_data_stream_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE); +} + +static int axi_dac_data_transfer_addr(struct iio_backend *back, u32 address) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + if (address > FIELD_MAX(AXI_DAC_CUSTOM_CTRL_ADDRESS)) + return -EINVAL; + + /* + * Sample register address, when the DAC is configured, or stream + * start address when the FSM is in stream state. + */ + return regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_ADDRESS, + FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, + address)); +} + +static int axi_dac_data_format_set(struct iio_backend *back, unsigned int ch, + const struct iio_backend_data_fmt *data) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (data->type) { + case IIO_BACKEND_DATA_UNSIGNED: + return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_UNSIGNED_DATA); + default: + return -EINVAL; + } +} + +static int __axi_dac_bus_reg_write(struct iio_backend *back, u32 reg, + u32 val, size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + int ret; + u32 ival; + + /* + * Both AXI_DAC_CNTRL_2_REG and AXI_DAC_CUSTOM_WR_REG need to know + * the data size. So keeping data size control here only, + * since data size is mandatory for the current transfer. + * DDR state handled separately by specific backend calls, + * generally all raw register writes are SDR. + */ + if (data_size == sizeof(u16)) + ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_16, val); + else + ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_8, val); + + ret = regmap_write(st->regmap, AXI_DAC_CUSTOM_WR_REG, ival); + if (ret) + return ret; + + if (data_size == sizeof(u8)) + ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SYMB_8B); + else + ret = regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SYMB_8B); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_ADDRESS, + FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, reg)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(st->regmap, + AXI_DAC_UI_STATUS_REG, ival, + FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0, + 10, 100 * KILO); + if (ret == -ETIMEDOUT) + dev_err(st->dev, "AXI read timeout\n"); + + /* Cleaning always AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA */ + return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA); +} + +static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg, + u32 val, size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + guard(mutex)(&st->lock); + return __axi_dac_bus_reg_write(back, reg, val, data_size); +} + +static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val, + size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + int ret; + + guard(mutex)(&st->lock); + + /* + * SPI, we write with read flag, then we read just at the AXI + * io address space to get data read. + */ + ret = __axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0, + data_size); + if (ret) + return ret; + + return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val); +} + +static void axi_dac_child_remove(void *data) +{ + platform_device_unregister(data); +} + +static int axi_dac_create_platform_device(struct axi_dac_state *st, + struct fwnode_handle *child) +{ + struct ad3552r_hs_platform_data pdata = { + .bus_reg_read = axi_dac_bus_reg_read, + .bus_reg_write = axi_dac_bus_reg_write, + .bus_sample_data_clock_hz = st->dac_clk_rate, + }; + struct platform_device_info pi = { + .parent = st->dev, + .name = fwnode_get_name(child), + .id = PLATFORM_DEVID_AUTO, + .fwnode = child, + .data = &pdata, + .size_data = sizeof(pdata), + }; + struct platform_device *pdev; + + pdev = platform_device_register_full(&pi); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return devm_add_action_or_reset(st->dev, axi_dac_child_remove, pdev); +} + static const struct iio_backend_ops axi_dac_generic_ops = { .enable = axi_dac_enable, .disable = axi_dac_disable, @@ -541,11 +757,30 @@ static const struct iio_backend_ops axi_dac_generic_ops = { .debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access), }; +static const struct iio_backend_ops axi_ad3552r_ops = { + .enable = axi_dac_enable, + .disable = axi_dac_disable, + .request_buffer = axi_dac_request_buffer, + .free_buffer = axi_dac_free_buffer, + .data_source_set = axi_dac_data_source_set, + .ddr_enable = axi_dac_ddr_enable, + .ddr_disable = axi_dac_ddr_disable, + .data_stream_enable = axi_dac_data_stream_enable, + .data_stream_disable = axi_dac_data_stream_disable, + .data_format_set = axi_dac_data_format_set, + .data_transfer_addr = axi_dac_data_transfer_addr, +}; + static const struct iio_backend_info axi_dac_generic = { .name = "axi-dac", .ops = &axi_dac_generic_ops, }; +static const struct iio_backend_info axi_ad3552r = { + .name = "axi-ad3552r", + .ops = &axi_ad3552r_ops, +}; + static const struct regmap_config axi_dac_regmap_config = { .val_bits = 32, .reg_bits = 32, @@ -555,7 +790,6 @@ static const struct regmap_config axi_dac_regmap_config = { static int axi_dac_probe(struct platform_device *pdev) { - const unsigned int *expected_ver; struct axi_dac_state *st; void __iomem *base; unsigned int ver; @@ -566,14 +800,29 @@ static int axi_dac_probe(struct platform_device *pdev) if (!st) return -ENOMEM; - expected_ver = device_get_match_data(&pdev->dev); - if (!expected_ver) + st->info = device_get_match_data(&pdev->dev); + if (!st->info) return -ENODEV; + clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk"); + if (IS_ERR(clk)) { + /* Backward compat., old fdt versions without clock-names. */ + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); + } - clk = devm_clk_get_enabled(&pdev->dev, NULL); - if (IS_ERR(clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(clk), - "failed to get clock\n"); + if (st->info->has_dac_clk) { + struct clk *dac_clk; + + dac_clk = devm_clk_get_enabled(&pdev->dev, "dac_clk"); + if (IS_ERR(dac_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dac_clk), + "failed to get dac_clk clock\n"); + + /* We only care about the streaming mode rate */ + st->dac_clk_rate = clk_get_rate(dac_clk) / 2; + } base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -598,12 +847,13 @@ static int axi_dac_probe(struct platform_device *pdev) if (ret) return ret; - if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) { + if (ADI_AXI_PCORE_VER_MAJOR(ver) != + ADI_AXI_PCORE_VER_MAJOR(st->info->version)) { dev_err(&pdev->dev, "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", - ADI_AXI_PCORE_VER_MAJOR(*expected_ver), - ADI_AXI_PCORE_VER_MINOR(*expected_ver), - ADI_AXI_PCORE_VER_PATCH(*expected_ver), + ADI_AXI_PCORE_VER_MAJOR(st->info->version), + ADI_AXI_PCORE_VER_MINOR(st->info->version), + ADI_AXI_PCORE_VER_PATCH(st->info->version), ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), ADI_AXI_PCORE_VER_PATCH(ver)); @@ -629,11 +879,34 @@ static int axi_dac_probe(struct platform_device *pdev) return ret; mutex_init(&st->lock); - ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st); + + ret = devm_iio_backend_register(&pdev->dev, st->info->backend_info, st); if (ret) return dev_err_probe(&pdev->dev, ret, "failed to register iio backend\n"); + device_for_each_child_node_scoped(&pdev->dev, child) { + int val; + + if (!st->info->has_child_nodes) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid fdt axi-dac compatible."); + + /* Processing only reg 0 node */ + ret = fwnode_property_read_u32(child, "reg", &val); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "invalid reg property."); + if (val != 0) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid node address."); + + ret = axi_dac_create_platform_device(st, child); + if (ret) + return dev_err_probe(&pdev->dev, -EINVAL, + "cannot create device."); + } + dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), @@ -642,10 +915,21 @@ static int axi_dac_probe(struct platform_device *pdev) return 0; } -static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b'); +static const struct axi_dac_info dac_generic = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .backend_info = &axi_dac_generic, +}; + +static const struct axi_dac_info dac_ad3552r = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .backend_info = &axi_ad3552r, + .has_dac_clk = true, + .has_child_nodes = true, +}; static const struct of_device_id axi_dac_of_match[] = { - { .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info }, + { .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic }, + { .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r }, {} }; MODULE_DEVICE_TABLE(of, axi_dac_of_match); diff --git a/drivers/iio/dummy/iio_simple_dummy.h b/drivers/iio/dummy/iio_simple_dummy.h index a91622ac54e0..8246f25dbad0 100644 --- a/drivers/iio/dummy/iio_simple_dummy.h +++ b/drivers/iio/dummy/iio_simple_dummy.h @@ -60,7 +60,7 @@ int iio_simple_dummy_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); int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c index 63a2b844be50..b51ec21b6309 100644 --- a/drivers/iio/dummy/iio_simple_dummy_events.c +++ b/drivers/iio/dummy/iio_simple_dummy_events.c @@ -53,7 +53,7 @@ int iio_simple_dummy_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 iio_dummy_state *st = iio_priv(indio_dev); @@ -183,36 +183,34 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private) switch (st->regs->reg_data) { case 0: iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, 0, 0, 0), + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), st->event_timestamp); break; case 1: if (st->activity_running > st->event_val) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - IIO_MOD_RUNNING, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, - 0, 0, 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + IIO_MOD_RUNNING, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), st->event_timestamp); break; case 2: if (st->activity_walking < st->event_val) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - IIO_MOD_WALKING, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, - 0, 0, 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + IIO_MOD_WALKING, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), st->event_timestamp); break; case 3: 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), st->event_timestamp); break; default: diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 97b86c4a53a6..3e193ee0fb61 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -27,7 +27,7 @@ config ADIS16136 select IIO_ADIS_LIB_BUFFER if IIO_BUFFER help Say yes here to build support for the Analog Devices ADIS16133, ADIS16135, - ADIS16136 gyroscope devices. + ADIS16136, ADIS16137 gyroscope devices. config ADIS16260 tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 10728d5ccae3..ba877d067afb 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -8,7 +8,6 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/acpi.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/iio/iio.h> @@ -444,7 +443,7 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data, static int bmg160_get_bw(struct bmg160_data *data, int *val) { - struct device *dev = regmap_get_device(data->regmap); + struct device *dev = regmap_get_device(data->regmap); int i; unsigned int bw_bits; int ret; @@ -749,7 +748,7 @@ static int bmg160_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 bmg160_data *data = iio_priv(indio_dev); int ret; @@ -1055,17 +1054,6 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = { .postdisable = bmg160_buffer_postdisable, }; -static const char *bmg160_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); -} - int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { @@ -1098,9 +1086,6 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, mutex_init(&data->mutex); - if (ACPI_HANDLE(dev)) - name = bmg160_match_acpi_device(dev); - indio_dev->channels = bmg160_channels; indio_dev->num_channels = ARRAY_SIZE(bmg160_channels); indio_dev->name = name; diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 672d0b720f61..9c5d7e8ee99c 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -17,7 +17,7 @@ static int bmg160_i2c_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); struct regmap *regmap; - const char *name = NULL; + const char *name; regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf); if (IS_ERR(regmap)) { @@ -28,6 +28,8 @@ static int bmg160_i2c_probe(struct i2c_client *client) if (id) name = id->name; + else + name = iio_get_acpi_device_name(&client->dev); return bmg160_core_probe(&client->dev, regmap, client->irq, name); } @@ -39,8 +41,6 @@ static void bmg160_i2c_remove(struct i2c_client *client) static const struct acpi_device_id bmg160_acpi_match[] = { {"BMG0160", 0}, - {"BMI055B", 0}, - {"BMI088B", 0}, {}, }; diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 489dd898830b..ca0efecb5b5c 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -97,6 +97,20 @@ config KMX61 source "drivers/iio/imu/inv_icm42600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" + +config SMI240 + tristate "Bosch Sensor SMI240 Inertial Measurement Unit" + depends on SPI + select REGMAP_SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for SMI240 IMU on SPI with + accelerometer and gyroscope. + + This driver can also be built as a module. If so, the module will be + called smi240. + source "drivers/iio/imu/st_lsm6dsx/Kconfig" source "drivers/iio/imu/st_lsm9ds0/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 79f83ea6f644..04c77c2c4df8 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -28,5 +28,7 @@ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o +obj-$(CONFIG_SMI240) += smi240.o + obj-y += st_lsm6dsx/ obj-y += st_lsm9ds0/ diff --git a/drivers/iio/imu/bmi270/Kconfig b/drivers/iio/imu/bmi270/Kconfig index 0ffd29794fda..6362acc706da 100644 --- a/drivers/iio/imu/bmi270/Kconfig +++ b/drivers/iio/imu/bmi270/Kconfig @@ -6,6 +6,7 @@ config BMI270 tristate select IIO_BUFFER + select IIO_TRIGGERED_BUFFER config BMI270_I2C tristate "Bosch BMI270 I2C driver" diff --git a/drivers/iio/imu/bmi270/bmi270.h b/drivers/iio/imu/bmi270/bmi270.h index 8ac20ad7ee94..fdfad5784cc5 100644 --- a/drivers/iio/imu/bmi270/bmi270.h +++ b/drivers/iio/imu/bmi270/bmi270.h @@ -10,10 +10,29 @@ struct device; struct bmi270_data { struct device *dev; struct regmap *regmap; + const struct bmi270_chip_info *chip_info; + + /* + * Where IIO_DMA_MINALIGN may be larger than 8 bytes, align to + * that to ensure a DMA safe buffer. + */ + struct { + __le16 channels[6]; + aligned_s64 timestamp; + } data __aligned(IIO_DMA_MINALIGN); +}; + +struct bmi270_chip_info { + const char *name; + int chip_id; + const char *fw_name; }; extern const struct regmap_config bmi270_regmap_config; +extern const struct bmi270_chip_info bmi260_chip_info; +extern const struct bmi270_chip_info bmi270_chip_info; -int bmi270_core_probe(struct device *dev, struct regmap *regmap); +int bmi270_core_probe(struct device *dev, struct regmap *regmap, + const struct bmi270_chip_info *chip_info); #endif /* BMI270_H_ */ diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c index aeda7c4228df..70db83a20239 100644 --- a/drivers/iio/imu/bmi270/bmi270_core.c +++ b/drivers/iio/imu/bmi270/bmi270_core.c @@ -7,10 +7,18 @@ #include <linux/regmap.h> #include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> #include "bmi270.h" #define BMI270_CHIP_ID_REG 0x00 + +/* Checked to prevent sending incompatible firmware to BMI160 devices */ +#define BMI160_CHIP_ID_VAL 0xD1 + +#define BMI260_CHIP_ID_VAL 0x27 #define BMI270_CHIP_ID_VAL 0x24 #define BMI270_CHIP_ID_MSK GENMASK(7, 0) @@ -31,6 +39,9 @@ #define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02 #define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7) +#define BMI270_ACC_CONF_RANGE_REG 0x41 +#define BMI270_ACC_CONF_RANGE_MSK GENMASK(1, 0) + #define BMI270_GYR_CONF_REG 0x42 #define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0) #define BMI270_GYR_CONF_ODR_200HZ 0x09 @@ -39,6 +50,9 @@ #define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6) #define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7) +#define BMI270_GYR_CONF_RANGE_REG 0x43 +#define BMI270_GYR_CONF_RANGE_MSK GENMASK(2, 0) + #define BMI270_INIT_CTRL_REG 0x59 #define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0) @@ -55,6 +69,7 @@ #define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2) #define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3) +#define BMI260_INIT_DATA_FILE "bmi260-init-data.fw" #define BMI270_INIT_DATA_FILE "bmi270-init-data.fw" enum bmi270_scan { @@ -64,8 +79,312 @@ enum bmi270_scan { BMI270_SCAN_GYRO_X, BMI270_SCAN_GYRO_Y, BMI270_SCAN_GYRO_Z, + BMI270_SCAN_TIMESTAMP, +}; + +static const unsigned long bmi270_avail_scan_masks[] = { + (BIT(BMI270_SCAN_ACCEL_X) | + BIT(BMI270_SCAN_ACCEL_Y) | + BIT(BMI270_SCAN_ACCEL_Z) | + BIT(BMI270_SCAN_GYRO_X) | + BIT(BMI270_SCAN_GYRO_Y) | + BIT(BMI270_SCAN_GYRO_Z)), + 0 +}; + +const struct bmi270_chip_info bmi260_chip_info = { + .name = "bmi260", + .chip_id = BMI260_CHIP_ID_VAL, + .fw_name = BMI260_INIT_DATA_FILE, +}; +EXPORT_SYMBOL_NS_GPL(bmi260_chip_info, IIO_BMI270); + +const struct bmi270_chip_info bmi270_chip_info = { + .name = "bmi270", + .chip_id = BMI270_CHIP_ID_VAL, + .fw_name = BMI270_INIT_DATA_FILE, +}; +EXPORT_SYMBOL_NS_GPL(bmi270_chip_info, IIO_BMI270); + +enum bmi270_sensor_type { + BMI270_ACCEL = 0, + BMI270_GYRO, +}; + +struct bmi270_scale { + int scale; + int uscale; +}; + +struct bmi270_odr { + int odr; + int uodr; +}; + +static const struct bmi270_scale bmi270_accel_scale[] = { + { 0, 598 }, + { 0, 1197 }, + { 0, 2394 }, + { 0, 4788 }, +}; + +static const struct bmi270_scale bmi270_gyro_scale[] = { + { 0, 1065 }, + { 0, 532 }, + { 0, 266 }, + { 0, 133 }, + { 0, 66 }, +}; + +struct bmi270_scale_item { + const struct bmi270_scale *tbl; + int num; +}; + +static const struct bmi270_scale_item bmi270_scale_table[] = { + [BMI270_ACCEL] = { + .tbl = bmi270_accel_scale, + .num = ARRAY_SIZE(bmi270_accel_scale), + }, + [BMI270_GYRO] = { + .tbl = bmi270_gyro_scale, + .num = ARRAY_SIZE(bmi270_gyro_scale), + }, +}; + +static const struct bmi270_odr bmi270_accel_odr[] = { + { 0, 781250 }, + { 1, 562500 }, + { 3, 125000 }, + { 6, 250000 }, + { 12, 500000 }, + { 25, 0 }, + { 50, 0 }, + { 100, 0 }, + { 200, 0 }, + { 400, 0 }, + { 800, 0 }, + { 1600, 0 }, +}; + +static const u8 bmi270_accel_odr_vals[] = { + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, +}; + +static const struct bmi270_odr bmi270_gyro_odr[] = { + { 25, 0 }, + { 50, 0 }, + { 100, 0 }, + { 200, 0 }, + { 400, 0 }, + { 800, 0 }, + { 1600, 0 }, + { 3200, 0 }, +}; + +static const u8 bmi270_gyro_odr_vals[] = { + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, +}; + +struct bmi270_odr_item { + const struct bmi270_odr *tbl; + const u8 *vals; + int num; +}; + +static const struct bmi270_odr_item bmi270_odr_table[] = { + [BMI270_ACCEL] = { + .tbl = bmi270_accel_odr, + .vals = bmi270_accel_odr_vals, + .num = ARRAY_SIZE(bmi270_accel_odr), + }, + [BMI270_GYRO] = { + .tbl = bmi270_gyro_odr, + .vals = bmi270_gyro_odr_vals, + .num = ARRAY_SIZE(bmi270_gyro_odr), + }, }; +static int bmi270_set_scale(struct bmi270_data *data, int chan_type, int uscale) +{ + int i; + int reg, mask; + struct bmi270_scale_item bmi270_scale_item; + + switch (chan_type) { + case IIO_ACCEL: + reg = BMI270_ACC_CONF_RANGE_REG; + mask = BMI270_ACC_CONF_RANGE_MSK; + bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + reg = BMI270_GYR_CONF_RANGE_REG; + mask = BMI270_GYR_CONF_RANGE_MSK; + bmi270_scale_item = bmi270_scale_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + for (i = 0; i < bmi270_scale_item.num; i++) { + if (bmi270_scale_item.tbl[i].uscale != uscale) + continue; + + return regmap_update_bits(data->regmap, reg, mask, i); + } + + return -EINVAL; +} + +static int bmi270_get_scale(struct bmi270_data *bmi270_device, int chan_type, + int *uscale) +{ + int ret; + unsigned int val; + struct bmi270_scale_item bmi270_scale_item; + + switch (chan_type) { + case IIO_ACCEL: + ret = regmap_read(bmi270_device->regmap, + BMI270_ACC_CONF_RANGE_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_ACC_CONF_RANGE_MSK, val); + bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + ret = regmap_read(bmi270_device->regmap, + BMI270_GYR_CONF_RANGE_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_GYR_CONF_RANGE_MSK, val); + bmi270_scale_item = bmi270_scale_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + if (val >= bmi270_scale_item.num) + return -EINVAL; + + *uscale = bmi270_scale_item.tbl[val].uscale; + return 0; +} + +static int bmi270_set_odr(struct bmi270_data *data, int chan_type, int odr, + int uodr) +{ + int i; + int reg, mask; + struct bmi270_odr_item bmi270_odr_item; + + switch (chan_type) { + case IIO_ACCEL: + reg = BMI270_ACC_CONF_REG; + mask = BMI270_ACC_CONF_ODR_MSK; + bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + reg = BMI270_GYR_CONF_REG; + mask = BMI270_GYR_CONF_ODR_MSK; + bmi270_odr_item = bmi270_odr_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + for (i = 0; i < bmi270_odr_item.num; i++) { + if (bmi270_odr_item.tbl[i].odr != odr || + bmi270_odr_item.tbl[i].uodr != uodr) + continue; + + return regmap_update_bits(data->regmap, reg, mask, + bmi270_odr_item.vals[i]); + } + + return -EINVAL; +} + +static int bmi270_get_odr(struct bmi270_data *data, int chan_type, int *odr, + int *uodr) +{ + int i, val, ret; + struct bmi270_odr_item bmi270_odr_item; + + switch (chan_type) { + case IIO_ACCEL: + ret = regmap_read(data->regmap, BMI270_ACC_CONF_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_ACC_CONF_ODR_MSK, val); + bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + ret = regmap_read(data->regmap, BMI270_GYR_CONF_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_GYR_CONF_ODR_MSK, val); + bmi270_odr_item = bmi270_odr_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + for (i = 0; i < bmi270_odr_item.num; i++) { + if (val != bmi270_odr_item.vals[i]) + continue; + + *odr = bmi270_odr_item.tbl[i].odr; + *uodr = bmi270_odr_item.tbl[i].uodr; + return 0; + } + + return -EINVAL; +} + +static irqreturn_t bmi270_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bmi270_data *bmi270_device = iio_priv(indio_dev); + int ret; + + ret = regmap_bulk_read(bmi270_device->regmap, BMI270_ACCEL_X_REG, + &bmi270_device->data.channels, + sizeof(bmi270_device->data.channels)); + + if (ret) + goto done; + + iio_push_to_buffers_with_timestamp(indio_dev, &bmi270_device->data, + pf->timestamp); +done: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + static int bmi270_get_data(struct bmi270_data *bmi270_device, int chan_type, int axis, int *val) { @@ -107,6 +426,68 @@ static int bmi270_read_raw(struct iio_dev *indio_dev, return ret; return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + ret = bmi270_get_scale(bmi270_device, chan->type, val2); + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = bmi270_get_odr(bmi270_device, chan->type, val, val2); + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int bmi270_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmi270_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return bmi270_set_scale(data, chan->type, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return bmi270_set_odr(data, chan->type, val, val2); + default: + return -EINVAL; + } +} + +static int bmi270_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT_PLUS_MICRO; + switch (chan->type) { + case IIO_ANGL_VEL: + *vals = (const int *)bmi270_gyro_scale; + *length = ARRAY_SIZE(bmi270_gyro_scale) * 2; + return IIO_AVAIL_LIST; + case IIO_ACCEL: + *vals = (const int *)bmi270_accel_scale; + *length = ARRAY_SIZE(bmi270_accel_scale) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + switch (chan->type) { + case IIO_ANGL_VEL: + *vals = (const int *)bmi270_gyro_odr; + *length = ARRAY_SIZE(bmi270_gyro_odr) * 2; + return IIO_AVAIL_LIST; + case IIO_ACCEL: + *vals = (const int *)bmi270_accel_odr; + *length = ARRAY_SIZE(bmi270_accel_odr) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } default: return -EINVAL; } @@ -114,6 +495,8 @@ static int bmi270_read_raw(struct iio_dev *indio_dev, static const struct iio_info bmi270_info = { .read_raw = bmi270_read_raw, + .write_raw = bmi270_write_raw, + .read_avail = bmi270_read_avail, }; #define BMI270_ACCEL_CHANNEL(_axis) { \ @@ -122,7 +505,17 @@ static const struct iio_info bmi270_info = { .channel2 = IIO_MOD_##_axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_FREQUENCY), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = BMI270_SCAN_ACCEL_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ } #define BMI270_ANG_VEL_CHANNEL(_axis) { \ @@ -131,7 +524,17 @@ static const struct iio_info bmi270_info = { .channel2 = IIO_MOD_##_axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_FREQUENCY), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = BMI270_SCAN_GYRO_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ } static const struct iio_chan_spec bmi270_channels[] = { @@ -141,6 +544,7 @@ static const struct iio_chan_spec bmi270_channels[] = { BMI270_ANG_VEL_CHANNEL(X), BMI270_ANG_VEL_CHANNEL(Y), BMI270_ANG_VEL_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(BMI270_SCAN_TIMESTAMP), }; static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device) @@ -154,8 +558,21 @@ static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device) if (ret) return dev_err_probe(dev, ret, "Failed to read chip id"); - if (chip_id != BMI270_CHIP_ID_VAL) - dev_info(dev, "Unknown chip id 0x%x", chip_id); + /* + * Some manufacturers use "BMI0160" for both the BMI160 and + * BMI260. If the device is actually a BMI160, the bmi160 + * driver should handle it and this driver should not. + */ + if (chip_id == BMI160_CHIP_ID_VAL) + return -ENODEV; + + if (chip_id != bmi270_device->chip_info->chip_id) + dev_info(dev, "Unexpected chip id 0x%x", chip_id); + + if (chip_id == bmi260_chip_info.chip_id) + bmi270_device->chip_info = &bmi260_chip_info; + else if (chip_id == bmi270_chip_info.chip_id) + bmi270_device->chip_info = &bmi270_chip_info; return 0; } @@ -187,7 +604,8 @@ static int bmi270_write_calibration_data(struct bmi270_data *bmi270_device) return dev_err_probe(dev, ret, "Failed to prepare device to load init data"); - ret = request_firmware(&init_data, BMI270_INIT_DATA_FILE, dev); + ret = request_firmware(&init_data, + bmi270_device->chip_info->fw_name, dev); if (ret) return dev_err_probe(dev, ret, "Failed to load init data file"); @@ -274,7 +692,8 @@ static int bmi270_chip_init(struct bmi270_data *bmi270_device) return bmi270_configure_imu(bmi270_device); } -int bmi270_core_probe(struct device *dev, struct regmap *regmap) +int bmi270_core_probe(struct device *dev, struct regmap *regmap, + const struct bmi270_chip_info *chip_info) { int ret; struct bmi270_data *bmi270_device; @@ -287,6 +706,7 @@ int bmi270_core_probe(struct device *dev, struct regmap *regmap) bmi270_device = iio_priv(indio_dev); bmi270_device->dev = dev; bmi270_device->regmap = regmap; + bmi270_device->chip_info = chip_info; ret = bmi270_chip_init(bmi270_device); if (ret) @@ -294,10 +714,17 @@ int bmi270_core_probe(struct device *dev, struct regmap *regmap) indio_dev->channels = bmi270_channels; indio_dev->num_channels = ARRAY_SIZE(bmi270_channels); - indio_dev->name = "bmi270"; + indio_dev->name = chip_info->name; + indio_dev->available_scan_masks = bmi270_avail_scan_masks; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmi270_info; + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + bmi270_trigger_handler, NULL); + if (ret) + return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS_GPL(bmi270_core_probe, IIO_BMI270); diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c index d59161f23f9a..6bd82e4362ab 100644 --- a/drivers/iio/imu/bmi270/bmi270_i2c.c +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -17,28 +17,42 @@ static int bmi270_i2c_probe(struct i2c_client *client) { struct regmap *regmap; struct device *dev = &client->dev; + const struct bmi270_chip_info *chip_info; + + chip_info = i2c_get_match_data(client); + if (!chip_info) + return -ENODEV; regmap = devm_regmap_init_i2c(client, &bmi270_i2c_regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init i2c regmap"); - return bmi270_core_probe(dev, regmap); + return bmi270_core_probe(dev, regmap, chip_info); } static const struct i2c_device_id bmi270_i2c_id[] = { - { "bmi270", 0 }, + { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, + { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, + { } +}; + +static const struct acpi_device_id bmi270_acpi_match[] = { + /* GPD Win Mini, Aya Neo AIR Pro, OXP Mini Pro, etc. */ + { "BMI0160", (kernel_ulong_t)&bmi260_chip_info }, { } }; static const struct of_device_id bmi270_of_match[] = { - { .compatible = "bosch,bmi270" }, + { .compatible = "bosch,bmi260", .data = &bmi260_chip_info }, + { .compatible = "bosch,bmi270", .data = &bmi270_chip_info }, { } }; static struct i2c_driver bmi270_i2c_driver = { .driver = { .name = "bmi270_i2c", + .acpi_match_table = bmi270_acpi_match, .of_match_table = bmi270_of_match, }, .probe = bmi270_i2c_probe, diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c index b53784d4a1f4..30b6d13a329c 100644 --- a/drivers/iio/imu/bmi270/bmi270_spi.c +++ b/drivers/iio/imu/bmi270/bmi270_spi.c @@ -49,6 +49,11 @@ static int bmi270_spi_probe(struct spi_device *spi) { struct regmap *regmap; struct device *dev = &spi->dev; + const struct bmi270_chip_info *chip_info; + + chip_info = spi_get_device_match_data(spi); + if (!chip_info) + return -ENODEV; regmap = devm_regmap_init(dev, &bmi270_regmap_bus, dev, &bmi270_spi_regmap_config); @@ -56,16 +61,18 @@ static int bmi270_spi_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init i2c regmap"); - return bmi270_core_probe(dev, regmap); + return bmi270_core_probe(dev, regmap, chip_info); } static const struct spi_device_id bmi270_spi_id[] = { - { "bmi270" }, + { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, + { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, { } }; static const struct of_device_id bmi270_of_match[] = { - { .compatible = "bosch,bmi270" }, + { .compatible = "bosch,bmi260", .data = &bmi260_chip_info }, + { .compatible = "bosch,bmi270", .data = &bmi270_chip_info }, { } }; diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c index 1e6c083ea5c1..161bb1d2e761 100644 --- a/drivers/iio/imu/bmi323/bmi323_core.c +++ b/drivers/iio/imu/bmi323/bmi323_core.c @@ -467,7 +467,7 @@ static int bmi323_feature_engine_events(struct bmi323_data *data, BMI323_FEAT_IO_STATUS_MSK); } -static int bmi323_step_wtrmrk_en(struct bmi323_data *data, int state) +static int bmi323_step_wtrmrk_en(struct bmi323_data *data, bool state) { enum bmi323_irq_pin step_irq; int ret; @@ -484,7 +484,7 @@ static int bmi323_step_wtrmrk_en(struct bmi323_data *data, int state) ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, BMI323_STEP_SC1_WTRMRK_MSK, FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK, - state ? 1 : 0)); + state)); if (ret) return ret; @@ -506,7 +506,7 @@ static int bmi323_motion_config_reg(enum iio_event_direction dir) } static int bmi323_motion_event_en(struct bmi323_data *data, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { unsigned int state_value = state ? BMI323_FEAT_XYZ_MSK : 0; int config, ret, msk, raw, field_value; @@ -570,7 +570,7 @@ static int bmi323_motion_event_en(struct bmi323_data *data, } static int bmi323_tap_event_en(struct bmi323_data *data, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { enum bmi323_irq_pin tap_irq; int ret, tap_enabled; @@ -785,7 +785,7 @@ static const struct attribute_group bmi323_event_attribute_group = { static int bmi323_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 bmi323_data *data = iio_priv(indio_dev); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index b15d8c94cc11..373e59f6d91a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -104,14 +104,11 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client, unsigned short *secondary_addr) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); - const struct acpi_device_id *id; u32 i2c_addr = 0; LIST_HEAD(resources); int ret; - id = acpi_match_device(client->dev.driver->acpi_match_table, - &client->dev); - if (!id) + if (!is_acpi_device_node(dev_fwnode(&client->dev))) return -ENODEV; ret = acpi_dev_get_resources(adev, &resources, diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 5680be153127..40271352b02c 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1173,24 +1173,21 @@ static int inv_mpu6050_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 inv_mpu6050_state *st = iio_priv(indio_dev); - int enable; /* support only WoM (accel roc rising) event */ if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) return -EINVAL; - enable = !!state; - guard(mutex)(&st->lock); - if (st->chip_config.wom_en == enable) + if (st->chip_config.wom_en == state) return 0; - return inv_mpu6050_enable_wom(st, enable); + return inv_mpu6050_enable_wom(st, state); } static int inv_mpu6050_read_event_value(struct iio_dev *indio_dev, diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 2af772775b68..324c38764656 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -942,7 +942,7 @@ static int kmx61_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 kmx61_data *data = kmx61_get_data(indio_dev); int ret = 0; diff --git a/drivers/iio/imu/smi240.c b/drivers/iio/imu/smi240.c new file mode 100644 index 000000000000..4492c4d013bd --- /dev/null +++ b/drivers/iio/imu/smi240.c @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * Copyright (c) 2024 Robert Bosch GmbH. + */ +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/unaligned.h> +#include <linux/units.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define SMI240_CHIP_ID 0x0024 + +#define SMI240_SOFT_CONFIG_EOC_MASK BIT(0) +#define SMI240_SOFT_CONFIG_GYR_BW_MASK BIT(1) +#define SMI240_SOFT_CONFIG_ACC_BW_MASK BIT(2) +#define SMI240_SOFT_CONFIG_BITE_AUTO_MASK BIT(3) +#define SMI240_SOFT_CONFIG_BITE_REP_MASK GENMASK(6, 4) + +#define SMI240_CHIP_ID_REG 0x00 +#define SMI240_SOFT_CONFIG_REG 0x0A +#define SMI240_TEMP_CUR_REG 0x10 +#define SMI240_ACCEL_X_CUR_REG 0x11 +#define SMI240_GYRO_X_CUR_REG 0x14 +#define SMI240_DATA_CAP_FIRST_REG 0x17 +#define SMI240_CMD_REG 0x2F + +#define SMI240_SOFT_RESET_CMD 0xB6 + +#define SMI240_BITE_SEQUENCE_DELAY_US 140000 +#define SMI240_FILTER_FLUSH_DELAY_US 60000 +#define SMI240_DIGITAL_STARTUP_DELAY_US 120000 +#define SMI240_MECH_STARTUP_DELAY_US 100000 + +#define SMI240_BUS_ID 0x00 +#define SMI240_CRC_INIT 0x05 +#define SMI240_CRC_POLY 0x0B +#define SMI240_CRC_MASK GENMASK(2, 0) + +#define SMI240_READ_SD_BIT_MASK BIT(31) +#define SMI240_READ_DATA_MASK GENMASK(19, 4) +#define SMI240_READ_CS_BIT_MASK BIT(3) + +#define SMI240_WRITE_BUS_ID_MASK GENMASK(31, 30) +#define SMI240_WRITE_ADDR_MASK GENMASK(29, 22) +#define SMI240_WRITE_BIT_MASK BIT(21) +#define SMI240_WRITE_CAP_BIT_MASK BIT(20) +#define SMI240_WRITE_DATA_MASK GENMASK(18, 3) + +/* T°C = (temp / 256) + 25 */ +#define SMI240_TEMP_OFFSET 6400 /* 25 * 256 */ +#define SMI240_TEMP_SCALE 3906250 /* (1 / 256) * 1e9 */ + +#define SMI240_ACCEL_SCALE 500 /* (1 / 2000) * 1e6 */ +#define SMI240_GYRO_SCALE 10000 /* (1 / 100) * 1e6 */ + +#define SMI240_LOW_BANDWIDTH_HZ 50 +#define SMI240_HIGH_BANDWIDTH_HZ 400 + +#define SMI240_BUILT_IN_SELF_TEST_COUNT 3 + +#define SMI240_DATA_CHANNEL(_type, _axis, _index) { \ + .type = _type, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define SMI240_TEMP_CHANNEL(_index) { \ + .type = IIO_TEMP, \ + .modified = 1, \ + .channel2 = IIO_MOD_TEMP_OBJECT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +enum capture_mode { SMI240_CAPTURE_OFF = 0, SMI240_CAPTURE_ON = 1 }; + +struct smi240_data { + struct regmap *regmap; + u16 accel_filter_freq; + u16 anglvel_filter_freq; + u8 built_in_self_test_count; + enum capture_mode capture; + /* + * Ensure natural alignment for timestamp if present. + * Channel size: 2 bytes. + * Max length needed: 2 * 3 channels + temp channel + 2 bytes padding + 8 byte ts. + * If fewer channels are enabled, less space may be needed, as + * long as the timestamp is still aligned to 8 bytes. + */ + s16 buf[12] __aligned(8); + + __be32 spi_buf __aligned(IIO_DMA_MINALIGN); +}; + +enum { + SMI240_TEMP_OBJECT, + SMI240_SCAN_ACCEL_X, + SMI240_SCAN_ACCEL_Y, + SMI240_SCAN_ACCEL_Z, + SMI240_SCAN_GYRO_X, + SMI240_SCAN_GYRO_Y, + SMI240_SCAN_GYRO_Z, + SMI240_SCAN_TIMESTAMP, +}; + +static const struct iio_chan_spec smi240_channels[] = { + SMI240_TEMP_CHANNEL(SMI240_TEMP_OBJECT), + SMI240_DATA_CHANNEL(IIO_ACCEL, X, SMI240_SCAN_ACCEL_X), + SMI240_DATA_CHANNEL(IIO_ACCEL, Y, SMI240_SCAN_ACCEL_Y), + SMI240_DATA_CHANNEL(IIO_ACCEL, Z, SMI240_SCAN_ACCEL_Z), + SMI240_DATA_CHANNEL(IIO_ANGL_VEL, X, SMI240_SCAN_GYRO_X), + SMI240_DATA_CHANNEL(IIO_ANGL_VEL, Y, SMI240_SCAN_GYRO_Y), + SMI240_DATA_CHANNEL(IIO_ANGL_VEL, Z, SMI240_SCAN_GYRO_Z), + IIO_CHAN_SOFT_TIMESTAMP(SMI240_SCAN_TIMESTAMP), +}; + +static const int smi240_low_pass_freqs[] = { SMI240_LOW_BANDWIDTH_HZ, + SMI240_HIGH_BANDWIDTH_HZ }; + +static u8 smi240_crc3(u32 data, u8 init, u8 poly) +{ + u8 crc = init; + u8 do_xor; + s8 i = 31; + + do { + do_xor = crc & 0x04; + crc <<= 1; + crc |= 0x01 & (data >> i); + if (do_xor) + crc ^= poly; + + crc &= SMI240_CRC_MASK; + } while (--i >= 0); + + return crc; +} + +static bool smi240_sensor_data_is_valid(u32 data) +{ + if (smi240_crc3(data, SMI240_CRC_INIT, SMI240_CRC_POLY) != 0) + return false; + + if (FIELD_GET(SMI240_READ_SD_BIT_MASK, data) & + FIELD_GET(SMI240_READ_CS_BIT_MASK, data)) + return false; + + return true; +} + +static int smi240_regmap_spi_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + int ret; + u32 request, response; + u16 *val = val_buf; + struct spi_device *spi = context; + struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); + struct smi240_data *iio_priv_data = iio_priv(indio_dev); + + if (reg_size != 1 || val_size != 2) + return -EINVAL; + + request = FIELD_PREP(SMI240_WRITE_BUS_ID_MASK, SMI240_BUS_ID); + request |= FIELD_PREP(SMI240_WRITE_CAP_BIT_MASK, iio_priv_data->capture); + request |= FIELD_PREP(SMI240_WRITE_ADDR_MASK, *(u8 *)reg_buf); + request |= smi240_crc3(request, SMI240_CRC_INIT, SMI240_CRC_POLY); + + iio_priv_data->spi_buf = cpu_to_be32(request); + + /* + * SMI240 module consists of a 32Bit Out Of Frame (OOF) + * SPI protocol, where the slave interface responds to + * the Master request in the next frame. + * CS signal must toggle (> 700 ns) between the frames. + */ + ret = spi_write(spi, &iio_priv_data->spi_buf, sizeof(request)); + if (ret) + return ret; + + ret = spi_read(spi, &iio_priv_data->spi_buf, sizeof(response)); + if (ret) + return ret; + + response = be32_to_cpu(iio_priv_data->spi_buf); + + if (!smi240_sensor_data_is_valid(response)) + return -EIO; + + *val = FIELD_GET(SMI240_READ_DATA_MASK, response); + + return 0; +} + +static int smi240_regmap_spi_write(void *context, const void *data, + size_t count) +{ + u8 reg_addr; + u16 reg_data; + u32 request; + const u8 *data_ptr = data; + struct spi_device *spi = context; + struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); + struct smi240_data *iio_priv_data = iio_priv(indio_dev); + + if (count < 2) + return -EINVAL; + + reg_addr = data_ptr[0]; + memcpy(®_data, &data_ptr[1], sizeof(reg_data)); + + request = FIELD_PREP(SMI240_WRITE_BUS_ID_MASK, SMI240_BUS_ID); + request |= FIELD_PREP(SMI240_WRITE_BIT_MASK, 1); + request |= FIELD_PREP(SMI240_WRITE_ADDR_MASK, reg_addr); + request |= FIELD_PREP(SMI240_WRITE_DATA_MASK, reg_data); + request |= smi240_crc3(request, SMI240_CRC_INIT, SMI240_CRC_POLY); + + iio_priv_data->spi_buf = cpu_to_be32(request); + + return spi_write(spi, &iio_priv_data->spi_buf, sizeof(request)); +} + +static const struct regmap_bus smi240_regmap_bus = { + .read = smi240_regmap_spi_read, + .write = smi240_regmap_spi_write, +}; + +static const struct regmap_config smi240_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .val_format_endian = REGMAP_ENDIAN_NATIVE, +}; + +static int smi240_soft_reset(struct smi240_data *data) +{ + int ret; + + ret = regmap_write(data->regmap, SMI240_CMD_REG, SMI240_SOFT_RESET_CMD); + if (ret) + return ret; + fsleep(SMI240_DIGITAL_STARTUP_DELAY_US); + + return 0; +} + +static int smi240_soft_config(struct smi240_data *data) +{ + int ret; + u8 acc_bw, gyr_bw; + u16 request; + + switch (data->accel_filter_freq) { + case SMI240_LOW_BANDWIDTH_HZ: + acc_bw = 0x1; + break; + case SMI240_HIGH_BANDWIDTH_HZ: + acc_bw = 0x0; + break; + default: + return -EINVAL; + } + + switch (data->anglvel_filter_freq) { + case SMI240_LOW_BANDWIDTH_HZ: + gyr_bw = 0x1; + break; + case SMI240_HIGH_BANDWIDTH_HZ: + gyr_bw = 0x0; + break; + default: + return -EINVAL; + } + + request = FIELD_PREP(SMI240_SOFT_CONFIG_EOC_MASK, 1); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_GYR_BW_MASK, gyr_bw); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_ACC_BW_MASK, acc_bw); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_BITE_AUTO_MASK, 1); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_BITE_REP_MASK, + data->built_in_self_test_count - 1); + + ret = regmap_write(data->regmap, SMI240_SOFT_CONFIG_REG, request); + if (ret) + return ret; + + fsleep(SMI240_MECH_STARTUP_DELAY_US + + data->built_in_self_test_count * SMI240_BITE_SEQUENCE_DELAY_US + + SMI240_FILTER_FLUSH_DELAY_US); + + return 0; +} + +static int smi240_get_low_pass_filter_freq(struct smi240_data *data, + int chan_type, int *val) +{ + switch (chan_type) { + case IIO_ACCEL: + *val = data->accel_filter_freq; + return 0; + case IIO_ANGL_VEL: + *val = data->anglvel_filter_freq; + return 0; + default: + return -EINVAL; + } +} + +static int smi240_get_data(struct smi240_data *data, int chan_type, int axis, + int *val) +{ + u8 reg; + int ret, sample; + + switch (chan_type) { + case IIO_TEMP: + reg = SMI240_TEMP_CUR_REG; + break; + case IIO_ACCEL: + reg = SMI240_ACCEL_X_CUR_REG + (axis - IIO_MOD_X); + break; + case IIO_ANGL_VEL: + reg = SMI240_GYRO_X_CUR_REG + (axis - IIO_MOD_X); + break; + default: + return -EINVAL; + } + + ret = regmap_read(data->regmap, reg, &sample); + if (ret) + return ret; + + *val = sign_extend32(sample, 15); + + return 0; +} + +static irqreturn_t smi240_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct smi240_data *data = iio_priv(indio_dev); + int base = SMI240_DATA_CAP_FIRST_REG, i = 0; + int ret, chan, sample; + + data->capture = SMI240_CAPTURE_ON; + + iio_for_each_active_channel(indio_dev, chan) { + ret = regmap_read(data->regmap, base + chan, &sample); + data->capture = SMI240_CAPTURE_OFF; + if (ret) + goto out; + data->buf[i++] = sample; + } + + iio_push_to_buffers_with_timestamp(indio_dev, data->buf, pf->timestamp); + +out: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int smi240_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, const int **vals, + int *type, int *length, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = smi240_low_pass_freqs; + *length = ARRAY_SIZE(smi240_low_pass_freqs); + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int smi240_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + int ret; + struct smi240_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = smi240_get_data(data, chan->type, chan->channel2, val); + iio_device_release_direct_mode(indio_dev); + if (ret) + return ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + ret = smi240_get_low_pass_filter_freq(data, chan->type, val); + if (ret) + return ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + *val = SMI240_TEMP_SCALE / GIGA; + *val2 = SMI240_TEMP_SCALE % GIGA; + return IIO_VAL_INT_PLUS_NANO; + case IIO_ACCEL: + *val = 0; + *val2 = SMI240_ACCEL_SCALE; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ANGL_VEL: + *val = 0; + *val2 = SMI240_GYRO_SCALE; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) { + *val = SMI240_TEMP_OFFSET; + return IIO_VAL_INT; + } else { + return -EINVAL; + } + + default: + return -EINVAL; + } +} + +static int smi240_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + int ret, i; + struct smi240_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + for (i = 0; i < ARRAY_SIZE(smi240_low_pass_freqs); i++) { + if (val == smi240_low_pass_freqs[i]) + break; + } + + if (i == ARRAY_SIZE(smi240_low_pass_freqs)) + return -EINVAL; + + switch (chan->type) { + case IIO_ACCEL: + data->accel_filter_freq = val; + break; + case IIO_ANGL_VEL: + data->anglvel_filter_freq = val; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + /* Write access to soft config is locked until hard/soft reset */ + ret = smi240_soft_reset(data); + if (ret) + return ret; + + return smi240_soft_config(data); +} + +static int smi240_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + +static int smi240_init(struct smi240_data *data) +{ + int ret; + + data->accel_filter_freq = SMI240_HIGH_BANDWIDTH_HZ; + data->anglvel_filter_freq = SMI240_HIGH_BANDWIDTH_HZ; + data->built_in_self_test_count = SMI240_BUILT_IN_SELF_TEST_COUNT; + + ret = smi240_soft_reset(data); + if (ret) + return ret; + + return smi240_soft_config(data); +} + +static const struct iio_info smi240_info = { + .read_avail = smi240_read_avail, + .read_raw = smi240_read_raw, + .write_raw = smi240_write_raw, + .write_raw_get_fmt = smi240_write_raw_get_fmt, +}; + +static int smi240_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct regmap *regmap; + struct smi240_data *data; + int ret, response; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init(dev, &smi240_regmap_bus, dev, + &smi240_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialize SPI Regmap\n"); + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + data->regmap = regmap; + data->capture = SMI240_CAPTURE_OFF; + + ret = regmap_read(data->regmap, SMI240_CHIP_ID_REG, &response); + if (ret) + return dev_err_probe(dev, ret, "Read chip id failed\n"); + + if (response != SMI240_CHIP_ID) + dev_info(dev, "Unknown chip id: 0x%04x\n", response); + + ret = smi240_init(data); + if (ret) + return dev_err_probe(dev, ret, + "Device initialization failed\n"); + + indio_dev->channels = smi240_channels; + indio_dev->num_channels = ARRAY_SIZE(smi240_channels); + indio_dev->name = "smi240"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &smi240_info; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + smi240_trigger_handler, NULL); + if (ret) + return dev_err_probe(dev, ret, + "Setup triggered buffer failed\n"); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Register IIO device failed\n"); + + return 0; +} + +static const struct spi_device_id smi240_spi_id[] = { + { "smi240" }, + { } +}; +MODULE_DEVICE_TABLE(spi, smi240_spi_id); + +static const struct of_device_id smi240_of_match[] = { + { .compatible = "bosch,smi240" }, + { } +}; +MODULE_DEVICE_TABLE(of, smi240_of_match); + +static struct spi_driver smi240_spi_driver = { + .probe = smi240_probe, + .id_table = smi240_spi_id, + .driver = { + .of_match_table = smi240_of_match, + .name = "smi240", + }, +}; +module_spi_driver(smi240_spi_driver); + +MODULE_AUTHOR("Markus Lochmann <markus.lochmann@de.bosch.com>"); +MODULE_AUTHOR("Stefan Gutmann <stefan.gutmann@de.bosch.com>"); +MODULE_DESCRIPTION("Bosch SMI240 SPI driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index fb4c6c39ff2e..509e0169dcd5 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1865,7 +1865,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, return err; } -static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) +static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, bool state) { const struct st_lsm6dsx_reg *reg; unsigned int data; @@ -1959,7 +1959,7 @@ static int st_lsm6dsx_write_event_config(struct iio_dev *iio_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 st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); struct st_lsm6dsx_hw *hw = sensor->hw; diff --git a/drivers/iio/industrialio-acpi.c b/drivers/iio/industrialio-acpi.c index 981b75d40780..d67a43843799 100644 --- a/drivers/iio/industrialio-acpi.c +++ b/drivers/iio/industrialio-acpi.c @@ -2,7 +2,8 @@ /* IIO ACPI helper functions */ #include <linux/acpi.h> -#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/export.h> #include <linux/iio/iio.h> #include <linux/sprintf.h> @@ -28,17 +29,21 @@ bool iio_read_acpi_mount_matrix(struct device *dev, char *acpi_method) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_device *adev = ACPI_COMPANION(dev); char *str; union acpi_object *obj, *elements; + acpi_handle handle; acpi_status status; int i, j, val[3]; bool ret = false; - if (!adev || !acpi_has_method(adev->handle, acpi_method)) + handle = ACPI_HANDLE(dev); + if (!handle) return false; - status = acpi_evaluate_object(adev->handle, acpi_method, NULL, &buffer); + if (!acpi_has_method(handle, acpi_method)) + return false; + + status = acpi_evaluate_object(handle, acpi_method, NULL, &buffer); if (ACPI_FAILURE(status)) { dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status); return false; @@ -83,3 +88,38 @@ out_free_buffer: return ret; } EXPORT_SYMBOL_GPL(iio_read_acpi_mount_matrix); + +/** + * iio_get_acpi_device_name_and_data() - Return ACPI device instance name and driver data + * @dev: Device structure + * @data: Optional pointer to return driver data + * + * When device was enumerated by ACPI ID matching, the user might + * want to set description for the physical chip. In such cases + * the ACPI device instance name might be used. This call may be + * performed to retrieve this information. + * + * NOTE: This helper function exists only for backward compatibility, + * do not use in a new code! + * + * Returns: ACPI device instance name or %NULL. + */ +const char *iio_get_acpi_device_name_and_data(struct device *dev, const void **data) +{ + const struct acpi_device_id *id; + acpi_handle handle; + + handle = ACPI_HANDLE(dev); + if (!handle) + return NULL; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + + if (data) + *data = (const void *)id->driver_data; + + return dev_name(dev); +} +EXPORT_SYMBOL_GPL(iio_get_acpi_device_name_and_data); diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index fb34a8e4d04e..529b1087d3fb 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -718,6 +718,84 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) return 0; } +/** + * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode + * @back: Backend device + * + * Enable DDR, data is generated by the IP at each front (raising and falling) + * of the bus clock signal. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_ddr_enable(struct iio_backend *back) +{ + return iio_backend_op_call(back, ddr_enable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, IIO_BACKEND); + +/** + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode + * @back: Backend device + * + * Disable DDR, setting into SDR mode (Single Data Rate). + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_ddr_disable(struct iio_backend *back) +{ + return iio_backend_op_call(back, ddr_disable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND); + +/** + * iio_backend_data_stream_enable - Enable data stream + * @back: Backend device + * + * Enable data stream over the bus interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_stream_enable(struct iio_backend *back) +{ + return iio_backend_op_call(back, data_stream_enable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_enable, IIO_BACKEND); + +/** + * iio_backend_data_stream_disable - Disable data stream + * @back: Backend device + * + * Disable data stream over the bus interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_stream_disable(struct iio_backend *back) +{ + return iio_backend_op_call(back, data_stream_disable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_disable, IIO_BACKEND); + +/** + * iio_backend_data_transfer_addr - Set data address. + * @back: Backend device + * @address: Data register address + * + * Some devices may need to inform the backend about an address + * where to read or write the data. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address) +{ + return iio_backend_op_call(back, data_transfer_addr, address); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, IIO_BACKEND); + static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name, struct fwnode_handle *fwnode) { diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 6a6568d4a2cb..a2117ad1337d 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -95,6 +95,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_DELTA_VELOCITY] = "deltavelocity", [IIO_COLORTEMP] = "colortemp", [IIO_CHROMATICITY] = "chromaticity", + [IIO_ATTENTION] = "attention", }; static const char * const iio_modifier_names[] = { @@ -1665,7 +1666,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) indio_dev = &iio_dev_opaque->indio_dev; if (sizeof_priv) - indio_dev->priv = (char *)iio_dev_opaque + + ACCESS_PRIVATE(indio_dev, priv) = (char *)iio_dev_opaque + ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN); indio_dev->dev.parent = parent; diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index c38b3c603ab4..29ffa8491927 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -248,7 +248,6 @@ config SENSORS_ISL29018 tristate "Intersil 29018 light and proximity sensor" depends on I2C select REGMAP_I2C - default n help If you say yes here you get support for ambient light sensing and proximity infrared sensing from Intersil ISL29018. @@ -476,7 +475,7 @@ config OPT3001 depends on I2C help If you say Y or M here, you get support for Texas Instruments - OPT3001 Ambient Light Sensor. + OPT3001 Ambient Light Sensor, OPT3002 Light-to-Digital Sensor. If built as a dynamically linked module, it will be called opt3001. @@ -670,6 +669,17 @@ config VCNL4035 To compile this driver as a module, choose M here: the module will be called vcnl4035. +config VEML3235 + tristate "VEML3235 ambient light sensor" + select REGMAP_I2C + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML3235 + ambient light sensor. + + To compile this driver as a module, choose M here: the + module will be called veml3235. + config VEML6030 tristate "VEML6030 and VEML6035 ambient light sensors" select REGMAP_I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 321010fc0b93..f14a37442712 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_VCNL4035) += vcnl4035.o +obj-$(CONFIG_VEML3235) += veml3235.o obj-$(CONFIG_VEML6030) += veml6030.o obj-$(CONFIG_VEML6040) += veml6040.o obj-$(CONFIG_VEML6070) += veml6070.o diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index 2e0170be077a..593d614b1689 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -502,7 +502,8 @@ fail: static int adux1020_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 adux1020_data *data = iio_priv(indio_dev); int ret, mask; @@ -526,12 +527,11 @@ static int adux1020_write_event_config(struct iio_dev *indio_dev, mask = ADUX1020_PROX_OFF1_INT; if (state) - state = 0; + ret = regmap_clear_bits(data->regmap, + ADUX1020_REG_INT_MASK, mask); else - state = mask; - - ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK, - mask, state); + ret = regmap_set_bits(data->regmap, + ADUX1020_REG_INT_MASK, mask); if (ret < 0) goto fail; diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 11f2ab4ca261..938d76f7e312 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -46,10 +46,10 @@ struct apds9300_data { struct i2c_client *client; struct mutex mutex; - int power_state; + bool power_state; int thresh_low; int thresh_hi; - int intr_en; + bool intr_en; }; /* Lux calculation */ @@ -148,7 +148,7 @@ static int apds9300_set_thresh_hi(struct apds9300_data *data, int value) return 0; } -static int apds9300_set_intr_state(struct apds9300_data *data, int state) +static int apds9300_set_intr_state(struct apds9300_data *data, bool state) { int ret; u8 cmd; @@ -169,7 +169,7 @@ static int apds9300_set_intr_state(struct apds9300_data *data, int state) return 0; } -static int apds9300_set_power_state(struct apds9300_data *data, int state) +static int apds9300_set_power_state(struct apds9300_data *data, bool state) { int ret; u8 cmd; @@ -221,7 +221,7 @@ static int apds9300_chip_init(struct apds9300_data *data) * Disable interrupt to ensure thai it is doesn't enable * i.e. after device soft reset */ - ret = apds9300_set_intr_state(data, 0); + ret = apds9300_set_intr_state(data, false); if (ret < 0) goto err; @@ -321,7 +321,7 @@ static int apds9300_read_interrupt_config(struct iio_dev *indio_dev, static int apds9300_write_interrupt_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 apds9300_data *data = iio_priv(indio_dev); int ret; @@ -459,8 +459,8 @@ static void apds9300_remove(struct i2c_client *client) iio_device_unregister(indio_dev); /* Ensure that power off and interrupts are disabled */ - apds9300_set_intr_state(data, 0); - apds9300_set_power_state(data, 0); + apds9300_set_intr_state(data, false); + apds9300_set_power_state(data, false); } static int apds9300_suspend(struct device *dev) @@ -470,7 +470,7 @@ static int apds9300_suspend(struct device *dev) int ret; mutex_lock(&data->mutex); - ret = apds9300_set_power_state(data, 0); + ret = apds9300_set_power_state(data, false); mutex_unlock(&data->mutex); return ret; @@ -483,7 +483,7 @@ static int apds9300_resume(struct device *dev) int ret; mutex_lock(&data->mutex); - ret = apds9300_set_power_state(data, 1); + ret = apds9300_set_power_state(data, true); mutex_unlock(&data->mutex); return ret; diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 079e02be1005..9c08e7c3ad0c 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -1071,7 +1071,7 @@ static int apds9306_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 apds9306_data *data = iio_priv(indio_dev); struct apds9306_regfields *rf = &data->rf; @@ -1125,10 +1125,7 @@ static int apds9306_write_event_config(struct iio_dev *indio_dev, } } case IIO_EV_TYPE_THRESH_ADAPTIVE: - if (state) - return regmap_field_write(rf->int_thresh_var_en, 1); - else - return regmap_field_write(rf->int_thresh_var_en, 0); + return regmap_field_write(rf->int_thresh_var_en, state); default: return -EINVAL; } diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 3c14e4c30805..d30441d33703 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -133,8 +133,8 @@ struct apds9960_data { struct regmap_field *reg_enable_pxs; /* state */ - int als_int; - int pxs_int; + bool als_int; + bool pxs_int; int gesture_mode_running; /* gain values */ @@ -749,21 +749,17 @@ static int apds9960_read_event_config(struct iio_dev *indio_dev, default: return -EINVAL; } - - return 0; } static int apds9960_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 apds9960_data *data = iio_priv(indio_dev); int ret; - state = !!state; - switch (chan->type) { case IIO_PROXIMITY: if (data->pxs_int == state) diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c index 2e458e9d5d85..23e9f16090cc 100644 --- a/drivers/iio/light/bh1745.c +++ b/drivers/iio/light/bh1745.c @@ -638,46 +638,42 @@ static int bh1745_read_event_config(struct iio_dev *indio_dev, static int bh1745_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 bh1745_data *data = iio_priv(indio_dev); int value; - if (state == 0) + if (!state) return regmap_clear_bits(data->regmap, BH1745_INTR, BH1745_INTR_ENABLE); - if (state == 1) { - /* Latch is always enabled when enabling interrupt */ - value = BH1745_INTR_ENABLE; + /* Latch is always enabled when enabling interrupt */ + value = BH1745_INTR_ENABLE; - switch (chan->channel2) { - case IIO_MOD_LIGHT_RED: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_RED)); + switch (chan->channel2) { + case IIO_MOD_LIGHT_RED: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_RED)); - case IIO_MOD_LIGHT_GREEN: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_GREEN)); + case IIO_MOD_LIGHT_GREEN: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_GREEN)); - case IIO_MOD_LIGHT_BLUE: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_BLUE)); + case IIO_MOD_LIGHT_BLUE: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_BLUE)); - case IIO_MOD_LIGHT_CLEAR: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_CLEAR)); + case IIO_MOD_LIGHT_CLEAR: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_CLEAR)); - default: - return -EINVAL; - } + default: + return -EINVAL; } - - return -EINVAL; } static int bh1745_read_avail(struct iio_dev *indio_dev, diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index a4a1505534c0..ae3fc3299eec 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -529,7 +529,7 @@ static int cm36651_write_prox_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 cm36651_data *cm36651 = iio_priv(indio_dev); int cmd, ret; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index f8b1d7dd6f5f..d56ee217fe53 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -340,7 +340,7 @@ static int gp2ap002_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 gp2ap002 *gp2ap002 = iio_priv(indio_dev); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 81e718cdeae3..1a352c88598e 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1159,7 +1159,7 @@ static int gp2ap020a00f_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 gp2ap020a00f_data *data = iio_priv(indio_dev); enum gp2ap020a00f_cmd cmd; diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 8fe50f897169..e8e7b2999b4c 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -13,16 +13,32 @@ #include <linux/iio/buffer.h> #include "../common/hid-sensors/hid-sensor-trigger.h" -#define CHANNEL_SCAN_INDEX_PRESENCE 0 +static const u32 prox_usage_ids[] = { + HID_USAGE_SENSOR_HUMAN_PRESENCE, + HID_USAGE_SENSOR_HUMAN_PROXIMITY, + HID_USAGE_SENSOR_HUMAN_ATTENTION, +}; + +#define MAX_CHANNELS ARRAY_SIZE(prox_usage_ids) + +enum { + HID_HUMAN_PRESENCE, + HID_HUMAN_PROXIMITY, + HID_HUMAN_ATTENTION, +}; struct prox_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; - struct hid_sensor_hub_attribute_info prox_attr; - u32 human_presence; + struct hid_sensor_hub_attribute_info prox_attr[MAX_CHANNELS]; + struct iio_chan_spec channels[MAX_CHANNELS]; + u32 channel2usage[MAX_CHANNELS]; + u32 human_presence[MAX_CHANNELS]; int scale_pre_decml; int scale_post_decml; int scale_precision; + unsigned long scan_mask[2]; /* One entry plus one terminator. */ + int num_channels; }; static const u32 prox_sensitivity_addresses[] = { @@ -30,17 +46,24 @@ static const u32 prox_sensitivity_addresses[] = { HID_USAGE_SENSOR_DATA_PRESENCE, }; -/* Channel definitions */ -static const struct iio_chan_spec prox_channels[] = { - { - .type = IIO_PROXIMITY, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | - BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_PRESENCE, +#define PROX_CHANNEL(_is_proximity, _channel) \ + {\ + .type = _is_proximity ? IIO_PROXIMITY : IIO_ATTENTION,\ + .info_mask_separate = _is_proximity ? BIT(IIO_CHAN_INFO_RAW) :\ + BIT(IIO_CHAN_INFO_PROCESSED),\ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |\ + BIT(IIO_CHAN_INFO_SCALE) |\ + BIT(IIO_CHAN_INFO_SAMP_FREQ) |\ + BIT(IIO_CHAN_INFO_HYSTERESIS),\ + .indexed = _is_proximity,\ + .channel = _channel,\ } + +/* Channel definitions (same order as prox_usage_ids) */ +static const struct iio_chan_spec prox_channels[] = { + PROX_CHANNEL(true, HID_HUMAN_PRESENCE), + PROX_CHANNEL(true, HID_HUMAN_PROXIMITY), + PROX_CHANNEL(false, 0), }; /* Adjust channel real bits based on report descriptor */ @@ -62,7 +85,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, { struct prox_state *prox_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; - int report_id = -1; + int report_id; u32 address; int ret_type; s32 min; @@ -71,29 +94,23 @@ static int prox_read_raw(struct iio_dev *indio_dev, *val2 = 0; switch (mask) { case IIO_CHAN_INFO_RAW: - switch (chan->scan_index) { - case CHANNEL_SCAN_INDEX_PRESENCE: - report_id = prox_state->prox_attr.report_id; - min = prox_state->prox_attr.logical_minimum; - address = HID_USAGE_SENSOR_HUMAN_PRESENCE; - hsdev = prox_state->common_attributes.hsdev; - break; - default: - report_id = -1; - break; - } - if (report_id >= 0) { - hid_sensor_power_state(&prox_state->common_attributes, - true); - *val = sensor_hub_input_attr_get_raw_value( - hsdev, hsdev->usage, address, report_id, - SENSOR_HUB_SYNC, min < 0); - hid_sensor_power_state(&prox_state->common_attributes, - false); - } else { - *val = 0; + if (chan->scan_index >= prox_state->num_channels) return -EINVAL; - } + address = prox_state->channel2usage[chan->scan_index]; + report_id = prox_state->prox_attr[chan->scan_index].report_id; + hsdev = prox_state->common_attributes.hsdev; + min = prox_state->prox_attr[chan->scan_index].logical_minimum; + hid_sensor_power_state(&prox_state->common_attributes, true); + *val = sensor_hub_input_attr_get_raw_value(hsdev, + hsdev->usage, + address, + report_id, + SENSOR_HUB_SYNC, + min < 0); + if (prox_state->channel2usage[chan->scan_index] == + HID_USAGE_SENSOR_HUMAN_ATTENTION) + *val *= 100; + hid_sensor_power_state(&prox_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: @@ -103,7 +120,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_OFFSET: *val = hid_sensor_convert_exponent( - prox_state->prox_attr.unit_expo); + prox_state->prox_attr[chan->scan_index].unit_expo); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -153,14 +170,6 @@ static const struct iio_info prox_info = { .write_raw = &prox_write_raw, }; -/* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, - int len) -{ - dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, data); -} - /* Callback handler to send event after all samples are received and captured */ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, unsigned usage_id, @@ -170,10 +179,10 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, struct prox_state *prox_state = iio_priv(indio_dev); dev_dbg(&indio_dev->dev, "prox_proc_event\n"); - if (atomic_read(&prox_state->common_attributes.data_ready)) - hid_sensor_push_data(indio_dev, - &prox_state->human_presence, - sizeof(prox_state->human_presence)); + if (atomic_read(&prox_state->common_attributes.data_ready)) { + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + iio_push_to_buffers(indio_dev, &prox_state->human_presence); + } return 0; } @@ -186,48 +195,67 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct prox_state *prox_state = iio_priv(indio_dev); - int ret = -EINVAL; - - switch (usage_id) { - case HID_USAGE_SENSOR_HUMAN_PRESENCE: - switch (raw_len) { - case 1: - prox_state->human_presence = *(u8 *)raw_data; - return 0; - case 4: - prox_state->human_presence = *(u32 *)raw_data; - return 0; - default: + int multiplier = 1; + int chan; + + for (chan = 0; chan < prox_state->num_channels; chan++) + if (prox_state->channel2usage[chan] == usage_id) break; - } - break; + if (chan == prox_state->num_channels) + return -EINVAL; + + if (usage_id == HID_USAGE_SENSOR_HUMAN_ATTENTION) + multiplier = 100; + + switch (raw_len) { + case 1: + prox_state->human_presence[chan] = *(u8 *)raw_data * multiplier; + return 0; + case 4: + prox_state->human_presence[chan] = *(u32 *)raw_data * multiplier; + return 0; } - return ret; + return -EINVAL; } /* Parse report which is specific to an usage id*/ static int prox_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned usage_id, struct prox_state *st) { + struct iio_chan_spec *channels = st->channels; + int index = 0; int ret; + int i; + + for (i = 0; i < MAX_CHANNELS; i++) { + u32 usage_id = prox_usage_ids[i]; + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + hsdev->usage, + usage_id, + &st->prox_attr[index]); + if (ret < 0) + continue; + st->channel2usage[index] = usage_id; + st->scan_mask[0] |= BIT(index); + channels[index] = prox_channels[i]; + channels[index].scan_index = index; + prox_adjust_channel_bit_mask(channels, index, + st->prox_attr[index].size); + dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr[index].index, + st->prox_attr[index].report_id); + index++; + } - ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, - usage_id, - HID_USAGE_SENSOR_HUMAN_PRESENCE, - &st->prox_attr); - if (ret < 0) + if (!index) return ret; - prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE, - st->prox_attr.size); - dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index, - st->prox_attr.report_id); + st->num_channels = index; - return ret; + return 0; } /* Function to initialize the processing for usage id */ @@ -258,22 +286,15 @@ static int hid_prox_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = devm_kmemdup(&pdev->dev, prox_channels, - sizeof(prox_channels), GFP_KERNEL); - if (!indio_dev->channels) { - dev_err(&pdev->dev, "failed to duplicate channels\n"); - return -ENOMEM; - } - - ret = prox_parse_report(pdev, hsdev, - (struct iio_chan_spec *)indio_dev->channels, - hsdev->usage, prox_state); + ret = prox_parse_report(pdev, hsdev, prox_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; } - indio_dev->num_channels = ARRAY_SIZE(prox_channels); + indio_dev->num_channels = prox_state->num_channels; + indio_dev->channels = prox_state->channels; + indio_dev->available_scan_masks = prox_state->scan_mask; indio_dev->info = &prox_info; indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c index 6de33feada3a..b9f230210f07 100644 --- a/drivers/iio/light/iqs621-als.c +++ b/drivers/iio/light/iqs621-als.c @@ -271,7 +271,7 @@ static int iqs621_als_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 iqs621_als_private *iqs621_als = iio_priv(indio_dev); struct iqs62x_core *iqs62x = iqs621_als->iqs62x; diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 8dfc750e68c0..201eae1c4589 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -8,17 +8,18 @@ * Copyright (c) 2010, NVIDIA Corporation. */ -#include <linux/module.h> #include <linux/i2c.h> #include <linux/err.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/mutex.h> #include <linux/delay.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> + #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/acpi.h> #define ISL29018_CONV_TIME_MS 100 @@ -687,20 +688,6 @@ static const struct isl29018_chip_info isl29018_chip_info_tbl[] = { }, }; -static const char *isl29018_match_acpi_device(struct device *dev, int *data) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - - if (!id) - return NULL; - - *data = (int)id->driver_data; - - return dev_name(dev); -} - static void isl29018_disable_regulator_action(void *_data) { struct isl29018_chip *chip = _data; @@ -716,9 +703,10 @@ static int isl29018_probe(struct i2c_client *client) const struct i2c_device_id *id = i2c_client_get_device_id(client); struct isl29018_chip *chip; struct iio_dev *indio_dev; + const void *ddata = NULL; + const char *name; + int dev_id; int err; - const char *name = NULL; - int dev_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); if (!indio_dev) @@ -731,11 +719,11 @@ static int isl29018_probe(struct i2c_client *client) if (id) { name = id->name; dev_id = id->driver_data; + } else { + name = iio_get_acpi_device_name_and_data(&client->dev, &ddata); + dev_id = (intptr_t)ddata; } - if (ACPI_HANDLE(&client->dev)) - name = isl29018_match_acpi_device(&client->dev, &dev_id); - mutex_init(&chip->lock); chip->type = dev_id; @@ -832,15 +820,13 @@ static int isl29018_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); -#ifdef CONFIG_ACPI static const struct acpi_device_id isl29018_acpi_match[] = { {"ISL29018", isl29018}, {"ISL29023", isl29023}, {"ISL29035", isl29035}, - {}, + {} }; MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); -#endif static const struct i2c_device_id isl29018_id[] = { {"isl29018", isl29018}, @@ -854,14 +840,14 @@ static const struct of_device_id isl29018_of_match[] = { { .compatible = "isil,isl29018", }, { .compatible = "isil,isl29023", }, { .compatible = "isil,isl29035", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, isl29018_of_match); static struct i2c_driver isl29018_driver = { .driver = { .name = "isl29018", - .acpi_match_table = ACPI_PTR(isl29018_acpi_match), + .acpi_match_table = isl29018_acpi_match, .pm = pm_sleep_ptr(&isl29018_pm_ops), .of_match_table = isl29018_of_match, }, diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index 8e0a3fc3d923..df664f360903 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -553,15 +553,12 @@ static int ltr390_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 ltr390_data *data = iio_priv(indio_dev); int ret; - if (state != 1 && state != 0) - return -EINVAL; - - if (state == 0) + if (!state) return regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); guard(mutex)(&data->lock); diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 8c516ede9116..604f5f900a2e 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -15,7 +15,6 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/regmap.h> -#include <linux/acpi.h> #include <linux/regulator/consumer.h> #include <linux/iio/iio.h> @@ -1078,15 +1077,11 @@ static int ltr501_read_event_config(struct iio_dev *indio_dev, static int ltr501_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 ltr501_data *data = iio_priv(indio_dev); int ret; - /* only 1 and 0 are valid inputs */ - if (state != 1 && state != 0) - return -EINVAL; - switch (chan->type) { case IIO_INTENSITY: mutex_lock(&data->lock_als); @@ -1422,17 +1417,6 @@ static int ltr501_powerdown(struct ltr501_data *data) data->ps_contr & ~LTR501_CONTR_ACTIVE); } -static const char *ltr501_match_acpi_device(struct device *dev, int *chip_idx) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - *chip_idx = id->driver_data; - return dev_name(dev); -} - static int ltr501_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -1440,8 +1424,10 @@ static int ltr501_probe(struct i2c_client *client) struct ltr501_data *data; struct iio_dev *indio_dev; struct regmap *regmap; - int ret, partid, chip_idx = 0; - const char *name = NULL; + const void *ddata = NULL; + int partid, chip_idx; + const char *name; + int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1523,11 +1509,12 @@ static int ltr501_probe(struct i2c_client *client) if (id) { name = id->name; chip_idx = id->driver_data; - } else if (ACPI_HANDLE(&client->dev)) { - name = ltr501_match_acpi_device(&client->dev, &chip_idx); } else { - return -ENODEV; + name = iio_get_acpi_device_name_and_data(&client->dev, &ddata); + chip_idx = (intptr_t)ddata; } + if (!name) + return -ENODEV; data->chip_info = <r501_chip_info_tbl[chip_idx]; @@ -1610,9 +1597,9 @@ static int ltr501_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume); static const struct acpi_device_id ltr_acpi_match[] = { - { "LTER0501", ltr501 }, - { "LTER0559", ltr559 }, { "LTER0301", ltr301 }, + /* https://www.catalog.update.microsoft.com/Search.aspx?q=lter0303 */ + { "LTER0303", ltr303 }, { }, }; MODULE_DEVICE_TABLE(acpi, ltr_acpi_match); diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 3b92362675dc..8cd7f5664e5b 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -422,7 +422,7 @@ static int max44009_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 max44009_data *data = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index 176e54bb48c3..65b295877b41 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -70,6 +70,35 @@ #define OPT3001_RESULT_READY_SHORT 150 #define OPT3001_RESULT_READY_LONG 1000 +struct opt3001_scale { + int val; + int val2; +}; + +struct opt3001_chip_info { + const struct iio_chan_spec (*channels)[2]; + enum iio_chan_type chan_type; + int num_channels; + + const struct opt3001_scale (*scales)[12]; + /* + * Factor as specified by conversion equation in datasheet. + * eg. 0.01 (scaled to integer 10) for opt3001. + */ + int factor_whole; + /* + * Factor to compensate for potentially scaled factor_whole. + */ + int factor_integer; + /* + * Factor used to align decimal part of proccessed value to six decimal + * places. + */ + int factor_decimal; + + bool has_id; +}; + struct opt3001 { struct i2c_client *client; struct device *dev; @@ -79,6 +108,7 @@ struct opt3001 { bool result_ready; wait_queue_head_t result_ready_queue; u16 result; + const struct opt3001_chip_info *chip_info; u32 int_time; u32 mode; @@ -92,11 +122,6 @@ struct opt3001 { bool use_irq; }; -struct opt3001_scale { - int val; - int val2; -}; - static const struct opt3001_scale opt3001_scales[] = { { .val = 40, @@ -148,21 +173,68 @@ static const struct opt3001_scale opt3001_scales[] = { }, }; +static const struct opt3001_scale opt3002_scales[] = { + { + .val = 4914, + .val2 = 0, + }, + { + .val = 9828, + .val2 = 0, + }, + { + .val = 19656, + .val2 = 0, + }, + { + .val = 39312, + .val2 = 0, + }, + { + .val = 78624, + .val2 = 0, + }, + { + .val = 157248, + .val2 = 0, + }, + { + .val = 314496, + .val2 = 0, + }, + { + .val = 628992, + .val2 = 0, + }, + { + .val = 1257984, + .val2 = 0, + }, + { + .val = 2515968, + .val2 = 0, + }, + { + .val = 5031936, + .val2 = 0, + }, + { + .val = 10063872, + .val2 = 0, + }, +}; + static int opt3001_find_scale(const struct opt3001 *opt, int val, int val2, u8 *exponent) { int i; - - for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) { - const struct opt3001_scale *scale = &opt3001_scales[i]; - + for (i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) { + const struct opt3001_scale *scale = &(*opt->chip_info->scales)[i]; /* - * Combine the integer and micro parts for comparison - * purposes. Use milli lux precision to avoid 32-bit integer - * overflows. + * Compare the integer and micro parts to determine value scale. */ - if ((val * 1000 + val2 / 1000) <= - (scale->val * 1000 + scale->val2 / 1000)) { + if (val < scale->val || + (val == scale->val && val2 <= scale->val2)) { *exponent = i; return 0; } @@ -174,11 +246,14 @@ static int opt3001_find_scale(const struct opt3001 *opt, int val, static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, u16 mantissa, int *val, int *val2) { - int lux; + int ret; + int whole = opt->chip_info->factor_whole; + int integer = opt->chip_info->factor_integer; + int decimal = opt->chip_info->factor_decimal; - lux = 10 * (mantissa << exponent); - *val = lux / 1000; - *val2 = (lux - (*val * 1000)) * 1000; + ret = whole * (mantissa << exponent); + *val = ret / integer; + *val2 = (ret - (*val * integer)) * decimal; } static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode) @@ -225,7 +300,18 @@ static const struct iio_chan_spec opt3001_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), }; -static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2) +static const struct iio_chan_spec opt3002_channels[] = { + { + .type = IIO_INTENSITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME), + .event_spec = opt3001_event_spec, + .num_event_specs = ARRAY_SIZE(opt3001_event_spec), + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2) { int ret; u16 mantissa; @@ -397,14 +483,15 @@ static int opt3001_read_raw(struct iio_dev *iio, if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; - if (chan->type != IIO_LIGHT) + if (chan->type != opt->chip_info->chan_type) return -EINVAL; mutex_lock(&opt->lock); switch (mask) { + case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: - ret = opt3001_get_lux(opt, val, val2); + ret = opt3001_get_processed(opt, val, val2); break; case IIO_CHAN_INFO_INT_TIME: ret = opt3001_get_int_time(opt, val, val2); @@ -428,7 +515,7 @@ static int opt3001_write_raw(struct iio_dev *iio, if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; - if (chan->type != IIO_LIGHT) + if (chan->type != opt->chip_info->chan_type) return -EINVAL; if (mask != IIO_CHAN_INFO_INT_TIME) @@ -479,6 +566,9 @@ static int opt3001_write_event_value(struct iio_dev *iio, { struct opt3001 *opt = iio_priv(iio); int ret; + int whole; + int integer; + int decimal; u16 mantissa; u16 value; @@ -497,7 +587,12 @@ static int opt3001_write_event_value(struct iio_dev *iio, goto err; } - mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent; + whole = opt->chip_info->factor_whole; + integer = opt->chip_info->factor_integer; + decimal = opt->chip_info->factor_decimal; + + mantissa = (((val * integer) + (val2 / decimal)) / whole) >> exponent; + value = (exponent << 12) | mantissa; switch (dir) { @@ -539,7 +634,7 @@ static int opt3001_read_event_config(struct iio_dev *iio, static int opt3001_write_event_config(struct iio_dev *iio, 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 opt3001 *opt = iio_priv(iio); int ret; @@ -610,7 +705,7 @@ static int opt3001_read_id(struct opt3001 *opt) ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID); if (ret < 0) { dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_DEVICE_ID); + OPT3001_DEVICE_ID); return ret; } @@ -692,6 +787,7 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) struct opt3001 *opt = iio_priv(iio); int ret; bool wake_result_ready_queue = false; + enum iio_chan_type chan_type = opt->chip_info->chan_type; if (!opt->ok_to_ignore_lock) mutex_lock(&opt->lock); @@ -707,13 +803,13 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) OPT3001_CONFIGURATION_M_CONTINUOUS) { if (ret & OPT3001_CONFIGURATION_FH) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_UNMOD_EVENT_CODE(chan_type, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), iio_get_time_ns(iio)); if (ret & OPT3001_CONFIGURATION_FL) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_UNMOD_EVENT_CODE(chan_type, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), iio_get_time_ns(iio)); @@ -755,22 +851,25 @@ static int opt3001_probe(struct i2c_client *client) opt = iio_priv(iio); opt->client = client; opt->dev = dev; + opt->chip_info = i2c_get_match_data(client); mutex_init(&opt->lock); init_waitqueue_head(&opt->result_ready_queue); i2c_set_clientdata(client, iio); - ret = opt3001_read_id(opt); - if (ret) - return ret; + if (opt->chip_info->has_id) { + ret = opt3001_read_id(opt); + if (ret) + return ret; + } ret = opt3001_configure(opt); if (ret) return ret; iio->name = client->name; - iio->channels = opt3001_channels; - iio->num_channels = ARRAY_SIZE(opt3001_channels); + iio->channels = *opt->chip_info->channels; + iio->num_channels = opt->chip_info->num_channels; iio->modes = INDIO_DIRECT_MODE; iio->info = &opt3001_info; @@ -825,14 +924,38 @@ static void opt3001_remove(struct i2c_client *client) } } +static const struct opt3001_chip_info opt3001_chip_information = { + .channels = &opt3001_channels, + .chan_type = IIO_LIGHT, + .num_channels = ARRAY_SIZE(opt3001_channels), + .scales = &opt3001_scales, + .factor_whole = 10, + .factor_integer = 1000, + .factor_decimal = 1000, + .has_id = true, +}; + +static const struct opt3001_chip_info opt3002_chip_information = { + .channels = &opt3002_channels, + .chan_type = IIO_INTENSITY, + .num_channels = ARRAY_SIZE(opt3002_channels), + .scales = &opt3002_scales, + .factor_whole = 12, + .factor_integer = 10, + .factor_decimal = 100000, + .has_id = false, +}; + static const struct i2c_device_id opt3001_id[] = { - { "opt3001" }, + { "opt3001", (kernel_ulong_t)&opt3001_chip_information }, + { "opt3002", (kernel_ulong_t)&opt3002_chip_information }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(i2c, opt3001_id); static const struct of_device_id opt3001_of_match[] = { - { .compatible = "ti,opt3001" }, + { .compatible = "ti,opt3001", .data = &opt3001_chip_information }, + { .compatible = "ti,opt3002", .data = &opt3002_chip_information }, { } }; MODULE_DEVICE_TABLE(of, opt3001_of_match); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index ed20b6714546..b81cc44db43c 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -324,15 +324,12 @@ static int stk3310_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) { int ret; struct stk3310_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; - if (state < 0 || state > 7) - return -EINVAL; - /* Set INT_PS value */ mutex_lock(&data->lock); ret = regmap_field_write(data->reg_int_ps, state); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 04452b4664f3..4186aac04902 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -327,7 +327,7 @@ static int tcs3472_read_event_config(struct iio_dev *indio_dev, static int tcs3472_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 tcs3472_data *data = iio_priv(indio_dev); int ret = 0; diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 1a6f514bced6..f1fe7640fce6 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -630,7 +630,7 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private) static int tsl2563_write_interrupt_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 tsl2563_chip *chip = iio_priv(indio_dev); int ret = 0; diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index 850c2465992f..b81ca6f73f92 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -985,7 +985,7 @@ static int tsl2591_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 tsl2591_chip *chip = iio_priv(indio_dev); struct i2c_client *client = chip->client; diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index cab468a82b61..349afdcbe30d 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -1081,14 +1081,14 @@ static int tsl2772_write_interrupt_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int val) + bool val) { struct tsl2772_chip *chip = iio_priv(indio_dev); if (chan->type == IIO_INTENSITY) - chip->settings.als_interrupt_en = val ? true : false; + chip->settings.als_interrupt_en = val; else - chip->settings.prox_interrupt_en = val ? true : false; + chip->settings.prox_interrupt_en = val; return tsl2772_invoke_change(indio_dev); } diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index de6967ac3b0b..c83114aed6b2 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -627,7 +627,7 @@ static int us5182d_read_event_config(struct iio_dev *indio_dev, static int us5182d_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 us5182d_data *data = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 4e3641ff2ed4..e19199b17f2e 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1456,7 +1456,7 @@ static int vcnl4010_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) { switch (chan->type) { case IIO_PROXIMITY: @@ -1501,7 +1501,8 @@ static int vcnl4040_read_event_config(struct iio_dev *indio_dev, static int vcnl4040_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) { int ret = -EINVAL; u16 val, mask; diff --git a/drivers/iio/light/veml3235.c b/drivers/iio/light/veml3235.c new file mode 100644 index 000000000000..66361c3012a3 --- /dev/null +++ b/drivers/iio/light/veml3235.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * VEML3235 Ambient Light Sensor + * + * Copyright (c) 2024, Javier Carrasco <javier.carrasco.cruz@gmail.com> + * + * Datasheet: https://www.vishay.com/docs/80131/veml3235.pdf + * Appnote-80222: https://www.vishay.com/docs/80222/designingveml3235.pdf + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#define VEML3235_REG_CONF 0x00 +#define VEML3235_REG_WH_DATA 0x04 +#define VEML3235_REG_ALS_DATA 0x05 +#define VEML3235_REG_ID 0x09 + +#define VEML3235_CONF_SD BIT(0) +#define VEML3235_CONF_SD0 BIT(15) + +struct veml3235_rf { + struct regmap_field *it; + struct regmap_field *gain; + struct regmap_field *id; +}; + +struct veml3235_data { + struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + struct veml3235_rf rf; +}; + +static const int veml3235_it_times[][2] = { + { 0, 50000 }, + { 0, 100000 }, + { 0, 200000 }, + { 0, 400000 }, + { 0, 800000 }, +}; + +static const int veml3235_scale_vals[] = { 1, 2, 4, 8 }; + +static int veml3235_power_on(struct veml3235_data *data) +{ + int ret; + + ret = regmap_clear_bits(data->regmap, VEML3235_REG_CONF, + VEML3235_CONF_SD | VEML3235_CONF_SD0); + if (ret) + return ret; + + /* Wait 4 ms to let processor & oscillator start correctly */ + fsleep(4000); + + return 0; +} + +static int veml3235_shut_down(struct veml3235_data *data) +{ + return regmap_set_bits(data->regmap, VEML3235_REG_CONF, + VEML3235_CONF_SD | VEML3235_CONF_SD0); +} + +static void veml3235_shut_down_action(void *data) +{ + veml3235_shut_down(data); +} + +enum veml3235_chan { + CH_ALS, + CH_WHITE, +}; + +static const struct iio_chan_spec veml3235_channels[] = { + { + .type = IIO_LIGHT, + .channel = CH_ALS, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_INTENSITY, + .channel = CH_WHITE, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static const struct regmap_config veml3235_regmap_config = { + .name = "veml3235_regmap", + .reg_bits = 8, + .val_bits = 16, + .max_register = VEML3235_REG_ID, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2) +{ + int ret, reg; + + ret = regmap_field_read(data->rf.it, ®); + if (ret) + return ret; + + switch (reg) { + case 0: + *val2 = 50000; + break; + case 1: + *val2 = 100000; + break; + case 2: + *val2 = 200000; + break; + case 3: + *val2 = 400000; + break; + case 4: + *val2 = 800000; + break; + default: + return -EINVAL; + } + + *val = 0; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml3235_set_it(struct iio_dev *indio_dev, int val, int val2) +{ + struct veml3235_data *data = iio_priv(indio_dev); + int ret, new_it; + + if (val) + return -EINVAL; + + switch (val2) { + case 50000: + new_it = 0x00; + break; + case 100000: + new_it = 0x01; + break; + case 200000: + new_it = 0x02; + break; + case 400000: + new_it = 0x03; + break; + case 800000: + new_it = 0x04; + break; + default: + return -EINVAL; + } + + ret = regmap_field_write(data->rf.it, new_it); + if (ret) { + dev_err(data->dev, + "failed to update integration time: %d\n", ret); + return ret; + } + + return 0; +} + +static int veml3235_set_gain(struct iio_dev *indio_dev, int val, int val2) +{ + struct veml3235_data *data = iio_priv(indio_dev); + int ret, new_gain; + + if (val2 != 0) + return -EINVAL; + + switch (val) { + case 1: + new_gain = 0x00; + break; + case 2: + new_gain = 0x01; + break; + case 4: + new_gain = 0x03; + break; + case 8: + new_gain = 0x07; + break; + default: + return -EINVAL; + } + + ret = regmap_field_write(data->rf.gain, new_gain); + if (ret) { + dev_err(data->dev, "failed to set gain: %d\n", ret); + return ret; + } + + return 0; +} + +static int veml3235_get_gain(struct veml3235_data *data, int *val) +{ + int ret, reg; + + ret = regmap_field_read(data->rf.gain, ®); + if (ret) { + dev_err(data->dev, "failed to read gain %d\n", ret); + return ret; + } + + switch (reg & 0x03) { + case 0: + *val = 1; + break; + case 1: + *val = 2; + break; + case 3: + *val = 4; + break; + default: + return -EINVAL; + } + + /* Double gain */ + if (reg & 0x04) + *val *= 2; + + return IIO_VAL_INT; +} + +static int veml3235_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct veml3235_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + int ret, reg; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_LIGHT: + ret = regmap_read(regmap, VEML3235_REG_ALS_DATA, ®); + if (ret < 0) + return ret; + + *val = reg; + return IIO_VAL_INT; + case IIO_INTENSITY: + ret = regmap_read(regmap, VEML3235_REG_WH_DATA, ®); + if (ret < 0) + return ret; + + *val = reg; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_INT_TIME: + return veml3235_get_it(data, val, val2); + case IIO_CHAN_INFO_SCALE: + return veml3235_get_gain(data, val); + default: + return -EINVAL; + } +} + +static int veml3235_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *vals = (int *)&veml3235_it_times; + *length = 2 * ARRAY_SIZE(veml3235_it_times); + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (int *)&veml3235_scale_vals; + *length = ARRAY_SIZE(veml3235_scale_vals); + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int veml3235_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return veml3235_set_it(indio_dev, val, val2); + case IIO_CHAN_INFO_SCALE: + return veml3235_set_gain(indio_dev, val, val2); + } + + return -EINVAL; +} + +static void veml3235_read_id(struct veml3235_data *data) +{ + int ret, reg; + + ret = regmap_field_read(data->rf.id, ®); + if (ret) { + dev_info(data->dev, "failed to read ID\n"); + return; + } + + if (reg != 0x35) + dev_info(data->dev, "Unknown ID %d\n", reg); +} + +static const struct reg_field veml3235_rf_it = + REG_FIELD(VEML3235_REG_CONF, 4, 6); + +static const struct reg_field veml3235_rf_gain = + REG_FIELD(VEML3235_REG_CONF, 11, 13); + +static const struct reg_field veml3235_rf_id = + REG_FIELD(VEML3235_REG_ID, 0, 7); + +static int veml3235_regfield_init(struct veml3235_data *data) +{ + struct regmap *regmap = data->regmap; + struct device *dev = data->dev; + struct regmap_field *rm_field; + struct veml3235_rf *rf = &data->rf; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_it); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->it = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_gain); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->gain = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_id); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->id = rm_field; + + return 0; +} + +static int veml3235_hw_init(struct iio_dev *indio_dev) +{ + struct veml3235_data *data = iio_priv(indio_dev); + struct device *dev = data->dev; + int ret; + + /* Set gain to 1 and integration time to 100 ms */ + ret = regmap_field_write(data->rf.gain, 0x00); + if (ret) + return dev_err_probe(data->dev, ret, "failed to set gain\n"); + + ret = regmap_field_write(data->rf.it, 0x01); + if (ret) + return dev_err_probe(data->dev, ret, + "failed to set integration time\n"); + + ret = veml3235_power_on(data); + if (ret) + return dev_err_probe(dev, ret, "failed to power on\n"); + + return devm_add_action_or_reset(dev, veml3235_shut_down_action, data); +} + +static const struct iio_info veml3235_info = { + .read_raw = veml3235_read_raw, + .read_avail = veml3235_read_avail, + .write_raw = veml3235_write_raw, +}; + +static int veml3235_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct veml3235_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(client, &veml3235_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "failed to setup regmap\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + data->dev = dev; + data->regmap = regmap; + + ret = veml3235_regfield_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to init regfield\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable regulator\n"); + + indio_dev->name = "veml3235"; + indio_dev->channels = veml3235_channels; + indio_dev->num_channels = ARRAY_SIZE(veml3235_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &veml3235_info; + + veml3235_read_id(data); + + ret = veml3235_hw_init(indio_dev); + if (ret < 0) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static int veml3235_runtime_suspend(struct device *dev) +{ + struct veml3235_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3235_shut_down(data); + if (ret < 0) + dev_err(data->dev, "failed to suspend: %d\n", ret); + + return ret; +} + +static int veml3235_runtime_resume(struct device *dev) +{ + struct veml3235_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3235_power_on(data); + if (ret < 0) + dev_err(data->dev, "failed to resume: %d\n", ret); + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(veml3235_pm_ops, veml3235_runtime_suspend, + veml3235_runtime_resume, NULL); + +static const struct of_device_id veml3235_of_match[] = { + { .compatible = "vishay,veml3235" }, + { } +}; +MODULE_DEVICE_TABLE(of, veml3235_of_match); + +static const struct i2c_device_id veml3235_id[] = { + { "veml3235" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, veml3235_id); + +static struct i2c_driver veml3235_driver = { + .driver = { + .name = "veml3235", + .of_match_table = veml3235_of_match, + .pm = pm_ptr(&veml3235_pm_ops), + }, + .probe = veml3235_probe, + .id_table = veml3235_id, +}; +module_i2c_driver(veml3235_driver); + +MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gmail.com>"); +MODULE_DESCRIPTION("VEML3235 Ambient Light Sensor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index a0bf03e37df7..ccb43dfd5cf7 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -821,14 +821,11 @@ static int veml6030_read_interrupt_config(struct iio_dev *indio_dev, */ static int veml6030_write_interrupt_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) { int ret; struct veml6030_data *data = iio_priv(indio_dev); - if (state < 0 || state > 1) - return -EINVAL; - ret = veml6030_als_shut_down(data); if (ret < 0) { dev_err(&data->client->dev, diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index 898e285322d4..6d4483c85f30 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -6,14 +6,16 @@ * * IIO driver for VEML6070 (7-bit I2C slave addresses 0x38 and 0x39) * - * TODO: integration time, ACK signal + * TODO: ACK signal */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/units.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -28,18 +30,79 @@ #define VEML6070_COMMAND_RSRVD BIT(1) /* reserved, set to 1 */ #define VEML6070_COMMAND_SD BIT(0) /* shutdown mode when set */ -#define VEML6070_IT_10 0x04 /* integration time 1x */ +#define VEML6070_IT_05 0x00 +#define VEML6070_IT_10 0x01 +#define VEML6070_IT_20 0x02 +#define VEML6070_IT_40 0x03 + +#define VEML6070_MIN_RSET_KOHM 75 +#define VEML6070_MIN_IT_US 15625 /* Rset = 75 kohm, IT = 1/2 */ struct veml6070_data { struct i2c_client *client1; struct i2c_client *client2; u8 config; struct mutex lock; + u32 rset; + int it[4][2]; }; +static int veml6070_calc_it(struct device *dev, struct veml6070_data *data) +{ + int i, tmp_it; + + data->rset = 270000; + device_property_read_u32(dev, "vishay,rset-ohms", &data->rset); + + if (data->rset < 75000 || data->rset > 1200000) + return dev_err_probe(dev, -EINVAL, "Rset out of range\n"); + + /* + * convert to kohm to avoid overflows and work with the same units as + * in the datasheet and simplify UVI operations. + */ + data->rset /= KILO; + + tmp_it = VEML6070_MIN_IT_US * data->rset / VEML6070_MIN_RSET_KOHM; + for (i = 0; i < ARRAY_SIZE(data->it); i++) { + data->it[i][0] = (tmp_it << i) / MICRO; + data->it[i][1] = (tmp_it << i) % MICRO; + } + + return 0; +} + +static int veml6070_get_it(struct veml6070_data *data, int *val, int *val2) +{ + int it_idx = FIELD_GET(VEML6070_COMMAND_IT, data->config); + + *val = data->it[it_idx][0]; + *val2 = data->it[it_idx][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml6070_set_it(struct veml6070_data *data, int val, int val2) +{ + int it_idx; + + for (it_idx = 0; it_idx < ARRAY_SIZE(data->it); it_idx++) { + if (data->it[it_idx][0] == val && data->it[it_idx][1] == val2) + break; + } + + if (it_idx >= ARRAY_SIZE(data->it)) + return -EINVAL; + + data->config = (data->config & ~VEML6070_COMMAND_IT) | + FIELD_PREP(VEML6070_COMMAND_IT, it_idx); + + return i2c_smbus_write_byte(data->client1, data->config); +} + static int veml6070_read(struct veml6070_data *data) { - int ret; + int ret, it_ms, val, val2; u8 msb, lsb; guard(mutex)(&data->lock); @@ -50,7 +113,9 @@ static int veml6070_read(struct veml6070_data *data) if (ret < 0) return ret; - msleep(125 + 10); /* measurement takes up to 125 ms for IT 1x */ + veml6070_get_it(data, &val, &val2); + it_ms = val * MILLI + val2 / (MICRO / MILLI); + msleep(it_ms + 10); ret = i2c_smbus_read_byte(data->client2); /* read MSB, address 0x39 */ if (ret < 0) @@ -80,26 +145,37 @@ static const struct iio_chan_spec veml6070_channels[] = { .modified = 1, .channel2 = IIO_MOD_LIGHT_UV, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), }, { .type = IIO_UVINDEX, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), } }; -static int veml6070_to_uv_index(unsigned val) +static int veml6070_to_uv_index(struct veml6070_data *data, unsigned int val) { /* * conversion of raw UV intensity values to UV index depends on * integration time (IT) and value of the resistor connected to - * the RSET pin (default: 270 KOhm) + * the RSET pin. */ - unsigned uvi[11] = { + unsigned int uvi[11] = { 187, 373, 560, /* low */ 746, 933, 1120, /* moderate */ 1308, 1494, /* high */ 1681, 1868, 2054}; /* very high */ - int i; + int i, it_idx; + + it_idx = FIELD_GET(VEML6070_COMMAND_IT, data->config); + + if (!it_idx) + val = (val * 270 / data->rset) << 1; + else + val = (val * 270 / data->rset) >> (it_idx - 1); for (i = 0; i < ARRAY_SIZE(uvi); i++) if (val <= uvi[i]) @@ -122,10 +198,44 @@ static int veml6070_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; if (mask == IIO_CHAN_INFO_PROCESSED) - *val = veml6070_to_uv_index(ret); + *val = veml6070_to_uv_index(data, ret); else *val = ret; return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + return veml6070_get_it(data, val, val2); + default: + return -EINVAL; + } +} + +static int veml6070_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct veml6070_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *vals = (int *)data->it; + *length = 2 * ARRAY_SIZE(data->it); + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int veml6070_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct veml6070_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return veml6070_set_it(data, val, val2); default: return -EINVAL; } @@ -133,6 +243,8 @@ static int veml6070_read_raw(struct iio_dev *indio_dev, static const struct iio_info veml6070_info = { .read_raw = veml6070_read_raw, + .read_avail = veml6070_read_avail, + .write_raw = veml6070_write_raw, }; static void veml6070_i2c_unreg(void *p) @@ -163,6 +275,10 @@ static int veml6070_probe(struct i2c_client *client) indio_dev->name = VEML6070_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; + ret = veml6070_calc_it(&client->dev, data); + if (ret < 0) + return ret; + ret = devm_regulator_get_enable(&client->dev, "vdd"); if (ret < 0) return ret; @@ -172,8 +288,8 @@ static int veml6070_probe(struct i2c_client *client) return dev_err_probe(&client->dev, PTR_ERR(data->client2), "i2c device for second chip address failed\n"); - data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD | - VEML6070_COMMAND_SD; + data->config = FIELD_PREP(VEML6070_COMMAND_IT, VEML6070_IT_10) | + VEML6070_COMMAND_RSRVD | VEML6070_COMMAND_SD; ret = i2c_smbus_write_byte(data->client1, data->config); if (ret < 0) return ret; diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index f69ac75500f9..7177cd1d67cb 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -54,6 +54,19 @@ config AK09911 help Deprecated: AK09911 is now supported by AK8975 driver. +config ALS31300 + tristate "Allegro MicroSystems ALS31300 3-D Linear Hall Effect Sensor" + depends on I2C + select REGMAP_I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Allegro MicroSystems + ALS31300 Hall Effect Sensor through its I2C interface. + + To compile this driver as a module, choose M here: the + module will be called als31300. + config BMC150_MAGN tristate select IIO_BUFFER diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index ec5c46fbf999..3e4c2ecd9adf 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_AF8133J) += af8133j.o obj-$(CONFIG_AK8974) += ak8974.o obj-$(CONFIG_AK8975) += ak8975.o +obj-$(CONFIG_ALS31300) += als31300.o obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o obj-$(CONFIG_BMC150_MAGN_I2C) += bmc150_magn_i2c.o obj-$(CONFIG_BMC150_MAGN_SPI) += bmc150_magn_spi.o diff --git a/drivers/iio/magnetometer/als31300.c b/drivers/iio/magnetometer/als31300.c new file mode 100644 index 000000000000..87b60c4e81fa --- /dev/null +++ b/drivers/iio/magnetometer/als31300.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the Allegro MicroSystems ALS31300 3-D Linear Hall Effect Sensor + * + * Copyright (c) 2024 Linaro Limited + */ + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +/* + * The Allegro MicroSystems ALS31300 has an EEPROM space to configure how + * the device works and how the interrupt line behaves. + * Only the default setup with external trigger is supported. + * + * While the bindings supports declaring an interrupt line, those + * events are not supported. + * + * It should be possible to adapt the driver to the current + * device EEPROM setup at runtime. + */ + +#define ALS31300_EEPROM_CONFIG 0x02 +#define ALS31300_EEPROM_INTERRUPT 0x03 +#define ALS31300_EEPROM_CUSTOMER_1 0x0d +#define ALS31300_EEPROM_CUSTOMER_2 0x0e +#define ALS31300_EEPROM_CUSTOMER_3 0x0f +#define ALS31300_VOL_MODE 0x27 +#define ALS31300_VOL_MODE_LPDCM GENMASK(6, 4) +#define ALS31300_LPDCM_INACTIVE_0_5_MS 0 +#define ALS31300_LPDCM_INACTIVE_1_0_MS 1 +#define ALS31300_LPDCM_INACTIVE_5_0_MS 2 +#define ALS31300_LPDCM_INACTIVE_10_0_MS 3 +#define ALS31300_LPDCM_INACTIVE_50_0_MS 4 +#define ALS31300_LPDCM_INACTIVE_100_0_MS 5 +#define ALS31300_LPDCM_INACTIVE_500_0_MS 6 +#define ALS31300_LPDCM_INACTIVE_1000_0_MS 7 +#define ALS31300_VOL_MODE_SLEEP GENMASK(1, 0) +#define ALS31300_VOL_MODE_ACTIVE_MODE 0 +#define ALS31300_VOL_MODE_SLEEP_MODE 1 +#define ALS31300_VOL_MODE_LPDCM_MODE 2 +#define ALS31300_VOL_MSB 0x28 +#define ALS31300_VOL_MSB_TEMPERATURE GENMASK(5, 0) +#define ALS31300_VOL_MSB_INTERRUPT BIT(6) +#define ALS31300_VOL_MSB_NEW_DATA BIT(7) +#define ALS31300_VOL_MSB_Z_AXIS GENMASK(15, 8) +#define ALS31300_VOL_MSB_Y_AXIS GENMASK(23, 16) +#define ALS31300_VOL_MSB_X_AXIS GENMASK(31, 24) +#define ALS31300_VOL_LSB 0x29 +#define ALS31300_VOL_LSB_TEMPERATURE GENMASK(5, 0) +#define ALS31300_VOL_LSB_HALL_STATUS GENMASK(7, 7) +#define ALS31300_VOL_LSB_Z_AXIS GENMASK(11, 8) +#define ALS31300_VOL_LSB_Y_AXIS GENMASK(15, 12) +#define ALS31300_VOL_LSB_X_AXIS GENMASK(19, 16) +#define ALS31300_VOL_LSB_INTERRUPT_WRITE BIT(20) +#define ALS31300_CUSTOMER_ACCESS 0x35 + +#define ALS31300_DATA_X_GET(b) \ + sign_extend32(FIELD_GET(ALS31300_VOL_MSB_X_AXIS, b[0]) << 4 | \ + FIELD_GET(ALS31300_VOL_LSB_X_AXIS, b[1]), 11) +#define ALS31300_DATA_Y_GET(b) \ + sign_extend32(FIELD_GET(ALS31300_VOL_MSB_Y_AXIS, b[0]) << 4 | \ + FIELD_GET(ALS31300_VOL_LSB_Y_AXIS, b[1]), 11) +#define ALS31300_DATA_Z_GET(b) \ + sign_extend32(FIELD_GET(ALS31300_VOL_MSB_Z_AXIS, b[0]) << 4 | \ + FIELD_GET(ALS31300_VOL_LSB_Z_AXIS, b[1]), 11) +#define ALS31300_TEMPERATURE_GET(b) \ + (FIELD_GET(ALS31300_VOL_MSB_TEMPERATURE, b[0]) << 6 | \ + FIELD_GET(ALS31300_VOL_LSB_TEMPERATURE, b[1])) + +enum als31300_channels { + TEMPERATURE = 0, + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +struct als31300_variant_info { + u8 sensitivity; +}; + +struct als31300_data { + struct device *dev; + /* protects power on/off the device and access HW */ + struct mutex mutex; + const struct als31300_variant_info *variant_info; + struct regmap *map; +}; + +/* The whole measure is split into 2x32-bit registers, we need to read them both at once */ +static int als31300_get_measure(struct als31300_data *data, + u16 *t, s16 *x, s16 *y, s16 *z) +{ + u32 buf[2]; + int ret, err; + + guard(mutex)(&data->mutex); + + ret = pm_runtime_resume_and_get(data->dev); + if (ret) + return ret; + + /* + * Loop until data is valid, new data should have the + * ALS31300_VOL_MSB_NEW_DATA bit set to 1. + * Max update rate is 2KHz, wait up to 1ms. + */ + ret = read_poll_timeout(regmap_bulk_read, err, + err || FIELD_GET(ALS31300_VOL_MSB_NEW_DATA, buf[0]), + 20, USEC_PER_MSEC, false, + data->map, ALS31300_VOL_MSB, buf, ARRAY_SIZE(buf)); + /* Bail out on read_poll_timeout() error */ + if (ret) + goto out; + + /* Bail out on regmap_bulk_read() error */ + if (err) { + dev_err(data->dev, "read data failed, error %d\n", ret); + ret = err; + goto out; + } + + *t = ALS31300_TEMPERATURE_GET(buf); + *x = ALS31300_DATA_X_GET(buf); + *y = ALS31300_DATA_Y_GET(buf); + *z = ALS31300_DATA_Z_GET(buf); + +out: + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static int als31300_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + struct als31300_data *data = iio_priv(indio_dev); + s16 x, y, z; + u16 t; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + case IIO_CHAN_INFO_RAW: + ret = als31300_get_measure(data, &t, &x, &y, &z); + if (ret) + return ret; + + switch (chan->address) { + case TEMPERATURE: + *val = t; + return IIO_VAL_INT; + case AXIS_X: + *val = x; + return IIO_VAL_INT; + case AXIS_Y: + *val = y; + return IIO_VAL_INT; + case AXIS_Z: + *val = z; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + /* + * Fractional part of: + * 1000 * 302 * (value - 1708) + * temp = ---------------------------- + * 4096 + * to convert temperature in millicelcius. + */ + *val = MILLI * 302; + *val2 = 4096; + return IIO_VAL_FRACTIONAL; + case IIO_MAGN: + /* + * Devices are configured in factory + * with different sensitivities: + * - 500 GAUSS <-> 4 LSB/Gauss + * - 1000 GAUSS <-> 2 LSB/Gauss + * - 2000 GAUSS <-> 1 LSB/Gauss + * with translates by a division of the returned + * value to get Gauss value. + * The sensitivity cannot be read at runtime + * so the value depends on the model compatible + * or device id. + */ + *val = 1; + *val2 = data->variant_info->sensitivity; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = -1708; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static irqreturn_t als31300_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct als31300_data *data = iio_priv(indio_dev); + struct { + u16 temperature; + s16 channels[3]; + aligned_s64 timestamp; + } scan; + s16 x, y, z; + int ret; + u16 t; + + ret = als31300_get_measure(data, &t, &x, &y, &z); + if (ret) + goto trigger_out; + + scan.temperature = t; + scan.channels[0] = x; + scan.channels[1] = y; + scan.channels[2] = z; + iio_push_to_buffers_with_timestamp(indio_dev, &scan, + pf->timestamp); + +trigger_out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +#define ALS31300_AXIS_CHANNEL(axis, index) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ + } + +static const struct iio_chan_spec als31300_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .address = TEMPERATURE, + .scan_index = TEMPERATURE, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + ALS31300_AXIS_CHANNEL(X, AXIS_X), + ALS31300_AXIS_CHANNEL(Y, AXIS_Y), + ALS31300_AXIS_CHANNEL(Z, AXIS_Z), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct iio_info als31300_info = { + .read_raw = als31300_read_raw, +}; + +static int als31300_set_operating_mode(struct als31300_data *data, + unsigned int val) +{ + int ret; + + ret = regmap_update_bits(data->map, ALS31300_VOL_MODE, + ALS31300_VOL_MODE_SLEEP, val); + if (ret) { + dev_err(data->dev, "failed to set operating mode (%pe)\n", ERR_PTR(ret)); + return ret; + } + + /* The time it takes to exit sleep mode is equivalent to Power-On Delay Time */ + if (val == ALS31300_VOL_MODE_ACTIVE_MODE) + fsleep(600); + + return 0; +} + +static void als31300_power_down(void *data) +{ + als31300_set_operating_mode(data, ALS31300_VOL_MODE_SLEEP_MODE); +} + +static const struct iio_buffer_setup_ops als31300_setup_ops = {}; + +static const unsigned long als31300_scan_masks[] = { GENMASK(3, 0), 0 }; + +static bool als31300_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == ALS31300_VOL_MSB || reg == ALS31300_VOL_LSB; +} + +static const struct regmap_config als31300_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .max_register = ALS31300_CUSTOMER_ACCESS, + .volatile_reg = als31300_volatile_reg, +}; + +static int als31300_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct als31300_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->dev = dev; + i2c_set_clientdata(i2c, indio_dev); + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + data->variant_info = i2c_get_match_data(i2c); + if (!data->variant_info) + return -EINVAL; + + data->map = devm_regmap_init_i2c(i2c, &als31300_regmap_config); + if (IS_ERR(data->map)) + return dev_err_probe(dev, PTR_ERR(data->map), + "failed to allocate register map\n"); + + ret = devm_regulator_get_enable(dev, "vcc"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable regulator\n"); + + ret = als31300_set_operating_mode(data, ALS31300_VOL_MODE_ACTIVE_MODE); + if (ret) + return dev_err_probe(dev, ret, "failed to power on device\n"); + + ret = devm_add_action_or_reset(dev, als31300_power_down, data); + if (ret) + return dev_err_probe(dev, ret, "failed to add powerdown action\n"); + + indio_dev->info = &als31300_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = i2c->name; + indio_dev->channels = als31300_channels; + indio_dev->num_channels = ARRAY_SIZE(als31300_channels); + indio_dev->available_scan_masks = als31300_scan_masks; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + als31300_trigger_handler, + &als31300_setup_ops); + if (ret < 0) + return dev_err_probe(dev, ret, "iio triggered buffer setup failed\n"); + + ret = pm_runtime_set_active(dev); + if (ret < 0) + return ret; + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + pm_runtime_get_noresume(dev); + pm_runtime_set_autosuspend_delay(dev, 200); + pm_runtime_use_autosuspend(dev); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "device register failed\n"); + + return 0; +} + +static int als31300_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct als31300_data *data = iio_priv(indio_dev); + + return als31300_set_operating_mode(data, ALS31300_VOL_MODE_SLEEP_MODE); +} + +static int als31300_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct als31300_data *data = iio_priv(indio_dev); + + return als31300_set_operating_mode(data, ALS31300_VOL_MODE_ACTIVE_MODE); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(als31300_pm_ops, + als31300_runtime_suspend, als31300_runtime_resume, + NULL); + +static const struct als31300_variant_info al31300_variant_500 = { + .sensitivity = 4, +}; + +static const struct als31300_variant_info al31300_variant_1000 = { + .sensitivity = 2, +}; + +static const struct als31300_variant_info al31300_variant_2000 = { + .sensitivity = 1, +}; + +static const struct i2c_device_id als31300_id[] = { + { + .name = "als31300-500", + .driver_data = (kernel_ulong_t)&al31300_variant_500, + }, + { + .name = "als31300-1000", + .driver_data = (kernel_ulong_t)&al31300_variant_1000, + }, + { + .name = "als31300-2000", + .driver_data = (kernel_ulong_t)&al31300_variant_2000, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, als31300_id); + +static const struct of_device_id als31300_of_match[] = { + { + .compatible = "allegromicro,als31300-500", + .data = &al31300_variant_500, + }, + { + .compatible = "allegromicro,als31300-1000", + .data = &al31300_variant_1000, + }, + { + .compatible = "allegromicro,als31300-2000", + .data = &al31300_variant_2000, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, als31300_of_match); + +static struct i2c_driver als31300_driver = { + .driver = { + .name = "als31300", + .of_match_table = als31300_of_match, + .pm = pm_ptr(&als31300_pm_ops), + }, + .probe = als31300_probe, + .id_table = als31300_id, +}; +module_i2c_driver(als31300_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ALS31300 3-D Linear Hall Effect Driver"); +MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>"); diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 06d5a1ef1fbd..7de18c4a0ccb 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/acpi.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/iio/iio.h> @@ -855,17 +854,6 @@ static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = { .postdisable = bmc150_magn_buffer_postdisable, }; -static const char *bmc150_magn_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); -} - int bmc150_magn_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { @@ -894,9 +882,6 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; - if (!name && ACPI_HANDLE(dev)) - name = bmc150_magn_match_acpi_device(dev); - mutex_init(&data->mutex); ret = bmc150_magn_init(data); diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index a28d46d59875..17e10a462ac8 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -38,14 +38,6 @@ static void bmc150_magn_i2c_remove(struct i2c_client *client) bmc150_magn_remove(&client->dev); } -static const struct acpi_device_id bmc150_magn_acpi_match[] = { - {"BMC150B", 0}, - {"BMC156B", 0}, - {"BMM150B", 0}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); - static const struct i2c_device_id bmc150_magn_i2c_id[] = { { "bmc150_magn" }, { "bmc156_magn" }, @@ -67,7 +59,6 @@ static struct i2c_driver bmc150_magn_driver = { .driver = { .name = "bmc150_magn_i2c", .of_match_table = bmc150_magn_of_match, - .acpi_match_table = bmc150_magn_acpi_match, .pm = &bmc150_magn_pm_ops, }, .probe = bmc150_magn_i2c_probe, diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index abc75a05c46a..c850de1bc79b 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -41,20 +41,11 @@ static const struct spi_device_id bmc150_magn_spi_id[] = { }; MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id); -static const struct acpi_device_id bmc150_magn_acpi_match[] = { - {"BMC150B", 0}, - {"BMC156B", 0}, - {"BMM150B", 0}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); - static struct spi_driver bmc150_magn_spi_driver = { .probe = bmc150_magn_spi_probe, .remove = bmc150_magn_spi_remove, .id_table = bmc150_magn_spi_id, .driver = { - .acpi_match_table = bmc150_magn_acpi_match, .name = "bmc150_magn_spi", }, }; diff --git a/drivers/iio/position/iqs624-pos.c b/drivers/iio/position/iqs624-pos.c index 4d7452314209..8239239c6ee2 100644 --- a/drivers/iio/position/iqs624-pos.c +++ b/drivers/iio/position/iqs624-pos.c @@ -181,7 +181,7 @@ static int iqs624_pos_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 iqs624_pos_private *iqs624_pos = iio_priv(indio_dev); struct iqs62x_core *iqs62x = iqs624_pos->iqs62x; diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 682329f81886..e5ec8137961f 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -16,6 +16,11 @@ * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf * + * Sensor API: + * https://github.com/boschsensortec/BME280_SensorAPI + * https://github.com/boschsensortec/BMP3_SensorAPI + * https://github.com/boschsensortec/BMP5_SensorAPI + * * Notice: * The link to the bmp180 datasheet points to an outdated version missing these changes: * - Changed document referral from ANP015 to BST-MPS-AN004-00 on page 26 @@ -37,12 +42,14 @@ #include <linux/module.h> #include <linux/nvmem-provider.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/random.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> +#include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> @@ -616,6 +623,14 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: + ret = data->chip_info->set_mode(data, BMP280_FORCED); + if (ret) + return ret; + + ret = data->chip_info->wait_conv(data); + if (ret) + return ret; + switch (chan->type) { case IIO_HUMIDITYRELATIVE: ret = data->chip_info->read_humid(data, &chan_value); @@ -645,6 +660,14 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_RAW: + ret = data->chip_info->set_mode(data, BMP280_FORCED); + if (ret) + return ret; + + ret = data->chip_info->wait_conv(data); + if (ret) + return ret; + switch (chan->type) { case IIO_HUMIDITYRELATIVE: ret = data->chip_info->read_humid(data, &chan_value); @@ -991,6 +1014,65 @@ static int bmp280_preinit(struct bmp280_data *data) return 0; } +static const u8 bmp280_operation_mode[] = { + [BMP280_SLEEP] = BMP280_MODE_SLEEP, + [BMP280_FORCED] = BMP280_MODE_FORCED, + [BMP280_NORMAL] = BMP280_MODE_NORMAL, +}; + +static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + int ret; + + ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS, + BMP280_MODE_MASK, bmp280_operation_mode[mode]); + if (ret) { + dev_err(data->dev, "failed to write ctrl_meas register.\n"); + return ret; + } + + data->op_mode = mode; + + return 0; +} + +static int bmp280_wait_conv(struct bmp280_data *data) +{ + unsigned int reg, meas_time_us; + int ret; + + /* Check if we are using a BME280 device */ + if (data->oversampling_humid) + meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET + + BIT(data->oversampling_humid) * BMP280_MEAS_DUR; + + else + meas_time_us = 0; + + /* Pressure measurement time */ + meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET + + BIT(data->oversampling_press) * BMP280_MEAS_DUR; + + /* Temperature measurement time */ + meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR; + + /* Waiting time according to the BM(P/E)2 Sensor API */ + fsleep(meas_time_us); + + ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®); + if (ret) { + dev_err(data->dev, "failed to read status register.\n"); + return ret; + } + + if (reg & BMP280_REG_STATUS_MEAS_BIT) { + dev_err(data->dev, "Measurement cycle didn't complete.\n"); + return -EBUSY; + } + + return 0; +} + static int bmp280_chip_config(struct bmp280_data *data) { u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) | @@ -1001,7 +1083,7 @@ static int bmp280_chip_config(struct bmp280_data *data) BMP280_OSRS_TEMP_MASK | BMP280_OSRS_PRESS_MASK | BMP280_MODE_MASK, - osrs | BMP280_MODE_NORMAL); + osrs | BMP280_MODE_SLEEP); if (ret) { dev_err(data->dev, "failed to write ctrl_meas register\n"); return ret; @@ -1111,6 +1193,8 @@ const struct bmp280_chip_info bmp280_chip_info = { .read_temp = bmp280_read_temp, .read_press = bmp280_read_press, .read_calib = bmp280_read_calib, + .set_mode = bmp280_set_mode, + .wait_conv = bmp280_wait_conv, .preinit = bmp280_preinit, .trigger_handler = bmp280_trigger_handler, @@ -1198,6 +1282,63 @@ out: return IRQ_HANDLED; } +static int __bmp280_trigger_probe(struct iio_dev *indio_dev, + const struct iio_trigger_ops *trigger_ops, + int (*int_pin_config)(struct bmp280_data *data), + irq_handler_t irq_thread_handler) +{ + struct bmp280_data *data = iio_priv(indio_dev); + struct device *dev = data->dev; + u32 irq_type; + int ret, irq; + + irq = fwnode_irq_get(dev_fwnode(dev), 0); + if (irq < 0) + return dev_err_probe(dev, irq, "No interrupt found.\n"); + + irq_type = irq_get_trigger_type(irq); + switch (irq_type) { + case IRQF_TRIGGER_RISING: + data->trig_active_high = true; + break; + case IRQF_TRIGGER_FALLING: + data->trig_active_high = false; + break; + default: + return dev_err_probe(dev, -EINVAL, "Invalid interrupt type specified.\n"); + } + + data->trig_open_drain = + fwnode_property_read_bool(dev_fwnode(dev), "int-open-drain"); + + ret = int_pin_config(data); + if (ret) + return ret; + + data->trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops = trigger_ops; + iio_trigger_set_drvdata(data->trig, data); + + ret = devm_request_threaded_irq(data->dev, irq, NULL, + irq_thread_handler, IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "request IRQ failed.\n"); + + ret = devm_iio_trigger_register(data->dev, data->trig); + if (ret) + return dev_err_probe(dev, ret, "iio trigger register failed.\n"); + + indio_dev->trig = iio_trigger_get(data->trig); + + return 0; +} + static const u8 bme280_chip_ids[] = { BME280_CHIP_ID }; static const int bme280_humid_coeffs[] = { 1000, 1024 }; @@ -1235,6 +1376,8 @@ const struct bmp280_chip_info bme280_chip_info = { .read_press = bmp280_read_press, .read_humid = bme280_read_humid, .read_calib = bme280_read_calib, + .set_mode = bmp280_set_mode, + .wait_conv = bmp280_wait_conv, .preinit = bmp280_preinit, .trigger_handler = bme280_trigger_handler, @@ -1522,6 +1665,64 @@ static int bmp380_preinit(struct bmp280_data *data) return bmp380_cmd(data, BMP380_CMD_SOFT_RESET); } +static const u8 bmp380_operation_mode[] = { + [BMP280_SLEEP] = BMP380_MODE_SLEEP, + [BMP280_FORCED] = BMP380_MODE_FORCED, + [BMP280_NORMAL] = BMP380_MODE_NORMAL, +}; + +static int bmp380_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + int ret; + + ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, + BMP380_MODE_MASK, + FIELD_PREP(BMP380_MODE_MASK, + bmp380_operation_mode[mode])); + if (ret) { + dev_err(data->dev, "failed to write power control register.\n"); + return ret; + } + + data->op_mode = mode; + + return 0; +} + +static int bmp380_wait_conv(struct bmp280_data *data) +{ + unsigned int reg; + int ret, meas_time_us; + + /* Offset measurement time */ + meas_time_us = BMP380_MEAS_OFFSET; + + /* Pressure measurement time */ + meas_time_us += BMP380_PRESS_MEAS_OFFSET + + BIT(data->oversampling_press) * BMP380_MEAS_DUR; + + /* Temperature measurement time */ + meas_time_us += BMP380_TEMP_MEAS_OFFSET + + BIT(data->oversampling_temp) * BMP380_MEAS_DUR; + + /* Measurement time defined in Datasheet Section 3.9.2 */ + fsleep(meas_time_us); + + ret = regmap_read(data->regmap, BMP380_REG_STATUS, ®); + if (ret) { + dev_err(data->dev, "failed to read status register.\n"); + return ret; + } + + if (!((reg & BMP380_STATUS_DRDY_PRESS_MASK) && + (reg & BMP380_STATUS_DRDY_TEMP_MASK))) { + dev_err(data->dev, "Measurement cycle didn't complete.\n"); + return -EBUSY; + } + + return 0; +} + static int bmp380_chip_config(struct bmp280_data *data) { bool change = false, aux; @@ -1582,17 +1783,19 @@ static int bmp380_chip_config(struct bmp280_data *data) * Resets sensor measurement loop toggling between sleep and * normal operating modes. */ - ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, - BMP380_MODE_MASK, - FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_SLEEP)); + ret = bmp380_set_mode(data, BMP280_SLEEP); if (ret) { dev_err(data->dev, "failed to set sleep mode\n"); return ret; } - usleep_range(2000, 2500); - ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, - BMP380_MODE_MASK, - FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_NORMAL)); + + /* + * According to the BMP3 Sensor API, the sensor needs 5ms + * in order to go to the sleep mode. + */ + fsleep(5 * USEC_PER_MSEC); + + ret = bmp380_set_mode(data, BMP280_NORMAL); if (ret) { dev_err(data->dev, "failed to set normal mode\n"); return ret; @@ -1618,7 +1821,77 @@ static int bmp380_chip_config(struct bmp280_data *data) } } - return 0; + /* Dummy read to empty data registers. */ + ret = bmp380_read_press(data, &tmp); + if (ret) + return ret; + + ret = bmp380_set_mode(data, BMP280_SLEEP); + if (ret) + dev_err(data->dev, "failed to set sleep mode.\n"); + + return ret; +} + +static int bmp380_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bmp280_data *data = iio_trigger_get_drvdata(trig); + int ret; + + guard(mutex)(&data->lock); + + ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL, + BMP380_INT_CTRL_DRDY_EN, + FIELD_PREP(BMP380_INT_CTRL_DRDY_EN, !!state)); + if (ret) + dev_err(data->dev, + "Could not %s interrupt.\n", str_enable_disable(state)); + return ret; +} + +static const struct iio_trigger_ops bmp380_trigger_ops = { + .set_trigger_state = &bmp380_data_rdy_trigger_set_state, +}; + +static int bmp380_int_pin_config(struct bmp280_data *data) +{ + int pin_drive_cfg = FIELD_PREP(BMP380_INT_CTRL_OPEN_DRAIN, + data->trig_open_drain); + int pin_level_cfg = FIELD_PREP(BMP380_INT_CTRL_LEVEL, + data->trig_active_high); + int ret, int_pin_cfg = pin_drive_cfg | pin_level_cfg; + + ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL, + BMP380_INT_CTRL_SETTINGS_MASK, int_pin_cfg); + if (ret) + dev_err(data->dev, "Could not set interrupt settings.\n"); + + return ret; +} + +static irqreturn_t bmp380_irq_thread_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct bmp280_data *data = iio_priv(indio_dev); + unsigned int int_ctrl; + int ret; + + ret = regmap_read(data->regmap, BMP380_REG_INT_STATUS, &int_ctrl); + if (ret) + return IRQ_NONE; + + if (FIELD_GET(BMP380_INT_STATUS_DRDY, int_ctrl)) + iio_trigger_poll_nested(data->trig); + + return IRQ_HANDLED; +} + +static int bmp380_trigger_probe(struct iio_dev *indio_dev) +{ + return __bmp280_trigger_probe(indio_dev, &bmp380_trigger_ops, + bmp380_int_pin_config, + bmp380_irq_thread_handler); } static irqreturn_t bmp380_trigger_handler(int irq, void *p) @@ -1714,8 +1987,11 @@ const struct bmp280_chip_info bmp380_chip_info = { .read_temp = bmp380_read_temp, .read_press = bmp380_read_press, .read_calib = bmp380_read_calib, + .set_mode = bmp380_set_mode, + .wait_conv = bmp380_wait_conv, .preinit = bmp380_preinit, + .trigger_probe = bmp380_trigger_probe, .trigger_handler = bmp380_trigger_handler, }; EXPORT_SYMBOL_NS(bmp380_chip_info, IIO_BMP280); @@ -2101,6 +2377,70 @@ static int bmp580_preinit(struct bmp280_data *data) return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); } +static const u8 bmp580_operation_mode[] = { + [BMP280_SLEEP] = BMP580_MODE_SLEEP, + [BMP280_FORCED] = BMP580_MODE_FORCED, + [BMP280_NORMAL] = BMP580_MODE_NORMAL, +}; + +static int bmp580_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + struct device *dev = data->dev; + int ret; + + if (mode == BMP280_FORCED) { + ret = regmap_set_bits(data->regmap, BMP580_REG_DSP_CONFIG, + BMP580_DSP_IIR_FORCED_FLUSH); + if (ret) { + dev_err(dev, "Could not flush IIR filter constants.\n"); + return ret; + } + } + + ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG, + BMP580_MODE_MASK, + FIELD_PREP(BMP580_MODE_MASK, + bmp580_operation_mode[mode])); + if (ret) { + dev_err(dev, "failed to write power control register.\n"); + return ret; + } + + data->op_mode = mode; + + return 0; +} + +static int bmp580_wait_conv(struct bmp280_data *data) +{ + /* + * Taken from datasheet, Section 2 "Specification, Table 3 "Electrical + * characteristics. + */ + static const int time_conv_press[] = { + 0, 1050, 1785, 3045, 5670, 10920, 21420, 42420, + 84420, + }; + static const int time_conv_temp[] = { + 0, 1050, 1105, 1575, 2205, 3465, 6090, 11340, + 21840, + }; + int meas_time_us; + + meas_time_us = 4 * USEC_PER_MSEC + + time_conv_temp[data->oversampling_temp] + + time_conv_press[data->oversampling_press]; + + /* + * Measurement time mentioned in Chapter 2, Table 4 of the datasheet. + * The extra 4ms is the required mode change to start of measurement + * time. + */ + fsleep(meas_time_us); + + return 0; +} + static int bmp580_chip_config(struct bmp280_data *data) { bool change = false, aux; @@ -2171,17 +2511,6 @@ static int bmp580_chip_config(struct bmp280_data *data) return ret; } - /* Restore sensor to normal operation mode */ - ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG, - BMP580_MODE_MASK, - FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_NORMAL)); - if (ret) { - dev_err(data->dev, "failed to set normal mode\n"); - return ret; - } - /* From datasheet's table 4: electrical characteristics */ - usleep_range(3000, 3500); - if (change) { /* * Check if ODR and OSR settings are valid or we are @@ -2205,6 +2534,74 @@ static int bmp580_chip_config(struct bmp280_data *data) return 0; } +static int bmp580_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bmp280_data *data = iio_trigger_get_drvdata(trig); + int ret; + + guard(mutex)(&data->lock); + + ret = regmap_update_bits(data->regmap, BMP580_REG_INT_CONFIG, + BMP580_INT_CONFIG_INT_EN, + FIELD_PREP(BMP580_INT_CONFIG_INT_EN, !!state)); + if (ret) + dev_err(data->dev, + "Could not %s interrupt.\n", str_enable_disable(state)); + return ret; +} + +static const struct iio_trigger_ops bmp580_trigger_ops = { + .set_trigger_state = &bmp580_data_rdy_trigger_set_state, +}; + +static int bmp580_int_pin_config(struct bmp280_data *data) +{ + int pin_drive_cfg = FIELD_PREP(BMP580_INT_CONFIG_OPEN_DRAIN, + data->trig_open_drain); + int pin_level_cfg = FIELD_PREP(BMP580_INT_CONFIG_LEVEL, + data->trig_active_high); + int ret, int_pin_cfg = pin_drive_cfg | pin_level_cfg; + + ret = regmap_update_bits(data->regmap, BMP580_REG_INT_CONFIG, + BMP580_INT_CONFIG_MASK, int_pin_cfg); + if (ret) { + dev_err(data->dev, "Could not set interrupt settings.\n"); + return ret; + } + + ret = regmap_set_bits(data->regmap, BMP580_REG_INT_SOURCE, + BMP580_INT_SOURCE_DRDY); + if (ret) + dev_err(data->dev, "Could not set interrupt source.\n"); + + return ret; +} + +static irqreturn_t bmp580_irq_thread_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct bmp280_data *data = iio_priv(indio_dev); + unsigned int int_ctrl; + int ret; + + ret = regmap_read(data->regmap, BMP580_REG_INT_STATUS, &int_ctrl); + if (ret) + return IRQ_NONE; + + if (FIELD_GET(BMP580_INT_STATUS_DRDY_MASK, int_ctrl)) + iio_trigger_poll_nested(data->trig); + + return IRQ_HANDLED; +} + +static int bmp580_trigger_probe(struct iio_dev *indio_dev) +{ + return __bmp280_trigger_probe(indio_dev, &bmp580_trigger_ops, + bmp580_int_pin_config, + bmp580_irq_thread_handler); +} + static irqreturn_t bmp580_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -2281,8 +2678,11 @@ const struct bmp280_chip_info bmp580_chip_info = { .chip_config = bmp580_chip_config, .read_temp = bmp580_read_temp, .read_press = bmp580_read_press, + .set_mode = bmp580_set_mode, + .wait_conv = bmp580_wait_conv, .preinit = bmp580_preinit, + .trigger_probe = bmp580_trigger_probe, .trigger_handler = bmp580_trigger_handler, }; EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280); @@ -2528,6 +2928,19 @@ static int bmp180_read_press(struct bmp280_data *data, u32 *comp_press) return 0; } +/* Keep compatibility with newer generations of the sensor */ +static int bmp180_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + return 0; +} + +/* Keep compatibility with newer generations of the sensor */ +static int bmp180_wait_conv(struct bmp280_data *data) +{ + return 0; +} + +/* Keep compatibility with newer generations of the sensor */ static int bmp180_chip_config(struct bmp280_data *data) { return 0; @@ -2599,6 +3012,8 @@ const struct bmp280_chip_info bmp180_chip_info = { .read_temp = bmp180_read_temp, .read_press = bmp180_read_press, .read_calib = bmp180_read_calib, + .set_mode = bmp180_set_mode, + .wait_conv = bmp180_wait_conv, .trigger_handler = bmp180_trigger_handler, }; @@ -2613,13 +3028,16 @@ static irqreturn_t bmp085_eoc_irq(int irq, void *d) return IRQ_HANDLED; } -static int bmp085_fetch_eoc_irq(struct device *dev, - const char *name, - int irq, - struct bmp280_data *data) +static int bmp085_trigger_probe(struct iio_dev *indio_dev) { + struct bmp280_data *data = iio_priv(indio_dev); + struct device *dev = data->dev; unsigned long irq_trig; - int ret; + int ret, irq; + + irq = fwnode_irq_get(dev_fwnode(dev), 0); + if (irq < 0) + return dev_err_probe(dev, irq, "No interrupt found.\n"); irq_trig = irq_get_trigger_type(irq); if (irq_trig != IRQF_TRIGGER_RISING) { @@ -2629,13 +3047,8 @@ static int bmp085_fetch_eoc_irq(struct device *dev, init_completion(&data->done); - ret = devm_request_threaded_irq(dev, - irq, - bmp085_eoc_irq, - NULL, - irq_trig, - name, - data); + ret = devm_request_irq(dev, irq, bmp085_eoc_irq, irq_trig, + indio_dev->name, data); if (ret) { /* Bail out without IRQ but keep the driver in place */ dev_err(dev, "unable to request DRDY IRQ\n"); @@ -2643,14 +3056,54 @@ static int bmp085_fetch_eoc_irq(struct device *dev, } data->use_eoc = true; + return 0; } +/* Identical to bmp180_chip_info + bmp085_trigger_probe */ +const struct bmp280_chip_info bmp085_chip_info = { + .id_reg = BMP280_REG_ID, + .chip_id = bmp180_chip_ids, + .num_chip_id = ARRAY_SIZE(bmp180_chip_ids), + .regmap_config = &bmp180_regmap_config, + .start_up_time = 2000, + .channels = bmp280_channels, + .num_channels = ARRAY_SIZE(bmp280_channels), + .avail_scan_masks = bmp280_avail_scan_masks, + + .oversampling_temp_avail = bmp180_oversampling_temp_avail, + .num_oversampling_temp_avail = + ARRAY_SIZE(bmp180_oversampling_temp_avail), + .oversampling_temp_default = 0, + + .oversampling_press_avail = bmp180_oversampling_press_avail, + .num_oversampling_press_avail = + ARRAY_SIZE(bmp180_oversampling_press_avail), + .oversampling_press_default = BMP180_MEAS_PRESS_8X, + + .temp_coeffs = bmp180_temp_coeffs, + .temp_coeffs_type = IIO_VAL_FRACTIONAL, + .press_coeffs = bmp180_press_coeffs, + .press_coeffs_type = IIO_VAL_FRACTIONAL, + + .chip_config = bmp180_chip_config, + .read_temp = bmp180_read_temp, + .read_press = bmp180_read_press, + .read_calib = bmp180_read_calib, + .set_mode = bmp180_set_mode, + .wait_conv = bmp180_wait_conv, + + .trigger_probe = bmp085_trigger_probe, + .trigger_handler = bmp180_trigger_handler, +}; +EXPORT_SYMBOL_NS(bmp085_chip_info, IIO_BMP280); + static int bmp280_buffer_preenable(struct iio_dev *indio_dev) { struct bmp280_data *data = iio_priv(indio_dev); pm_runtime_get_sync(data->dev); + data->chip_info->set_mode(data, BMP280_NORMAL); return 0; } @@ -2815,12 +3268,17 @@ int bmp280_common_probe(struct device *dev, * however as it happens, the BMP085 shares the chip ID of BMP180 * so we look for an IRQ if we have that. */ - if (irq > 0 && (chip_id == BMP180_CHIP_ID)) { - ret = bmp085_fetch_eoc_irq(dev, name, irq, data); + if (irq > 0) { + if (data->chip_info->trigger_probe) + ret = data->chip_info->trigger_probe(indio_dev); if (ret) return ret; } + ret = data->chip_info->set_mode(data, BMP280_SLEEP); + if (ret) + return dev_err_probe(dev, ret, "Failed to set sleep mode\n"); + /* Enable runtime PM */ pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); @@ -2846,6 +3304,9 @@ static int bmp280_runtime_suspend(struct device *dev) struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmp280_data *data = iio_priv(indio_dev); + data->chip_info->set_mode(data, BMP280_SLEEP); + + fsleep(data->start_up_time); return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies); } @@ -2860,7 +3321,12 @@ static int bmp280_runtime_resume(struct device *dev) return ret; usleep_range(data->start_up_time, data->start_up_time + 100); - return data->chip_info->chip_config(data); + + ret = data->chip_info->chip_config(data); + if (ret) + return ret; + + return data->chip_info->set_mode(data, data->op_mode); } EXPORT_RUNTIME_DEV_PM_OPS(bmp280_dev_pm_ops, bmp280_runtime_suspend, diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 5c3a63b4327c..2f7b25984c7b 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -27,7 +27,7 @@ static int bmp280_i2c_probe(struct i2c_client *client) } static const struct of_device_id bmp280_of_i2c_match[] = { - { .compatible = "bosch,bmp085", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp085", .data = &bmp085_chip_info }, { .compatible = "bosch,bmp180", .data = &bmp180_chip_info }, { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, { .compatible = "bosch,bme280", .data = &bme280_chip_info }, @@ -38,7 +38,7 @@ static const struct of_device_id bmp280_of_i2c_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); static const struct i2c_device_id bmp280_i2c_id[] = { - {"bmp085", (kernel_ulong_t)&bmp180_chip_info }, + {"bmp085", (kernel_ulong_t)&bmp085_chip_info }, {"bmp180", (kernel_ulong_t)&bmp180_chip_info }, {"bmp280", (kernel_ulong_t)&bmp280_chip_info }, {"bme280", (kernel_ulong_t)&bme280_chip_info }, diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index d18549d9bb64..49aa8c2cd85b 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -114,7 +114,7 @@ static int bmp280_spi_probe(struct spi_device *spi) } static const struct of_device_id bmp280_of_spi_match[] = { - { .compatible = "bosch,bmp085", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp085", .data = &bmp085_chip_info }, { .compatible = "bosch,bmp180", .data = &bmp180_chip_info }, { .compatible = "bosch,bmp181", .data = &bmp180_chip_info }, { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, @@ -126,7 +126,7 @@ static const struct of_device_id bmp280_of_spi_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); static const struct spi_device_id bmp280_spi_id[] = { - { "bmp085", (kernel_ulong_t)&bmp180_chip_info }, + { "bmp085", (kernel_ulong_t)&bmp085_chip_info }, { "bmp180", (kernel_ulong_t)&bmp180_chip_info }, { "bmp181", (kernel_ulong_t)&bmp180_chip_info }, { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index dc1bf04cb0b5..2df1175b6b85 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -55,8 +55,17 @@ #define BMP580_CMD_NVM_WRITE_SEQ_1 0xA0 #define BMP580_CMD_SOFT_RESET 0xB6 +#define BMP580_INT_STATUS_DRDY_MASK BIT(0) #define BMP580_INT_STATUS_POR_MASK BIT(4) +#define BMP580_INT_SOURCE_DRDY BIT(0) + +#define BMP580_INT_CONFIG_MASK GENMASK(3, 0) +#define BMP580_INT_CONFIG_LATCH BIT(0) +#define BMP580_INT_CONFIG_LEVEL BIT(1) +#define BMP580_INT_CONFIG_OPEN_DRAIN BIT(2) +#define BMP580_INT_CONFIG_INT_EN BIT(3) + #define BMP580_STATUS_CORE_RDY_MASK BIT(0) #define BMP580_STATUS_NVM_RDY_MASK BIT(1) #define BMP580_STATUS_NVM_ERR_MASK BIT(2) @@ -170,6 +179,19 @@ #define BMP380_MODE_FORCED 1 #define BMP380_MODE_NORMAL 3 +#define BMP380_MEAS_OFFSET 234 +#define BMP380_MEAS_DUR 2020 +#define BMP380_TEMP_MEAS_OFFSET 163 +#define BMP380_PRESS_MEAS_OFFSET 392 + +#define BMP380_INT_STATUS_DRDY BIT(3) + +#define BMP380_INT_CTRL_SETTINGS_MASK GENMASK(2, 0) +#define BMP380_INT_CTRL_OPEN_DRAIN BIT(0) +#define BMP380_INT_CTRL_LEVEL BIT(1) +#define BMP380_INT_CTRL_LATCH BIT(2) +#define BMP380_INT_CTRL_DRDY_EN BIT(6) + #define BMP380_MIN_TEMP -4000 #define BMP380_MAX_TEMP 8500 #define BMP380_MIN_PRES 3000000 @@ -206,6 +228,7 @@ #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_STATUS 0xF3 #define BMP280_REG_STATUS_IM_UPDATE BIT(0) +#define BMP280_REG_STATUS_MEAS_BIT BIT(3) #define BMP280_REG_RESET 0xE0 #define BMP280_RST_SOFT_CMD 0xB6 @@ -246,6 +269,10 @@ #define BMP280_MODE_FORCED 1 #define BMP280_MODE_NORMAL 3 +#define BMP280_MEAS_OFFSET 1250 +#define BMP280_MEAS_DUR 2300 +#define BMP280_PRESS_HUMID_MEAS_OFFSET 575 + /* BME280 specific registers */ #define BME280_REG_HUMIDITY_LSB 0xFE #define BME280_REG_HUMIDITY_MSB 0xFD @@ -385,12 +412,21 @@ struct bmp380_calib { s8 P11; }; +enum bmp280_op_mode { + BMP280_SLEEP, + BMP280_FORCED, + BMP280_NORMAL, +}; + struct bmp280_data { struct device *dev; struct mutex lock; struct regmap *regmap; struct completion done; bool use_eoc; + bool trig_open_drain; + bool trig_active_high; + struct iio_trigger *trig; const struct bmp280_chip_info *chip_info; union { struct bmp180_calib bmp180; @@ -423,6 +459,9 @@ struct bmp280_data { u8 sensor_data[ALIGN(sizeof(s32) * BME280_NUM_MAX_CHANNELS, sizeof(s64)) + sizeof(s64)] __aligned(sizeof(s64)); + /* Value to hold the current operation mode of the device */ + enum bmp280_op_mode op_mode; + /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. @@ -487,11 +526,15 @@ struct bmp280_chip_info { int (*read_humid)(struct bmp280_data *data, u32 *adc_humidity); int (*read_calib)(struct bmp280_data *data); int (*preinit)(struct bmp280_data *data); + int (*set_mode)(struct bmp280_data *data, enum bmp280_op_mode mode); + int (*wait_conv)(struct bmp280_data *data); + int (*trigger_probe)(struct iio_dev *indio_dev); irqreturn_t (*trigger_handler)(int irq, void *p); }; /* Chip infos for each variant */ +extern const struct bmp280_chip_info bmp085_chip_info; extern const struct bmp280_chip_info bmp180_chip_info; extern const struct bmp280_chip_info bmp280_chip_info; extern const struct bmp280_chip_info bme280_chip_info; diff --git a/drivers/iio/proximity/aw96103.c b/drivers/iio/proximity/aw96103.c index 707ba0a510aa..cdd254da9e50 100644 --- a/drivers/iio/proximity/aw96103.c +++ b/drivers/iio/proximity/aw96103.c @@ -422,7 +422,7 @@ static int aw96103_read_event_config(struct iio_dev *indio_dev, static int aw96103_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 aw96103 *aw96103 = iio_priv(indio_dev); diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c index b1a4a923e788..667369be0555 100644 --- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -167,7 +167,7 @@ static int cros_ec_mkbp_proximity_read_event_config(struct iio_dev *indio_dev, static int cros_ec_mkbp_proximity_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 cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev); diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c index d8fb34060d3d..4021feb7a7ac 100644 --- a/drivers/iio/proximity/hx9023s.c +++ b/drivers/iio/proximity/hx9023s.c @@ -874,12 +874,12 @@ static int hx9023s_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 hx9023s_data *data = iio_priv(indio_dev); if (test_bit(chan->channel, &data->chan_in_use)) { - hx9023s_ch_en(data, chan->channel, !!state); + hx9023s_ch_en(data, chan->channel, state); __assign_bit(chan->channel, &data->chan_event, data->ch_data[chan->channel].enable); } diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c index 6e96b764fed8..b09d15230111 100644 --- a/drivers/iio/proximity/irsd200.c +++ b/drivers/iio/proximity/irsd200.c @@ -648,7 +648,8 @@ static int irsd200_read_event_config(struct iio_dev *indio_dev, static int irsd200_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 irsd200_data *data = iio_priv(indio_dev); unsigned int tmp; @@ -662,7 +663,7 @@ static int irsd200_write_event_config(struct iio_dev *indio_dev, return ret; return regmap_field_write( - data->regfields[IRS_REGF_INTR_COUNT_THR_OR], !!state); + data->regfields[IRS_REGF_INTR_COUNT_THR_OR], state); default: return -EINVAL; } diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 3f4eace05cfc..c4e94d0fb163 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -540,7 +540,7 @@ static int sx9500_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 sx9500_data *data = iio_priv(indio_dev); int ret; @@ -551,7 +551,7 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, mutex_lock(&data->mutex); - if (state == 1) { + if (state) { ret = sx9500_inc_chan_users(data, chan->channel); if (ret < 0) goto out_unlock; @@ -571,7 +571,7 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, goto out_unlock; out_undo_chan: - if (state == 1) + if (state) sx9500_dec_chan_users(data, chan->channel); else sx9500_inc_chan_users(data, chan->channel); diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index bcf502e02342..76384c74fe01 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -268,7 +268,7 @@ EXPORT_SYMBOL_NS_GPL(sx_common_read_event_config, SEMTECH_PROX); int sx_common_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 sx_common_data *data = iio_priv(indio_dev); unsigned int eventirq = SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ; diff --git a/drivers/iio/proximity/sx_common.h b/drivers/iio/proximity/sx_common.h index da53268201a9..fb14e6f06a6d 100644 --- a/drivers/iio/proximity/sx_common.h +++ b/drivers/iio/proximity/sx_common.h @@ -143,7 +143,7 @@ int sx_common_read_event_config(struct iio_dev *indio_dev, int sx_common_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); int sx_common_probe(struct i2c_client *client, const struct sx_common_chip_info *chip_info, diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index d1ddf85f5383..bb6c9cc88b35 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -449,7 +449,7 @@ static int vcnl3020_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) { switch (chan->type) { case IIO_PROXIMITY: diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index f1bb0976273d..c2447860adfd 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -200,7 +200,7 @@ static int mcp9600_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 mcp9600_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index 9bdfa9423492..fd4d389ce1df 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -216,7 +216,7 @@ static irqreturn_t tmp007_interrupt_handler(int irq, void *private) static int tmp007_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 tmp007_data *data = iio_priv(indio_dev); unsigned int status_mask; |