diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 11:05:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-18 11:05:34 -0700 |
commit | e6874fc29410fabfdbc8c12b467f41a16cbcfd2b (patch) | |
tree | bb869a9b481a6c05bf334a0a4db0b1397ce4ca90 /drivers/iio | |
parent | e444d51b14c4795074f485c79debd234931f0e49 (diff) | |
parent | 3fb73eddba106ad2a265a5c5c29d14b0ed6aaee1 (diff) | |
download | linux-e6874fc29410fabfdbc8c12b467f41a16cbcfd2b.tar.gz linux-e6874fc29410fabfdbc8c12b467f41a16cbcfd2b.tar.bz2 linux-e6874fc29410fabfdbc8c12b467f41a16cbcfd2b.zip |
Merge tag 'staging-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging and IIO driver updates from Greg KH:
"Here is the big staging/iio driver update for 5.4-rc1.
Lots of churn here, with a few driver/filesystems moving out of
staging finally:
- erofs moved out of staging
- greybus core code moved out of staging
Along with that, a new filesytem has been added:
- extfat
to provide support for those devices requiring that filesystem (i.e.
transfer devices to/from windows systems or printers)
Other than that, there a number of new IIO drivers, and lots and lots
and lots of staging driver cleanups and minor fixes as people continue
to dig into those for easy changes.
All of these have been in linux-next for a while with no reported
issues"
* tag 'staging-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (453 commits)
Staging: gasket: Use temporaries to reduce line length.
Staging: octeon: Avoid several usecases of strcpy
staging: vhciq_core: replace snprintf with scnprintf
staging: wilc1000: avoid twice IRQ handler execution for each single interrupt
staging: wilc1000: remove unused interrupt status handling code
staging: fbtft: make several arrays static const, makes object smaller
staging: rtl8188eu: make two arrays static const, makes object smaller
staging: rtl8723bs: core: Remove Macro "IS_MAC_ADDRESS_BROADCAST"
dt-bindings: anybus-controller: move to staging/ tree
staging: emxx_udc: remove local TRUE/FALSE definition
staging: wilc1000: look for rtc_clk clock
staging: dt-bindings: wilc1000: add optional rtc_clk property
staging: nvec: make use of devm_platform_ioremap_resource
staging: exfat: drop unused function parameter
Staging: exfat: Avoid use of strcpy
staging: exfat: use integer constants
staging: exfat: cleanup spacing for casts
staging: exfat: cleanup spacing for operators
staging: rtl8723bs: hal: remove redundant variable n
staging: pi433: Fix typo in documentation
...
Diffstat (limited to 'drivers/iio')
96 files changed, 3214 insertions, 1477 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 9b9656ce37e6..d4ef35aeb579 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -202,9 +202,7 @@ config HID_SENSOR_ACCEL_3D config IIO_CROS_EC_ACCEL_LEGACY tristate "ChromeOS EC Legacy Accelerometer Sensor" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select CROS_EC_LPC_REGISTER_DEVICE + depends on IIO_CROS_EC_SENSORS_CORE help Say yes here to get support for accelerometers on Chromebook using legacy EC firmware. diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index ad19d9c716f4..39002cb5605d 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -5,13 +5,14 @@ * Copyright 2017 Google, Inc * * This driver uses the memory mapper cros-ec interface to communicate - * with the Chrome OS EC about accelerometer data. + * with the Chrome OS EC about accelerometer data or older commands. * Accelerometer access is presented through iio sysfs. */ #include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> +#include <linux/iio/common/cros_ec_sensors_core.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/trigger_consumer.h> @@ -25,160 +26,41 @@ #define DRV_NAME "cros-ec-accel-legacy" +#define CROS_EC_SENSOR_LEGACY_NUM 2 /* * Sensor scale hard coded at 10 bits per g, computed as: * g / (2^10 - 1) = 0.009586168; with g = 9.80665 m.s^-2 */ #define ACCEL_LEGACY_NSCALE 9586168 -/* Indices for EC sensor values. */ -enum { - X, - Y, - Z, - MAX_AXIS, -}; - -/* State data for cros_ec_accel_legacy iio driver. */ -struct cros_ec_accel_legacy_state { - struct cros_ec_device *ec; - - /* - * Array holding data from a single capture. 2 bytes per channel - * for the 3 channels plus the timestamp which is always last and - * 8-bytes aligned. - */ - s16 capture_data[8]; - s8 sign[MAX_AXIS]; - u8 sensor_num; -}; - -static int ec_cmd_read_u8(struct cros_ec_device *ec, unsigned int offset, - u8 *dest) -{ - return ec->cmd_readmem(ec, offset, 1, dest); -} - -static int ec_cmd_read_u16(struct cros_ec_device *ec, unsigned int offset, - u16 *dest) -{ - __le16 tmp; - int ret = ec->cmd_readmem(ec, offset, 2, &tmp); - - *dest = le16_to_cpu(tmp); - - return ret; -} - -/** - * read_ec_until_not_busy() - Read from EC status byte until it reads not busy. - * @st: Pointer to state information for device. - * - * This function reads EC status until its busy bit gets cleared. It does not - * wait indefinitely and returns -EIO if the EC status is still busy after a - * few hundreds milliseconds. - * - * Return: 8-bit status if ok, -EIO on error - */ -static int read_ec_until_not_busy(struct cros_ec_accel_legacy_state *st) -{ - struct cros_ec_device *ec = st->ec; - u8 status; - int attempts = 0; - - ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status); - while (status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) { - /* Give up after enough attempts, return error. */ - if (attempts++ >= 50) - return -EIO; - - /* Small delay every so often. */ - if (attempts % 5 == 0) - msleep(25); - - ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status); - } - - return status; -} - -/** - * read_ec_accel_data_unsafe() - Read acceleration data from EC shared memory. - * @st: Pointer to state information for device. - * @scan_mask: Bitmap of the sensor indices to scan. - * @data: Location to store data. - * - * This is the unsafe function for reading the EC data. It does not guarantee - * that the EC will not modify the data as it is being read in. - */ -static void read_ec_accel_data_unsafe(struct cros_ec_accel_legacy_state *st, - unsigned long scan_mask, s16 *data) -{ - int i = 0; - int num_enabled = bitmap_weight(&scan_mask, MAX_AXIS); - - /* Read all sensors enabled in scan_mask. Each value is 2 bytes. */ - while (num_enabled--) { - i = find_next_bit(&scan_mask, MAX_AXIS, i); - ec_cmd_read_u16(st->ec, - EC_MEMMAP_ACC_DATA + - sizeof(s16) * - (1 + i + st->sensor_num * MAX_AXIS), - data); - *data *= st->sign[i]; - i++; - data++; - } -} - -/** - * read_ec_accel_data() - Read acceleration data from EC shared memory. - * @st: Pointer to state information for device. - * @scan_mask: Bitmap of the sensor indices to scan. - * @data: Location to store data. - * - * This is the safe function for reading the EC data. It guarantees that - * the data sampled was not modified by the EC while being read. - * - * Return: 0 if ok, -ve on error - */ -static int read_ec_accel_data(struct cros_ec_accel_legacy_state *st, - unsigned long scan_mask, s16 *data) +static int cros_ec_accel_legacy_read_cmd(struct iio_dev *indio_dev, + unsigned long scan_mask, s16 *data) { - u8 samp_id = 0xff; - u8 status = 0; + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); int ret; - int attempts = 0; + unsigned int i; + u8 sensor_num; /* - * Continually read all data from EC until the status byte after - * all reads reflects that the EC is not busy and the sample id - * matches the sample id from before all reads. This guarantees - * that data read in was not modified by the EC while reading. + * Read all sensor data through a command. + * Save sensor_num, it is assumed to stay. */ - while ((status & (EC_MEMMAP_ACC_STATUS_BUSY_BIT | - EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK)) != samp_id) { - /* If we have tried to read too many times, return error. */ - if (attempts++ >= 5) - return -EIO; - - /* Read status byte until EC is not busy. */ - ret = read_ec_until_not_busy(st); - if (ret < 0) - return ret; - status = ret; - - /* - * Store the current sample id so that we can compare to the - * sample id after reading the data. - */ - samp_id = status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; - - /* Read all EC data, format it, and store it into data. */ - read_ec_accel_data_unsafe(st, scan_mask, data); + sensor_num = st->param.info.sensor_num; + st->param.cmd = MOTIONSENSE_CMD_DUMP; + st->param.dump.max_sensor_count = CROS_EC_SENSOR_LEGACY_NUM; + ret = cros_ec_motion_send_host_cmd(st, + sizeof(st->resp->dump) + CROS_EC_SENSOR_LEGACY_NUM * + sizeof(struct ec_response_motion_sensor_data)); + st->param.info.sensor_num = sensor_num; + if (ret != 0) { + dev_warn(&indio_dev->dev, "Unable to read sensor data\n"); + return ret; + } - /* Read status byte. */ - ec_cmd_read_u8(st->ec, EC_MEMMAP_ACC_STATUS, &status); + for_each_set_bit(i, &scan_mask, indio_dev->masklength) { + *data = st->resp->dump.sensor[sensor_num].data[i] * + st->sign[i]; + data++; } return 0; @@ -188,28 +70,40 @@ static int cros_ec_accel_legacy_read(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); s16 data = 0; - int ret = IIO_VAL_INT; + int ret; + int idx = chan->scan_index; + + mutex_lock(&st->cmd_lock); switch (mask) { case IIO_CHAN_INFO_RAW: - ret = read_ec_accel_data(st, (1 << chan->scan_index), &data); - if (ret) - return ret; + ret = st->read_ec_sensors_data(indio_dev, 1 << idx, &data); + if (ret < 0) + break; + ret = IIO_VAL_INT; *val = data; - return IIO_VAL_INT; + break; case IIO_CHAN_INFO_SCALE: + WARN_ON(st->type != MOTIONSENSE_TYPE_ACCEL); *val = 0; *val2 = ACCEL_LEGACY_NSCALE; - return IIO_VAL_INT_PLUS_NANO; + ret = IIO_VAL_INT_PLUS_NANO; + break; case IIO_CHAN_INFO_CALIBBIAS: /* Calibration not supported. */ *val = 0; - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; default: - return -EINVAL; + ret = cros_ec_sensors_core_read(st, chan, val, val2, + mask); + break; } + mutex_unlock(&st->cmd_lock); + + return ret; } static int cros_ec_accel_legacy_write(struct iio_dev *indio_dev, @@ -231,86 +125,14 @@ static const struct iio_info cros_ec_accel_legacy_info = { .write_raw = &cros_ec_accel_legacy_write, }; -/** - * cros_ec_accel_legacy_capture() - The trigger handler function - * @irq: The interrupt number. - * @p: Private data - always a pointer to the poll func. - * - * On a trigger event occurring, if the pollfunc is attached then this - * handler is called as a threaded interrupt (and hence may sleep). It - * is responsible for grabbing data from the device and pushing it into - * the associated buffer. - * - * Return: IRQ_HANDLED +/* + * Present the channel using HTML5 standard: + * need to invert X and Y and invert some lid axis. */ -static irqreturn_t cros_ec_accel_legacy_capture(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); - - /* Clear capture data. */ - memset(st->capture_data, 0, sizeof(st->capture_data)); - - /* - * Read data based on which channels are enabled in scan mask. Note - * that on a capture we are always reading the calibrated data. - */ - read_ec_accel_data(st, *indio_dev->active_scan_mask, st->capture_data); - - iio_push_to_buffers_with_timestamp(indio_dev, (void *)st->capture_data, - iio_get_time_ns(indio_dev)); - - /* - * Tell the core we are done with this trigger and ready for the - * next one. - */ - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -static char *cros_ec_accel_legacy_loc_strings[] = { - [MOTIONSENSE_LOC_BASE] = "base", - [MOTIONSENSE_LOC_LID] = "lid", - [MOTIONSENSE_LOC_MAX] = "unknown", -}; - -static ssize_t cros_ec_accel_legacy_loc(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - char *buf) -{ - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%s\n", - cros_ec_accel_legacy_loc_strings[st->sensor_num + - MOTIONSENSE_LOC_BASE]); -} - -static ssize_t cros_ec_accel_legacy_id(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - char *buf) -{ - struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", st->sensor_num); -} - -static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = { - { - .name = "id", - .shared = IIO_SHARED_BY_ALL, - .read = cros_ec_accel_legacy_id, - }, - { - .name = "location", - .shared = IIO_SHARED_BY_ALL, - .read = cros_ec_accel_legacy_loc, - }, - { } -}; +#define CROS_EC_ACCEL_ROTATE_AXIS(_axis) \ + ((_axis) == CROS_EC_SENSOR_Z ? CROS_EC_SENSOR_Z : \ + ((_axis) == CROS_EC_SENSOR_X ? CROS_EC_SENSOR_Y : \ + CROS_EC_SENSOR_X)) #define CROS_EC_ACCEL_LEGACY_CHAN(_axis) \ { \ @@ -321,28 +143,28 @@ static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = { BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \ - .ext_info = cros_ec_accel_legacy_ext_info, \ + .ext_info = cros_ec_sensors_ext_info, \ .scan_type = { \ .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ + .realbits = CROS_EC_SENSOR_BITS, \ + .storagebits = CROS_EC_SENSOR_BITS, \ }, \ + .scan_index = CROS_EC_ACCEL_ROTATE_AXIS(_axis), \ } \ -static struct iio_chan_spec ec_accel_channels[] = { - CROS_EC_ACCEL_LEGACY_CHAN(X), - CROS_EC_ACCEL_LEGACY_CHAN(Y), - CROS_EC_ACCEL_LEGACY_CHAN(Z), - IIO_CHAN_SOFT_TIMESTAMP(MAX_AXIS) +static const struct iio_chan_spec cros_ec_accel_legacy_channels[] = { + CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_X), + CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Y), + CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Z), + IIO_CHAN_SOFT_TIMESTAMP(CROS_EC_SENSOR_MAX_AXIS) }; static int cros_ec_accel_legacy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct cros_ec_dev *ec = dev_get_drvdata(dev->parent); - struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); struct iio_dev *indio_dev; - struct cros_ec_accel_legacy_state *state; + struct cros_ec_sensors_core_state *state; int ret; if (!ec || !ec->ec_dev) { @@ -350,46 +172,32 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) return -EINVAL; } - if (!ec->ec_dev->cmd_readmem) { - dev_warn(&pdev->dev, "EC does not support direct reads.\n"); - return -EINVAL; - } - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state)); if (!indio_dev) return -ENOMEM; - platform_set_drvdata(pdev, indio_dev); - state = iio_priv(indio_dev); - state->ec = ec->ec_dev; - state->sensor_num = sensor_platform->sensor_num; - - indio_dev->dev.parent = dev; - indio_dev->name = pdev->name; - indio_dev->channels = ec_accel_channels; - /* - * Present the channel using HTML5 standard: - * need to invert X and Y and invert some lid axis. - */ - ec_accel_channels[X].scan_index = Y; - ec_accel_channels[Y].scan_index = X; - ec_accel_channels[Z].scan_index = Z; + ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + if (ret) + return ret; - state->sign[Y] = 1; + indio_dev->info = &cros_ec_accel_legacy_info; + state = iio_priv(indio_dev); - if (state->sensor_num == MOTIONSENSE_LOC_LID) - state->sign[X] = state->sign[Z] = -1; + if (state->ec->cmd_readmem != NULL) + state->read_ec_sensors_data = cros_ec_sensors_read_lpc; else - state->sign[X] = state->sign[Z] = 1; - - indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels); - indio_dev->dev.parent = &pdev->dev; - indio_dev->info = &cros_ec_accel_legacy_info; - indio_dev->modes = INDIO_DIRECT_MODE; + state->read_ec_sensors_data = cros_ec_accel_legacy_read_cmd; + + indio_dev->channels = cros_ec_accel_legacy_channels; + indio_dev->num_channels = ARRAY_SIZE(cros_ec_accel_legacy_channels); + /* The lid sensor needs to be presented inverted. */ + if (state->loc == MOTIONSENSE_LOC_LID) { + state->sign[CROS_EC_SENSOR_X] = -1; + state->sign[CROS_EC_SENSOR_Z] = -1; + } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - cros_ec_accel_legacy_capture, - NULL); + cros_ec_sensors_capture, NULL); if (ret) return ret; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 6645771aa349..fee535d6e45b 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1486,8 +1486,8 @@ static const struct acpi_device_id kx_acpi_match[] = { {"KIOX0008", KXCJ91008}, {"KIOX0009", KXTJ21009}, {"KIOX000A", KXCJ91008}, - {"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */ - {"KIOX020A", 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}, diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 637e6e676061..3d5bea651923 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -424,7 +424,7 @@ static int mxc4005_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mxc4005_info; - ret = iio_triggered_buffer_setup(indio_dev, + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, iio_pollfunc_store_time, mxc4005_trigger_handler, NULL); @@ -452,7 +452,7 @@ static int mxc4005_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "failed to init threaded irq\n"); - goto err_buffer_cleanup; + return ret; } data->dready_trig->dev.parent = &client->dev; @@ -460,43 +460,16 @@ static int mxc4005_probe(struct i2c_client *client, iio_trigger_set_drvdata(data->dready_trig, indio_dev); indio_dev->trig = data->dready_trig; iio_trigger_get(indio_dev->trig); - ret = iio_trigger_register(data->dready_trig); + ret = devm_iio_trigger_register(&client->dev, + data->dready_trig); if (ret) { dev_err(&client->dev, "failed to register trigger\n"); - goto err_trigger_unregister; + return ret; } } - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, - "unable to register iio device %d\n", ret); - goto err_buffer_cleanup; - } - - return 0; - -err_trigger_unregister: - iio_trigger_unregister(data->dready_trig); -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int mxc4005_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct mxc4005_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - if (data->dready_trig) - iio_trigger_unregister(data->dready_trig); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct acpi_device_id mxc4005_acpi_match[] = { @@ -517,7 +490,6 @@ static struct i2c_driver mxc4005_driver = { .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), }, .probe = mxc4005_probe, - .remove = mxc4005_remove, .id_table = mxc4005_id, }; diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index a923f90f6e80..66d768d971e1 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -111,7 +111,7 @@ /* Currently unsupported */ #define SCA3000_MD_CTRL_AND_Y BIT(3) #define SCA3000_MD_CTRL_AND_X BIT(4) -#define SAC3000_MD_CTRL_AND_Z BIT(5) +#define SCA3000_MD_CTRL_AND_Z BIT(5) /* * Some control registers of complex access methods requiring this register to diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 979ab9679b99..af09943f38c9 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -68,6 +68,7 @@ static const struct st_sensors_platform_data default_accel_pdata = { .drdy_int_pin = 1, }; +const struct st_sensor_settings *st_accel_get_settings(const char *name); int st_accel_common_probe(struct iio_dev *indio_dev); void st_accel_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index 0205c0167cdd..9f2b40474b8e 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -29,65 +29,51 @@ int st_accel_trig_set_state(struct iio_trigger *trig, bool state) return st_sensors_set_dataready_irq(indio_dev, state); } -static int st_accel_buffer_preenable(struct iio_dev *indio_dev) -{ - return st_sensors_set_enable(indio_dev, true); -} - static int st_accel_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *adata = iio_priv(indio_dev); - - adata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (adata->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } err = iio_triggered_buffer_postenable(indio_dev); if (err < 0) - goto st_accel_buffer_postenable_error; + return err; err = st_sensors_set_axis_enable(indio_dev, - (u8)indio_dev->active_scan_mask[0]); + (u8)indio_dev->active_scan_mask[0]); if (err < 0) - goto st_sensors_set_axis_enable_error; + goto st_accel_buffer_predisable; - return err; + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_accel_buffer_enable_all_axis; -st_sensors_set_axis_enable_error: + return 0; + +st_accel_buffer_enable_all_axis: + st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); +st_accel_buffer_predisable: iio_triggered_buffer_predisable(indio_dev); -st_accel_buffer_postenable_error: - kfree(adata->buffer_data); -allocate_memory_error: return err; } static int st_accel_buffer_predisable(struct iio_dev *indio_dev) { int err, err2; - struct st_sensor_data *adata = iio_priv(indio_dev); - - err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); - if (err < 0) - goto st_accel_buffer_predisable_error; err = st_sensors_set_enable(indio_dev, false); if (err < 0) - goto st_accel_buffer_predisable_error; + goto st_accel_buffer_predisable; + + err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); -st_accel_buffer_predisable_error: +st_accel_buffer_predisable: err2 = iio_triggered_buffer_predisable(indio_dev); if (!err) err = err2; - kfree(adata->buffer_data); return err; } static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = { - .preenable = &st_accel_buffer_preenable, .postenable = &st_accel_buffer_postenable, .predisable = &st_accel_buffer_predisable, }; diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index e02b79931979..2e37f8a6d8cf 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -13,7 +13,6 @@ #include <linux/acpi.h> #include <linux/errno.h> #include <linux/types.h> -#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/gpio.h> @@ -1147,32 +1146,45 @@ out: #endif } +/* + * st_accel_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_accel_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_accel_sensors_settings, + ARRAY_SIZE(st_accel_sensors_settings)); + if (index < 0) + return NULL; + + return &st_accel_sensors_settings[index]; +} +EXPORT_SYMBOL(st_accel_get_settings); + int st_accel_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); struct st_sensors_platform_data *pdata = (struct st_sensors_platform_data *)adata->dev->platform_data; - int irq = adata->get_irq_data_ready(indio_dev); struct iio_chan_spec *channels; size_t channels_size; int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; - mutex_init(&adata->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_accel_sensors_settings), - st_accel_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_accel_power_off; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; - adata->multiread_bit = adata->sensor_settings->multi_read_bit; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec); @@ -1204,7 +1216,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_accel_power_off; - if (irq > 0) { + if (adata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_ACCEL_TRIGGER_OPS); if (err < 0) @@ -1221,7 +1233,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) return 0; st_accel_device_register_error: - if (irq > 0) + if (adata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_accel_probe_trigger_error: st_accel_deallocate_ring(indio_dev); @@ -1239,7 +1251,7 @@ void st_accel_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (adata->get_irq_data_ready(indio_dev) > 0) + if (adata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_accel_deallocate_ring(indio_dev); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index c3c8f2e73c2a..50fa0fc32baa 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -150,22 +150,33 @@ MODULE_DEVICE_TABLE(i2c, st_accel_id_table); static int st_accel_i2c_probe(struct i2c_client *client) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *adata; + struct iio_dev *indio_dev; const char *match; int ret; + match = device_get_match_data(&client->dev); + if (match) + strlcpy(client->name, match, sizeof(client->name)); + + settings = st_accel_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata)); if (!indio_dev) return -ENOMEM; adata = iio_priv(indio_dev); + adata->sensor_settings = (struct st_sensor_settings *)settings; - match = device_get_match_data(&client->dev); - if (match) - strlcpy(client->name, match, sizeof(client->name)); - - st_sensors_i2c_configure(indio_dev, client, adata); + ret = st_sensors_i2c_configure(indio_dev, client); + if (ret < 0) + return ret; ret = st_accel_common_probe(indio_dev); if (ret < 0) diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 474742e35d92..8af7027d5598 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -102,19 +102,31 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match); static int st_accel_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *adata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_accel_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_accel_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adata)); if (!indio_dev) return -ENOMEM; adata = iio_priv(indio_dev); + adata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_accel_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, adata); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_accel_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index aba0fd123a51..f5ba94c03a8d 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -35,6 +35,11 @@ static const unsigned int ad7606_scale_avail[2] = { 152588, 305176 }; + +static const unsigned int ad7616_sw_scale_avail[3] = { + 76293, 152588, 305176 +}; + static const unsigned int ad7606_oversampling_avail[7] = { 1, 2, 4, 8, 16, 32, 64, }; @@ -55,6 +60,29 @@ static int ad7606_reset(struct ad7606_state *st) return -ENODEV; } +static int ad7606_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ad7606_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + if (readval) { + ret = st->bops->reg_read(st, reg); + if (ret < 0) + goto err_unlock; + *readval = ret; + ret = 0; + } else { + ret = st->bops->reg_write(st, reg, writeval); + } +err_unlock: + mutex_unlock(&st->lock); + return ret; +} + static int ad7606_read_samples(struct ad7606_state *st) { unsigned int num = st->chip_info->num_channels; @@ -308,29 +336,6 @@ static const struct attribute_group ad7606_attribute_group_range = { .attrs = ad7606_attributes_range, }; -#define AD760X_CHANNEL(num, mask) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = num, \ - .address = num, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ - .info_mask_shared_by_all = mask, \ - .scan_index = num, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ - .endianness = IIO_CPU, \ - }, \ -} - -#define AD7605_CHANNEL(num) \ - AD760X_CHANNEL(num, 0) - -#define AD7606_CHANNEL(num) \ - AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) - static const struct iio_chan_spec ad7605_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), AD7605_CHANNEL(0), @@ -405,12 +410,19 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { .oversampling_avail = ad7606_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), }, + [ID_AD7606B] = { + .channels = ad7606_channels, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + }, [ID_AD7616] = { .channels = ad7616_channels, .num_channels = 17, .oversampling_avail = ad7616_oversampling_avail, .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), .os_req_reset = true, + .init_delay_ms = 15, }, }; @@ -519,6 +531,14 @@ static const struct iio_info ad7606_info_os_and_range = { .validate_trigger = &ad7606_validate_trigger, }; +static const struct iio_info ad7606_info_os_range_and_debug = { + .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, + .debugfs_reg_access = &ad7606_reg_access, + .attrs = &ad7606_attribute_group_os_and_range, + .validate_trigger = &ad7606_validate_trigger, +}; + static const struct iio_info ad7606_info_os = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, @@ -617,35 +637,29 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); + /* AD7616 requires al least 15ms to reconfigure after a reset */ + if (st->chip_info->init_delay_ms) { + if (msleep_interruptible(st->chip_info->init_delay_ms)) + return -ERESTARTSYS; + } + st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; - if (st->chip_info->sw_mode_config) + if (st->bops->sw_mode_config) st->sw_mode_en = device_property_present(st->dev, "adi,sw-mode"); if (st->sw_mode_en) { + /* Scale of 0.076293 is only available in sw mode */ + st->scale_avail = ad7616_sw_scale_avail; + st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail); + /* After reset, in software mode, ±10 V is set by default */ memset32(st->range, 2, ARRAY_SIZE(st->range)); - indio_dev->info = &ad7606_info_os_and_range; - - /* - * In software mode, the range gpio has no longer its function. - * Instead, the scale can be configured individually for each - * channel from the range registers. - */ - if (st->chip_info->write_scale_sw) - st->write_scale = st->chip_info->write_scale_sw; - - /* - * In software mode, the oversampling is no longer configured - * with GPIO pins. Instead, the oversampling can be configured - * in configuratiion register. - */ - if (st->chip_info->write_os_sw) - st->write_os = st->chip_info->write_os_sw; - - ret = st->chip_info->sw_mode_config(indio_dev); + indio_dev->info = &ad7606_info_os_range_and_debug; + + ret = st->bops->sw_mode_config(indio_dev); if (ret < 0) return ret; } diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index d8a509c2c428..9350ef1f63b5 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -8,6 +8,36 @@ #ifndef IIO_ADC_AD7606_H_ #define IIO_ADC_AD7606_H_ +#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num, \ + .address = num, \ + .info_mask_separate = mask_sep, \ + .info_mask_shared_by_type = mask_type, \ + .info_mask_shared_by_all = mask_all, \ + .scan_index = num, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define AD7605_CHANNEL(num) \ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ + BIT(IIO_CHAN_INFO_SCALE), 0) + +#define AD7606_CHANNEL(num) \ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) + +#define AD7616_CHANNEL(num) \ + AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),\ + 0, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) + /** * struct ad7606_chip_info - chip specific information * @channels: channel specification @@ -16,12 +46,8 @@ * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array * @os_req_reset some devices require a reset to update oversampling - * @write_scale_sw pointer to the function which writes the scale via spi - in software mode - * @write_os_sw pointer to the function which writes the os via spi - in software mode - * @sw_mode_config: pointer to a function which configured the device - * for software mode + * @init_delay_ms required delay in miliseconds for initialization + * after a restart */ struct ad7606_chip_info { const struct iio_chan_spec *channels; @@ -29,9 +55,7 @@ struct ad7606_chip_info { const unsigned int *oversampling_avail; unsigned int oversampling_num; bool os_req_reset; - int (*write_scale_sw)(struct iio_dev *indio_dev, int ch, int val); - int (*write_os_sw)(struct iio_dev *indio_dev, int val); - int (*sw_mode_config)(struct iio_dev *indio_dev); + unsigned long init_delay_ms; }; /** @@ -63,6 +87,7 @@ struct ad7606_chip_info { * @complete completion to indicate end of conversion * @trig The IIO trigger associated with the device. * @data buffer for reading data from the device + * @d16 be16 buffer for reading data from the device */ struct ad7606_state { struct device *dev; @@ -96,15 +121,32 @@ struct ad7606_state { * 16 * 16-bit samples + 64-bit timestamp */ unsigned short data[20] ____cacheline_aligned; + __be16 d16[2]; }; /** * struct ad7606_bus_ops - driver bus operations * @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 + * @rd_wr_cmd pointer to the function which calculates the spi address */ struct ad7606_bus_ops { /* more methods added in future? */ 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); + int (*reg_write)(struct ad7606_state *st, + unsigned int addr, + unsigned int val); + int (*write_mask)(struct ad7606_state *st, + unsigned int addr, + unsigned long mask, + unsigned int val); + u16 (*rd_wr_cmd)(int addr, char isWriteOp); }; int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, @@ -116,6 +158,7 @@ enum ad7606_supported_device_ids { ID_AD7606_8, ID_AD7606_6, ID_AD7606_4, + ID_AD7606B, ID_AD7616, }; diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index 1b08028facde..f732b3ac7878 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -53,10 +53,8 @@ static int ad7606_par_probe(struct platform_device *pdev) int irq; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq: %d\n", irq); + if (irq < 0) return irq; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index b7faef69a58f..29945ad07dca 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -15,6 +15,91 @@ #define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ +#define AD7616_CONFIGURATION_REGISTER 0x02 +#define AD7616_OS_MASK GENMASK(4, 2) +#define AD7616_BURST_MODE BIT(6) +#define AD7616_SEQEN_MODE BIT(5) +#define AD7616_RANGE_CH_A_ADDR_OFF 0x04 +#define AD7616_RANGE_CH_B_ADDR_OFF 0x06 +/* + * Range of channels from a group are stored in 2 registers. + * 0, 1, 2, 3 in a register followed by 4, 5, 6, 7 in second register. + * For channels from second group(8-15) the order is the same, only with + * an offset of 2 for register address. + */ +#define AD7616_RANGE_CH_ADDR(ch) ((ch) >> 2) +/* The range of the channel is stored in 2 bits */ +#define AD7616_RANGE_CH_MSK(ch) (0b11 << (((ch) & 0b11) * 2)) +#define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ((((ch) & 0b11)) * 2)) + +#define AD7606_CONFIGURATION_REGISTER 0x02 +#define AD7606_SINGLE_DOUT 0x00 + +/* + * Range for AD7606B channels are stored in registers starting with address 0x3. + * Each register stores range for 2 channels(4 bits per channel). + */ +#define AD7606_RANGE_CH_MSK(ch) (GENMASK(3, 0) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_MODE(ch, mode) \ + ((GENMASK(3, 0) & mode) << (4 * ((ch) & 0x1))) +#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1)) +#define AD7606_OS_MODE 0x08 + +static const struct iio_chan_spec ad7616_sw_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(16), + AD7616_CHANNEL(0), + AD7616_CHANNEL(1), + AD7616_CHANNEL(2), + AD7616_CHANNEL(3), + AD7616_CHANNEL(4), + AD7616_CHANNEL(5), + AD7616_CHANNEL(6), + AD7616_CHANNEL(7), + AD7616_CHANNEL(8), + AD7616_CHANNEL(9), + AD7616_CHANNEL(10), + AD7616_CHANNEL(11), + AD7616_CHANNEL(12), + AD7616_CHANNEL(13), + AD7616_CHANNEL(14), + AD7616_CHANNEL(15), +}; + +static const struct iio_chan_spec ad7606b_sw_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7616_CHANNEL(0), + AD7616_CHANNEL(1), + AD7616_CHANNEL(2), + AD7616_CHANNEL(3), + AD7616_CHANNEL(4), + AD7616_CHANNEL(5), + AD7616_CHANNEL(6), + AD7616_CHANNEL(7), +}; + +static const unsigned int ad7606B_oversampling_avail[9] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256 +}; + +static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp) +{ + /* + * The address of register consist of one w/r bit + * 6 bits of address followed by one reserved bit. + */ + return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7); +} + +static u16 ad7606B_spi_rd_wr_cmd(int addr, char is_write_op) +{ + /* + * The address of register consists of one bit which + * specifies a read command placed in bit 6, followed by + * 6 bits of address. + */ + return (addr & 0x3F) | (((~is_write_op) & 0x1) << 6); +} + static int ad7606_spi_read_block(struct device *dev, int count, void *buf) { @@ -35,17 +120,210 @@ static int ad7606_spi_read_block(struct device *dev, return 0; } +static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) +{ + struct spi_device *spi = to_spi_device(st->dev); + struct spi_transfer t[] = { + { + .tx_buf = &st->d16[0], + .len = 2, + .cs_change = 0, + }, { + .rx_buf = &st->d16[1], + .len = 2, + }, + }; + int ret; + + st->d16[0] = cpu_to_be16(st->bops->rd_wr_cmd(addr, 0) << 8); + + ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); + if (ret < 0) + return ret; + + return be16_to_cpu(st->d16[1]); +} + +static int ad7606_spi_reg_write(struct ad7606_state *st, + unsigned int addr, + unsigned int val) +{ + struct spi_device *spi = to_spi_device(st->dev); + + st->d16[0] = cpu_to_be16((st->bops->rd_wr_cmd(addr, 1) << 8) | + (val & 0x1FF)); + + return spi_write(spi, &st->d16[0], sizeof(st->d16[0])); +} + +static int ad7606_spi_write_mask(struct ad7606_state *st, + unsigned int addr, + unsigned long mask, + unsigned int val) +{ + int readval; + + readval = st->bops->reg_read(st, addr); + if (readval < 0) + return readval; + + readval &= ~mask; + readval |= val; + + return st->bops->reg_write(st, addr, readval); +} + +static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int ch_addr, mode, ch_index; + + + /* + * Ad7616 has 16 channels divided in group A and group B. + * The range of channels from A are stored in registers with address 4 + * while channels from B are stored in register with address 6. + * The last bit from channels determines if it is from group A or B + * because the order of channels in iio is 0A, 0B, 1A, 1B... + */ + ch_index = ch >> 1; + + ch_addr = AD7616_RANGE_CH_ADDR(ch_index); + + if ((ch & 0x1) == 0) /* channel A */ + ch_addr += AD7616_RANGE_CH_A_ADDR_OFF; + else /* channel B */ + ch_addr += AD7616_RANGE_CH_B_ADDR_OFF; + + /* 0b01 for 2.5v, 0b10 for 5v and 0b11 for 10v */ + mode = AD7616_RANGE_CH_MODE(ch_index, ((val + 1) & 0b11)); + return st->bops->write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch_index), + mode); +} + +static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return st->bops->write_mask(st, AD7616_CONFIGURATION_REGISTER, + AD7616_OS_MASK, val << 2); +} + +static int ad7606_write_scale_sw(struct iio_dev *indio_dev, int ch, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_spi_write_mask(st, + AD7606_RANGE_CH_ADDR(ch), + AD7606_RANGE_CH_MSK(ch), + AD7606_RANGE_CH_MODE(ch, val)); +} + +static int ad7606_write_os_sw(struct iio_dev *indio_dev, int val) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_spi_reg_write(st, AD7606_OS_MODE, val); +} + +static int ad7616_sw_mode_config(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + /* + * Scale can be configured individually for each channel + * in software mode. + */ + indio_dev->channels = ad7616_sw_channels; + + st->write_scale = ad7616_write_scale_sw; + st->write_os = &ad7616_write_os_sw; + + /* Activate Burst mode and SEQEN MODE */ + return st->bops->write_mask(st, + AD7616_CONFIGURATION_REGISTER, + AD7616_BURST_MODE | AD7616_SEQEN_MODE, + AD7616_BURST_MODE | AD7616_SEQEN_MODE); +} + +static int ad7606B_sw_mode_config(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned long os[3] = {1}; + + /* + * Software mode is enabled when all three oversampling + * pins are set to high. If oversampling gpios are defined + * in the device tree, then they need to be set to high, + * otherwise, they must be hardwired to VDD + */ + if (st->gpio_os) { + gpiod_set_array_value(ARRAY_SIZE(os), + st->gpio_os->desc, st->gpio_os->info, os); + } + /* OS of 128 and 256 are available only in software mode */ + st->oversampling_avail = ad7606B_oversampling_avail; + st->num_os_ratios = ARRAY_SIZE(ad7606B_oversampling_avail); + + st->write_scale = ad7606_write_scale_sw; + st->write_os = &ad7606_write_os_sw; + + /* Configure device spi to output on a single channel */ + st->bops->reg_write(st, + AD7606_CONFIGURATION_REGISTER, + AD7606_SINGLE_DOUT); + + /* + * Scale can be configured individually for each channel + * in software mode. + */ + indio_dev->channels = ad7606b_sw_channels; + + return 0; +} + static const struct ad7606_bus_ops ad7606_spi_bops = { .read_block = ad7606_spi_read_block, }; +static const struct ad7606_bus_ops ad7616_spi_bops = { + .read_block = ad7606_spi_read_block, + .reg_read = ad7606_spi_reg_read, + .reg_write = ad7606_spi_reg_write, + .write_mask = ad7606_spi_write_mask, + .rd_wr_cmd = ad7616_spi_rd_wr_cmd, + .sw_mode_config = ad7616_sw_mode_config, +}; + +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, + .write_mask = ad7606_spi_write_mask, + .rd_wr_cmd = ad7606B_spi_rd_wr_cmd, + .sw_mode_config = ad7606B_sw_mode_config, +}; + 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: + bops = &ad7606B_spi_bops; + break; + default: + bops = &ad7606_spi_bops; + break; + } return ad7606_probe(&spi->dev, spi->irq, NULL, id->name, id->driver_data, - &ad7606_spi_bops); + bops); } static const struct spi_device_id ad7606_id_table[] = { @@ -53,6 +331,7 @@ static const struct spi_device_id ad7606_id_table[] = { { "ad7606-4", ID_AD7606_4 }, { "ad7606-6", ID_AD7606_6 }, { "ad7606-8", ID_AD7606_8 }, + { "ad7606b", ID_AD7606B }, { "ad7616", ID_AD7616 }, {} }; @@ -63,6 +342,7 @@ static const struct of_device_id ad7606_of_match[] = { { .compatible = "adi,ad7606-4" }, { .compatible = "adi,ad7606-6" }, { .compatible = "adi,ad7606-8" }, + { .compatible = "adi,ad7606b" }, { .compatible = "adi,ad7616" }, { }, }; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 32f1c4a33b20..abe99856c823 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1179,10 +1179,8 @@ static int at91_adc_probe(struct platform_device *pdev) idev->info = &at91_adc_info; st->irq = platform_get_irq(pdev, 0); - if (st->irq < 0) { - dev_err(&pdev->dev, "No IRQ ID is designated\n"); + if (st->irq < 0) return -ENODEV; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 31d51bcc5f2c..adc9cf7a075d 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -225,10 +225,8 @@ static int axp288_adc_probe(struct platform_device *pdev) info = iio_priv(indio_dev); info->irq = platform_get_irq(pdev, 0); - if (info->irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (info->irq < 0) return info->irq; - } platform_set_drvdata(pdev, indio_dev); info->regmap = axp20x->regmap; /* diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index c46c0aa15376..646ebdc0a8b4 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -540,11 +540,8 @@ static int iproc_adc_probe(struct platform_device *pdev) } adc_priv->irqno = platform_get_irq(pdev, 0); - if (adc_priv->irqno <= 0) { - dev_err(&pdev->dev, "platform_get_irq failed\n"); - ret = -ENODEV; - return ret; - } + if (adc_priv->irqno <= 0) + return -ENODEV; ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2, IPROC_ADC_AUXIN_SCAN_ENA, 0); diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c index 354433996101..ae8bcc32f63d 100644 --- a/drivers/iio/adc/da9150-gpadc.c +++ b/drivers/iio/adc/da9150-gpadc.c @@ -337,10 +337,8 @@ static int da9150_gpadc_probe(struct platform_device *pdev) init_completion(&gpadc->complete); irq = platform_get_irq_byname(pdev, "GPADC"); - if (irq < 0) { - dev_err(dev, "Failed to get IRQ: %d\n", irq); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, da9150_gpadc_irq, IRQF_ONESHOT, "GPADC", gpadc); diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c index 2f2b563c1162..28f3d6758eb5 100644 --- a/drivers/iio/adc/envelope-detector.c +++ b/drivers/iio/adc/envelope-detector.c @@ -357,11 +357,8 @@ static int envelope_detector_probe(struct platform_device *pdev) } env->comp_irq = platform_get_irq_byname(pdev, "comp"); - if (env->comp_irq < 0) { - if (env->comp_irq != -EPROBE_DEFER) - dev_err(dev, "failed to get compare interrupt\n"); + if (env->comp_irq < 0) return env->comp_irq; - } ret = devm_request_irq(dev, env->comp_irq, envelope_detector_comp_isr, 0, "envelope-detector", env); diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index d4c3ece21679..42a3ced11fbd 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -805,10 +805,8 @@ static int exynos_adc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } info->irq = irq; irq = platform_get_irq(pdev, 1); diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index df19ecae52f7..fa71489195c6 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -340,7 +340,6 @@ static int mx25_gcq_probe(struct platform_device *pdev) priv->irq = platform_get_irq(pdev, 0); if (priv->irq <= 0) { - dev_err(dev, "Failed to get IRQ\n"); ret = priv->irq; if (!ret) ret = -ENXIO; diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 35951c47004e..8da45bf36d36 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -456,6 +456,11 @@ err_read: return IRQ_HANDLED; } +static void hi8435_triggered_event_cleanup(void *data) +{ + iio_triggered_event_cleanup(data); +} + static int hi8435_probe(struct spi_device *spi) { struct iio_dev *idev; @@ -477,7 +482,7 @@ static int hi8435_probe(struct spi_device *spi) hi8435_writeb(priv, HI8435_CTRL_REG, 0); } else { udelay(5); - gpiod_set_value(reset_gpio, 1); + gpiod_set_value_cansleep(reset_gpio, 1); } spi_set_drvdata(spi, idev); @@ -513,27 +518,13 @@ static int hi8435_probe(struct spi_device *spi) if (ret) return ret; - ret = iio_device_register(idev); - if (ret < 0) { - dev_err(&spi->dev, "unable to register device\n"); - goto unregister_triggered_event; - } - - return 0; - -unregister_triggered_event: - iio_triggered_event_cleanup(idev); - return ret; -} - -static int hi8435_remove(struct spi_device *spi) -{ - struct iio_dev *idev = spi_get_drvdata(spi); - - iio_device_unregister(idev); - iio_triggered_event_cleanup(idev); + ret = devm_add_action_or_reset(&spi->dev, + hi8435_triggered_event_cleanup, + idev); + if (ret) + return ret; - return 0; + return devm_iio_device_register(&spi->dev, idev); } static const struct of_device_id hi8435_dt_ids[] = { @@ -554,7 +545,6 @@ static struct spi_driver hi8435_driver = { .of_match_table = of_match_ptr(hi8435_dt_ids), }, .probe = hi8435_probe, - .remove = hi8435_remove, .id_table = hi8435_id, }; module_spi_driver(hi8435_driver); diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c index 26a7bbe4d534..2a2fbf788e95 100644 --- a/drivers/iio/adc/imx7d_adc.c +++ b/drivers/iio/adc/imx7d_adc.c @@ -492,10 +492,8 @@ static int imx7d_adc_probe(struct platform_device *pdev) return PTR_ERR(info->regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "No irq resource?\n"); + if (irq < 0) return irq; - } info->clk = devm_clk_get(dev, "adc"); if (IS_ERR(info->clk)) { diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c index a6ee1c3a9064..b896f7ff4572 100644 --- a/drivers/iio/adc/lpc32xx_adc.c +++ b/drivers/iio/adc/lpc32xx_adc.c @@ -172,10 +172,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "failed getting interrupt resource\n"); + if (irq <= 0) return -ENXIO; - } retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, LPC32XXAD_NAME, st); diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index da84adfdb819..214883458582 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -427,8 +427,9 @@ static int max1027_probe(struct spi_device *spi) return -ENOMEM; } - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - &max1027_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, + &max1027_trigger_handler, NULL); if (ret < 0) { dev_err(&indio_dev->dev, "Failed to setup buffer\n"); return ret; @@ -439,7 +440,7 @@ static int max1027_probe(struct spi_device *spi) if (st->trig == NULL) { ret = -ENOMEM; dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n"); - goto fail_trigger_alloc; + return ret; } st->trig->ops = &max1027_trigger_ops; @@ -454,7 +455,7 @@ static int max1027_probe(struct spi_device *spi) spi->dev.driver->name, st->trig); if (ret < 0) { dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n"); - goto fail_dev_register; + return ret; } /* Disable averaging */ @@ -462,34 +463,10 @@ static int max1027_probe(struct spi_device *spi) ret = spi_write(st->spi, &st->reg, 1); if (ret < 0) { dev_err(&indio_dev->dev, "Failed to configure averaging register\n"); - goto fail_dev_register; - } - - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&indio_dev->dev, "Failed to register iio device\n"); - goto fail_dev_register; + return ret; } - return 0; - -fail_dev_register: -fail_trigger_alloc: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int max1027_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - - pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static struct spi_driver max1027_driver = { @@ -498,7 +475,6 @@ static struct spi_driver max1027_driver = { .of_match_table = of_match_ptr(max1027_adc_dt_ids), }, .probe = max1027_probe, - .remove = max1027_remove, .id_table = max1027_id, }; module_spi_driver(max1027_driver); diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 193b3b81de4d..910f3585fa54 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -225,7 +225,6 @@ static int npcm_adc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(dev, "failed getting interrupt resource\n"); ret = -EINVAL; goto err_disable_clk; } diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index dd8299831e09..582ba047c4a6 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -244,10 +244,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev) init_completion(&info->completion); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, 0, dev_name(&pdev->dev), info); diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c index f7f7a18904b4..a6c046575ec3 100644 --- a/drivers/iio/adc/sc27xx_adc.c +++ b/drivers/iio/adc/sc27xx_adc.c @@ -3,7 +3,6 @@ #include <linux/hwspinlock.h> #include <linux/iio/iio.h> -#include <linux/interrupt.h> #include <linux/module.h> #include <linux/nvmem-consumer.h> #include <linux/of.h> @@ -46,14 +45,18 @@ /* Bits definitions for SC27XX_ADC_INT_CLR registers */ #define SC27XX_ADC_IRQ_CLR BIT(0) +/* Bits definitions for SC27XX_ADC_INT_RAW registers */ +#define SC27XX_ADC_IRQ_RAW BIT(0) + /* Mask definition for SC27XX_ADC_DATA register */ #define SC27XX_ADC_DATA_MASK GENMASK(11, 0) /* Timeout (ms) for the trylock of hardware spinlocks */ #define SC27XX_ADC_HWLOCK_TIMEOUT 5000 -/* Timeout (ms) for ADC data conversion according to ADC datasheet */ -#define SC27XX_ADC_RDY_TIMEOUT 100 +/* Timeout (us) for ADC data conversion according to ADC datasheet */ +#define SC27XX_ADC_RDY_TIMEOUT 1000000 +#define SC27XX_ADC_POLL_RAW_STATUS 500 /* Maximum ADC channel number */ #define SC27XX_ADC_CHANNEL_MAX 32 @@ -72,10 +75,8 @@ struct sc27xx_adc_data { * subsystems which will access the unique ADC controller. */ struct hwspinlock *hwlock; - struct completion completion; int channel_scale[SC27XX_ADC_CHANNEL_MAX]; u32 base; - int value; int irq; }; @@ -188,9 +189,7 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, int scale, int *val) { int ret; - u32 tmp; - - reinit_completion(&data->completion); + u32 tmp, value, status; ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT); if (ret) { @@ -203,6 +202,11 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, if (ret) goto unlock_adc; + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, + SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); + if (ret) + goto disable_adc; + /* Configure the channel id and scale */ tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK; tmp |= channel & SC27XX_ADC_CHN_ID_MASK; @@ -226,15 +230,22 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, if (ret) goto disable_adc; - ret = wait_for_completion_timeout(&data->completion, - msecs_to_jiffies(SC27XX_ADC_RDY_TIMEOUT)); - if (!ret) { - dev_err(data->dev, "read ADC data timeout\n"); - ret = -ETIMEDOUT; - } else { - ret = 0; + ret = regmap_read_poll_timeout(data->regmap, + data->base + SC27XX_ADC_INT_RAW, + status, (status & SC27XX_ADC_IRQ_RAW), + SC27XX_ADC_POLL_RAW_STATUS, + SC27XX_ADC_RDY_TIMEOUT); + if (ret) { + dev_err(data->dev, "read adc timeout, status = 0x%x\n", status); + goto disable_adc; } + ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, &value); + if (ret) + goto disable_adc; + + value &= SC27XX_ADC_DATA_MASK; + disable_adc: regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, SC27XX_ADC_EN, 0); @@ -242,32 +253,11 @@ unlock_adc: hwspin_unlock_raw(data->hwlock); if (!ret) - *val = data->value; + *val = value; return ret; } -static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id) -{ - struct sc27xx_adc_data *data = dev_id; - int ret; - - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, - SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); - if (ret) - return IRQ_RETVAL(ret); - - ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, - &data->value); - if (ret) - return IRQ_RETVAL(ret); - - data->value &= SC27XX_ADC_DATA_MASK; - complete(&data->completion); - - return IRQ_HANDLED; -} - static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data, int channel, int scale, u32 *div_numerator, u32 *div_denominator) @@ -454,11 +444,6 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data) if (ret) goto disable_adc; - ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, - SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN); - if (ret) - goto disable_clk; - /* ADC channel scales' calibration from nvmem device */ ret = sc27xx_adc_scale_calibration(data, true); if (ret) @@ -484,9 +469,6 @@ static void sc27xx_adc_disable(void *_data) { struct sc27xx_adc_data *data = _data; - regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, - SC27XX_ADC_IRQ_EN, 0); - /* Disable ADC work clock and controller clock */ regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); @@ -504,88 +486,76 @@ static void sc27xx_adc_free_hwlock(void *_data) static int sc27xx_adc_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct sc27xx_adc_data *sc27xx_data; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*sc27xx_data)); if (!indio_dev) return -ENOMEM; sc27xx_data = iio_priv(indio_dev); - sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL); + sc27xx_data->regmap = dev_get_regmap(dev->parent, NULL); if (!sc27xx_data->regmap) { - dev_err(&pdev->dev, "failed to get ADC regmap\n"); + dev_err(dev, "failed to get ADC regmap\n"); return -ENODEV; } ret = of_property_read_u32(np, "reg", &sc27xx_data->base); if (ret) { - dev_err(&pdev->dev, "failed to get ADC base address\n"); + dev_err(dev, "failed to get ADC base address\n"); return ret; } sc27xx_data->irq = platform_get_irq(pdev, 0); - if (sc27xx_data->irq < 0) { - dev_err(&pdev->dev, "failed to get ADC irq number\n"); + if (sc27xx_data->irq < 0) return sc27xx_data->irq; - } ret = of_hwspin_lock_get_id(np, 0); if (ret < 0) { - dev_err(&pdev->dev, "failed to get hwspinlock id\n"); + dev_err(dev, "failed to get hwspinlock id\n"); return ret; } sc27xx_data->hwlock = hwspin_lock_request_specific(ret); if (!sc27xx_data->hwlock) { - dev_err(&pdev->dev, "failed to request hwspinlock\n"); + dev_err(dev, "failed to request hwspinlock\n"); return -ENXIO; } - ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock, + ret = devm_add_action_or_reset(dev, sc27xx_adc_free_hwlock, sc27xx_data->hwlock); if (ret) { - sc27xx_adc_free_hwlock(sc27xx_data->hwlock); - dev_err(&pdev->dev, "failed to add hwspinlock action\n"); + dev_err(dev, "failed to add hwspinlock action\n"); return ret; } - init_completion(&sc27xx_data->completion); - sc27xx_data->dev = &pdev->dev; + sc27xx_data->dev = dev; ret = sc27xx_adc_enable(sc27xx_data); if (ret) { - dev_err(&pdev->dev, "failed to enable ADC module\n"); - return ret; - } - - ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data); - if (ret) { - sc27xx_adc_disable(sc27xx_data); - dev_err(&pdev->dev, "failed to add ADC disable action\n"); + dev_err(dev, "failed to enable ADC module\n"); return ret; } - ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL, - sc27xx_adc_isr, IRQF_ONESHOT, - pdev->name, sc27xx_data); + ret = devm_add_action_or_reset(dev, sc27xx_adc_disable, sc27xx_data); if (ret) { - dev_err(&pdev->dev, "failed to request ADC irq\n"); + dev_err(dev, "failed to add ADC disable action\n"); return ret; } - indio_dev->dev.parent = &pdev->dev; - indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = dev; + indio_dev->name = dev_name(dev); indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &sc27xx_info; indio_dev->channels = sc27xx_channels; indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels); - ret = devm_iio_device_register(&pdev->dev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) - dev_err(&pdev->dev, "could not register iio (ADC)"); + dev_err(dev, "could not register iio (ADC)"); return ret; } diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index a33d0a4cc088..592b97c464da 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -301,7 +301,6 @@ static int spear_adc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(dev, "failed getting interrupt resource\n"); ret = -EINVAL; goto errout2; } diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 1f7ce5186dfc..9b85fefc0a96 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -14,9 +14,11 @@ #include <linux/irqchip/chained_irq.h> #include <linux/irqdesc.h> #include <linux/irqdomain.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -51,6 +53,17 @@ #define STM32_ADC_CORE_SLEEP_DELAY_MS 2000 +/* SYSCFG registers */ +#define STM32MP1_SYSCFG_PMCSETR 0x04 +#define STM32MP1_SYSCFG_PMCCLRR 0x44 + +/* SYSCFG bit fields */ +#define STM32MP1_SYSCFG_ANASWVDD_MASK BIT(9) + +/* SYSCFG capability flags */ +#define HAS_VBOOSTER BIT(0) +#define HAS_ANASWVDD BIT(1) + /** * stm32_adc_common_regs - stm32 common registers, compatible dependent data * @csr: common status register offset @@ -74,11 +87,13 @@ struct stm32_adc_priv; * @regs: common registers for all instances * @clk_sel: clock selection routine * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) + * @has_syscfg: SYSCFG capability flags */ struct stm32_adc_priv_cfg { const struct stm32_adc_common_regs *regs; int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); u32 max_clk_rate_hz; + unsigned int has_syscfg; }; /** @@ -87,22 +102,32 @@ struct stm32_adc_priv_cfg { * @domain: irq domain reference * @aclk: clock reference for the analog circuitry * @bclk: bus clock common for all ADCs, depends on part used + * @booster: booster supply reference + * @vdd: vdd supply reference * @vdda: vdda analog supply reference * @vref: regulator reference + * @vdd_uv: vdd supply voltage (microvolts) + * @vdda_uv: vdda supply voltage (microvolts) * @cfg: compatible configuration data * @common: common data for all ADC instances * @ccr_bak: backup CCR in low power mode + * @syscfg: reference to syscon, system control registers */ struct stm32_adc_priv { int irq[STM32_ADC_MAX_ADCS]; struct irq_domain *domain; struct clk *aclk; struct clk *bclk; + struct regulator *booster; + struct regulator *vdd; struct regulator *vdda; struct regulator *vref; + int vdd_uv; + int vdda_uv; const struct stm32_adc_priv_cfg *cfg; struct stm32_adc_common common; u32 ccr_bak; + struct regmap *syscfg; }; static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) @@ -349,7 +374,6 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, */ if (i && priv->irq[i] == -ENXIO) continue; - dev_err(&pdev->dev, "failed to get irq\n"); return priv->irq[i]; } @@ -390,6 +414,82 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, } } +static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv, + struct device *dev) +{ + int ret; + + /* + * On STM32H7 and STM32MP1, the ADC inputs are multiplexed with analog + * switches (via PCSEL) which have reduced performances when their + * supply is below 2.7V (vdda by default): + * - Voltage booster can be used, to get full ADC performances + * (increases power consumption). + * - Vdd can be used to supply them, if above 2.7V (STM32MP1 only). + * + * Recommended settings for ANASWVDD and EN_BOOSTER: + * - vdda < 2.7V but vdd > 2.7V: ANASWVDD = 1, EN_BOOSTER = 0 (stm32mp1) + * - vdda < 2.7V and vdd < 2.7V: ANASWVDD = 0, EN_BOOSTER = 1 + * - vdda >= 2.7V: ANASWVDD = 0, EN_BOOSTER = 0 (default) + */ + if (priv->vdda_uv < 2700000) { + if (priv->syscfg && priv->vdd_uv > 2700000) { + ret = regulator_enable(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd enable failed %d\n", ret); + return ret; + } + + ret = regmap_write(priv->syscfg, + STM32MP1_SYSCFG_PMCSETR, + STM32MP1_SYSCFG_ANASWVDD_MASK); + if (ret < 0) { + regulator_disable(priv->vdd); + dev_err(dev, "vdd select failed, %d\n", ret); + return ret; + } + dev_dbg(dev, "analog switches supplied by vdd\n"); + + return 0; + } + + if (priv->booster) { + /* + * This is optional, as this is a trade-off between + * analog performance and power consumption. + */ + ret = regulator_enable(priv->booster); + if (ret < 0) { + dev_err(dev, "booster enable failed %d\n", ret); + return ret; + } + dev_dbg(dev, "analog switches supplied by booster\n"); + + return 0; + } + } + + /* Fallback using vdda (default), nothing to do */ + dev_dbg(dev, "analog switches supplied by vdda (%d uV)\n", + priv->vdda_uv); + + return 0; +} + +static void stm32_adc_core_switches_supply_dis(struct stm32_adc_priv *priv) +{ + if (priv->vdda_uv < 2700000) { + if (priv->syscfg && priv->vdd_uv > 2700000) { + regmap_write(priv->syscfg, STM32MP1_SYSCFG_PMCCLRR, + STM32MP1_SYSCFG_ANASWVDD_MASK); + regulator_disable(priv->vdd); + return; + } + if (priv->booster) + regulator_disable(priv->booster); + } +} + static int stm32_adc_core_hw_start(struct device *dev) { struct stm32_adc_common *common = dev_get_drvdata(dev); @@ -402,10 +502,21 @@ static int stm32_adc_core_hw_start(struct device *dev) return ret; } + ret = regulator_get_voltage(priv->vdda); + if (ret < 0) { + dev_err(dev, "vdda get voltage failed, %d\n", ret); + goto err_vdda_disable; + } + priv->vdda_uv = ret; + + ret = stm32_adc_core_switches_supply_en(priv, dev); + if (ret < 0) + goto err_vdda_disable; + ret = regulator_enable(priv->vref); if (ret < 0) { dev_err(dev, "vref enable failed\n"); - goto err_vdda_disable; + goto err_switches_dis; } if (priv->bclk) { @@ -433,6 +544,8 @@ err_bclk_disable: clk_disable_unprepare(priv->bclk); err_regulator_disable: regulator_disable(priv->vref); +err_switches_dis: + stm32_adc_core_switches_supply_dis(priv); err_vdda_disable: regulator_disable(priv->vdda); @@ -451,9 +564,80 @@ static void stm32_adc_core_hw_stop(struct device *dev) if (priv->bclk) clk_disable_unprepare(priv->bclk); regulator_disable(priv->vref); + stm32_adc_core_switches_supply_dis(priv); regulator_disable(priv->vdda); } +static int stm32_adc_core_switches_probe(struct device *dev, + struct stm32_adc_priv *priv) +{ + struct device_node *np = dev->of_node; + int ret; + + /* Analog switches supply can be controlled by syscfg (optional) */ + priv->syscfg = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(priv->syscfg)) { + ret = PTR_ERR(priv->syscfg); + if (ret != -ENODEV) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Can't probe syscfg: %d\n", ret); + return ret; + } + priv->syscfg = NULL; + } + + /* Booster can be used to supply analog switches (optional) */ + if (priv->cfg->has_syscfg & HAS_VBOOSTER && + of_property_read_bool(np, "booster-supply")) { + priv->booster = devm_regulator_get_optional(dev, "booster"); + if (IS_ERR(priv->booster)) { + ret = PTR_ERR(priv->booster); + if (ret != -ENODEV) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "can't get booster %d\n", + ret); + return ret; + } + priv->booster = NULL; + } + } + + /* Vdd can be used to supply analog switches (optional) */ + if (priv->cfg->has_syscfg & HAS_ANASWVDD && + of_property_read_bool(np, "vdd-supply")) { + priv->vdd = devm_regulator_get_optional(dev, "vdd"); + if (IS_ERR(priv->vdd)) { + ret = PTR_ERR(priv->vdd); + if (ret != -ENODEV) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "can't get vdd %d\n", ret); + return ret; + } + priv->vdd = NULL; + } + } + + if (priv->vdd) { + ret = regulator_enable(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd enable failed %d\n", ret); + return ret; + } + + ret = regulator_get_voltage(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd get voltage failed %d\n", ret); + regulator_disable(priv->vdd); + return ret; + } + priv->vdd_uv = ret; + + regulator_disable(priv->vdd); + } + + return 0; +} + static int stm32_adc_probe(struct platform_device *pdev) { struct stm32_adc_priv *priv; @@ -514,6 +698,10 @@ static int stm32_adc_probe(struct platform_device *pdev) priv->bclk = NULL; } + ret = stm32_adc_core_switches_probe(dev, priv); + if (ret) + return ret; + pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS); @@ -611,12 +799,14 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { .regs = &stm32h7_adc_common_regs, .clk_sel = stm32h7_adc_clk_sel, .max_clk_rate_hz = 36000000, + .has_syscfg = HAS_VBOOSTER, }; static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { .regs = &stm32h7_adc_common_regs, .clk_sel = stm32h7_adc_clk_sel, .max_clk_rate_hz = 40000000, + .has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD, }; static const struct of_device_id stm32_adc_of_match[] = { diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 205e1699f954..6a7dd08b1e0b 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1919,10 +1919,8 @@ static int stm32_adc_probe(struct platform_device *pdev) } adc->irq = platform_get_irq(pdev, 0); - if (adc->irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); + if (adc->irq < 0) return adc->irq; - } ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr, 0, pdev->name, adc); diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index ee1e0569d0e1..e493242c266e 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1601,11 +1601,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) * So IRQ associated to filter instance 0 is dedicated to the Filter 0. */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(dev, "Failed to get IRQ: %d\n", irq); + if (irq < 0) return irq; - } ret = devm_request_irq(dev, irq, stm32_dfsdm_irq, 0, pdev->name, adc); diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index f13c6248a662..176e1cb4abb1 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -460,10 +460,8 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name, atomic_set(atomic, 1); ret = platform_get_irq_byname(pdev, name); - if (ret < 0) { - dev_err(&pdev->dev, "no %s interrupt registered\n", name); + if (ret < 0) return ret; - } ret = regmap_irq_get_virq(mfd_dev->regmap_irqc, ret); if (ret < 0) { diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 2fa6ec83bb13..f24148bd15de 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -905,10 +905,8 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, twl6030_gpadc_irq_handler, diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 41d3621c4787..98b30475bbc6 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -821,10 +821,8 @@ static int vf610_adc_probe(struct platform_device *pdev) return PTR_ERR(info->regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(info->dev, irq, vf610_adc_isr, 0, diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 17af4e0fd5f8..6a4919cd83c3 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -63,10 +63,35 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev, /* Save values */ for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) - st->core.calib[i] = + st->core.calib[i].offset = st->core.resp->sensor_offset.offset[i]; ret = IIO_VAL_INT; - *val = st->core.calib[idx]; + *val = st->core.calib[idx].offset; + break; + case IIO_CHAN_INFO_CALIBSCALE: + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE; + st->core.param.sensor_offset.flags = 0; + + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret == -EPROTO) { + /* Reading calibscale is not supported on older EC. */ + *val = 1; + *val2 = 0; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + } else if (ret) { + break; + } + + /* Save values */ + for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) + st->core.calib[i].scale = + st->core.resp->sensor_scale.scale[i]; + + *val = st->core.calib[idx].scale >> 15; + *val2 = ((st->core.calib[idx].scale & 0x7FFF) * 1000000LL) / + MOTION_SENSE_DEFAULT_SCALE; + ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_SCALE: st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; @@ -134,7 +159,7 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: - st->core.calib[idx] = val; + st->core.calib[idx].offset = val; /* Send to EC for each axis, even if not complete */ st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; @@ -142,12 +167,27 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev, MOTION_SENSE_SET_OFFSET; for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) st->core.param.sensor_offset.offset[i] = - st->core.calib[i]; + st->core.calib[i].offset; st->core.param.sensor_offset.temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; + case IIO_CHAN_INFO_CALIBSCALE: + st->core.calib[idx].scale = val; + /* Send to EC for each axis, even if not complete */ + + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE; + st->core.param.sensor_offset.flags = + MOTION_SENSE_SET_OFFSET; + for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) + st->core.param.sensor_scale.scale[i] = + st->core.calib[i].scale; + st->core.param.sensor_scale.temp = + EC_MOTION_SENSE_INVALID_CALIB_TEMP; + + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + break; case IIO_CHAN_INFO_SCALE: if (st->core.type == MOTIONSENSE_TYPE_MAG) { ret = -EINVAL; @@ -175,6 +215,7 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev, static const struct iio_info ec_sensors_info = { .read_raw = &cros_ec_sensors_read, .write_raw = &cros_ec_sensors_write, + .read_avail = &cros_ec_sensors_core_read_avail, }; static int cros_ec_sensors_probe(struct platform_device *pdev) @@ -206,11 +247,14 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) /* Common part */ channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBBIAS); + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE); channel->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_FREQUENCY) | BIT(IIO_CHAN_INFO_SAMP_FREQ); + channel->info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; channel->scan_type.storagebits = CROS_EC_SENSOR_BITS; channel->scan_index = i; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index 130362ca421b..d44ae126f457 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -25,6 +25,62 @@ static char *cros_ec_loc[] = { [MOTIONSENSE_LOC_MAX] = "unknown", }; +static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev, + u16 cmd_offset, u16 cmd, u32 *mask) +{ + int ret; + struct { + struct cros_ec_command msg; + union { + struct ec_params_get_cmd_versions params; + struct ec_response_get_cmd_versions resp; + }; + } __packed buf = { + .msg = { + .command = EC_CMD_GET_CMD_VERSIONS + cmd_offset, + .insize = sizeof(struct ec_response_get_cmd_versions), + .outsize = sizeof(struct ec_params_get_cmd_versions) + }, + .params = {.cmd = cmd} + }; + + ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg); + if (ret >= 0) + *mask = buf.resp.version_mask; + return ret; +} + +static void get_default_min_max_freq(enum motionsensor_type type, + u32 *min_freq, + u32 *max_freq) +{ + switch (type) { + case MOTIONSENSE_TYPE_ACCEL: + case MOTIONSENSE_TYPE_GYRO: + *min_freq = 12500; + *max_freq = 100000; + break; + case MOTIONSENSE_TYPE_MAG: + *min_freq = 5000; + *max_freq = 25000; + break; + case MOTIONSENSE_TYPE_PROX: + case MOTIONSENSE_TYPE_LIGHT: + *min_freq = 100; + *max_freq = 50000; + break; + case MOTIONSENSE_TYPE_BARO: + *min_freq = 250; + *max_freq = 20000; + break; + case MOTIONSENSE_TYPE_ACTIVITY: + default: + *min_freq = 0; + *max_freq = 0; + break; + } +} + int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device) @@ -33,6 +89,8 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent); struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); + u32 ver_mask; + int ret, i; platform_set_drvdata(pdev, indio_dev); @@ -47,8 +105,15 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, mutex_init(&state->cmd_lock); + ret = cros_ec_get_host_cmd_version_mask(state->ec, + ec->cmd_offset, + EC_CMD_MOTION_SENSE_CMD, + &ver_mask); + if (ret < 0) + return ret; + /* Set up the host command structure. */ - state->msg->version = 2; + state->msg->version = fls(ver_mask) - 1; state->msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; state->msg->outsize = sizeof(struct ec_params_motion_sense); @@ -60,12 +125,32 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, state->param.cmd = MOTIONSENSE_CMD_INFO; state->param.info.sensor_num = sensor_platform->sensor_num; - if (cros_ec_motion_send_host_cmd(state, 0)) { + ret = cros_ec_motion_send_host_cmd(state, 0); + if (ret) { dev_warn(dev, "Can not access sensor info\n"); - return -EIO; + return ret; } state->type = state->resp->info.type; state->loc = state->resp->info.location; + + /* Set sign vector, only used for backward compatibility. */ + memset(state->sign, 1, CROS_EC_SENSOR_MAX_AXIS); + + for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) + state->calib[i].scale = MOTION_SENSE_DEFAULT_SCALE; + + /* 0 is a correct value used to stop the device */ + state->frequencies[0] = 0; + if (state->msg->version < 3) { + get_default_min_max_freq(state->resp->info.type, + &state->frequencies[1], + &state->frequencies[2]); + } else { + state->frequencies[1] = + state->resp->info_3.min_frequency; + state->frequencies[2] = + state->resp->info_3.max_frequency; + } } return 0; @@ -86,7 +171,7 @@ int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *state, ret = cros_ec_cmd_xfer_status(state->ec, state->msg); if (ret < 0) - return -EIO; + return ret; if (ret && state->resp != (struct ec_response_motion_sense *)state->msg->data) @@ -118,7 +203,7 @@ static ssize_t cros_ec_sensors_calibrate(struct iio_dev *indio_dev, } else { /* Save values */ for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++) - st->calib[i] = st->resp->perform_calib.offset[i]; + st->calib[i].offset = st->resp->perform_calib.offset[i]; } mutex_unlock(&st->cmd_lock); @@ -268,6 +353,7 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev, if (ret < 0) return ret; + *data *= st->sign[i]; data++; } @@ -396,7 +482,7 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - int ret = IIO_VAL_INT; + int ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: @@ -404,22 +490,27 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, st->param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; - else - *val = st->resp->ec_rate.ret; + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret) + break; + + *val = st->resp->ec_rate.ret; + ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_FREQUENCY: st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR; st->param.sensor_odr.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; - else - *val = st->resp->sensor_odr.ret; + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret) + break; + + *val = st->resp->sensor_odr.ret; + ret = IIO_VAL_INT; break; default: + ret = -EINVAL; break; } @@ -427,11 +518,32 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, } EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read); +int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, + int *type, + int *length, + long mask) +{ + struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *length = ARRAY_SIZE(state->frequencies); + *vals = (const int *)&state->frequencies; + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read_avail); + int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int ret = 0; + int ret; switch (mask) { case IIO_CHAN_INFO_FREQUENCY: @@ -441,17 +553,16 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, /* Always roundup, so caller gets at least what it asks for. */ st->param.sensor_odr.roundup = 1; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(st, 0); break; case IIO_CHAN_INFO_SAMP_FREQ: st->param.cmd = MOTIONSENSE_CMD_EC_RATE; st->param.ec_rate.data = val; - if (cros_ec_motion_send_host_cmd(st, 0)) - ret = -EIO; - else - st->curr_sampl_freq = val; + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret) + break; + st->curr_sampl_freq = val; break; default: ret = -EINVAL; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index a8a3fe428d8d..442ff787f7af 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -8,11 +8,16 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/kernel.h> #include <linux/slab.h> +#include <linux/time.h> + #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#define HZ_PER_MHZ 1000000L + static struct { u32 usage_id; int unit; /* 0 for default others from HID sensor spec */ @@ -68,16 +73,6 @@ static struct { {HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0}, }; -static int pow_10(unsigned power) -{ - int i; - int ret = 1; - for (i = 0; i < power; ++i) - ret = ret * 10; - - return ret; -} - static void simple_div(int dividend, int divisor, int *whole, int *micro_frac) { @@ -96,14 +91,16 @@ static void simple_div(int dividend, int divisor, int *whole, rem *= 10; exp++; } - *micro_frac = (rem / divisor) * pow_10(6-exp); + *micro_frac = (rem / divisor) * int_pow(10, 6 - exp); } } static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2) { - *val1 = no/pow_10(exp); - *val2 = no%pow_10(exp) * pow_10(6-exp); + int divisor = int_pow(10, exp); + + *val1 = no / divisor; + *val2 = no % divisor * int_pow(10, 6 - exp); } /* @@ -125,7 +122,7 @@ static void convert_from_vtf_format(u32 value, int size, int exp, } exp = hid_sensor_convert_exponent(exp); if (exp >= 0) { - *val1 = sign * value * pow_10(exp); + *val1 = sign * value * int_pow(10, exp); *val2 = 0; } else { split_micro_fraction(value, -exp, val1, val2); @@ -138,6 +135,7 @@ static void convert_from_vtf_format(u32 value, int size, int exp, static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) { + int divisor; u32 value; int sign = 1; @@ -145,10 +143,13 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) sign = -1; exp = hid_sensor_convert_exponent(exp); if (exp < 0) { - value = abs(val1) * pow_10(-exp); - value += abs(val2) / pow_10(6+exp); - } else - value = abs(val1) / pow_10(exp); + divisor = int_pow(10, 6 + exp); + value = abs(val1) * int_pow(10, -exp); + value += abs(val2) / divisor; + } else { + divisor = int_pow(10, exp); + value = abs(val1) / divisor; + } if (sign < 0) value = ((1LL << (size * 8)) - value); @@ -211,12 +212,12 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, if (val1 < 0 || val2 < 0) return -EINVAL; - value = val1 * pow_10(6) + val2; + value = val1 * HZ_PER_MHZ + val2; if (value) { if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) - value = pow_10(9)/value; + value = NSEC_PER_SEC / value; else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) - value = pow_10(6)/value; + value = USEC_PER_SEC / value; else value = 0; } @@ -305,40 +306,44 @@ EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); static void adjust_exponent_nano(int *val0, int *val1, int scale0, int scale1, int exp) { + int divisor; int i; int x; int res; int rem; if (exp > 0) { - *val0 = scale0 * pow_10(exp); + *val0 = scale0 * int_pow(10, exp); res = 0; if (exp > 9) { *val1 = 0; return; } for (i = 0; i < exp; ++i) { - x = scale1 / pow_10(8 - i); - res += (pow_10(exp - 1 - i) * x); - scale1 = scale1 % pow_10(8 - i); + divisor = int_pow(10, 8 - i); + x = scale1 / divisor; + res += int_pow(10, exp - 1 - i) * x; + scale1 = scale1 % divisor; } *val0 += res; - *val1 = scale1 * pow_10(exp); + *val1 = scale1 * int_pow(10, exp); } else if (exp < 0) { exp = abs(exp); if (exp > 9) { *val0 = *val1 = 0; return; } - *val0 = scale0 / pow_10(exp); - rem = scale0 % pow_10(exp); + divisor = int_pow(10, exp); + *val0 = scale0 / divisor; + rem = scale0 % divisor; res = 0; for (i = 0; i < (9 - exp); ++i) { - x = scale1 / pow_10(8 - i); - res += (pow_10(8 - exp - i) * x); - scale1 = scale1 % pow_10(8 - i); + divisor = int_pow(10, 8 - i); + x = scale1 / divisor; + res += int_pow(10, 8 - exp - i) * x; + scale1 = scale1 % divisor; } - *val1 = rem * pow_10(9 - exp) + res; + *val1 = rem * int_pow(10, 9 - exp) + res; } else { *val0 = scale0; *val1 = scale1; diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig index 91b98e152d75..9364ec7a811f 100644 --- a/drivers/iio/common/st_sensors/Kconfig +++ b/drivers/iio/common/st_sensors/Kconfig @@ -5,9 +5,11 @@ config IIO_ST_SENSORS_I2C tristate + select REGMAP_I2C config IIO_ST_SENSORS_SPI tristate + select REGMAP_SPI config IIO_ST_SENSORS_CORE tristate diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 4a68669dc555..eee30130ae23 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -17,15 +17,16 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> #include <linux/irqreturn.h> +#include <linux/regmap.h> #include <linux/iio/common/st_sensors.h> static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) { - int i; struct st_sensor_data *sdata = iio_priv(indio_dev); unsigned int num_data_channels = sdata->num_data_channels; + int i; for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) { const struct iio_chan_spec *channel = &indio_dev->channels[i]; @@ -36,11 +37,8 @@ static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) channel->scan_type.storagebits >> 3; buf = PTR_ALIGN(buf, storage_bytes); - if (sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, - channel->address, - bytes_to_read, buf, - sdata->multiread_bit) < - bytes_to_read) + if (regmap_bulk_read(sdata->regmap, channel->address, + buf, bytes_to_read) < 0) return -EIO; /* Advance the buffer pointer */ diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 8b22dc241482..4a3064fb6cd9 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -15,6 +15,7 @@ #include <linux/regulator/consumer.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/regmap.h> #include <asm/unaligned.h> #include <linux/iio/common/st_sensors.h> @@ -28,19 +29,10 @@ static inline u32 st_sensors_get_unaligned_le24(const u8 *p) int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, u8 reg_addr, u8 mask, u8 data) { - int err; - u8 new_data; struct st_sensor_data *sdata = iio_priv(indio_dev); - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data); - if (err < 0) - goto st_sensors_write_data_with_mask_error; - - new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask)); - err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data); - -st_sensors_write_data_with_mask_error: - return err; + return regmap_update_bits(sdata->regmap, + reg_addr, mask, data << __ffs(mask)); } int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, @@ -48,19 +40,15 @@ int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, unsigned *readval) { struct st_sensor_data *sdata = iio_priv(indio_dev); - u8 readdata; int err; if (!readval) - return sdata->tf->write_byte(&sdata->tb, sdata->dev, - (u8)reg, (u8)writeval); + return regmap_write(sdata->regmap, reg, writeval); - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata); + err = regmap_read(sdata->regmap, reg, readval); if (err < 0) return err; - *readval = (unsigned)readdata; - return 0; } EXPORT_SYMBOL(st_sensors_debugfs_reg_access); @@ -545,7 +533,7 @@ st_sensors_match_scale_error: EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain); static int st_sensors_read_axis_data(struct iio_dev *indio_dev, - struct iio_chan_spec const *ch, int *data) + struct iio_chan_spec const *ch, int *data) { int err; u8 *outdata; @@ -554,13 +542,12 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits + ch->scan_type.shift, 8); - outdata = kmalloc(byte_for_channel, GFP_KERNEL); + outdata = kmalloc(byte_for_channel, GFP_DMA | GFP_KERNEL); if (!outdata) return -ENOMEM; - err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, - ch->address, byte_for_channel, - outdata, sdata->multiread_bit); + err = regmap_bulk_read(sdata->regmap, ch->address, + outdata, byte_for_channel); if (err < 0) goto st_sensors_free_memory; @@ -608,69 +595,55 @@ out: } EXPORT_SYMBOL(st_sensors_read_info_raw); -static int st_sensors_init_interface_mode(struct iio_dev *indio_dev, - const struct st_sensor_settings *sensor_settings) +/* + * st_sensors_get_settings_index() - get index of the sensor settings for a + * specific device from list of settings + * @name: device name buffer reference. + * @list: sensor settings list. + * @list_length: length of sensor settings list. + * + * Return: non negative number on success (valid index), + * negative error code otherwise. + */ +int st_sensors_get_settings_index(const char *name, + const struct st_sensor_settings *list, + const int list_length) { - struct st_sensor_data *sdata = iio_priv(indio_dev); - struct device_node *np = sdata->dev->of_node; - struct st_sensors_platform_data *pdata; + int i, n; - pdata = (struct st_sensors_platform_data *)sdata->dev->platform_data; - if (((np && of_property_read_bool(np, "spi-3wire")) || - (pdata && pdata->spi_3wire)) && sensor_settings->sim.addr) { - int err; - - err = sdata->tf->write_byte(&sdata->tb, sdata->dev, - sensor_settings->sim.addr, - sensor_settings->sim.value); - if (err < 0) { - dev_err(&indio_dev->dev, - "failed to init interface mode\n"); - return err; + for (i = 0; i < list_length; i++) { + for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { + if (strcmp(name, list[i].sensors_supported[n]) == 0) + return i; } } - return 0; + return -ENODEV; } +EXPORT_SYMBOL(st_sensors_get_settings_index); -int st_sensors_check_device_support(struct iio_dev *indio_dev, - int num_sensors_list, - const struct st_sensor_settings *sensor_settings) +/* + * st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the + * expected value + * @indio_dev: IIO device reference. + * + * Return: 0 on success (valid sensor ID), else a negative error code. + */ +int st_sensors_verify_id(struct iio_dev *indio_dev) { - int i, n, err = 0; - u8 wai; struct st_sensor_data *sdata = iio_priv(indio_dev); + int wai, err; - for (i = 0; i < num_sensors_list; i++) { - for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { - if (strcmp(indio_dev->name, - sensor_settings[i].sensors_supported[n]) == 0) { - break; - } - } - if (n < ST_SENSORS_MAX_4WAI) - break; - } - if (i == num_sensors_list) { - dev_err(&indio_dev->dev, "device name %s not recognized.\n", - indio_dev->name); - return -ENODEV; - } - - err = st_sensors_init_interface_mode(indio_dev, &sensor_settings[i]); - if (err < 0) - return err; - - if (sensor_settings[i].wai_addr) { - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sensor_settings[i].wai_addr, &wai); + if (sdata->sensor_settings->wai_addr) { + err = regmap_read(sdata->regmap, + sdata->sensor_settings->wai_addr, &wai); if (err < 0) { dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); return err; } - if (sensor_settings[i].wai != wai) { + if (sdata->sensor_settings->wai != wai) { dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", indio_dev->name, wai); @@ -678,12 +651,9 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, } } - sdata->sensor_settings = - (struct st_sensor_settings *)&sensor_settings[i]; - - return i; + return 0; } -EXPORT_SYMBOL(st_sensors_check_device_support); +EXPORT_SYMBOL(st_sensors_verify_id); ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index b1c9812407e7..aa89d54a7c59 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -13,68 +13,58 @@ #include <linux/iio/iio.h> #include <linux/of_device.h> #include <linux/acpi.h> +#include <linux/regmap.h> #include <linux/iio/common/st_sensors_i2c.h> #define ST_SENSORS_I2C_MULTIREAD 0x80 -static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev) -{ - struct st_sensor_data *sdata = iio_priv(indio_dev); - - return to_i2c_client(sdata->dev)->irq; -} - -static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 *res_byte) -{ - int err; - - err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr); - if (err < 0) - goto st_accel_i2c_read_byte_error; - - *res_byte = err & 0xff; - -st_accel_i2c_read_byte_error: - return err < 0 ? err : 0; -} - -static int st_sensors_i2c_read_multiple_byte( - struct st_sensor_transfer_buffer *tb, struct device *dev, - u8 reg_addr, int len, u8 *data, bool multiread_bit) -{ - if (multiread_bit) - reg_addr |= ST_SENSORS_I2C_MULTIREAD; - - return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev), - reg_addr, len, data); -} - -static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 data) -{ - return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data); -} +static const struct regmap_config st_sensors_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; -static const struct st_sensor_transfer_function st_sensors_tf_i2c = { - .read_byte = st_sensors_i2c_read_byte, - .write_byte = st_sensors_i2c_write_byte, - .read_multiple_byte = st_sensors_i2c_read_multiple_byte, +static const struct regmap_config st_sensors_i2c_regmap_multiread_bit_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = ST_SENSORS_I2C_MULTIREAD, }; -void st_sensors_i2c_configure(struct iio_dev *indio_dev, - struct i2c_client *client, struct st_sensor_data *sdata) +/* + * st_sensors_i2c_configure() - configure I2C interface + * @indio_dev: IIO device reference. + * @client: i2c client reference. + * + * Return: 0 on success, else a negative error code. + */ +int st_sensors_i2c_configure(struct iio_dev *indio_dev, + struct i2c_client *client) { + struct st_sensor_data *sdata = iio_priv(indio_dev); + const struct regmap_config *config; + + if (sdata->sensor_settings->multi_read_bit) + config = &st_sensors_i2c_regmap_multiread_bit_config; + else + config = &st_sensors_i2c_regmap_config; + + sdata->regmap = devm_regmap_init_i2c(client, config); + if (IS_ERR(sdata->regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap (%d)\n", + (int)PTR_ERR(sdata->regmap)); + return PTR_ERR(sdata->regmap); + } + i2c_set_clientdata(client, indio_dev); indio_dev->dev.parent = &client->dev; indio_dev->name = client->name; sdata->dev = &client->dev; - sdata->tf = &st_sensors_tf_i2c; - sdata->get_irq_data_ready = st_sensors_i2c_get_irq; + sdata->irq = client->irq; + + return 0; } EXPORT_SYMBOL(st_sensors_i2c_configure); diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c index 2213843f02cb..2262f81b07c2 100644 --- a/drivers/iio/common/st_sensors/st_sensors_spi.c +++ b/drivers/iio/common/st_sensors/st_sensors_spi.c @@ -11,108 +11,108 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/iio/iio.h> +#include <linux/regmap.h> #include <linux/iio/common/st_sensors_spi.h> - +#include "st_sensors_core.h" #define ST_SENSORS_SPI_MULTIREAD 0xc0 -#define ST_SENSORS_SPI_READ 0x80 -static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev) -{ - struct st_sensor_data *sdata = iio_priv(indio_dev); +static const struct regmap_config st_sensors_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; - return to_spi_device(sdata->dev)->irq; -} +static const struct regmap_config st_sensors_spi_regmap_multiread_bit_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = ST_SENSORS_SPI_MULTIREAD, +}; -static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit) +/* + * st_sensors_is_spi_3_wire() - check if SPI 3-wire mode has been selected + * @spi: spi device reference. + * + * Return: true if SPI 3-wire mode is selected, false otherwise. + */ +static bool st_sensors_is_spi_3_wire(struct spi_device *spi) { - int err; - - struct spi_transfer xfers[] = { - { - .tx_buf = tb->tx_buf, - .bits_per_word = 8, - .len = 1, - }, - { - .rx_buf = tb->rx_buf, - .bits_per_word = 8, - .len = len, - } - }; - - mutex_lock(&tb->buf_lock); - if ((multiread_bit) && (len > 1)) - tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD; - else - tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ; + struct device_node *np = spi->dev.of_node; + struct st_sensors_platform_data *pdata; - err = spi_sync_transfer(to_spi_device(dev), xfers, ARRAY_SIZE(xfers)); - if (err) - goto acc_spi_read_error; + pdata = (struct st_sensors_platform_data *)spi->dev.platform_data; + if ((np && of_property_read_bool(np, "spi-3wire")) || + (pdata && pdata->spi_3wire)) { + return true; + } - memcpy(data, tb->rx_buf, len); - mutex_unlock(&tb->buf_lock); - return len; - -acc_spi_read_error: - mutex_unlock(&tb->buf_lock); - return err; + return false; } -static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 *res_byte) +/* + * st_sensors_configure_spi_3_wire() - configure SPI 3-wire if needed + * @spi: spi device reference. + * @settings: sensor specific settings reference. + * + * Return: 0 on success, else a negative error code. + */ +static int st_sensors_configure_spi_3_wire(struct spi_device *spi, + struct st_sensor_settings *settings) { - return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false); -} + if (settings->sim.addr) { + u8 buffer[] = { + settings->sim.addr, + settings->sim.value + }; -static int st_sensors_spi_read_multiple_byte( - struct st_sensor_transfer_buffer *tb, struct device *dev, - u8 reg_addr, int len, u8 *data, bool multiread_bit) -{ - return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit); + return spi_write(spi, buffer, 2); + } + + return 0; } -static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb, - struct device *dev, u8 reg_addr, u8 data) +/* + * st_sensors_spi_configure() - configure SPI interface + * @indio_dev: IIO device reference. + * @spi: spi device reference. + * + * Return: 0 on success, else a negative error code. + */ +int st_sensors_spi_configure(struct iio_dev *indio_dev, + struct spi_device *spi) { + struct st_sensor_data *sdata = iio_priv(indio_dev); + const struct regmap_config *config; int err; - struct spi_transfer xfers = { - .tx_buf = tb->tx_buf, - .bits_per_word = 8, - .len = 2, - }; + if (st_sensors_is_spi_3_wire(spi)) { + err = st_sensors_configure_spi_3_wire(spi, + sdata->sensor_settings); + if (err < 0) + return err; + } - mutex_lock(&tb->buf_lock); - tb->tx_buf[0] = reg_addr; - tb->tx_buf[1] = data; - - err = spi_sync_transfer(to_spi_device(dev), &xfers, 1); - mutex_unlock(&tb->buf_lock); + if (sdata->sensor_settings->multi_read_bit) + config = &st_sensors_spi_regmap_multiread_bit_config; + else + config = &st_sensors_spi_regmap_config; - return err; -} + sdata->regmap = devm_regmap_init_spi(spi, config); + if (IS_ERR(sdata->regmap)) { + dev_err(&spi->dev, "Failed to register spi regmap (%d)\n", + (int)PTR_ERR(sdata->regmap)); + return PTR_ERR(sdata->regmap); + } -static const struct st_sensor_transfer_function st_sensors_tf_spi = { - .read_byte = st_sensors_spi_read_byte, - .write_byte = st_sensors_spi_write_byte, - .read_multiple_byte = st_sensors_spi_read_multiple_byte, -}; - -void st_sensors_spi_configure(struct iio_dev *indio_dev, - struct spi_device *spi, struct st_sensor_data *sdata) -{ spi_set_drvdata(spi, indio_dev); indio_dev->dev.parent = &spi->dev; indio_dev->name = spi->modalias; sdata->dev = &spi->dev; - sdata->tf = &st_sensors_tf_spi; - sdata->get_irq_data_ready = st_sensors_spi_get_irq; + sdata->irq = spi->irq; + + return 0; } EXPORT_SYMBOL(st_sensors_spi_configure); diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 630c8cb35e8b..4a2efa00f7f2 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -13,6 +13,7 @@ #include <linux/iio/iio.h> #include <linux/iio/trigger.h> #include <linux/interrupt.h> +#include <linux/regmap.h> #include <linux/iio/common/st_sensors.h> #include "st_sensors_core.h" @@ -26,8 +27,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, struct st_sensor_data *sdata) { - u8 status; - int ret; + int ret, status; /* How would I know if I can't check it? */ if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr) @@ -37,9 +37,9 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, if (!indio_dev->active_scan_mask) return 0; - ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sdata->sensor_settings->drdy_irq.stat_drdy.addr, - &status); + ret = regmap_read(sdata->regmap, + sdata->sensor_settings->drdy_irq.stat_drdy.addr, + &status); if (ret < 0) { dev_err(sdata->dev, "error checking samples available\n"); @@ -121,9 +121,9 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p) int st_sensors_allocate_trigger(struct iio_dev *indio_dev, const struct iio_trigger_ops *trigger_ops) { - int err, irq; struct st_sensor_data *sdata = iio_priv(indio_dev); unsigned long irq_trig; + int err; sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name); if (sdata->trig == NULL) { @@ -135,8 +135,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, sdata->trig->ops = trigger_ops; sdata->trig->dev.parent = sdata->dev; - irq = sdata->get_irq_data_ready(indio_dev); - irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); + irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq)); /* * If the IRQ is triggered on falling edge, we need to mark the * interrupt as active low, if the hardware supports this. @@ -206,12 +205,12 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, sdata->sensor_settings->drdy_irq.stat_drdy.addr) irq_trig |= IRQF_SHARED; - err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), - st_sensors_irq_handler, - st_sensors_irq_thread, - irq_trig, - sdata->trig->name, - sdata->trig); + err = request_threaded_irq(sdata->irq, + st_sensors_irq_handler, + st_sensors_irq_thread, + irq_trig, + sdata->trig->name, + sdata->trig); if (err) { dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n"); goto iio_trigger_free; @@ -227,7 +226,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, return 0; iio_trigger_register_error: - free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); + free_irq(sdata->irq, sdata->trig); iio_trigger_free: iio_trigger_free(sdata->trig); return err; @@ -239,7 +238,7 @@ void st_sensors_deallocate_trigger(struct iio_dev *indio_dev) struct st_sensor_data *sdata = iio_priv(indio_dev); iio_trigger_unregister(sdata->trig); - free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); + free_irq(sdata->irq, sdata->trig); iio_trigger_free(sdata->trig); } EXPORT_SYMBOL(st_sensors_deallocate_trigger); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 4335214800d2..2ebe08326048 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -220,7 +220,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev, if (ret) return ret; *val >>= chan->scan_type.shift; - val -= (1 << chan->scan_type.realbits) / 2; + *val -= (1 << chan->scan_type.realbits) / 2; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 2 * st->vref; diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h index 460d190be4a4..592f6b34e987 100644 --- a/drivers/iio/gyro/st_gyro.h +++ b/drivers/iio/gyro/st_gyro.h @@ -32,6 +32,7 @@ static const struct st_sensors_platform_data gyro_pdata = { .drdy_int_pin = 2, }; +const struct st_sensor_settings *st_gyro_get_settings(const char *name); int st_gyro_common_probe(struct iio_dev *indio_dev); void st_gyro_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index 6e362f735e92..7465ad62391c 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -29,61 +29,51 @@ int st_gyro_trig_set_state(struct iio_trigger *trig, bool state) return st_sensors_set_dataready_irq(indio_dev, state); } -static int st_gyro_buffer_preenable(struct iio_dev *indio_dev) -{ - return st_sensors_set_enable(indio_dev, true); -} - static int st_gyro_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *gdata = iio_priv(indio_dev); - gdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (gdata->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } + err = iio_triggered_buffer_postenable(indio_dev); + if (err < 0) + return err; err = st_sensors_set_axis_enable(indio_dev, - (u8)indio_dev->active_scan_mask[0]); + (u8)indio_dev->active_scan_mask[0]); if (err < 0) - goto st_gyro_buffer_postenable_error; + goto st_gyro_buffer_predisable; - err = iio_triggered_buffer_postenable(indio_dev); + err = st_sensors_set_enable(indio_dev, true); if (err < 0) - goto st_gyro_buffer_postenable_error; + goto st_gyro_buffer_enable_all_axis; - return err; + return 0; -st_gyro_buffer_postenable_error: - kfree(gdata->buffer_data); -allocate_memory_error: +st_gyro_buffer_enable_all_axis: + st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); +st_gyro_buffer_predisable: + iio_triggered_buffer_predisable(indio_dev); return err; } static int st_gyro_buffer_predisable(struct iio_dev *indio_dev) { - int err; - struct st_sensor_data *gdata = iio_priv(indio_dev); + int err, err2; - err = iio_triggered_buffer_predisable(indio_dev); + err = st_sensors_set_enable(indio_dev, false); if (err < 0) - goto st_gyro_buffer_predisable_error; + goto st_gyro_buffer_predisable; err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); - if (err < 0) - goto st_gyro_buffer_predisable_error; - err = st_sensors_set_enable(indio_dev, false); +st_gyro_buffer_predisable: + err2 = iio_triggered_buffer_predisable(indio_dev); + if (!err) + err = err2; -st_gyro_buffer_predisable_error: - kfree(gdata->buffer_data); return err; } static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = { - .preenable = &st_gyro_buffer_preenable, .postenable = &st_gyro_buffer_postenable, .predisable = &st_gyro_buffer_predisable, }; diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index e995dc77e30e..c0acbb5d2ffb 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -12,7 +12,6 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/types.h> -#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/gpio.h> @@ -368,28 +367,41 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = { #define ST_GYRO_TRIGGER_OPS NULL #endif +/* + * st_gyro_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_gyro_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_gyro_sensors_settings, + ARRAY_SIZE(st_gyro_sensors_settings)); + if (index < 0) + return NULL; + + return &st_gyro_sensors_settings[index]; +} +EXPORT_SYMBOL(st_gyro_get_settings); + int st_gyro_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *gdata = iio_priv(indio_dev); - int irq = gdata->get_irq_data_ready(indio_dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; - mutex_init(&gdata->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_gyro_sensors_settings), - st_gyro_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_gyro_power_off; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; - gdata->multiread_bit = gdata->sensor_settings->multi_read_bit; indio_dev->channels = gdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; @@ -406,7 +418,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_gyro_power_off; - if (irq > 0) { + if (gdata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_GYRO_TRIGGER_OPS); if (err < 0) @@ -423,7 +435,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) return 0; st_gyro_device_register_error: - if (irq > 0) + if (gdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_gyro_probe_trigger_error: st_gyro_deallocate_ring(indio_dev); @@ -441,7 +453,7 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (gdata->get_irq_data_ready(indio_dev) > 0) + if (gdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_gyro_deallocate_ring(indio_dev); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index f2a8683db7d9..05a1a0874bd5 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -63,21 +63,33 @@ MODULE_DEVICE_TABLE(of, st_gyro_of_match); #endif static int st_gyro_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *gdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&client->dev, st_gyro_of_match, + client->name, sizeof(client->name)); + + settings = st_gyro_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*gdata)); if (!indio_dev) return -ENOMEM; gdata = iio_priv(indio_dev); - st_sensors_of_name_probe(&client->dev, st_gyro_of_match, - client->name, sizeof(client->name)); + gdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_i2c_configure(indio_dev, client, gdata); + err = st_sensors_i2c_configure(indio_dev, client); + if (err < 0) + return err; err = st_gyro_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 93c48248bea6..b5c624251231 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -69,19 +69,31 @@ MODULE_DEVICE_TABLE(of, st_gyro_of_match); static int st_gyro_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *gdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_gyro_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_gyro_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*gdata)); if (!indio_dev) return -ENOMEM; gdata = iio_priv(indio_dev); + gdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_gyro_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, gdata); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_gyro_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index f18da7859229..3bac98e731d9 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -240,32 +240,15 @@ static int am2315_probe(struct i2c_client *client, indio_dev->channels = am2315_channels; indio_dev->num_channels = ARRAY_SIZE(am2315_channels); - ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, + ret = devm_iio_triggered_buffer_setup(&client->dev, + indio_dev, iio_pollfunc_store_time, am2315_trigger_handler, NULL); if (ret < 0) { dev_err(&client->dev, "iio triggered buffer setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) - goto err_buffer_cleanup; - - return 0; - -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} - -static int am2315_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id am2315_i2c_id[] = { @@ -287,7 +270,6 @@ static struct i2c_driver am2315_driver = { .acpi_match_table = ACPI_PTR(am2315_acpi_id), }, .probe = am2315_probe, - .remove = am2315_remove, .id_table = am2315_i2c_id, }; diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 066e05f92081..bfe1cdb16846 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -385,28 +385,16 @@ static int hdc100x_probe(struct i2c_client *client, hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]); hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(&client->dev, + indio_dev, NULL, hdc100x_trigger_handler, &hdc_buffer_setup_ops); if (ret < 0) { dev_err(&client->dev, "iio triggered buffer setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} - -static int hdc100x_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id hdc100x_id[] = { @@ -436,7 +424,6 @@ static struct i2c_driver hdc100x_driver = { .of_match_table = of_match_ptr(hdc100x_dt_ids), }, .probe = hdc100x_probe, - .remove = hdc100x_remove, .id_table = hdc100x_id, }; module_i2c_driver(hdc100x_driver); diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 4957e6df447e..f3c7282321a8 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -17,6 +17,18 @@ config ADIS16400 adis16365, adis16400 and adis16405 triaxial inertial sensors (adis16400 series also have magnetometers). +config ADIS16460 + tristate "Analog Devices ADIS16460 and similar IMU driver" + depends on SPI + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + help + Say yes here to build support for Analog Devices ADIS16460 inertial + sensor. + + To compile this driver as a module, choose M here: the module will be + called adis16460. + config ADIS16480 tristate "Analog Devices ADIS16480 and similar IMU driver" depends on SPI diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 9e452fce1aaf..4a6958865504 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADIS16400) += adis16400.o +obj-$(CONFIG_ADIS16460) += adis16460.o obj-$(CONFIG_ADIS16480) += adis16480.o adis_lib-y += adis.o diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 30281e91dbf9..1631c255deab 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -39,18 +39,24 @@ int adis_write_reg(struct adis *adis, unsigned int reg, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 4, .bits_per_word = 8, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 6, .bits_per_word = 8, @@ -133,12 +139,16 @@ int adis_read_reg(struct adis *adis, unsigned int reg, .len = 2, .cs_change = 1, .delay_usecs = adis->data->write_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 2, .bits_per_word = 8, .len = 2, .cs_change = 1, .delay_usecs = adis->data->read_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .tx_buf = adis->tx + 4, .rx_buf = adis->rx, @@ -146,6 +156,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg, .len = 2, .cs_change = 1, .delay_usecs = adis->data->read_delay, + .cs_change_delay = adis->data->cs_change_delay, + .cs_change_delay_unit = SPI_DELAY_UNIT_USECS, }, { .rx_buf = adis->rx + 2, .bits_per_word = 8, diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c new file mode 100644 index 000000000000..6aed9e84abbf --- /dev/null +++ b/drivers/iio/imu/adis16460.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ADIS16460 IMU driver + * + * Copyright 2019 Analog Devices Inc. + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include <linux/iio/iio.h> +#include <linux/iio/imu/adis.h> + +#include <linux/debugfs.h> + +#define ADIS16460_REG_FLASH_CNT 0x00 +#define ADIS16460_REG_DIAG_STAT 0x02 +#define ADIS16460_REG_X_GYRO_LOW 0x04 +#define ADIS16460_REG_X_GYRO_OUT 0x06 +#define ADIS16460_REG_Y_GYRO_LOW 0x08 +#define ADIS16460_REG_Y_GYRO_OUT 0x0A +#define ADIS16460_REG_Z_GYRO_LOW 0x0C +#define ADIS16460_REG_Z_GYRO_OUT 0x0E +#define ADIS16460_REG_X_ACCL_LOW 0x10 +#define ADIS16460_REG_X_ACCL_OUT 0x12 +#define ADIS16460_REG_Y_ACCL_LOW 0x14 +#define ADIS16460_REG_Y_ACCL_OUT 0x16 +#define ADIS16460_REG_Z_ACCL_LOW 0x18 +#define ADIS16460_REG_Z_ACCL_OUT 0x1A +#define ADIS16460_REG_SMPL_CNTR 0x1C +#define ADIS16460_REG_TEMP_OUT 0x1E +#define ADIS16460_REG_X_DELT_ANG 0x24 +#define ADIS16460_REG_Y_DELT_ANG 0x26 +#define ADIS16460_REG_Z_DELT_ANG 0x28 +#define ADIS16460_REG_X_DELT_VEL 0x2A +#define ADIS16460_REG_Y_DELT_VEL 0x2C +#define ADIS16460_REG_Z_DELT_VEL 0x2E +#define ADIS16460_REG_MSC_CTRL 0x32 +#define ADIS16460_REG_SYNC_SCAL 0x34 +#define ADIS16460_REG_DEC_RATE 0x36 +#define ADIS16460_REG_FLTR_CTRL 0x38 +#define ADIS16460_REG_GLOB_CMD 0x3E +#define ADIS16460_REG_X_GYRO_OFF 0x40 +#define ADIS16460_REG_Y_GYRO_OFF 0x42 +#define ADIS16460_REG_Z_GYRO_OFF 0x44 +#define ADIS16460_REG_X_ACCL_OFF 0x46 +#define ADIS16460_REG_Y_ACCL_OFF 0x48 +#define ADIS16460_REG_Z_ACCL_OFF 0x4A +#define ADIS16460_REG_LOT_ID1 0x52 +#define ADIS16460_REG_LOT_ID2 0x54 +#define ADIS16460_REG_PROD_ID 0x56 +#define ADIS16460_REG_SERIAL_NUM 0x58 +#define ADIS16460_REG_CAL_SGNTR 0x60 +#define ADIS16460_REG_CAL_CRC 0x62 +#define ADIS16460_REG_CODE_SGNTR 0x64 +#define ADIS16460_REG_CODE_CRC 0x66 + +struct adis16460_chip_info { + unsigned int num_channels; + const struct iio_chan_spec *channels; + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + unsigned int accel_max_val; + unsigned int accel_max_scale; +}; + +struct adis16460 { + const struct adis16460_chip_info *chip_info; + struct adis adis; +}; + +#ifdef CONFIG_DEBUG_FS + +static int adis16460_show_serial_number(void *arg, u64 *val) +{ + struct adis16460 *adis16460 = arg; + u16 serial; + int ret; + + ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_SERIAL_NUM, + &serial); + if (ret < 0) + return ret; + + *val = serial; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16460_serial_number_fops, + adis16460_show_serial_number, NULL, "0x%.4llx\n"); + +static int adis16460_show_product_id(void *arg, u64 *val) +{ + struct adis16460 *adis16460 = arg; + u16 prod_id; + int ret; + + ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_PROD_ID, + &prod_id); + if (ret < 0) + return ret; + + *val = prod_id; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16460_product_id_fops, + adis16460_show_product_id, NULL, "%llu\n"); + +static int adis16460_show_flash_count(void *arg, u64 *val) +{ + struct adis16460 *adis16460 = arg; + u32 flash_count; + int ret; + + ret = adis_read_reg_32(&adis16460->adis, ADIS16460_REG_FLASH_CNT, + &flash_count); + if (ret < 0) + return ret; + + *val = flash_count; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16460_flash_count_fops, + adis16460_show_flash_count, NULL, "%lld\n"); + +static int adis16460_debugfs_init(struct iio_dev *indio_dev) +{ + struct adis16460 *adis16460 = iio_priv(indio_dev); + + debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry, + adis16460, &adis16460_serial_number_fops); + debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, + adis16460, &adis16460_product_id_fops); + debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, + adis16460, &adis16460_flash_count_fops); + + return 0; +} + +#else + +static int adis16460_debugfs_init(struct iio_dev *indio_dev) +{ + return 0; +} + +#endif + +static int adis16460_set_freq(struct iio_dev *indio_dev, int val, int val2) +{ + struct adis16460 *st = iio_priv(indio_dev); + int t; + + t = val * 1000 + val2 / 1000; + if (t <= 0) + return -EINVAL; + + t = 2048000 / t; + if (t > 2048) + t = 2048; + + if (t != 0) + t--; + + return adis_write_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, t); +} + +static int adis16460_get_freq(struct iio_dev *indio_dev, int *val, int *val2) +{ + struct adis16460 *st = iio_priv(indio_dev); + uint16_t t; + int ret; + unsigned int freq; + + ret = adis_read_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, &t); + if (ret < 0) + return ret; + + freq = 2048000 / (t + 1); + *val = freq / 1000; + *val2 = (freq % 1000) * 1000; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int adis16460_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, int *val2, long info) +{ + struct adis16460 *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + return adis_single_conversion(indio_dev, chan, 0, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + *val = st->chip_info->gyro_max_scale; + *val2 = st->chip_info->gyro_max_val; + return IIO_VAL_FRACTIONAL; + case IIO_ACCEL: + *val = st->chip_info->accel_max_scale; + *val2 = st->chip_info->accel_max_val; + return IIO_VAL_FRACTIONAL; + case IIO_TEMP: + *val = 50; /* 50 milli degrees Celsius/LSB */ + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + *val = 500; /* 25 degrees Celsius = 0x0000 */ + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + return adis16460_get_freq(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +static int adis16460_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int val, int val2, long info) +{ + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + return adis16460_set_freq(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +enum { + ADIS16460_SCAN_GYRO_X, + ADIS16460_SCAN_GYRO_Y, + ADIS16460_SCAN_GYRO_Z, + ADIS16460_SCAN_ACCEL_X, + ADIS16460_SCAN_ACCEL_Y, + ADIS16460_SCAN_ACCEL_Z, + ADIS16460_SCAN_TEMP, +}; + +#define ADIS16460_MOD_CHANNEL(_type, _mod, _address, _si, _bits) \ + { \ + .type = (_type), \ + .modified = 1, \ + .channel2 = (_mod), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .address = (_address), \ + .scan_index = (_si), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (_bits), \ + .storagebits = (_bits), \ + .endianness = IIO_BE, \ + }, \ + } + +#define ADIS16460_GYRO_CHANNEL(_mod) \ + ADIS16460_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \ + ADIS16460_REG_ ## _mod ## _GYRO_LOW, ADIS16460_SCAN_GYRO_ ## _mod, \ + 32) + +#define ADIS16460_ACCEL_CHANNEL(_mod) \ + ADIS16460_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \ + ADIS16460_REG_ ## _mod ## _ACCL_LOW, ADIS16460_SCAN_ACCEL_ ## _mod, \ + 32) + +#define ADIS16460_TEMP_CHANNEL() { \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .address = ADIS16460_REG_TEMP_OUT, \ + .scan_index = ADIS16460_SCAN_TEMP, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec adis16460_channels[] = { + ADIS16460_GYRO_CHANNEL(X), + ADIS16460_GYRO_CHANNEL(Y), + ADIS16460_GYRO_CHANNEL(Z), + ADIS16460_ACCEL_CHANNEL(X), + ADIS16460_ACCEL_CHANNEL(Y), + ADIS16460_ACCEL_CHANNEL(Z), + ADIS16460_TEMP_CHANNEL(), + IIO_CHAN_SOFT_TIMESTAMP(7) +}; + +static const struct adis16460_chip_info adis16460_chip_info = { + .channels = adis16460_channels, + .num_channels = ARRAY_SIZE(adis16460_channels), + /* + * storing the value in rad/degree and the scale in degree + * gives us the result in rad and better precession than + * storing the scale directly in rad. + */ + .gyro_max_val = IIO_RAD_TO_DEGREE(200 << 16), + .gyro_max_scale = 1, + .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), + .accel_max_scale = 5, +}; + +static const struct iio_info adis16460_info = { + .read_raw = &adis16460_read_raw, + .write_raw = &adis16460_write_raw, + .update_scan_mode = adis_update_scan_mode, + .debugfs_reg_access = adis_debugfs_reg_access, +}; + +static int adis16460_enable_irq(struct adis *adis, bool enable) +{ + /* + * There is no way to gate the data-ready signal internally inside the + * ADIS16460 :( + */ + if (enable) + enable_irq(adis->spi->irq); + else + disable_irq(adis->spi->irq); + + return 0; +} + +static int adis16460_initial_setup(struct iio_dev *indio_dev) +{ + struct adis16460 *st = iio_priv(indio_dev); + uint16_t prod_id; + unsigned int device_id; + int ret; + + adis_reset(&st->adis); + msleep(222); + + ret = adis_write_reg_16(&st->adis, ADIS16460_REG_GLOB_CMD, BIT(1)); + if (ret) + return ret; + msleep(75); + + ret = adis_check_status(&st->adis); + if (ret) + return ret; + + ret = adis_read_reg_16(&st->adis, ADIS16460_REG_PROD_ID, &prod_id); + if (ret) + return ret; + + ret = sscanf(indio_dev->name, "adis%u\n", &device_id); + if (ret != 1) + return -EINVAL; + + if (prod_id != device_id) + dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", + device_id, prod_id); + + return 0; +} + +#define ADIS16460_DIAG_STAT_IN_CLK_OOS 7 +#define ADIS16460_DIAG_STAT_FLASH_MEM 6 +#define ADIS16460_DIAG_STAT_SELF_TEST 5 +#define ADIS16460_DIAG_STAT_OVERRANGE 4 +#define ADIS16460_DIAG_STAT_SPI_COMM 3 +#define ADIS16460_DIAG_STAT_FLASH_UPT 2 + +static const char * const adis16460_status_error_msgs[] = { + [ADIS16460_DIAG_STAT_IN_CLK_OOS] = "Input clock out of sync", + [ADIS16460_DIAG_STAT_FLASH_MEM] = "Flash memory failure", + [ADIS16460_DIAG_STAT_SELF_TEST] = "Self test diagnostic failure", + [ADIS16460_DIAG_STAT_OVERRANGE] = "Sensor overrange", + [ADIS16460_DIAG_STAT_SPI_COMM] = "SPI communication failure", + [ADIS16460_DIAG_STAT_FLASH_UPT] = "Flash update failure", +}; + +static const struct adis_data adis16460_data = { + .diag_stat_reg = ADIS16460_REG_DIAG_STAT, + .glob_cmd_reg = ADIS16460_REG_GLOB_CMD, + .has_paging = false, + .read_delay = 5, + .write_delay = 5, + .cs_change_delay = 16, + .status_error_msgs = adis16460_status_error_msgs, + .status_error_mask = BIT(ADIS16460_DIAG_STAT_IN_CLK_OOS) | + BIT(ADIS16460_DIAG_STAT_FLASH_MEM) | + BIT(ADIS16460_DIAG_STAT_SELF_TEST) | + BIT(ADIS16460_DIAG_STAT_OVERRANGE) | + BIT(ADIS16460_DIAG_STAT_SPI_COMM) | + BIT(ADIS16460_DIAG_STAT_FLASH_UPT), + .enable_irq = adis16460_enable_irq, +}; + +static int adis16460_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct adis16460 *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, indio_dev); + + st = iio_priv(indio_dev); + + st->chip_info = &adis16460_chip_info; + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + indio_dev->info = &adis16460_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis_init(&st->adis, indio_dev, spi, &adis16460_data); + if (ret) + return ret; + + ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); + if (ret) + return ret; + + adis16460_enable_irq(&st->adis, 0); + + ret = adis16460_initial_setup(indio_dev); + if (ret) + goto error_cleanup_buffer; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_buffer; + + adis16460_debugfs_init(indio_dev); + + return 0; + +error_cleanup_buffer: + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); + return ret; +} + +static int adis16460_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis16460 *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); + + return 0; +} + +static const struct spi_device_id adis16460_ids[] = { + { "adis16460", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, adis16460_ids); + +static const struct of_device_id adis16460_of_match[] = { + { .compatible = "adi,adis16460" }, + {} +}; +MODULE_DEVICE_TABLE(of, adis16460_of_match); + +static struct spi_driver adis16460_driver = { + .driver = { + .name = "adis16460", + .of_match_table = adis16460_of_match, + }, + .id_table = adis16460_ids, + .probe = adis16460_probe, + .remove = adis16460_remove, +}; +module_spi_driver(adis16460_driver); + +MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16460 IMU driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 395f3bd7de0a..e4c4c12236a7 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -14,8 +14,9 @@ config INV_MPU6050_I2C select INV_MPU6050_IIO select REGMAP_I2C help - This driver supports the Invensense MPU6050/6500/9150 and - ICM20608/20602 motion tracking devices over I2C. + This driver supports the Invensense MPU6000/6050/6500/6515, + MPU9150/9250/9255 and ICM20608/20602 motion tracking devices + over I2C. This driver can be built as a module. The module will be called inv-mpu6050-i2c. @@ -25,7 +26,8 @@ config INV_MPU6050_SPI select INV_MPU6050_IIO select REGMAP_SPI help - This driver supports the Invensense MPU6050/6500/9150 and - ICM20608/20602 motion tracking devices over SPI. + This driver supports the Invensense MPU6000/6050/6500/6515, + MPU9150/9250/9255 and ICM20608/20602 motion tracking devices + over SPI. This driver can be built as a module. The module will be called inv-mpu6050-spi. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 8a704cd5bddb..b17f060b52fc 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1137,10 +1137,9 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, if (result) return result; - result = devm_add_action(dev, inv_mpu_core_disable_regulator_action, + result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action, st); if (result) { - inv_mpu_core_disable_regulator_action(st); dev_err(dev, "Failed to setup regulator cleanup action %d\n", result); return result; diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 002a423eae52..77aa0e77212d 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -2,15 +2,17 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, - ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr + ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c, + ism330dhcx and the accelerometer/gyroscope of lsm9ds1. To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. @@ -24,3 +26,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index 28cc67399d94..57cbcd67d64f 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -5,3 +5,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index c14bf533b66b..80e42c7dbcbe 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -22,6 +22,9 @@ #define ST_ASM330LHH_DEV_NAME "asm330lhh" #define ST_LSM6DSOX_DEV_NAME "lsm6dsox" #define ST_LSM6DSR_DEV_NAME "lsm6dsr" +#define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c" +#define ST_ISM330DHCX_DEV_NAME "ism330dhcx" +#define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, @@ -33,6 +36,9 @@ enum st_lsm6dsx_hw_id { ST_ASM330LHH_ID, ST_LSM6DSOX_ID, ST_LSM6DSR_ID, + ST_LSM6DS3TRC_ID, + ST_ISM330DHCX_ID, + ST_LSM9DS1_ID, ST_LSM6DSX_MAX_ID, }; @@ -54,8 +60,8 @@ enum st_lsm6dsx_hw_id { .address = addr, \ .modified = 1, \ .channel2 = mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .scan_index = scan_idx, \ .scan_type = { \ @@ -71,6 +77,7 @@ struct st_lsm6dsx_reg { u8 mask; }; +struct st_lsm6dsx_sensor; struct st_lsm6dsx_hw; struct st_lsm6dsx_odr { @@ -97,12 +104,14 @@ struct st_lsm6dsx_fs_table_entry { /** * struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings + * @update_fifo: Update FIFO configuration callback. * @read_fifo: Read FIFO callback. * @fifo_th: FIFO threshold register info (addr + mask). * @fifo_diff: FIFO diff status register info (addr + mask). * @th_wl: FIFO threshold word length. */ struct st_lsm6dsx_fifo_ops { + int (*update_fifo)(struct st_lsm6dsx_sensor *sensor, bool enable); int (*read_fifo)(struct st_lsm6dsx_hw *hw); struct { u8 addr; @@ -196,8 +205,14 @@ struct st_lsm6dsx_ext_dev_settings { /** * struct st_lsm6dsx_settings - ST IMU sensor settings * @wai: Sensor WhoAmI default value. + * @int1_addr: Control Register address for INT1 + * @int2_addr: Control Register address for INT2 + * @reset_addr: register address for reset/reboot * @max_fifo_size: Sensor max fifo length in FIFO words. * @id: List of hw id/device name supported by the driver configuration. + * @channels: IIO channels supported by the device. + * @odr_table: Hw sensors odr table (Hz + val). + * @fs_table: Hw sensors gain table (gain + val). * @decimator: List of decimator register info (addr + mask). * @batch: List of FIFO batching register info (addr + mask). * @fifo_ops: Sensor hw FIFO parameters. @@ -206,11 +221,20 @@ struct st_lsm6dsx_ext_dev_settings { */ struct st_lsm6dsx_settings { u8 wai; + u8 int1_addr; + u8 int2_addr; + u8 reset_addr; u16 max_fifo_size; struct { enum st_lsm6dsx_hw_id hw_id; const char *name; } id[ST_LSM6DSX_MAX_ID]; + struct { + const struct iio_chan_spec *chan; + int len; + } channels[2]; + struct st_lsm6dsx_odr_table_entry odr_table[2]; + struct st_lsm6dsx_fs_table_entry fs_table[2]; struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_fifo_ops fifo_ops; @@ -314,6 +338,7 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw); int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val); int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark); +int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw); int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, enum st_lsm6dsx_fifo_mode fifo_mode); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index e4d8a79d557d..b0f3da1976e4 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -2,10 +2,10 @@ /* * STMicroelectronics st_lsm6dsx FIFO buffer library driver * - * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: The FIFO buffer can be - * configured to store data from gyroscope and accelerometer. Samples are - * queued without any tag according to a specific pattern based on - * 'FIFO data sets' (6 bytes each): + * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: + * The FIFO buffer can be configured to store data from gyroscope and + * accelerometer. Samples are queued without any tag according to a + * specific pattern based on 'FIFO data sets' (6 bytes each): * - 1st data set is reserved for gyroscope data * - 2nd data set is reserved for accelerometer data * The FIFO pattern changes depending on the ODRs and decimation factors @@ -14,9 +14,10 @@ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * value of the decimation factor and ODR set for each FIFO data set. * - * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR: The FIFO buffer can be configured to - * store data from gyroscope and accelerometer. Each sample is queued with - * a tag (1B) indicating data source (gyroscope, accelerometer, hw timer). + * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: The FIFO buffer can be + * configured to store data from gyroscope and accelerometer. Each sample + * is queued with a tag (1B) indicating data source (gyroscope, accelerometer, + * hw timer). * * FIFO supported modes: * - BYPASS: FIFO disabled @@ -601,9 +602,8 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) return err; } -static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable) +int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable) { - struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); struct st_lsm6dsx_hw *hw = sensor->hw; int err; @@ -670,17 +670,29 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) count = hw->settings->fifo_ops.read_fifo(hw); mutex_unlock(&hw->fifo_lock); - return !count ? IRQ_NONE : IRQ_HANDLED; + return count ? IRQ_HANDLED : IRQ_NONE; } static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev) { - return st_lsm6dsx_update_fifo(iio_dev, true); + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + + if (!hw->settings->fifo_ops.update_fifo) + return -ENOTSUPP; + + return hw->settings->fifo_ops.update_fifo(sensor, true); } static int st_lsm6dsx_buffer_postdisable(struct iio_dev *iio_dev) { - return st_lsm6dsx_update_fifo(iio_dev, false); + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + + if (!hw->settings->fifo_ops.update_fifo) + return -ENOTSUPP; + + return hw->settings->fifo_ops.update_fifo(sensor, false); } static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index a6702a74570e..2d3495560136 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -10,6 +10,8 @@ * +-125/+-245/+-500/+-1000/+-2000 dps * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer * allowing dynamic batching of sensor data. + * LSM9DSx series is similar but includes an additional magnetometer, handled + * by a different driver. * * Supported sensors: * - LSM6DS3: @@ -18,18 +20,25 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * - * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: + * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 4KB * - * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR + * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 3KB * + * - LSM9DS1: + * - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952 + * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 + * - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952 + * - Gyroscope supported full-scale [dps]: +-245/+-500/+-2000 + * - FIFO size: 32 + * * Copyright 2016 STMicroelectronics Inc. * * Lorenzo Bianconi <lorenzo.bianconi@st.com> @@ -49,79 +58,110 @@ #include "st_lsm6dsx.h" -#define ST_LSM6DSX_REG_INT1_ADDR 0x0d -#define ST_LSM6DSX_REG_INT2_ADDR 0x0e #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3) #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f -#define ST_LSM6DSX_REG_RESET_ADDR 0x12 #define ST_LSM6DSX_REG_RESET_MASK BIT(0) #define ST_LSM6DSX_REG_BOOT_MASK BIT(7) #define ST_LSM6DSX_REG_BDU_ADDR 0x12 #define ST_LSM6DSX_REG_BDU_MASK BIT(6) -#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13 -#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5) - -#define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28 -#define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a -#define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c - -#define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22 -#define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 -#define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 - -static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { - [ST_LSM6DSX_ID_ACC] = { - .reg = { - .addr = 0x10, - .mask = GENMASK(7, 4), - }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, - }, - [ST_LSM6DSX_ID_GYRO] = { - .reg = { - .addr = 0x11, - .mask = GENMASK(7, 4), - }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, - } + +static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { + ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x28, IIO_MOD_X, 0), + ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1), + ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2c, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), }; -static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { - [ST_LSM6DSX_ID_ACC] = { - .reg = { - .addr = 0x10, - .mask = GENMASK(3, 2), - }, - .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, - .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, - .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, - .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, - }, - [ST_LSM6DSX_ID_GYRO] = { - .reg = { - .addr = 0x11, - .mask = GENMASK(3, 2), - }, - .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, - .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, - .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, - .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, - } +static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x22, IIO_MOD_X, 0), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x24, IIO_MOD_Y, 1), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x26, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = { + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x18, IIO_MOD_X, 0), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x1a, IIO_MOD_Y, 1), + ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x1c, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), }; static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { + .wai = 0x68, + .int1_addr = 0x0c, + .int2_addr = 0x0d, + .reset_addr = 0x22, + .max_fifo_size = 32, + .id = { + { + .hw_id = ST_LSM9DS1_ID, + .name = ST_LSM9DS1_DEV_NAME, + }, + }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6ds0_gyro_channels, + .len = ARRAY_SIZE(st_lsm6ds0_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x20, + .mask = GENMASK(7, 5), + }, + .odr_avl[0] = { 10, 0x01 }, + .odr_avl[1] = { 50, 0x02 }, + .odr_avl[2] = { 119, 0x03 }, + .odr_avl[3] = { 238, 0x04 }, + .odr_avl[4] = { 476, 0x05 }, + .odr_avl[5] = { 952, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 5), + }, + .odr_avl[0] = { 15, 0x01 }, + .odr_avl[1] = { 60, 0x02 }, + .odr_avl[2] = { 119, 0x03 }, + .odr_avl[3] = { 238, 0x04 }, + .odr_avl[4] = { 476, 0x05 }, + .odr_avl[5] = { 952, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x20, + .mask = GENMASK(4, 3), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(732), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(4, 3), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(245), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(2000), 0x3 }, + }, + }, + }, + { .wai = 0x69, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 1365, .id = { { @@ -129,6 +169,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_LSM6DS3_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -140,6 +238,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, .fifo_th = { .addr = 0x06, @@ -172,6 +271,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x69, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 682, .id = { { @@ -179,6 +281,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_LSM6DS3H_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -190,6 +350,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, .fifo_th = { .addr = 0x06, @@ -222,6 +383,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6a, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 682, .id = { { @@ -233,6 +397,67 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .hw_id = ST_ISM330DLC_ID, .name = ST_ISM330DLC_DEV_NAME, + }, { + .hw_id = ST_LSM6DS3TRC_ID, + .name = ST_LSM6DS3TRC_DEV_NAME, + }, + }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, }, }, .decimator = { @@ -246,6 +471,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, .fifo_th = { .addr = 0x06, @@ -278,6 +504,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6c, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 512, .id = { { @@ -288,6 +517,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_LSM6DSOX_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -299,6 +586,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, .fifo_th = { .addr = 0x07, @@ -306,7 +594,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(8, 0), + .mask = GENMASK(9, 0), }, .th_wl = 1, }, @@ -349,6 +637,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 512, .id = { { @@ -356,6 +647,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .name = ST_ASM330LHH_DEV_NAME, }, }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -367,6 +716,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, .fifo_th = { .addr = 0x07, @@ -374,7 +724,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(8, 0), + .mask = GENMASK(9, 0), }, .th_wl = 1, }, @@ -391,11 +741,75 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, + .int1_addr = 0x0d, + .int2_addr = 0x0e, + .reset_addr = 0x12, .max_fifo_size = 512, .id = { { .hw_id = ST_LSM6DSR_ID, .name = ST_LSM6DSR_DEV_NAME, + }, { + .hw_id = ST_ISM330DHCX_ID, + .name = ST_ISM330DHCX_DEV_NAME, + }, + }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 13, 0x01 }, + .odr_avl[1] = { 26, 0x02 }, + .odr_avl[2] = { 52, 0x03 }, + .odr_avl[3] = { 104, 0x04 }, + .odr_avl[4] = { 208, 0x05 }, + .odr_avl[5] = { 416, 0x06 }, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, }, }, .batch = { @@ -409,6 +823,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, .fifo_th = { .addr = 0x07, @@ -416,7 +831,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(8, 0), + .mask = GENMASK(9, 0), }, .th_wl = 1, }, @@ -459,26 +874,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }; -static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { - ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR, - IIO_MOD_X, 0), - ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR, - IIO_MOD_Y, 1), - ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR, - IIO_MOD_Z, 2), - IIO_CHAN_SOFT_TIMESTAMP(3), -}; - -static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { - ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR, - IIO_MOD_X, 0), - ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR, - IIO_MOD_Y, 1), - ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR, - IIO_MOD_Z, 2), - IIO_CHAN_SOFT_TIMESTAMP(3), -}; - int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable) { const struct st_lsm6dsx_shub_settings *hub_settings; @@ -533,23 +928,22 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id, static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, u32 gain) { - struct st_lsm6dsx_hw *hw = sensor->hw; - const struct st_lsm6dsx_reg *reg; + const struct st_lsm6dsx_fs_table_entry *fs_table; unsigned int data; int i, err; - u8 val; + fs_table = &sensor->hw->settings->fs_table[sensor->id]; for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) - if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain) + if (fs_table->fs_avl[i].gain == gain) break; if (i == ST_LSM6DSX_FS_LIST_SIZE) return -EINVAL; - val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val; - reg = &st_lsm6dsx_fs_table[sensor->id].reg; - data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); - err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data); + data = ST_LSM6DSX_SHIFT_VAL(fs_table->fs_avl[i].val, + fs_table->reg.mask); + err = st_lsm6dsx_update_bits_locked(sensor->hw, fs_table->reg.addr, + fs_table->reg.mask, data); if (err < 0) return err; @@ -560,20 +954,22 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) { + const struct st_lsm6dsx_odr_table_entry *odr_table; int i; + odr_table = &sensor->hw->settings->odr_table[sensor->id]; for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) /* * ext devices can run at different odr respect to * accel sensor */ - if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr) + if (odr_table->odr_avl[i].hz >= odr) break; if (i == ST_LSM6DSX_ODR_LIST_SIZE) return -EINVAL; - *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; + *val = odr_table->odr_avl[i].val; return 0; } @@ -638,7 +1034,7 @@ static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr) return err; } - reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg; + reg = &hw->settings->odr_table[ref_sensor->id].reg; data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data); } @@ -783,11 +1179,12 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, { struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); enum st_lsm6dsx_sensor_id id = sensor->id; + struct st_lsm6dsx_hw *hw = sensor->hw; int i, len = 0; for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - st_lsm6dsx_odr_table[id].odr_avl[i].hz); + hw->settings->odr_table[id].odr_avl[i].hz); buf[len - 1] = '\n'; return len; @@ -798,12 +1195,19 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, char *buf) { struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); + const struct st_lsm6dsx_fs_table_entry *fs_table; enum st_lsm6dsx_sensor_id id = sensor->id; + struct st_lsm6dsx_hw *hw = sensor->hw; int i, len = 0; - for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) + fs_table = &hw->settings->fs_table[id]; + for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) { + if (!fs_table->fs_avl[i].gain) + break; + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", - st_lsm6dsx_fs_table[id].fs_avl[i].gain); + fs_table->fs_avl[i].gain); + } buf[len - 1] = '\n'; return len; @@ -873,10 +1277,10 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) switch (drdy_pin) { case 1: - *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; + *drdy_reg = hw->settings->int1_addr; break; case 2: - *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; + *drdy_reg = hw->settings->int2_addr; break; default: dev_err(hw->dev, "unsupported data ready pin\n"); @@ -976,7 +1380,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) int err; /* device sw reset */ - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, + err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, ST_LSM6DSX_REG_RESET_MASK, FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1)); if (err < 0) @@ -985,7 +1389,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) msleep(50); /* reload trimming parameter */ - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, + err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, ST_LSM6DSX_REG_BOOT_MASK, FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1)); if (err < 0) @@ -1033,28 +1437,24 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, iio_dev->modes = INDIO_DIRECT_MODE; iio_dev->dev.parent = hw->dev; iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; + iio_dev->channels = hw->settings->channels[id].chan; + iio_dev->num_channels = hw->settings->channels[id].len; sensor = iio_priv(iio_dev); sensor->id = id; sensor->hw = hw; - sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; - sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; + sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz; + sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain; sensor->watermark = 1; switch (id) { case ST_LSM6DSX_ID_ACC: - iio_dev->channels = st_lsm6dsx_acc_channels; - iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); iio_dev->info = &st_lsm6dsx_acc_info; - scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", name); break; case ST_LSM6DSX_ID_GYRO: - iio_dev->channels = st_lsm6dsx_gyro_channels; - iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); iio_dev->info = &st_lsm6dsx_gyro_info; - scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", name); break; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index b3211e0ac07b..f52511059545 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -75,6 +75,18 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6dsr", .data = (void *)ST_LSM6DSR_ID, }, + { + .compatible = "st,lsm6ds3tr-c", + .data = (void *)ST_LSM6DS3TRC_ID, + }, + { + .compatible = "st,ism330dhcx", + .data = (void *)ST_ISM330DHCX_ID, + }, + { + .compatible = "st,lsm9ds1-imu", + .data = (void *)ST_LSM9DS1_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -89,6 +101,9 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, + { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, + { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, + { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 000000000000..57e633121bdc --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares <vitor.soares@synopsys.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i3c/device.h> +#include <linux/i3c/master.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/regmap.h> + +#include "st_lsm6dsx.h" + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, + st_lsm6dsx_i3c_ids); + struct regmap *regmap; + + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap); +} + +static struct i3c_driver st_lsm6dsx_driver = { + .driver = { + .name = "st_lsm6dsx_i3c", + .pm = &st_lsm6dsx_pm_ops, + }, + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares <vitor.soares@synopsys.com>"); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index c9d3c4711018..344b28dddebb 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -75,6 +75,18 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6dsr", .data = (void *)ST_LSM6DSR_ID, }, + { + .compatible = "st,lsm6ds3tr-c", + .data = (void *)ST_LSM6DS3TRC_ID, + }, + { + .compatible = "st,ism330dhcx", + .data = (void *)ST_ISM330DHCX_ID, + }, + { + .compatible = "st,lsm9ds1-imu", + .data = (void *)ST_LSM9DS1_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -89,6 +101,9 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, + { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, + { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, + { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index e3fd00b595d0..08d7e1ef2186 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -303,6 +303,7 @@ config MAX44000 config MAX44009 tristate "MAX44009 Ambient Light Sensor" depends on I2C + select REGMAP_I2C help Say Y here if you want to build support for Maxim Integrated's MAX44009 ambient light sensor device. @@ -310,6 +311,16 @@ config MAX44009 To compile this driver as a module, choose M here: the module will be called max44009. +config NOA1305 + tristate "ON Semiconductor NOA1305 ambient light sensor" + depends on I2C + help + Say Y here if you want to build support for the ON Semiconductor + NOA1305 ambient light sensor. + + To compile this driver as a module, choose M here: + The module will be called noa1305. + config OPT3001 tristate "Texas Instruments OPT3001 Light Sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index e40794fbb435..00d1f9b98f39 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_LTR501) += ltr501.o obj-$(CONFIG_LV0104CS) += lv0104cs.o obj-$(CONFIG_MAX44000) += max44000.o obj-$(CONFIG_MAX44009) += max44009.o +obj-$(CONFIG_NOA1305) += noa1305.o obj-$(CONFIG_OPT3001) += opt3001.o obj-$(CONFIG_PA12203001) += pa12203001.o obj-$(CONFIG_RPR0521) += rpr0521.o diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index b09b8b60bd83..c5dfb9a6b5a1 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1135,5 +1135,5 @@ static struct i2c_driver apds9960_driver = { module_i2c_driver(apds9960_driver); MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); -MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor"); +MODULE_DESCRIPTION("APDS9960 Gesture/RGB/ALS/Proximity sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 50f3438c2b49..0443861ba1ec 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -101,15 +101,16 @@ static int cm3323_init(struct iio_dev *indio_dev) return 0; } -static void cm3323_disable(struct iio_dev *indio_dev) +static void cm3323_disable(void *data) { int ret; - struct cm3323_data *data = iio_priv(indio_dev); + struct iio_dev *indio_dev = data; + struct cm3323_data *cm_data = iio_priv(indio_dev); - ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, + ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF, CM3323_CONF_SD_BIT); if (ret < 0) - dev_err(&data->client->dev, "Error writing reg_conf\n"); + dev_err(&cm_data->client->dev, "Error writing reg_conf\n"); } static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2) @@ -243,26 +244,11 @@ static int cm3323_probe(struct i2c_client *client, return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "failed to register iio dev\n"); - goto err_init; - } - - return 0; -err_init: - cm3323_disable(indio_dev); - return ret; -} - -static int cm3323_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - cm3323_disable(indio_dev); + ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev); + if (ret < 0) + return ret; - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id cm3323_id[] = { @@ -276,7 +262,6 @@ static struct i2c_driver cm3323_driver = { .name = CM3323_DRV_NAME, }, .probe = cm3323_probe, - .remove = cm3323_remove, .id_table = cm3323_id, }; diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 7702c2bcbcfa..1019d625adb1 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -646,18 +646,18 @@ static int cm36651_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); cm36651->client = client; - cm36651->ps_client = i2c_new_dummy(client->adapter, + cm36651->ps_client = i2c_new_dummy_device(client->adapter, CM36651_I2C_ADDR_PS); - if (!cm36651->ps_client) { + if (IS_ERR(cm36651->ps_client)) { dev_err(&client->dev, "%s: new i2c device failed\n", __func__); - ret = -ENODEV; + ret = PTR_ERR(cm36651->ps_client); goto error_disable_reg; } - cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA); - if (!cm36651->ara_client) { + cm36651->ara_client = i2c_new_dummy_device(client->adapter, CM36651_ARA); + if (IS_ERR(cm36651->ara_client)) { dev_err(&client->dev, "%s: new i2c device failed\n", __func__); - ret = -ENODEV; + ret = PTR_ERR(cm36651->ara_client); goto error_i2c_unregister_ps; } diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 308ee6ff2e22..44313a009928 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -42,7 +42,7 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, struct cros_ec_light_prox_state *st = iio_priv(indio_dev); u16 data = 0; s64 val64; - int ret = IIO_VAL_INT; + int ret; int idx = chan->scan_index; mutex_lock(&st->core.cmd_lock); @@ -50,23 +50,22 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: if (chan->type == IIO_PROXIMITY) { - if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, - (s16 *)&data) < 0) { - ret = -EIO; + ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data); + if (ret) break; - } *val = data; + ret = IIO_VAL_INT; } else { ret = -EINVAL; } break; case IIO_CHAN_INFO_PROCESSED: if (chan->type == IIO_LIGHT) { - if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, - (s16 *)&data) < 0) { - ret = -EIO; + ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data); + if (ret) break; - } /* * The data coming from the light sensor is * pre-processed and represents the ambient light @@ -82,15 +81,16 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; st->core.param.sensor_offset.flags = 0; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) { - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret) break; - } /* Save values */ - st->core.calib[0] = st->core.resp->sensor_offset.offset[0]; + st->core.calib[0].offset = + st->core.resp->sensor_offset.offset[0]; - *val = st->core.calib[idx]; + *val = st->core.calib[idx].offset; + ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_CALIBSCALE: /* @@ -101,10 +101,9 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev, st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) { - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret) break; - } val64 = st->core.resp->sensor_range.ret; *val = val64 >> 16; @@ -127,28 +126,27 @@ static int cros_ec_light_prox_write(struct iio_dev *indio_dev, int val, int val2, long mask) { struct cros_ec_light_prox_state *st = iio_priv(indio_dev); - int ret = 0; + int ret; int idx = chan->scan_index; mutex_lock(&st->core.cmd_lock); switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: - st->core.calib[idx] = val; + st->core.calib[idx].offset = val; /* Send to EC for each axis, even if not complete */ st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; st->core.param.sensor_offset.flags = MOTION_SENSE_SET_OFFSET; - st->core.param.sensor_offset.offset[0] = st->core.calib[0]; + st->core.param.sensor_offset.offset[0] = + st->core.calib[0].offset; st->core.param.sensor_offset.temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; case IIO_CHAN_INFO_CALIBSCALE: st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; st->core.param.sensor_range.data = (val << 16) | (val2 / 100); - if (cros_ec_motion_send_host_cmd(&st->core, 0)) - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; default: ret = cros_ec_sensors_core_write(&st->core, chan, val, val2, @@ -164,6 +162,7 @@ static int cros_ec_light_prox_write(struct iio_dev *indio_dev, static const struct iio_info cros_ec_light_prox_info = { .read_raw = &cros_ec_light_prox_read, .write_raw = &cros_ec_light_prox_write, + .read_avail = &cros_ec_sensors_core_read_avail, }; static int cros_ec_light_prox_probe(struct platform_device *pdev) @@ -198,6 +197,8 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) channel->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_FREQUENCY); + channel->info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; channel->scan_type.storagebits = CROS_EC_SENSOR_BITS; channel->scan_type.shift = 0; @@ -205,8 +206,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) channel->ext_info = cros_ec_sensors_ext_info; channel->scan_type.sign = 'u'; - state->core.calib[0] = 0; - /* Sensor specific */ switch (state->core.type) { case MOTIONSENSE_TYPE_LIGHT: diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c new file mode 100644 index 000000000000..5ebfbc52f541 --- /dev/null +++ b/drivers/iio/light/noa1305.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Support for ON Semiconductor NOA1305 ambient light sensor + * + * Copyright (C) 2016 Emcraft Systems + * Copyright (C) 2019 Collabora Ltd. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#define NOA1305_REG_POWER_CONTROL 0x0 +#define NOA1305_POWER_CONTROL_DOWN 0x00 +#define NOA1305_POWER_CONTROL_ON 0x08 +#define NOA1305_REG_RESET 0x1 +#define NOA1305_RESET_RESET 0x10 +#define NOA1305_REG_INTEGRATION_TIME 0x2 +#define NOA1305_INTEGR_TIME_800MS 0x00 +#define NOA1305_INTEGR_TIME_400MS 0x01 +#define NOA1305_INTEGR_TIME_200MS 0x02 +#define NOA1305_INTEGR_TIME_100MS 0x03 +#define NOA1305_INTEGR_TIME_50MS 0x04 +#define NOA1305_INTEGR_TIME_25MS 0x05 +#define NOA1305_INTEGR_TIME_12_5MS 0x06 +#define NOA1305_INTEGR_TIME_6_25MS 0x07 +#define NOA1305_REG_INT_SELECT 0x3 +#define NOA1305_INT_SEL_ACTIVE_HIGH 0x01 +#define NOA1305_INT_SEL_ACTIVE_LOW 0x02 +#define NOA1305_INT_SEL_INACTIVE 0x03 +#define NOA1305_REG_INT_THRESH_LSB 0x4 +#define NOA1305_REG_INT_THRESH_MSB 0x5 +#define NOA1305_REG_ALS_DATA_LSB 0x6 +#define NOA1305_REG_ALS_DATA_MSB 0x7 +#define NOA1305_REG_DEVICE_ID_LSB 0x8 +#define NOA1305_REG_DEVICE_ID_MSB 0x9 + +#define NOA1305_DEVICE_ID 0x0519 +#define NOA1305_DRIVER_NAME "noa1305" + +struct noa1305_priv { + struct i2c_client *client; + struct regmap *regmap; + struct regulator *vin_reg; +}; + +static int noa1305_measure(struct noa1305_priv *priv) +{ + __le16 data; + int ret; + + ret = regmap_bulk_read(priv->regmap, NOA1305_REG_ALS_DATA_LSB, &data, + 2); + if (ret < 0) + return ret; + + return le16_to_cpu(data); +} + +static int noa1305_scale(struct noa1305_priv *priv, int *val, int *val2) +{ + int data; + int ret; + + ret = regmap_read(priv->regmap, NOA1305_REG_INTEGRATION_TIME, &data); + if (ret < 0) + return ret; + + /* + * Lux = count / (<Integration Constant> * <Integration Time>) + * + * Integration Constant = 7.7 + * Integration Time in Seconds + */ + switch (data) { + case NOA1305_INTEGR_TIME_800MS: + *val = 100; + *val2 = 77 * 8; + break; + case NOA1305_INTEGR_TIME_400MS: + *val = 100; + *val2 = 77 * 4; + break; + case NOA1305_INTEGR_TIME_200MS: + *val = 100; + *val2 = 77 * 2; + break; + case NOA1305_INTEGR_TIME_100MS: + *val = 100; + *val2 = 77; + break; + case NOA1305_INTEGR_TIME_50MS: + *val = 1000; + *val2 = 77 * 5; + break; + case NOA1305_INTEGR_TIME_25MS: + *val = 10000; + *val2 = 77 * 25; + break; + case NOA1305_INTEGR_TIME_12_5MS: + *val = 100000; + *val2 = 77 * 125; + break; + case NOA1305_INTEGR_TIME_6_25MS: + *val = 1000000; + *val2 = 77 * 625; + break; + default: + return -EINVAL; + } + + return IIO_VAL_FRACTIONAL; +} + +static const struct iio_chan_spec noa1305_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static int noa1305_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret = -EINVAL; + struct noa1305_priv *priv = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_LIGHT: + ret = noa1305_measure(priv); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + default: + break; + } + break; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_LIGHT: + return noa1305_scale(priv, val, val2); + default: + break; + } + break; + default: + break; + } + + return ret; +} + +static const struct iio_info noa1305_info = { + .read_raw = noa1305_read_raw, +}; + +static bool noa1305_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NOA1305_REG_POWER_CONTROL: + case NOA1305_REG_RESET: + case NOA1305_REG_INTEGRATION_TIME: + case NOA1305_REG_INT_SELECT: + case NOA1305_REG_INT_THRESH_LSB: + case NOA1305_REG_INT_THRESH_MSB: + return true; + default: + return false; + } +} + +static const struct regmap_config noa1305_regmap_config = { + .name = NOA1305_DRIVER_NAME, + .reg_bits = 8, + .val_bits = 8, + .max_register = NOA1305_REG_DEVICE_ID_MSB, + .writeable_reg = noa1305_writable_reg, +}; + +static void noa1305_reg_remove(void *data) +{ + struct noa1305_priv *priv = data; + + regulator_disable(priv->vin_reg); +} + +static int noa1305_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct noa1305_priv *priv; + struct iio_dev *indio_dev; + struct regmap *regmap; + __le16 data; + unsigned int dev_id; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(client, &noa1305_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Regmap initialization failed.\n"); + return PTR_ERR(regmap); + } + + priv = iio_priv(indio_dev); + + priv->vin_reg = devm_regulator_get(&client->dev, "vin"); + if (IS_ERR(priv->vin_reg)) { + dev_err(&client->dev, "get regulator vin failed\n"); + return PTR_ERR(priv->vin_reg); + } + + ret = regulator_enable(priv->vin_reg); + if (ret) { + dev_err(&client->dev, "enable regulator vin failed\n"); + return ret; + } + + ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv); + if (ret) { + dev_err(&client->dev, "addition of devm action failed\n"); + return ret; + } + + i2c_set_clientdata(client, indio_dev); + priv->client = client; + priv->regmap = regmap; + + ret = regmap_bulk_read(regmap, NOA1305_REG_DEVICE_ID_LSB, &data, 2); + if (ret < 0) { + dev_err(&client->dev, "ID reading failed: %d\n", ret); + return ret; + } + + dev_id = le16_to_cpu(data); + if (dev_id != NOA1305_DEVICE_ID) { + dev_err(&client->dev, "Unknown device ID: 0x%x\n", dev_id); + return -ENODEV; + } + + ret = regmap_write(regmap, NOA1305_REG_POWER_CONTROL, + NOA1305_POWER_CONTROL_ON); + if (ret < 0) { + dev_err(&client->dev, "Enabling power control failed\n"); + return ret; + } + + ret = regmap_write(regmap, NOA1305_REG_RESET, NOA1305_RESET_RESET); + if (ret < 0) { + dev_err(&client->dev, "Device reset failed\n"); + return ret; + } + + ret = regmap_write(regmap, NOA1305_REG_INTEGRATION_TIME, + NOA1305_INTEGR_TIME_800MS); + if (ret < 0) { + dev_err(&client->dev, "Setting integration time failed\n"); + return ret; + } + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &noa1305_info; + indio_dev->channels = noa1305_channels; + indio_dev->num_channels = ARRAY_SIZE(noa1305_channels); + indio_dev->name = NOA1305_DRIVER_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_device_register(&client->dev, indio_dev); + if (ret) + dev_err(&client->dev, "registering device failed\n"); + + return ret; +} + +static const struct of_device_id noa1305_of_match[] = { + { .compatible = "onnn,noa1305" }, + { } +}; +MODULE_DEVICE_TABLE(of, noa1305_of_match); + +static const struct i2c_device_id noa1305_ids[] = { + { "noa1305", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, noa1305_ids); + +static struct i2c_driver noa1305_driver = { + .driver = { + .name = NOA1305_DRIVER_NAME, + .of_match_table = noa1305_of_match, + }, + .probe = noa1305_probe, + .id_table = noa1305_ids, +}; + +module_i2c_driver(noa1305_driver); + +MODULE_AUTHOR("Sergei Miroshnichenko <sergeimir@emcraft.com>"); +MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.com"); +MODULE_DESCRIPTION("ON Semiconductor NOA1305 ambient light sensor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index 6579d2418814..982bba0c54e7 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -1261,7 +1261,7 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev) return ret; } - ret = iio_trigger_register(trig); + ret = devm_iio_trigger_register(&client->dev, trig); if (ret) return ret; @@ -1271,16 +1271,6 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev) return 0; } -static void si1145_remove_trigger(struct iio_dev *indio_dev) -{ - struct si1145_data *data = iio_priv(indio_dev); - - if (data->trig) { - iio_trigger_unregister(data->trig); - data->trig = NULL; - } -} - static int si1145_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1332,7 +1322,8 @@ static int si1145_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(&client->dev, + indio_dev, NULL, si1145_trigger_handler, &si1145_buffer_setup_ops); if (ret < 0) return ret; @@ -1340,23 +1331,12 @@ static int si1145_probe(struct i2c_client *client, if (client->irq) { ret = si1145_probe_trigger(indio_dev); if (ret < 0) - goto error_free_buffer; + return ret; } else { dev_info(&client->dev, "no irq, using polling\n"); } - ret = iio_device_register(indio_dev); - if (ret < 0) - goto error_free_trigger; - - return 0; - -error_free_trigger: - si1145_remove_trigger(indio_dev); -error_free_buffer: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id si1145_ids[] = { @@ -1371,23 +1351,11 @@ static const struct i2c_device_id si1145_ids[] = { }; MODULE_DEVICE_TABLE(i2c, si1145_ids); -static int si1145_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - si1145_remove_trigger(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; -} - static struct i2c_driver si1145_driver = { .driver = { .name = "si1145", }, .probe = si1145_probe, - .remove = si1145_remove, .id_table = si1145_ids, }; diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index b955183edfe8..185c24a75ae6 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -679,9 +679,18 @@ static const struct acpi_device_id stk3310_acpi_id[] = { MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id); +static const struct of_device_id stk3310_of_match[] = { + { .compatible = "sensortek,stk3310", }, + { .compatible = "sensortek,stk3311", }, + { .compatible = "sensortek,stk3335", }, + {} +}; +MODULE_DEVICE_TABLE(of, stk3310_of_match); + static struct i2c_driver stk3310_driver = { .driver = { .name = "stk3310", + .of_match_table = stk3310_of_match, .pm = STK3310_PM_OPS, .acpi_match_table = ACPI_PTR(stk3310_acpi_id), }, diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index 83cece921843..be37fcbd4654 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -134,6 +134,12 @@ enum { TSL2772_CHIP_SUSPENDED = 2 }; +enum { + TSL2772_SUPPLY_VDD = 0, + TSL2772_SUPPLY_VDDIO = 1, + TSL2772_NUM_SUPPLIES = 2 +}; + /* Per-device data */ struct tsl2772_als_info { u16 als_ch0; @@ -161,8 +167,7 @@ struct tsl2772_chip { struct mutex prox_mutex; struct mutex als_mutex; struct i2c_client *client; - struct regulator *vdd_supply; - struct regulator *vddio_supply; + struct regulator_bulk_data supplies[TSL2772_NUM_SUPPLIES]; u16 prox_data; struct tsl2772_als_info als_cur_info; struct tsl2772_settings settings; @@ -697,46 +702,7 @@ static void tsl2772_disable_regulators_action(void *_data) { struct tsl2772_chip *chip = _data; - regulator_disable(chip->vdd_supply); - regulator_disable(chip->vddio_supply); -} - -static int tsl2772_enable_regulator(struct tsl2772_chip *chip, - struct regulator *regulator) -{ - int ret; - - ret = regulator_enable(regulator); - if (ret < 0) { - dev_err(&chip->client->dev, "Failed to enable regulator: %d\n", - ret); - return ret; - } - - return 0; -} - -static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip, - char *name) -{ - struct regulator *regulator; - int ret; - - regulator = devm_regulator_get(&chip->client->dev, name); - if (IS_ERR(regulator)) { - if (PTR_ERR(regulator) != -EPROBE_DEFER) - dev_err(&chip->client->dev, - "Failed to get %s regulator %d\n", - name, (int)PTR_ERR(regulator)); - - return regulator; - } - - ret = tsl2772_enable_regulator(chip, regulator); - if (ret < 0) - return ERR_PTR(ret); - - return regulator; + regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies); } static int tsl2772_chip_on(struct iio_dev *indio_dev) @@ -860,6 +826,13 @@ static int tsl2772_chip_off(struct iio_dev *indio_dev) return tsl2772_write_control_reg(chip, 0x00); } +static void tsl2772_chip_off_action(void *data) +{ + struct iio_dev *indio_dev = data; + + tsl2772_chip_off(indio_dev); +} + /** * tsl2772_invoke_change - power cycle the device to implement the user * parameters @@ -1797,20 +1770,32 @@ static int tsl2772_probe(struct i2c_client *clientp, chip->client = clientp; i2c_set_clientdata(clientp, indio_dev); - chip->vddio_supply = tsl2772_get_regulator(chip, "vddio"); - if (IS_ERR(chip->vddio_supply)) - return PTR_ERR(chip->vddio_supply); + chip->supplies[TSL2772_SUPPLY_VDD].supply = "vdd"; + chip->supplies[TSL2772_SUPPLY_VDDIO].supply = "vddio"; + + ret = devm_regulator_bulk_get(&clientp->dev, + ARRAY_SIZE(chip->supplies), + chip->supplies); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(&clientp->dev, + "Failed to get regulators: %d\n", + ret); + + return ret; + } - chip->vdd_supply = tsl2772_get_regulator(chip, "vdd"); - if (IS_ERR(chip->vdd_supply)) { - regulator_disable(chip->vddio_supply); - return PTR_ERR(chip->vdd_supply); + ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies); + if (ret < 0) { + dev_err(&clientp->dev, "Failed to enable regulators: %d\n", + ret); + return ret; } - ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action, - chip); + ret = devm_add_action_or_reset(&clientp->dev, + tsl2772_disable_regulators_action, + chip); if (ret < 0) { - tsl2772_disable_regulators_action(chip); dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n", ret); return ret; @@ -1877,15 +1862,13 @@ static int tsl2772_probe(struct i2c_client *clientp, if (ret < 0) return ret; - ret = iio_device_register(indio_dev); - if (ret) { - tsl2772_chip_off(indio_dev); - dev_err(&clientp->dev, - "%s: iio registration failed\n", __func__); + ret = devm_add_action_or_reset(&clientp->dev, + tsl2772_chip_off_action, + indio_dev); + if (ret < 0) return ret; - } - return 0; + return devm_iio_device_register(&clientp->dev, indio_dev); } static int tsl2772_suspend(struct device *dev) @@ -1895,8 +1878,7 @@ static int tsl2772_suspend(struct device *dev) int ret; ret = tsl2772_chip_off(indio_dev); - regulator_disable(chip->vdd_supply); - regulator_disable(chip->vddio_supply); + regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies); return ret; } @@ -1907,32 +1889,15 @@ static int tsl2772_resume(struct device *dev) struct tsl2772_chip *chip = iio_priv(indio_dev); int ret; - ret = tsl2772_enable_regulator(chip, chip->vddio_supply); + ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies); if (ret < 0) return ret; - ret = tsl2772_enable_regulator(chip, chip->vdd_supply); - if (ret < 0) { - regulator_disable(chip->vddio_supply); - return ret; - } - usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); return tsl2772_chip_on(indio_dev); } -static int tsl2772_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - tsl2772_chip_off(indio_dev); - - iio_device_unregister(indio_dev); - - return 0; -} - static const struct i2c_device_id tsl2772_idtable[] = { { "tsl2571", tsl2571 }, { "tsl2671", tsl2671 }, @@ -1979,7 +1944,6 @@ static struct i2c_driver tsl2772_driver = { }, .id_table = tsl2772_idtable, .probe = tsl2772_probe, - .remove = tsl2772_remove, }; module_i2c_driver(tsl2772_driver); diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index a3138e1b5803..0be553ad5989 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -158,10 +158,10 @@ static int veml6070_probe(struct i2c_client *client, indio_dev->name = VEML6070_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - data->client2 = i2c_new_dummy(client->adapter, VEML6070_ADDR_DATA_LSB); - if (!data->client2) { + data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB); + if (IS_ERR(data->client2)) { dev_err(&client->dev, "i2c device for second chip address failed\n"); - return -ENODEV; + return PTR_ERR(data->client2); } data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD | diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 7de10281ad9e..425cdd07b4e5 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -53,7 +53,7 @@ #define MMC35240_CTRL1_BW_SHIFT 0 #define MMC35240_WAIT_CHARGE_PUMP 50000 /* us */ -#define MMC53240_WAIT_SET_RESET 1000 /* us */ +#define MMC35240_WAIT_SET_RESET 1000 /* us */ /* * Memsic OTP process code piece is put here for reference: @@ -225,7 +225,7 @@ static int mmc35240_init(struct mmc35240_data *data) ret = mmc35240_hw_set(data, true); if (ret < 0) return ret; - usleep_range(MMC53240_WAIT_SET_RESET, MMC53240_WAIT_SET_RESET + 1); + usleep_range(MMC35240_WAIT_SET_RESET, MMC35240_WAIT_SET_RESET + 1); ret = mmc35240_hw_set(data, false); if (ret < 0) diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index d69ef9b2a731..204b285725c8 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -22,6 +22,7 @@ #define LIS2MDL_MAGN_DEV_NAME "lis2mdl" #define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn" +const struct st_sensor_settings *st_magn_get_settings(const char *name); int st_magn_common_probe(struct iio_dev *indio_dev); void st_magn_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index 11d7806655bc..bb425c167a96 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -32,39 +32,32 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state) static int st_magn_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *mdata = iio_priv(indio_dev); - - mdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (mdata->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } err = iio_triggered_buffer_postenable(indio_dev); if (err < 0) - goto st_magn_buffer_postenable_error; + return err; + + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_magn_buffer_predisable; - return st_sensors_set_enable(indio_dev, true); + return 0; -st_magn_buffer_postenable_error: - kfree(mdata->buffer_data); -allocate_memory_error: +st_magn_buffer_predisable: + iio_triggered_buffer_predisable(indio_dev); return err; } static int st_magn_buffer_predisable(struct iio_dev *indio_dev) { - int err; - struct st_sensor_data *mdata = iio_priv(indio_dev); + int err, err2; err = st_sensors_set_enable(indio_dev, false); - if (err < 0) - goto st_magn_buffer_predisable_error; - err = iio_triggered_buffer_predisable(indio_dev); + err2 = iio_triggered_buffer_predisable(indio_dev); + if (!err) + err = err2; -st_magn_buffer_predisable_error: - kfree(mdata->buffer_data); return err; } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 2f7a1dbcdeb3..a3a268ee2896 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -12,7 +12,6 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/types.h> -#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/gpio.h> @@ -470,28 +469,41 @@ static const struct iio_trigger_ops st_magn_trigger_ops = { #define ST_MAGN_TRIGGER_OPS NULL #endif +/* + * st_magn_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_magn_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_magn_sensors_settings, + ARRAY_SIZE(st_magn_sensors_settings)); + if (index < 0) + return NULL; + + return &st_magn_sensors_settings[index]; +} +EXPORT_SYMBOL(st_magn_get_settings); + int st_magn_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); - int irq = mdata->get_irq_data_ready(indio_dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &magn_info; - mutex_init(&mdata->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_magn_sensors_settings), - st_magn_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_magn_power_off; mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; - mdata->multiread_bit = mdata->sensor_settings->multi_read_bit; indio_dev->channels = mdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; @@ -507,7 +519,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_magn_power_off; - if (irq > 0) { + if (mdata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_MAGN_TRIGGER_OPS); if (err < 0) @@ -524,7 +536,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) return 0; st_magn_device_register_error: - if (irq > 0) + if (mdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_magn_probe_trigger_error: st_magn_deallocate_ring(indio_dev); @@ -542,7 +554,7 @@ void st_magn_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (mdata->get_irq_data_ready(indio_dev) > 0) + if (mdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_magn_deallocate_ring(indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 4d014fd1aeb0..fdba480a12be 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -55,21 +55,33 @@ MODULE_DEVICE_TABLE(of, st_magn_of_match); #endif static int st_magn_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *mdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&client->dev, st_magn_of_match, + client->name, sizeof(client->name)); + + settings = st_magn_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mdata)); if (!indio_dev) return -ENOMEM; mdata = iio_priv(indio_dev); - st_sensors_of_name_probe(&client->dev, st_magn_of_match, - client->name, sizeof(client->name)); + mdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_i2c_configure(indio_dev, client, mdata); + err = st_sensors_i2c_configure(indio_dev, client); + if (err < 0) + return err; err = st_magn_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 0d47070611b1..fbf909bde841 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -51,19 +51,31 @@ MODULE_DEVICE_TABLE(of, st_magn_of_match); static int st_magn_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *mdata; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_magn_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_magn_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*mdata)); if (!indio_dev) return -ENOMEM; mdata = iio_priv(indio_dev); + mdata->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_magn_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, mdata); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_magn_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index ebc7c72a5e36..4cac0173db8b 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -26,6 +26,17 @@ config DS1803 To compile this driver as a module, choose M here: the module will be called ds1803. +config MAX5432 + tristate "Maxim MAX5432-MAX5435 Digital Potentiometer driver" + depends on I2C + help + Say yes here to build support for the Maxim + MAX5432, MAX5433, MAX5434 and MAX5435 digital + potentiometer chips. + + To compile this driver as a module, choose M here: the + module will be called max5432. + config MAX5481 tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver" depends on SPI diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile index 8ff55138cf12..091adf3cdd0b 100644 --- a/drivers/iio/potentiometer/Makefile +++ b/drivers/iio/potentiometer/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD5272) += ad5272.o obj-$(CONFIG_DS1803) += ds1803.o +obj-$(CONFIG_MAX5432) += max5432.o obj-$(CONFIG_MAX5481) += max5481.o obj-$(CONFIG_MAX5487) += max5487.o obj-$(CONFIG_MCP4018) += mcp4018.o diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c new file mode 100644 index 000000000000..641b1821fdf6 --- /dev/null +++ b/drivers/iio/potentiometer/max5432.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Maxim Integrated MAX5432-MAX5435 digital potentiometer driver + * Copyright (C) 2019 Martin Kaiser <martin@kaiser.cx> + * + * Datasheet: + * https://datasheets.maximintegrated.com/en/ds/MAX5432-MAX5435.pdf + */ + +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/limits.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> + +/* All chip variants have 32 wiper positions. */ +#define MAX5432_MAX_POS 31 + +#define MAX5432_OHM_50K (50 * 1000) +#define MAX5432_OHM_100K (100 * 1000) + +/* Update the volatile (currently active) setting. */ +#define MAX5432_CMD_VREG 0x11 + +struct max5432_data { + struct i2c_client *client; + unsigned long ohm; +}; + +static const struct iio_chan_spec max5432_channels[] = { + { + .type = IIO_RESISTANCE, + .indexed = 1, + .output = 1, + .channel = 0, + .address = MAX5432_CMD_VREG, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static int max5432_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max5432_data *data = iio_priv(indio_dev); + + if (mask != IIO_CHAN_INFO_SCALE) + return -EINVAL; + + if (unlikely(data->ohm > INT_MAX)) + return -ERANGE; + + *val = data->ohm; + *val2 = MAX5432_MAX_POS; + + return IIO_VAL_FRACTIONAL; +} + +static int max5432_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct max5432_data *data = iio_priv(indio_dev); + u8 data_byte; + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + if (val < 0 || val > MAX5432_MAX_POS) + return -EINVAL; + + if (val2 != 0) + return -EINVAL; + + /* Wiper position is in bits D7-D3. (D2-D0 are don't care bits.) */ + data_byte = val << 3; + return i2c_smbus_write_byte_data(data->client, chan->address, + data_byte); +} + +static const struct iio_info max5432_info = { + .read_raw = max5432_read_raw, + .write_raw = max5432_write_raw, +}; + +static int max5432_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct iio_dev *indio_dev; + struct max5432_data *data; + + indio_dev = devm_iio_device_alloc(dev, sizeof(struct max5432_data)); + if (!indio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, indio_dev); + + data = iio_priv(indio_dev); + data->client = client; + data->ohm = (unsigned long)of_device_get_match_data(dev); + + indio_dev->dev.parent = dev; + indio_dev->info = &max5432_info; + indio_dev->channels = max5432_channels; + indio_dev->num_channels = ARRAY_SIZE(max5432_channels); + indio_dev->name = client->name; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id max5432_dt_ids[] = { + { .compatible = "maxim,max5432", .data = (void *)MAX5432_OHM_50K }, + { .compatible = "maxim,max5433", .data = (void *)MAX5432_OHM_100K }, + { .compatible = "maxim,max5434", .data = (void *)MAX5432_OHM_50K }, + { .compatible = "maxim,max5435", .data = (void *)MAX5432_OHM_100K }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, max5432_dt_ids); + +static struct i2c_driver max5432_driver = { + .driver = { + .name = "max5432", + .of_match_table = of_match_ptr(max5432_dt_ids), + }, + .probe = max5432_probe, +}; + +module_i2c_driver(max5432_driver); + +MODULE_AUTHOR("Martin Kaiser <martin@kaiser.cx>"); +MODULE_DESCRIPTION("max5432-max5435 digital potentiometers"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 034ce98d6e97..70148624db64 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -39,26 +39,29 @@ static int cros_ec_baro_read(struct iio_dev *indio_dev, { struct cros_ec_baro_state *st = iio_priv(indio_dev); u16 data = 0; - int ret = IIO_VAL_INT; + int ret; int idx = chan->scan_index; mutex_lock(&st->core.cmd_lock); switch (mask) { case IIO_CHAN_INFO_RAW: - if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, - (s16 *)&data) < 0) - ret = -EIO; + ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data); + if (ret) + break; + *val = data; + ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) { - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret) break; - } + *val = st->core.resp->sensor_range.ret; /* scale * in_pressure_raw --> kPa */ @@ -152,8 +155,6 @@ static int cros_ec_baro_probe(struct platform_device *pdev) channel->ext_info = cros_ec_sensors_ext_info; channel->scan_type.sign = 'u'; - state->core.calib[0] = 0; - /* Sensor specific */ switch (state->core.type) { case MOTIONSENSE_TYPE_BARO: diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index f00102577fd5..026ba15ef68f 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -243,10 +243,10 @@ static int hp03_probe(struct i2c_client *client, * which has it's dedicated I2C address and contains * the calibration constants for the sensor. */ - priv->eeprom_client = i2c_new_dummy(client->adapter, HP03_EEPROM_ADDR); - if (!priv->eeprom_client) { + priv->eeprom_client = i2c_new_dummy_device(client->adapter, HP03_EEPROM_ADDR); + if (IS_ERR(priv->eeprom_client)) { dev_err(dev, "New EEPROM I2C device failed\n"); - return -ENODEV; + return PTR_ERR(priv->eeprom_client); } priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client, diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index 6a720cfb5686..c2e47a6c3118 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -41,6 +41,7 @@ static const struct st_sensors_platform_data default_press_pdata = { .drdy_int_pin = 1, }; +const struct st_sensor_settings *st_press_get_settings(const char *name); int st_press_common_probe(struct iio_dev *indio_dev); void st_press_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index 4566e08a64a1..418dbf9e6e1e 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -29,52 +29,39 @@ int st_press_trig_set_state(struct iio_trigger *trig, bool state) return st_sensors_set_dataready_irq(indio_dev, state); } -static int st_press_buffer_preenable(struct iio_dev *indio_dev) -{ - return st_sensors_set_enable(indio_dev, true); -} - static int st_press_buffer_postenable(struct iio_dev *indio_dev) { int err; - struct st_sensor_data *press_data = iio_priv(indio_dev); - - press_data->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (press_data->buffer_data == NULL) { - err = -ENOMEM; - goto allocate_memory_error; - } err = iio_triggered_buffer_postenable(indio_dev); if (err < 0) - goto st_press_buffer_postenable_error; + return err; - return err; + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto st_press_buffer_predisable; -st_press_buffer_postenable_error: - kfree(press_data->buffer_data); -allocate_memory_error: + return 0; + +st_press_buffer_predisable: + iio_triggered_buffer_predisable(indio_dev); return err; } static int st_press_buffer_predisable(struct iio_dev *indio_dev) { - int err; - struct st_sensor_data *press_data = iio_priv(indio_dev); - - err = iio_triggered_buffer_predisable(indio_dev); - if (err < 0) - goto st_press_buffer_predisable_error; + int err, err2; err = st_sensors_set_enable(indio_dev, false); -st_press_buffer_predisable_error: - kfree(press_data->buffer_data); + err2 = iio_triggered_buffer_predisable(indio_dev); + if (!err) + err = err2; + return err; } static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { - .preenable = &st_press_buffer_preenable, .postenable = &st_press_buffer_postenable, .predisable = &st_press_buffer_predisable, }; diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index b960e76f7dfd..ca6863b32a5f 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -12,7 +12,6 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/types.h> -#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/gpio.h> @@ -664,25 +663,39 @@ static const struct iio_trigger_ops st_press_trigger_ops = { #define ST_PRESS_TRIGGER_OPS NULL #endif +/* + * st_press_get_settings() - get sensor settings from device name + * @name: device name buffer reference. + * + * Return: valid reference on success, NULL otherwise. + */ +const struct st_sensor_settings *st_press_get_settings(const char *name) +{ + int index = st_sensors_get_settings_index(name, + st_press_sensors_settings, + ARRAY_SIZE(st_press_sensors_settings)); + if (index < 0) + return NULL; + + return &st_press_sensors_settings[index]; +} +EXPORT_SYMBOL(st_press_get_settings); + int st_press_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *press_data = iio_priv(indio_dev); struct st_sensors_platform_data *pdata = (struct st_sensors_platform_data *)press_data->dev->platform_data; - int irq = press_data->get_irq_data_ready(indio_dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; - mutex_init(&press_data->tb.buf_lock); err = st_sensors_power_enable(indio_dev); if (err) return err; - err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_press_sensors_settings), - st_press_sensors_settings); + err = st_sensors_verify_id(indio_dev); if (err < 0) goto st_press_power_off; @@ -693,7 +706,6 @@ int st_press_common_probe(struct iio_dev *indio_dev) * element. */ press_data->num_data_channels = press_data->sensor_settings->num_ch - 1; - press_data->multiread_bit = press_data->sensor_settings->multi_read_bit; indio_dev->channels = press_data->sensor_settings->ch; indio_dev->num_channels = press_data->sensor_settings->num_ch; @@ -716,7 +728,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_press_power_off; - if (irq > 0) { + if (press_data->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_PRESS_TRIGGER_OPS); if (err < 0) @@ -733,7 +745,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) return err; st_press_device_register_error: - if (irq > 0) + if (press_data->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: st_press_deallocate_ring(indio_dev); @@ -751,7 +763,7 @@ void st_press_common_remove(struct iio_dev *indio_dev) st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); - if (press_data->get_irq_data_ready(indio_dev) > 0) + if (press_data->irq > 0) st_sensors_deallocate_trigger(indio_dev); st_press_deallocate_ring(indio_dev); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index b7d9ba706abc..71d2ed6b4948 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -78,18 +78,13 @@ static const struct i2c_device_id st_press_id_table[] = { MODULE_DEVICE_TABLE(i2c, st_press_id_table); static int st_press_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *press_data; + struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data)); - if (!indio_dev) - return -ENOMEM; - - press_data = iio_priv(indio_dev); - if (client->dev.of_node) { st_sensors_of_name_probe(&client->dev, st_press_of_match, client->name, sizeof(client->name)); @@ -99,11 +94,27 @@ static int st_press_i2c_probe(struct i2c_client *client, return -ENODEV; strlcpy(client->name, st_press_id_table[ret].name, - sizeof(client->name)); + sizeof(client->name)); } else if (!id) return -ENODEV; - st_sensors_i2c_configure(indio_dev, client, press_data); + settings = st_press_get_settings(client->name); + if (!settings) { + dev_err(&client->dev, "device name %s not recognized.\n", + client->name); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data)); + if (!indio_dev) + return -ENOMEM; + + press_data = iio_priv(indio_dev); + press_data->sensor_settings = (struct st_sensor_settings *)settings; + + ret = st_sensors_i2c_configure(indio_dev, client); + if (ret < 0) + return ret; ret = st_press_common_probe(indio_dev); if (ret < 0) diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index ef61401c41d3..7c8b70221e70 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -61,19 +61,31 @@ MODULE_DEVICE_TABLE(of, st_press_of_match); static int st_press_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct st_sensor_settings *settings; struct st_sensor_data *press_data; + struct iio_dev *indio_dev; int err; + st_sensors_of_name_probe(&spi->dev, st_press_of_match, + spi->modalias, sizeof(spi->modalias)); + + settings = st_press_get_settings(spi->modalias); + if (!settings) { + dev_err(&spi->dev, "device name %s not recognized.\n", + spi->modalias); + return -ENODEV; + } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*press_data)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; press_data = iio_priv(indio_dev); + press_data->sensor_settings = (struct st_sensor_settings *)settings; - st_sensors_of_name_probe(&spi->dev, st_press_of_match, - spi->modalias, sizeof(spi->modalias)); - st_sensors_spi_configure(indio_dev, spi, press_data); + err = st_sensors_spi_configure(indio_dev, spi); + if (err < 0) + return err; err = st_press_common_probe(indio_dev); if (err < 0) diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 6b5cce6f1a7b..d53601447da4 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -62,7 +62,7 @@ config RFD77402 tristate "RFD77402 ToF sensor" depends on I2C help - Say Y to build a driver for the RFD77420 Time-of-Flight (distance) + Say Y to build a driver for the RFD77402 Time-of-Flight (distance) sensor module with I2C interface. To compile this driver as a module, choose M here: the diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index c613a64c017f..2ab68282d0b6 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -230,31 +230,13 @@ static int maxim_thermocouple_probe(struct spi_device *spi) data->spi = spi; data->chip = chip; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(&spi->dev, + indio_dev, NULL, maxim_thermocouple_trigger_handler, NULL); if (ret) return ret; - ret = iio_device_register(indio_dev); - if (ret) - goto error_unreg_buffer; - - return 0; - -error_unreg_buffer: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int maxim_thermocouple_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id maxim_thermocouple_id[] = { @@ -277,7 +259,6 @@ static struct spi_driver maxim_thermocouple_driver = { .of_match_table = maxim_thermocouple_of_match, }, .probe = maxim_thermocouple_probe, - .remove = maxim_thermocouple_remove, .id_table = maxim_thermocouple_id, }; module_spi_driver(maxim_thermocouple_driver); diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index ccf1ce653b25..a5dfe65cd9b9 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -608,86 +608,6 @@ static const struct iio_enum stm32_enable_mode_enum = { .get = stm32_get_enable_mode }; -static const char *const stm32_quadrature_modes[] = { - "channel_A", - "channel_B", - "quadrature", -}; - -static int stm32_set_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int mode) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - - regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, mode + 1); - - return 0; -} - -static int stm32_get_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - u32 smcr; - int mode; - - regmap_read(priv->regmap, TIM_SMCR, &smcr); - mode = (smcr & TIM_SMCR_SMS) - 1; - if ((mode < 0) || (mode > ARRAY_SIZE(stm32_quadrature_modes))) - return -EINVAL; - - return mode; -} - -static const struct iio_enum stm32_quadrature_mode_enum = { - .items = stm32_quadrature_modes, - .num_items = ARRAY_SIZE(stm32_quadrature_modes), - .set = stm32_set_quadrature_mode, - .get = stm32_get_quadrature_mode -}; - -static const char *const stm32_count_direction_states[] = { - "up", - "down" -}; - -static int stm32_set_count_direction(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int dir) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - u32 val; - int mode; - - /* In encoder mode, direction is RO (given by TI1/TI2 signals) */ - regmap_read(priv->regmap, TIM_SMCR, &val); - mode = (val & TIM_SMCR_SMS) - 1; - if ((mode >= 0) || (mode < ARRAY_SIZE(stm32_quadrature_modes))) - return -EBUSY; - - return regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_DIR, - dir ? TIM_CR1_DIR : 0); -} - -static int stm32_get_count_direction(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_timer_trigger *priv = iio_priv(indio_dev); - u32 cr1; - - regmap_read(priv->regmap, TIM_CR1, &cr1); - - return ((cr1 & TIM_CR1_DIR) ? 1 : 0); -} - -static const struct iio_enum stm32_count_direction_enum = { - .items = stm32_count_direction_states, - .num_items = ARRAY_SIZE(stm32_count_direction_states), - .set = stm32_set_count_direction, - .get = stm32_get_count_direction -}; - static ssize_t stm32_count_get_preset(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, @@ -728,10 +648,6 @@ static const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = { .read = stm32_count_get_preset, .write = stm32_count_set_preset }, - IIO_ENUM("count_direction", IIO_SEPARATE, &stm32_count_direction_enum), - IIO_ENUM_AVAILABLE("count_direction", &stm32_count_direction_enum), - IIO_ENUM("quadrature_mode", IIO_SEPARATE, &stm32_quadrature_mode_enum), - IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_quadrature_mode_enum), IIO_ENUM("enable_mode", IIO_SEPARATE, &stm32_enable_mode_enum), IIO_ENUM_AVAILABLE("enable_mode", &stm32_enable_mode_enum), IIO_ENUM("trigger_mode", IIO_SEPARATE, &stm32_trigger_mode_enum), |