diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-09-22 11:30:12 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-09-22 11:30:12 -0700 |
commit | 3ffdea3feca9e2c95c2e93e217d77c9c368f747a (patch) | |
tree | e970c502cbd02244344ee1449af072d0d7086bbd | |
parent | 9076b09e07da4b2644a17d7d18e117944cbc09be (diff) | |
parent | 074b6a8d9d73db27d48abe4200ce149bd4189b39 (diff) | |
download | linux-stable-3ffdea3feca9e2c95c2e93e217d77c9c368f747a.tar.gz linux-stable-3ffdea3feca9e2c95c2e93e217d77c9c368f747a.tar.bz2 linux-stable-3ffdea3feca9e2c95c2e93e217d77c9c368f747a.zip |
Merge tag 'iio-for-3.13a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
First round of new drivers, functionality and cleanups for IIO in the 3.13 cycle
A number of new drivers and some new functionality + a lot of cleanups
all over IIO.
New Core Elements
1) New INT_TIME info_mask element for integration time, which may have
different effects on measurement noise and similar, than an amplifier
and hence is different from existing SCALE. Already existed in some
drivers as a custom attribute.
2) Introduce a iio_push_buffers_with_timestamp helper to cover the common
case of filling the last 64 bits of data to be passed to the buffer with
a timestamp. Applied to lots of drivers. Cuts down on repeated code and
moves a slightly fiddly bit of logic into a single location.
3) Introduce info_mask_[shared_by_dir/shared_by_all] elements to allow support
of elements such as sampling_frequency which is typically shared by all
input channels on a device. This reduces code and makes these controls
available from in kernel consumers of IIO devices.
New drivers
1) MCP3422/3/4 ADC
2) TSL4531 ambient light sensor
3) TCS3472/5 color light sensor
4) GP2AP020A00F ambient light / proximity sensor
5) LPS001WP support added to ST pressure sensor driver.
New driver functionality
1) ti_am335x_adc Add buffered sampling support.
This device has a hardware fifo that is fed directly into an IIO kfifo
buffer based on a watershed interrupt. Note this will act as an example
of how to handle this increasingly common type of device.
The only previous example - sca3000 - take a less than optimal approach
which is largely why it is still in staging.
A couple of little cleanups for that new functionality followed later.
Core cleanups:
1) MAINTAINERS - Sachin actually brought my email address up to date because
I said I'd do it and never got around to it :)
2) Assign buffer list elements as single element lists to simplify the
iio_buffer_is_active logic.
3) wake_up_interruptible_poll instead of wake_up_interruptible to only wake
up threads waiting for poll notifications.
4) Add O_CLOEXEC flag to anon_inode_get_fd call for IIO event interface.
5) Change iio_push_to_buffers to take a void * pointer so as to avoid some
annoying and unnecessary type casts.
6) iio_compute_scan_bytes incorrectly took a long rather than unsigned long.
7) Various minor tidy ups.
Driver cleanups (in no particular order)
1) Another set of devm_ allocations patches from Sachin Kamat.
2) tsl2x7x - 0 to NULL cleanup.
3) hmc5843 - fix missing > in MODULE_AUTHOR
4) Set of strict_strto* to kstrto* conversions.
5) mxs-lradc - fix ordering of resource removal to match creation
6) mxs-lradc - add MODULE_ALIAS
7) adc7606 - drop a work pending test duplicated in core functions.
8) hmc5843 - devm_ allocation patch
9) Series of redundant breaks removed.
10) ad2s1200 - pr_err -> dev_err
11) adjd_s311 - use INT_TIME
12) ST sensors - large set of cleanups from Lee Jones and removed restriction
to using only triggers provided by the st_sensors themselves from
Dennis Ciocca.
13) dummy and tmp006 provide sampling_frequency via info_mask_shared_by_all.
14) tcs3472 - fix incorrect buffer size and wrong device pointer used in
suspend / resume functions.
15) max1363 - use defaults for buffer setup ops as provided by the triggered
buffer helpers as they are the same as were specified in max1363 driver.
16) Trivial tidy ups in a number of other drivers.
108 files changed, 3913 insertions, 1145 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 39c8de0e53d0..ab1047c20495 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -811,3 +811,14 @@ Description: Writing '1' stores the current device configuration into on-chip EEPROM. After power-up or chip reset the device will automatically load the saved configuration. + +What: /sys/.../iio:deviceX/in_intensity_red_integration_time +What: /sys/.../iio:deviceX/in_intensity_green_integration_time +What: /sys/.../iio:deviceX/in_intensity_blue_integration_time +What: /sys/.../iio:deviceX/in_intensity_clear_integration_time +What: /sys/.../iio:deviceX/in_illuminance_integration_time +KernelVersion: 3.12 +Contact: linux-iio@vger.kernel.org +Description: + This attribute is used to get/set the integration time in + seconds. diff --git a/Documentation/devicetree/bindings/iio/light/gp2ap020a00f.txt b/Documentation/devicetree/bindings/iio/light/gp2ap020a00f.txt new file mode 100644 index 000000000000..9231c82317ad --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/gp2ap020a00f.txt @@ -0,0 +1,21 @@ +* Sharp GP2AP020A00F I2C Proximity/ALS sensor + +The proximity detector sensor requires power supply +for its built-in led. It is also defined by this binding. + +Required properties: + + - compatible : should be "sharp,gp2ap020a00f" + - reg : the I2C slave address of the light sensor + - interrupts : interrupt specifier for the sole interrupt generated + by the device + - vled-supply : VLED power supply, as covered in ../regulator/regulator.txt + +Example: + +gp2ap020a00f@39 { + compatible = "sharp,gp2ap020a00f"; + reg = <0x39>; + interrupts = <2 0>; + vled-supply = <...>; +}; diff --git a/MAINTAINERS b/MAINTAINERS index e61c2e83fc2b..e8ee569fdce5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4195,7 +4195,7 @@ S: Maintained F: drivers/media/rc/iguanair.c IIO SUBSYSTEM AND DRIVERS -M: Jonathan Cameron <jic23@cam.ac.uk> +M: Jonathan Cameron <jic23@kernel.org> L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/ @@ -7947,7 +7947,7 @@ S: Maintained F: drivers/staging/media/go7007/ STAGING - INDUSTRIAL IO -M: Jonathan Cameron <jic23@cam.ac.uk> +M: Jonathan Cameron <jic23@kernel.org> L: linux-iio@vger.kernel.org S: Odd Fixes F: drivers/staging/iio/ diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 12e32e6b4103..bda7a8343ddd 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -471,13 +471,10 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bma180_data *data = iio_priv(indio_dev); + int64_t time_ns = iio_get_time_ns(); int bit, ret, i = 0; mutex_lock(&data->mutex); - if (indio_dev->scan_timestamp) { - ret = indio_dev->scan_bytes / sizeof(s64) - 1; - ((s64 *)data->buff)[ret] = iio_get_time_ns(); - } for_each_set_bit(bit, indio_dev->buffer->scan_mask, indio_dev->masklength) { @@ -490,7 +487,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) } mutex_unlock(&data->mutex); - iio_push_to_buffers(indio_dev, (u8 *)data->buff); + iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 46d22f3fb1a9..dcda17395c4e 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -182,10 +182,11 @@ static const struct iio_info accel_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -200,7 +201,7 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, accel_state->common_attributes.data_ready); if (accel_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)accel_state->accel_val, + accel_state->accel_val, sizeof(accel_state->accel_val)); return 0; diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 1458343f6f3f..38caedc76b98 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -452,8 +452,9 @@ static const struct iio_trigger_ops st_accel_trigger_ops = { int st_accel_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *plat_data) { - int err; struct st_sensor_data *adata = iio_priv(indio_dev); + int irq = adata->get_irq_data_ready(indio_dev); + int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; @@ -461,7 +462,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev, err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_accel_sensors), st_accel_sensors); if (err < 0) - goto st_accel_common_probe_error; + return err; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; adata->multiread_bit = adata->sensor->multi_read_bit; @@ -478,13 +479,13 @@ int st_accel_common_probe(struct iio_dev *indio_dev, err = st_sensors_init_sensor(indio_dev, plat_data); if (err < 0) - goto st_accel_common_probe_error; + return err; - if (adata->get_irq_data_ready(indio_dev) > 0) { - err = st_accel_allocate_ring(indio_dev); - if (err < 0) - goto st_accel_common_probe_error; + err = st_accel_allocate_ring(indio_dev); + if (err < 0) + return err; + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_ACCEL_TRIGGER_OPS); if (err < 0) @@ -495,15 +496,14 @@ int st_accel_common_probe(struct iio_dev *indio_dev, if (err) goto st_accel_device_register_error; - return err; + return 0; st_accel_device_register_error: - if (adata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_accel_probe_trigger_error: - if (adata->get_irq_data_ready(indio_dev) > 0) - st_accel_deallocate_ring(indio_dev); -st_accel_common_probe_error: + st_accel_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_accel_common_probe); @@ -513,10 +513,10 @@ void st_accel_common_remove(struct iio_dev *indio_dev) struct st_sensor_data *adata = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (adata->get_irq_data_ready(indio_dev) > 0) { + if (adata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_accel_deallocate_ring(indio_dev); - } + + st_accel_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_accel_common_remove); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 09371cbc9dc1..8b885188b839 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -145,6 +145,16 @@ config MCP320X This driver can also be built as a module. If so, the module will be called mcp320x. +config MCP3422 + tristate "Microchip Technology MCP3422/3/4 driver" + depends on I2C + help + Say yes here to build support for Microchip Technology's MCP3422, + MCP3423 or MCP3424 analog to digital converters. + + This driver can also be built as a module. If so, the module will be + called mcp3422. + config NAU7802 tristate "Nuvoton NAU7802 ADC driver" depends on I2C @@ -167,6 +177,7 @@ config TI_ADC081C config TI_AM335X_ADC tristate "TI's AM335X ADC driver" depends on MFD_TI_AM335X_TSCADC + select IIO_KFIFO_BUF help Say yes here to build support for Texas Instruments ADC driver which is also a MFD client. diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 33656ef7d1f6..ba9a10a24cd0 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MCP320X) += mcp320x.o +obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 371731df1634..656aa3e102f2 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -96,9 +96,8 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p) ret = spi_read(st->spi, st->data, 4); if (ret == 0) { - if (indio_dev->scan_timestamp) - ((s64 *)st->data)[1] = pf->timestamp; - iio_push_to_buffers(indio_dev, (u8 *)st->data); + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + pf->timestamp); } iio_trigger_notify_done(indio_dev->trig); @@ -293,7 +292,7 @@ static const struct iio_info ad7266_info = { .driver_module = THIS_MODULE, }; -static unsigned long ad7266_available_scan_masks[] = { +static const unsigned long ad7266_available_scan_masks[] = { 0x003, 0x00c, 0x030, @@ -303,14 +302,14 @@ static unsigned long ad7266_available_scan_masks[] = { 0x000, }; -static unsigned long ad7266_available_scan_masks_diff[] = { +static const unsigned long ad7266_available_scan_masks_diff[] = { 0x003, 0x00c, 0x030, 0x000, }; -static unsigned long ad7266_available_scan_masks_fixed[] = { +static const unsigned long ad7266_available_scan_masks_fixed[] = { 0x003, 0x000, }; @@ -318,7 +317,7 @@ static unsigned long ad7266_available_scan_masks_fixed[] = { struct ad7266_chan_info { const struct iio_chan_spec *channels; unsigned int num_channels; - unsigned long *scan_masks; + const unsigned long *scan_masks; }; #define AD7266_CHAN_INFO_INDEX(_differential, _signed, _fixed) \ diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 85d1481c312f..2a3b65c74af9 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -159,20 +159,14 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7298_state *st = iio_priv(indio_dev); - s64 time_ns = 0; int b_sent; b_sent = spi_sync(st->spi, &st->ring_msg); if (b_sent) goto done; - if (indio_dev->scan_timestamp) { - time_ns = iio_get_time_ns(); - memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - } - - iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf); + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 6d2b1d8d1a1f..8d808b9de909 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -64,19 +64,14 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7476_state *st = iio_priv(indio_dev); - s64 time_ns; int b_sent; b_sent = spi_sync(st->spi, &st->msg); if (b_sent < 0) goto done; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - ((s64 *)st->data)[1] = time_ns; - - iio_push_to_buffers(indio_dev, st->data); + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 9dd077b78759..faedd0e165f6 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -121,20 +121,14 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7887_state *st = iio_priv(indio_dev); - s64 time_ns; int b_sent; b_sent = spi_sync(st->spi, st->ring_msg); if (b_sent) goto done; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(st->data + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - - iio_push_to_buffers(indio_dev, st->data); + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index 4108dbb28c3d..28732c28e819 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -174,20 +174,14 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7923_state *st = iio_priv(indio_dev); - s64 time_ns = 0; int b_sent; b_sent = spi_sync(st->spi, &st->ring_msg); if (b_sent) goto done; - if (indio_dev->scan_timestamp) { - time_ns = iio_get_time_ns(); - memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - } - - iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf); + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index f0d6335ae087..2b5911274763 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -368,10 +368,6 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) memset(data, 0x00, 16); - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - ((s64 *)data)[1] = pf->timestamp; - reg_size = indio_dev->channels[0].scan_type.realbits + indio_dev->channels[0].scan_type.shift; reg_size = DIV_ROUND_UP(reg_size, 8); @@ -391,7 +387,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) break; } - iio_push_to_buffers(indio_dev, (uint8_t *)data); + iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); sigma_delta->irq_dis = false; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 84be63bdf038..5c8f690ce92f 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -83,13 +83,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) j++; } - if (idev->scan_timestamp) { - s64 *timestamp = (s64 *)((u8 *)st->buffer + - ALIGN(j, sizeof(s64))); - *timestamp = pf->timestamp; - } - - iio_push_to_buffers(idev, (u8 *)st->buffer); + iio_push_to_buffers_with_timestamp(idev, st->buffer, pf->timestamp); iio_trigger_notify_done(idev->trig); @@ -279,7 +273,7 @@ static int at91_adc_trigger_init(struct iio_dev *idev) int i, ret; st->trig = devm_kzalloc(&idev->dev, - st->trigger_number * sizeof(st->trig), + st->trigger_number * sizeof(*st->trig), GFP_KERNEL); if (st->trig == NULL) { diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 4fb35d1d7494..b4bc166d57b0 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1436,7 +1436,6 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct max1363_state *st = iio_priv(indio_dev); - s64 time_ns; __u8 *rxbuf; int b_sent; size_t d_size; @@ -1470,11 +1469,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) if (b_sent < 0) goto done_free; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); - iio_push_to_buffers(indio_dev, rxbuf); + iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, iio_get_time_ns()); done_free: kfree(rxbuf); @@ -1484,12 +1479,6 @@ done: return IRQ_HANDLED; } -static const struct iio_buffer_setup_ops max1363_buffered_setup_ops = { - .postenable = &iio_triggered_buffer_postenable, - .preenable = &iio_sw_buffer_preenable, - .predisable = &iio_triggered_buffer_predisable, -}; - static int max1363_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1559,7 +1548,7 @@ static int max1363_probe(struct i2c_client *client, goto error_disable_reg; ret = iio_triggered_buffer_setup(indio_dev, NULL, - &max1363_trigger_handler, &max1363_buffered_setup_ops); + &max1363_trigger_handler, NULL); if (ret) goto error_disable_reg; diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c new file mode 100644 index 000000000000..bc93f538cb13 --- /dev/null +++ b/drivers/iio/adc/mcp3422.c @@ -0,0 +1,409 @@ +/* + * mcp3422.c - driver for the Microchip mcp3422/3/4 chip family + * + * Copyright (C) 2013, Angelo Compagnucci + * Author: Angelo Compagnucci <angelo.compagnucci@gmail.com> + * + * Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf + * + * This driver exports the value of analog input voltage to sysfs, the + * voltage unit is nV. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/sysfs.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +/* Masks */ +#define MCP3422_CHANNEL_MASK 0x60 +#define MCP3422_PGA_MASK 0x03 +#define MCP3422_SRATE_MASK 0x0C +#define MCP3422_SRATE_240 0x0 +#define MCP3422_SRATE_60 0x1 +#define MCP3422_SRATE_15 0x2 +#define MCP3422_SRATE_3 0x3 +#define MCP3422_PGA_1 0 +#define MCP3422_PGA_2 1 +#define MCP3422_PGA_4 2 +#define MCP3422_PGA_8 3 +#define MCP3422_CONT_SAMPLING 0x10 + +#define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5) +#define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK) +#define MCP3422_SAMPLE_RATE(config) (((config) & MCP3422_SRATE_MASK) >> 2) + +#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK) +#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK) +#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK) + +#define MCP3422_CHAN(_index) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ + | BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + } + +/* LSB is in nV to eliminate floating point */ +static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625}; + +/* + * scales calculated as: + * rates_to_lsb[sample_rate] / (1 << pga); + * pga is 1 for 0, 2 + */ + +static const int mcp3422_scales[4][4] = { + { 1000000, 250000, 62500, 15625 }, + { 500000 , 125000, 31250, 7812 }, + { 250000 , 62500 , 15625, 3906 }, + { 125000 , 31250 , 7812 , 1953 } }; + +/* Constant msleep times for data acquisitions */ +static const int mcp3422_read_times[4] = { + [MCP3422_SRATE_240] = 1000 / 240, + [MCP3422_SRATE_60] = 1000 / 60, + [MCP3422_SRATE_15] = 1000 / 15, + [MCP3422_SRATE_3] = 1000 / 3 }; + +/* sample rates to integer conversion table */ +static const int mcp3422_sample_rates[4] = { + [MCP3422_SRATE_240] = 240, + [MCP3422_SRATE_60] = 60, + [MCP3422_SRATE_15] = 15, + [MCP3422_SRATE_3] = 3 }; + +/* sample rates to sign extension table */ +static const int mcp3422_sign_extend[4] = { + [MCP3422_SRATE_240] = 12, + [MCP3422_SRATE_60] = 14, + [MCP3422_SRATE_15] = 16, + [MCP3422_SRATE_3] = 18 }; + +/* Client data (each client gets its own) */ +struct mcp3422 { + struct i2c_client *i2c; + u8 config; + u8 pga[4]; + struct mutex lock; +}; + +static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig) +{ + int ret; + + mutex_lock(&adc->lock); + + ret = i2c_master_send(adc->i2c, &newconfig, 1); + if (ret > 0) { + adc->config = newconfig; + ret = 0; + } + + mutex_unlock(&adc->lock); + + return ret; +} + +static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config) +{ + int ret = 0; + u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 buf[4] = {0, 0, 0, 0}; + u32 temp; + + if (sample_rate == MCP3422_SRATE_3) { + ret = i2c_master_recv(adc->i2c, buf, 4); + temp = buf[0] << 16 | buf[1] << 8 | buf[2]; + *config = buf[3]; + } else { + ret = i2c_master_recv(adc->i2c, buf, 3); + temp = buf[0] << 8 | buf[1]; + *config = buf[2]; + } + + *value = sign_extend32(temp, mcp3422_sign_extend[sample_rate]); + + return ret; +} + +static int mcp3422_read_channel(struct mcp3422 *adc, + struct iio_chan_spec const *channel, int *value) +{ + int ret; + u8 config; + u8 req_channel = channel->channel; + + if (req_channel != MCP3422_CHANNEL(adc->config)) { + config = adc->config; + config &= ~MCP3422_CHANNEL_MASK; + config |= MCP3422_CHANNEL_VALUE(req_channel); + config &= ~MCP3422_PGA_MASK; + config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + ret = mcp3422_update_config(adc, config); + if (ret < 0) + return ret; + msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]); + } + + return mcp3422_read(adc, value, &config); +} + +static int mcp3422_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *channel, int *val1, + int *val2, long mask) +{ + struct mcp3422 *adc = iio_priv(iio); + int err; + + u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 pga = MCP3422_PGA(adc->config); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = mcp3422_read_channel(adc, channel, val1); + if (err < 0) + return -EINVAL; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + + *val1 = 0; + *val2 = mcp3422_scales[sample_rate][pga]; + return IIO_VAL_INT_PLUS_NANO; + + case IIO_CHAN_INFO_SAMP_FREQ: + *val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)]; + return IIO_VAL_INT; + + default: + break; + } + + return -EINVAL; +} + +static int mcp3422_write_raw(struct iio_dev *iio, + struct iio_chan_spec const *channel, int val1, + int val2, long mask) +{ + struct mcp3422 *adc = iio_priv(iio); + u8 temp; + u8 config = adc->config; + u8 req_channel = channel->channel; + u8 sample_rate = MCP3422_SAMPLE_RATE(config); + u8 i; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val1 != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) { + if (val2 == mcp3422_scales[sample_rate][i]) { + adc->pga[req_channel] = i; + + config &= ~MCP3422_CHANNEL_MASK; + config |= MCP3422_CHANNEL_VALUE(req_channel); + config &= ~MCP3422_PGA_MASK; + config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + + return mcp3422_update_config(adc, config); + } + } + return -EINVAL; + + case IIO_CHAN_INFO_SAMP_FREQ: + switch (val1) { + case 240: + temp = MCP3422_SRATE_240; + break; + case 60: + temp = MCP3422_SRATE_60; + break; + case 15: + temp = MCP3422_SRATE_15; + break; + case 3: + temp = MCP3422_SRATE_3; + break; + default: + return -EINVAL; + } + + config &= ~MCP3422_CHANNEL_MASK; + config |= MCP3422_CHANNEL_VALUE(req_channel); + config &= ~MCP3422_SRATE_MASK; + config |= MCP3422_SAMPLE_RATE_VALUE(temp); + + return mcp3422_update_config(adc, config); + + default: + break; + } + + return -EINVAL; +} + +static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static ssize_t mcp3422_show_scales(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); + u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + + return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", + mcp3422_scales[sample_rate][0], + mcp3422_scales[sample_rate][1], + mcp3422_scales[sample_rate][2], + mcp3422_scales[sample_rate][3]); +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("240 60 15 3"); +static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, + mcp3422_show_scales, NULL, 0); + +static struct attribute *mcp3422_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group mcp3422_attribute_group = { + .attrs = mcp3422_attributes, +}; + +static const struct iio_chan_spec mcp3422_channels[] = { + MCP3422_CHAN(0), + MCP3422_CHAN(1), +}; + +static const struct iio_chan_spec mcp3424_channels[] = { + MCP3422_CHAN(0), + MCP3422_CHAN(1), + MCP3422_CHAN(2), + MCP3422_CHAN(3), +}; + +static const struct iio_info mcp3422_info = { + .read_raw = mcp3422_read_raw, + .write_raw = mcp3422_write_raw, + .write_raw_get_fmt = mcp3422_write_raw_get_fmt, + .attrs = &mcp3422_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int mcp3422_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct mcp3422 *adc; + int err; + u8 config; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->i2c = client; + + mutex_init(&adc->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->name = dev_name(&client->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mcp3422_info; + + switch ((unsigned int)(id->driver_data)) { + case 2: + case 3: + indio_dev->channels = mcp3422_channels; + indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); + break; + case 4: + indio_dev->channels = mcp3424_channels; + indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); + break; + } + + /* meaningful default configuration */ + config = (MCP3422_CONT_SAMPLING + | MCP3422_CHANNEL_VALUE(1) + | MCP3422_PGA_VALUE(MCP3422_PGA_1) + | MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240)); + mcp3422_update_config(adc, config); + + err = iio_device_register(indio_dev); + if (err < 0) + return err; + + i2c_set_clientdata(client, indio_dev); + + return 0; +} + +static int mcp3422_remove(struct i2c_client *client) +{ + iio_device_unregister(i2c_get_clientdata(client)); + return 0; +} + +static const struct i2c_device_id mcp3422_id[] = { + { "mcp3422", 2 }, + { "mcp3423", 3 }, + { "mcp3424", 4 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mcp3422_id); + +#ifdef CONFIG_OF +static const struct of_device_id mcp3422_of_match[] = { + { .compatible = "mcp3422" }, + { } +}; +MODULE_DEVICE_TABLE(of, mcp3422_of_match); +#endif + +static struct i2c_driver mcp3422_driver = { + .driver = { + .name = "mcp3422", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mcp3422_of_match), + }, + .probe = mcp3422_probe, + .remove = mcp3422_remove, + .id_table = mcp3422_id, +}; +module_i2c_driver(mcp3422_driver); + +MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>"); +MODULE_DESCRIPTION("Microchip mcp3422/3/4 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index a952538a1a8b..8fb5429e39ae 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -28,12 +28,16 @@ #include <linux/iio/driver.h> #include <linux/mfd/ti_am335x_tscadc.h> +#include <linux/iio/buffer.h> +#include <linux/iio/kfifo_buf.h> struct tiadc_device { struct ti_tscadc_dev *mfd_tscadc; int channels; u8 channel_line[8]; u8 channel_step[8]; + int buffer_en_ch_steps; + u16 data[8]; }; static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) @@ -56,8 +60,14 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev) return step_en; } -static void tiadc_step_config(struct tiadc_device *adc_dev) +static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) { + return 1 << adc_dev->channel_step[chan]; +} + +static void tiadc_step_config(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); unsigned int stepconfig; int i, steps; @@ -72,7 +82,11 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) */ steps = TOTAL_STEPS - adc_dev->channels; - stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; + if (iio_buffer_enabled(indio_dev)) + stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 + | STEPCONFIG_MODE_SWCNT; + else + stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; for (i = 0; i < adc_dev->channels; i++) { int chan; @@ -85,9 +99,175 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) adc_dev->channel_step[i] = steps; steps++; } +} + +static irqreturn_t tiadc_irq_h(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tiadc_device *adc_dev = iio_priv(indio_dev); + unsigned int status, config; + status = tiadc_readl(adc_dev, REG_IRQSTATUS); + + /* + * ADC and touchscreen share the IRQ line. + * FIFO0 interrupts are used by TSC. Handle FIFO1 IRQs here only + */ + if (status & IRQENB_FIFO1OVRRUN) { + /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */ + config = tiadc_readl(adc_dev, REG_CTRL); + config &= ~(CNTRLREG_TSCSSENB); + tiadc_writel(adc_dev, REG_CTRL, config); + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN + | IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES); + tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB)); + return IRQ_HANDLED; + } else if (status & IRQENB_FIFO1THRES) { + /* Disable irq and wake worker thread */ + tiadc_writel(adc_dev, REG_IRQCLR, IRQENB_FIFO1THRES); + return IRQ_WAKE_THREAD; + } + + return IRQ_NONE; +} + +static irqreturn_t tiadc_worker_h(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tiadc_device *adc_dev = iio_priv(indio_dev); + int i, k, fifo1count, read; + u16 *data = adc_dev->data; + + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + for (k = 0; k < fifo1count; k = k + i) { + for (i = 0; i < (indio_dev->scan_bytes)/2; i++) { + read = tiadc_readl(adc_dev, REG_FIFO1); + data[i] = read & FIFOREAD_DATA_MASK; + } + iio_push_to_buffers(indio_dev, (u8 *) data); + } + + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES); + tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); + + return IRQ_HANDLED; +} + +static int tiadc_buffer_preenable(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + int i, fifo1count, read; + + tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | + IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW)); + + /* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */ + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + for (i = 0; i < fifo1count; i++) + read = tiadc_readl(adc_dev, REG_FIFO1); + + return iio_sw_buffer_preenable(indio_dev); +} + +static int tiadc_buffer_postenable(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + struct iio_buffer *buffer = indio_dev->buffer; + unsigned int enb = 0; + u8 bit; + + tiadc_step_config(indio_dev); + for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels) + enb |= (get_adc_step_bit(adc_dev, bit) << 1); + adc_dev->buffer_en_ch_steps = enb; + + am335x_tsc_se_set(adc_dev->mfd_tscadc, enb); + + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES + | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); + tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES + | IRQENB_FIFO1OVRRUN); + + return 0; +} + +static int tiadc_buffer_predisable(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + int fifo1count, i, read; + + tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | + IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW)); + am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); + + /* Flush FIFO of leftover data in the time it takes to disable adc */ + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + for (i = 0; i < fifo1count; i++) + read = tiadc_readl(adc_dev, REG_FIFO1); + + return 0; +} + +static int tiadc_buffer_postdisable(struct iio_dev *indio_dev) +{ + tiadc_step_config(indio_dev); + return 0; } +static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = { + .preenable = &tiadc_buffer_preenable, + .postenable = &tiadc_buffer_postenable, + .predisable = &tiadc_buffer_predisable, + .postdisable = &tiadc_buffer_postdisable, +}; + +static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev, + irqreturn_t (*pollfunc_bh)(int irq, void *p), + irqreturn_t (*pollfunc_th)(int irq, void *p), + int irq, + unsigned long flags, + const struct iio_buffer_setup_ops *setup_ops) +{ + int ret; + + indio_dev->buffer = iio_kfifo_allocate(indio_dev); + if (!indio_dev->buffer) + return -ENOMEM; + + ret = request_threaded_irq(irq, pollfunc_th, pollfunc_bh, + flags, indio_dev->name, indio_dev); + if (ret) + goto error_kfifo_free; + + indio_dev->setup_ops = setup_ops; + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + + ret = iio_buffer_register(indio_dev, + indio_dev->channels, + indio_dev->num_channels); + if (ret) + goto error_free_irq; + + return 0; + +error_free_irq: + free_irq(irq, indio_dev); +error_kfifo_free: + iio_kfifo_free(indio_dev->buffer); + return ret; +} + +static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + + free_irq(adc_dev->mfd_tscadc->irq, indio_dev); + iio_kfifo_free(indio_dev->buffer); + iio_buffer_unregister(indio_dev); +} + + static const char * const chan_name_ain[] = { "AIN0", "AIN1", @@ -120,9 +300,10 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) chan->channel = adc_dev->channel_line[i]; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); chan->datasheet_name = chan_name_ain[chan->channel]; + chan->scan_index = i; chan->scan_type.sign = 'u'; chan->scan_type.realbits = 12; - chan->scan_type.storagebits = 32; + chan->scan_type.storagebits = 16; } indio_dev->channels = chan_array; @@ -142,11 +323,14 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, struct tiadc_device *adc_dev = iio_priv(indio_dev); int i, map_val; unsigned int fifo1count, read, stepid; - u32 step = UINT_MAX; bool found = false; u32 step_en; unsigned long timeout = jiffies + usecs_to_jiffies (IDLE_TIMEOUT * adc_dev->channels); + + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + step_en = get_adc_step_mask(adc_dev); am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en); @@ -168,15 +352,6 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, * Hence we need to flush out this data. */ - for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) { - if (chan->channel == adc_dev->channel_line[i]) { - step = adc_dev->channel_step[i]; - break; - } - } - if (WARN_ON_ONCE(step == UINT_MAX)) - return -EINVAL; - fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); for (i = 0; i < fifo1count; i++) { read = tiadc_readl(adc_dev, REG_FIFO1); @@ -186,7 +361,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, if (stepid == map_val) { read = read & FIFOREAD_DATA_MASK; found = true; - *val = read; + *val = (u16) read; } } @@ -237,20 +412,33 @@ static int tiadc_probe(struct platform_device *pdev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &tiadc_info; - tiadc_step_config(adc_dev); + tiadc_step_config(indio_dev); + tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD); err = tiadc_channel_init(indio_dev, adc_dev->channels); if (err < 0) return err; - err = iio_device_register(indio_dev); + err = tiadc_iio_buffered_hardware_setup(indio_dev, + &tiadc_worker_h, + &tiadc_irq_h, + adc_dev->mfd_tscadc->irq, + IRQF_SHARED, + &tiadc_buffer_setup_ops); + if (err) goto err_free_channels; + err = iio_device_register(indio_dev); + if (err) + goto err_buffer_unregister; + platform_set_drvdata(pdev, indio_dev); return 0; +err_buffer_unregister: + tiadc_iio_buffered_hardware_remove(indio_dev); err_free_channels: tiadc_channels_remove(indio_dev); return err; @@ -263,6 +451,7 @@ static int tiadc_remove(struct platform_device *pdev) u32 step_en; iio_device_unregister(indio_dev); + tiadc_iio_buffered_hardware_remove(indio_dev); tiadc_channels_remove(indio_dev); step_en = get_adc_step_mask(adc_dev); @@ -301,7 +490,7 @@ static int tiadc_resume(struct device *dev) restore &= ~(CNTRLREG_POWERDOWN); tiadc_writel(adc_dev, REG_CTRL, restore); - tiadc_step_config(adc_dev); + tiadc_step_config(indio_dev); return 0; } diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c index 9d19ba74f22b..578f7199ed51 100644 --- a/drivers/iio/buffer_cb.c +++ b/drivers/iio/buffer_cb.c @@ -7,12 +7,12 @@ struct iio_cb_buffer { struct iio_buffer buffer; - int (*cb)(u8 *data, void *private); + int (*cb)(const void *data, void *private); void *private; struct iio_channel *channels; }; -static int iio_buffer_cb_store_to(struct iio_buffer *buffer, u8 *data) +static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data) { struct iio_cb_buffer *cb_buff = container_of(buffer, struct iio_cb_buffer, @@ -21,12 +21,12 @@ static int iio_buffer_cb_store_to(struct iio_buffer *buffer, u8 *data) return cb_buff->cb(data, cb_buff->private); } -static struct iio_buffer_access_funcs iio_cb_access = { +static const struct iio_buffer_access_funcs iio_cb_access = { .store_to = &iio_buffer_cb_store_to, }; struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, - int (*cb)(u8 *data, + int (*cb)(const void *data, void *private), void *private) { diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 71a2c5f63b9c..1665c8e4b62b 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -113,11 +113,8 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) if (len < 0) goto st_sensors_get_buffer_element_error; - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)sdata->buffer_data + - ALIGN(len, sizeof(s64))) = pf->timestamp; - - iio_push_to_buffers(indio_dev, sdata->buffer_data); + iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data, + pf->timestamp); st_sensors_get_buffer_element_error: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 965ee22d3ac8..7ba1ef270213 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -198,21 +198,17 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) } EXPORT_SYMBOL(st_sensors_set_axis_enable); -int st_sensors_init_sensor(struct iio_dev *indio_dev, - struct st_sensors_platform_data *pdata) +static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, + struct st_sensors_platform_data *pdata) { - int err; struct st_sensor_data *sdata = iio_priv(indio_dev); - mutex_init(&sdata->tb.buf_lock); - switch (pdata->drdy_int_pin) { case 1: if (sdata->sensor->drdy_irq.mask_int1 == 0) { dev_err(&indio_dev->dev, "DRDY on INT1 not available.\n"); - err = -EINVAL; - goto init_error; + return -EINVAL; } sdata->drdy_int_pin = 1; break; @@ -220,39 +216,53 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, if (sdata->sensor->drdy_irq.mask_int2 == 0) { dev_err(&indio_dev->dev, "DRDY on INT2 not available.\n"); - err = -EINVAL; - goto init_error; + return -EINVAL; } sdata->drdy_int_pin = 2; break; default: dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n"); - err = -EINVAL; - goto init_error; + return -EINVAL; } + return 0; +} + +int st_sensors_init_sensor(struct iio_dev *indio_dev, + struct st_sensors_platform_data *pdata) +{ + struct st_sensor_data *sdata = iio_priv(indio_dev); + int err = 0; + + mutex_init(&sdata->tb.buf_lock); + + if (pdata) + err = st_sensors_set_drdy_int_pin(indio_dev, pdata); + err = st_sensors_set_enable(indio_dev, false); if (err < 0) - goto init_error; + return err; - err = st_sensors_set_fullscale(indio_dev, - sdata->current_fullscale->num); - if (err < 0) - goto init_error; + if (sdata->current_fullscale) { + err = st_sensors_set_fullscale(indio_dev, + sdata->current_fullscale->num); + if (err < 0) + return err; + } else + dev_info(&indio_dev->dev, "Full-scale not possible\n"); err = st_sensors_set_odr(indio_dev, sdata->odr); if (err < 0) - goto init_error; + return err; /* set BDU */ err = st_sensors_write_data_with_mask(indio_dev, sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true); if (err < 0) - goto init_error; + return err; err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); -init_error: return err; } EXPORT_SYMBOL(st_sensors_init_sensor); @@ -263,6 +273,9 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) u8 drdy_mask; struct st_sensor_data *sdata = iio_priv(indio_dev); + if (!sdata->sensor->drdy_irq.addr) + return 0; + /* Enable/Disable the interrupt generator 1. */ if (sdata->sensor->drdy_irq.ig1.en_addr > 0) { err = st_sensors_write_data_with_mask(indio_dev, @@ -318,10 +331,8 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, unsigned int byte_for_channel = ch->scan_type.storagebits >> 3; outdata = kmalloc(byte_for_channel, GFP_KERNEL); - if (!outdata) { - err = -EINVAL; - goto st_sensors_read_axis_data_error; - } + if (!outdata) + return -ENOMEM; err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, ch->address, byte_for_channel, @@ -336,7 +347,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, st_sensors_free_memory: kfree(outdata); -st_sensors_read_axis_data_error: + return err; } @@ -349,28 +360,25 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { err = -EBUSY; - goto read_error; + goto out; } else { err = st_sensors_set_enable(indio_dev, true); if (err < 0) - goto read_error; + goto out; msleep((sdata->sensor->bootime * 1000) / sdata->odr); err = st_sensors_read_axis_data(indio_dev, ch, val); if (err < 0) - goto read_error; + goto out; *val = *val >> ch->scan_type.shift; err = st_sensors_set_enable(indio_dev, false); } +out: mutex_unlock(&indio_dev->mlock); return err; - -read_error: - mutex_unlock(&indio_dev->mlock); - return err; } EXPORT_SYMBOL(st_sensors_read_info_raw); diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index a3a52be4852c..b18e8c4347c2 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -285,8 +285,9 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { .name = "powerdown", .read = ad5064_read_dac_powerdown, .write = ad5064_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &ad5064_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5064_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 1c44ae3920e2..4c791e66e0d7 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -247,8 +247,10 @@ static struct iio_chan_spec_ext_info ad5380_ext_info[] = { .name = "powerdown", .read = ad5380_read_dac_powerdown, .write = ad5380_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", true, &ad5380_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5380_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5380_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 96e9ed4c2d01..6dcb6d93f0e4 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -132,8 +132,9 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { .name = "powerdown", .read = ad5446_read_dac_powerdown, .write = ad5446_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &ad5446_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index caffb16bc05c..31f4ff29f914 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -248,8 +248,10 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = { .name = "powerdown", .read = ad5504_read_dac_powerdown, .write = ad5504_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", true, &ad5504_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5504_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5504_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 714af757cd56..dbb1289cc7a6 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -163,8 +163,10 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = { .name = "powerdown", .read = ad5624r_read_dac_powerdown, .write = ad5624r_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", true, &ad5624r_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5624r_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5624r_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 57825ead7db2..f472b48445f6 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -213,7 +213,6 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, return ret; *val = ret; return IIO_VAL_INT; - break; case IIO_CHAN_INFO_SCALE: scale_uv = (st->vref_mv * 100000) >> (chan->scan_type.realbits); @@ -265,8 +264,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .name = "powerdown", .read = ad5686_read_dac_powerdown, .write = ad5686_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &ad5686_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5686_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5686_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 36a4361aece1..f305a0c83418 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -386,6 +386,7 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { .name = "powerdown", .read = ad5755_read_powerdown, .write = ad5755_write_powerdown, + .shared = IIO_SEPARATE, }, { }, }; diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index ce7458963309..3cee89be68c3 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -287,11 +287,12 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { { .name = "powerdown", - .shared = true, + .shared = IIO_SHARED_BY_TYPE, .read = ad5791_read_dac_powerdown, .write = ad5791_write_dac_powerdown, }, - IIO_ENUM("powerdown_mode", true, &ad5791_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5791_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5791_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index ed2d276477bd..d0505fd22ef4 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -169,6 +169,7 @@ static const struct iio_chan_spec_ext_info ad7303_ext_info[] = { .name = "powerdown", .read = ad7303_read_dac_powerdown, .write = ad7303_write_dac_powerdown, + .shared = IIO_SEPARATE, }, { }, }; diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 1f4a48e6a82c..6711a33b16ba 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -195,8 +195,9 @@ static const struct iio_chan_spec_ext_info mcp4725_ext_info[] = { .name = "powerdown", .read = mcp4725_read_powerdown, .write = mcp4725_write_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &mcp4725_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp4725_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &mcp4725_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index a7b30be86ae0..85152547aa8b 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -351,6 +351,7 @@ static ssize_t adf4350_read(struct iio_dev *indio_dev, .read = adf4350_read, \ .write = adf4350_write, \ .private = _ident, \ + .shared = IIO_SEPARATE, \ } static const struct iio_chan_spec_ext_info adf4350_ext_info[] = { diff --git a/drivers/iio/gyro/adis16130.c b/drivers/iio/gyro/adis16130.c index ac66fc184042..9155cf6cf287 100644 --- a/drivers/iio/gyro/adis16130.c +++ b/drivers/iio/gyro/adis16130.c @@ -103,7 +103,6 @@ static int adis16130_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; case IIO_CHAN_INFO_OFFSET: switch (chan->type) { case IIO_ANGL_VEL: @@ -115,7 +114,6 @@ static int adis16130_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; } return -EINVAL; diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 06541162fc02..22b6fb80fa1a 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -239,7 +239,6 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; case IIO_CHAN_INFO_OFFSET: *val = 250000 / 1453; /* 25 C = 0x00 */ return IIO_VAL_INT; diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index 6dab2995f0f2..c1f40efbf639 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -354,7 +354,6 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW: ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t); if (ret) diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index c688d974d3e3..ea01c6bcfb56 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -182,10 +182,11 @@ static const struct iio_info gyro_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -200,7 +201,7 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, gyro_state->common_attributes.data_ready); if (gyro_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)gyro_state->gyro_val, + gyro_state->gyro_val, sizeof(gyro_state->gyro_val)); return 0; diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index 6c43af9bb0a4..e3b3c5084070 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -55,11 +55,8 @@ static irqreturn_t itg3200_trigger_handler(int irq, void *p) if (ret < 0) goto error_ret; - if (indio_dev->scan_timestamp) - memcpy(buf + indio_dev->scan_bytes - sizeof(s64), - &pf->timestamp, sizeof(pf->timestamp)); + iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp); - iio_push_to_buffers(indio_dev, (u8 *)buf); iio_trigger_notify_done(indio_dev->trig); error_ret: diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index e13c2b0bf3d1..d53d91adfb55 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -305,8 +305,9 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = { int st_gyro_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) { - int err; 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; @@ -314,7 +315,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors); if (err < 0) - goto st_gyro_common_probe_error; + return err; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; gdata->multiread_bit = gdata->sensor->multi_read_bit; @@ -327,13 +328,13 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_gyro_common_probe_error; + return err; - if (gdata->get_irq_data_ready(indio_dev) > 0) { - err = st_gyro_allocate_ring(indio_dev); - if (err < 0) - goto st_gyro_common_probe_error; + err = st_gyro_allocate_ring(indio_dev); + if (err < 0) + return err; + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_GYRO_TRIGGER_OPS); if (err < 0) @@ -344,15 +345,14 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, if (err) goto st_gyro_device_register_error; - return err; + return 0; st_gyro_device_register_error: - if (gdata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_gyro_probe_trigger_error: - if (gdata->get_irq_data_ready(indio_dev) > 0) - st_gyro_deallocate_ring(indio_dev); -st_gyro_common_probe_error: + st_gyro_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_gyro_common_probe); @@ -362,10 +362,10 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) struct st_sensor_data *gdata = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (gdata->get_irq_data_ready(indio_dev) > 0) { + if (gdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_gyro_deallocate_ring(indio_dev); - } + + st_gyro_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_gyro_common_remove); diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 05c1b74502a3..6be5ab864b1a 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -30,7 +30,7 @@ int __iio_add_chan_devattr(const char *postfix, const char *buf, size_t len), u64 mask, - bool generic, + enum iio_shared_by shared_by, struct device *dev, struct list_head *attr_list); diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c index 054c01d6e73c..f2cf829e5df1 100644 --- a/drivers/iio/imu/adis16400_buffer.c +++ b/drivers/iio/imu/adis16400_buffer.c @@ -82,13 +82,8 @@ irqreturn_t adis16400_trigger_handler(int irq, void *p) spi_setup(st->adis.spi); } - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) { - void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); - *(s64 *)b = pf->timestamp; - } - - iio_push_to_buffers(indio_dev, adis->buffer); + iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 99d8e0b0dd34..cb32b593f1c5 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -102,13 +102,8 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) mutex_unlock(&adis->txrx_lock); } - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) { - void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); - *(s64 *)b = pf->timestamp; - } - - iio_push_to_buffers(indio_dev, adis->buffer); + iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 7da0832f187b..429517117eff 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -124,7 +124,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; u16 fifo_count; s64 timestamp; - u64 *tmp; mutex_lock(&indio_dev->mlock); if (!(st->chip_config.accl_fifo_enable | @@ -170,9 +169,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) if (0 == result) timestamp = 0; - tmp = (u64 *)data; - tmp[DIV_ROUND_UP(bytes_per_datum, 8)] = timestamp; - result = iio_push_to_buffers(indio_dev, data); + result = iio_push_to_buffers_with_timestamp(indio_dev, data, + timestamp); if (result) goto flush_fifo; fifo_count -= bytes_per_datum; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index e73033f3839a..2361fbc74e33 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -31,16 +31,9 @@ static const char * const iio_endian_prefix[] = { [IIO_LE] = "le", }; -static bool iio_buffer_is_active(struct iio_dev *indio_dev, - struct iio_buffer *buf) +static bool iio_buffer_is_active(struct iio_buffer *buf) { - struct list_head *p; - - list_for_each(p, &indio_dev->buffer_list) - if (p == &buf->buffer_list) - return true; - - return false; + return !list_empty(&buf->buffer_list); } /** @@ -79,6 +72,7 @@ unsigned int iio_buffer_poll(struct file *filp, void iio_buffer_init(struct iio_buffer *buffer) { INIT_LIST_HEAD(&buffer->demux_list); + INIT_LIST_HEAD(&buffer->buffer_list); init_waitqueue_head(&buffer->pollq); } EXPORT_SYMBOL(iio_buffer_init); @@ -146,7 +140,7 @@ static ssize_t iio_scan_el_store(struct device *dev, if (ret < 0) return ret; mutex_lock(&indio_dev->mlock); - if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) { + if (iio_buffer_is_active(indio_dev->buffer)) { ret = -EBUSY; goto error_ret; } @@ -192,7 +186,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev, return ret; mutex_lock(&indio_dev->mlock); - if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) { + if (iio_buffer_is_active(indio_dev->buffer)) { ret = -EBUSY; goto error_ret; } @@ -214,7 +208,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, &iio_show_scan_index, NULL, 0, - 0, + IIO_SEPARATE, &indio_dev->dev, &buffer->scan_el_dev_attr_list); if (ret) @@ -249,6 +243,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, &indio_dev->dev, &buffer->scan_el_dev_attr_list); + if (ret) + goto error_ret; attrcount++; ret = attrcount; error_ret: @@ -396,7 +392,7 @@ ssize_t iio_buffer_write_length(struct device *dev, return len; mutex_lock(&indio_dev->mlock); - if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) { + if (iio_buffer_is_active(indio_dev->buffer)) { ret = -EBUSY; } else { if (buffer->access->set_length) @@ -414,13 +410,11 @@ ssize_t iio_buffer_show_enable(struct device *dev, char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - return sprintf(buf, "%d\n", - iio_buffer_is_active(indio_dev, - indio_dev->buffer)); + return sprintf(buf, "%d\n", iio_buffer_is_active(indio_dev->buffer)); } EXPORT_SYMBOL(iio_buffer_show_enable); -/* note NULL used as error indicator as it doesn't make sense. */ +/* Note NULL used as error indicator as it doesn't make sense. */ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, unsigned int masklength, const unsigned long *mask) @@ -435,8 +429,8 @@ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, return NULL; } -static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask, - bool timestamp) +static int iio_compute_scan_bytes(struct iio_dev *indio_dev, + const unsigned long *mask, bool timestamp) { const struct iio_chan_spec *ch; unsigned bytes = 0; @@ -490,7 +484,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, indio_dev->active_scan_mask = NULL; if (remove_buffer) - list_del(&remove_buffer->buffer_list); + list_del_init(&remove_buffer->buffer_list); if (insert_buffer) list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list); @@ -502,7 +496,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, return 0; } - /* What scan mask do we actually have ?*/ + /* What scan mask do we actually have? */ compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long), GFP_KERNEL); if (compound_mask == NULL) { @@ -527,7 +521,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, * Roll back. * Note can only occur when adding a buffer. */ - list_del(&insert_buffer->buffer_list); + list_del_init(&insert_buffer->buffer_list); indio_dev->active_scan_mask = old_mask; success = -EINVAL; } @@ -568,7 +562,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, goto error_run_postdisable; } } - /* Definitely possible for devices to support both of these.*/ + /* Definitely possible for devices to support both of these. */ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) { if (!indio_dev->trig) { printk(KERN_INFO "Buffer not started: no trigger\n"); @@ -579,7 +573,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, indio_dev->currentmode = INDIO_BUFFER_TRIGGERED; } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) { indio_dev->currentmode = INDIO_BUFFER_HARDWARE; - } else { /* should never be reached */ + } else { /* Should never be reached */ ret = -EINVAL; goto error_run_postdisable; } @@ -611,7 +605,7 @@ error_run_postdisable: error_remove_inserted: if (insert_buffer) - list_del(&insert_buffer->buffer_list); + list_del_init(&insert_buffer->buffer_list); indio_dev->active_scan_mask = old_mask; kfree(compound_mask); error_ret: @@ -628,7 +622,6 @@ ssize_t iio_buffer_store_enable(struct device *dev, int ret; bool requested_state; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *pbuf = indio_dev->buffer; bool inlist; ret = strtobool(buf, &requested_state); @@ -638,7 +631,7 @@ ssize_t iio_buffer_store_enable(struct device *dev, mutex_lock(&indio_dev->mlock); /* Find out if it is in the list */ - inlist = iio_buffer_is_active(indio_dev, pbuf); + inlist = iio_buffer_is_active(indio_dev->buffer); /* Already in desired state */ if (inlist == requested_state) goto done; @@ -703,6 +696,7 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev, /** * iio_scan_mask_set() - set particular bit in the scan mask + * @indio_dev: the iio device * @buffer: the buffer whose scan mask we are interested in * @bit: the bit to be set. * @@ -723,7 +717,7 @@ int iio_scan_mask_set(struct iio_dev *indio_dev, if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { - WARN_ON("trying to set scanmask prior to registering buffer\n"); + WARN_ON("Trying to set scanmask prior to registering buffer\n"); goto err_invalid_mask; } bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength); @@ -778,8 +772,8 @@ struct iio_demux_table { struct list_head l; }; -static unsigned char *iio_demux(struct iio_buffer *buffer, - unsigned char *datain) +static const void *iio_demux(struct iio_buffer *buffer, + const void *datain) { struct iio_demux_table *t; @@ -792,9 +786,9 @@ static unsigned char *iio_demux(struct iio_buffer *buffer, return buffer->demux_bounce; } -static int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data) +static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data) { - unsigned char *dataout = iio_demux(buffer, data); + const void *dataout = iio_demux(buffer, data); return buffer->access->store_to(buffer, dataout); } @@ -809,7 +803,7 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer) } -int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data) +int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data) { int ret; struct iio_buffer *buf; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 97f0297b120f..24db1855dbab 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -101,6 +101,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_PHASE] = "phase", [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain", [IIO_CHAN_INFO_HYSTERESIS] = "hysteresis", + [IIO_CHAN_INFO_INT_TIME] = "integration_time", }; const struct iio_chan_spec @@ -516,14 +517,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, struct device_attribute *attr, const char *buf, size_t len), - bool generic) + enum iio_shared_by shared_by) { - int ret; - char *name_format, *full_postfix; + int ret = 0; + char *name_format = NULL; + char *full_postfix; sysfs_attr_init(&dev_attr->attr); /* Build up postfix of <extend_name>_<modifier>_postfix */ - if (chan->modified && !generic) { + if (chan->modified && (shared_by == IIO_SEPARATE)) { if (chan->extend_name) full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_modifier_names[chan @@ -544,53 +546,78 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, chan->extend_name, postfix); } - if (full_postfix == NULL) { - ret = -ENOMEM; - goto error_ret; - } + if (full_postfix == NULL) + return -ENOMEM; if (chan->differential) { /* Differential can not have modifier */ - if (generic) + switch (shared_by) { + case IIO_SHARED_BY_ALL: + name_format = kasprintf(GFP_KERNEL, "%s", full_postfix); + break; + case IIO_SHARED_BY_DIR: + name_format = kasprintf(GFP_KERNEL, "%s_%s", + iio_direction[chan->output], + full_postfix); + break; + case IIO_SHARED_BY_TYPE: name_format = kasprintf(GFP_KERNEL, "%s_%s-%s_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], iio_chan_type_name_spec[chan->type], full_postfix); - else if (chan->indexed) + break; + case IIO_SEPARATE: + if (!chan->indexed) { + WARN_ON("Differential channels must be indexed\n"); + ret = -EINVAL; + goto error_free_full_postfix; + } name_format - = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s", + = kasprintf(GFP_KERNEL, + "%s_%s%d-%s%d_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], chan->channel, iio_chan_type_name_spec[chan->type], chan->channel2, full_postfix); - else { - WARN_ON("Differential channels must be indexed\n"); - ret = -EINVAL; - goto error_free_full_postfix; + break; } } else { /* Single ended */ - if (generic) - name_format - = kasprintf(GFP_KERNEL, "%s_%s_%s", - iio_direction[chan->output], - iio_chan_type_name_spec[chan->type], - full_postfix); - else if (chan->indexed) - name_format - = kasprintf(GFP_KERNEL, "%s_%s%d_%s", - iio_direction[chan->output], - iio_chan_type_name_spec[chan->type], - chan->channel, - full_postfix); - else + switch (shared_by) { + case IIO_SHARED_BY_ALL: + name_format = kasprintf(GFP_KERNEL, "%s", full_postfix); + break; + case IIO_SHARED_BY_DIR: + name_format = kasprintf(GFP_KERNEL, "%s_%s", + iio_direction[chan->output], + full_postfix); + break; + case IIO_SHARED_BY_TYPE: name_format = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], full_postfix); + break; + + case IIO_SEPARATE: + if (chan->indexed) + name_format + = kasprintf(GFP_KERNEL, "%s_%s%d_%s", + iio_direction[chan->output], + iio_chan_type_name_spec[chan->type], + chan->channel, + full_postfix); + else + name_format + = kasprintf(GFP_KERNEL, "%s_%s_%s", + iio_direction[chan->output], + iio_chan_type_name_spec[chan->type], + full_postfix); + break; + } } if (name_format == NULL) { ret = -ENOMEM; @@ -614,16 +641,11 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, dev_attr->attr.mode |= S_IWUSR; dev_attr->store = writefunc; } - kfree(name_format); - kfree(full_postfix); - - return 0; - error_free_name_format: kfree(name_format); error_free_full_postfix: kfree(full_postfix); -error_ret: + return ret; } @@ -642,7 +664,7 @@ int __iio_add_chan_devattr(const char *postfix, const char *buf, size_t len), u64 mask, - bool generic, + enum iio_shared_by shared_by, struct device *dev, struct list_head *attr_list) { @@ -656,7 +678,7 @@ int __iio_add_chan_devattr(const char *postfix, } ret = __iio_device_attr_init(&iio_attr->dev_attr, postfix, chan, - readfunc, writefunc, generic); + readfunc, writefunc, shared_by); if (ret) goto error_iio_dev_attr_free; iio_attr->c = chan; @@ -664,7 +686,7 @@ int __iio_add_chan_devattr(const char *postfix, list_for_each_entry(t, attr_list, l) if (strcmp(t->dev_attr.attr.name, iio_attr->dev_attr.attr.name) == 0) { - if (!generic) + if (shared_by == IIO_SEPARATE) dev_err(dev, "tried to double register : %s\n", t->dev_attr.attr.name); ret = -EBUSY; @@ -682,46 +704,68 @@ error_ret: return ret; } -static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan) +static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + enum iio_shared_by shared_by, + const long *infomask) { - int ret, attrcount = 0; - int i; - const struct iio_chan_spec_ext_info *ext_info; + int i, ret, attrcount = 0; - if (chan->channel < 0) - return 0; - for_each_set_bit(i, &chan->info_mask_separate, sizeof(long)*8) { + for_each_set_bit(i, infomask, sizeof(infomask)*8) { ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], chan, &iio_read_channel_info, &iio_write_channel_info, i, - 0, + shared_by, &indio_dev->dev, &indio_dev->channel_attr_list); - if (ret < 0) - goto error_ret; - attrcount++; - } - for_each_set_bit(i, &chan->info_mask_shared_by_type, sizeof(long)*8) { - ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], - chan, - &iio_read_channel_info, - &iio_write_channel_info, - i, - 1, - &indio_dev->dev, - &indio_dev->channel_attr_list); - if (ret == -EBUSY) { - ret = 0; + if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) continue; - } else if (ret < 0) { - goto error_ret; - } + else if (ret < 0) + return ret; attrcount++; } + return attrcount; +} + +static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) +{ + int ret, attrcount = 0; + const struct iio_chan_spec_ext_info *ext_info; + + if (chan->channel < 0) + return 0; + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SEPARATE, + &chan->info_mask_separate); + if (ret < 0) + return ret; + attrcount += ret; + + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SHARED_BY_TYPE, + &chan->info_mask_shared_by_type); + if (ret < 0) + return ret; + attrcount += ret; + + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SHARED_BY_DIR, + &chan->info_mask_shared_by_dir); + if (ret < 0) + return ret; + attrcount += ret; + + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SHARED_BY_ALL, + &chan->info_mask_shared_by_all); + if (ret < 0) + return ret; + attrcount += ret; + if (chan->ext_info) { unsigned int i = 0; for (ext_info = chan->ext_info; ext_info->name; ext_info++) { @@ -740,15 +784,13 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, continue; if (ret) - goto error_ret; + return ret; attrcount++; } } - ret = attrcount; -error_ret: - return ret; + return attrcount; } static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev, diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 10aa9ef86cec..2390e3d08e48 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -159,7 +159,7 @@ int iio_event_getfd(struct iio_dev *indio_dev) } spin_unlock_irq(&ev_int->wait.lock); fd = anon_inode_getfd("iio:event", - &iio_event_chrdev_fileops, ev_int, O_RDONLY); + &iio_event_chrdev_fileops, ev_int, O_RDONLY | O_CLOEXEC); if (fd < 0) { spin_lock_irq(&ev_int->wait.lock); __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index a923c78d5cb4..538d4616e48f 100644 --- a/drivers/iio/kfifo_buf.c +++ b/drivers/iio/kfifo_buf.c @@ -7,6 +7,7 @@ #include <linux/mutex.h> #include <linux/iio/kfifo_buf.h> #include <linux/sched.h> +#include <linux/poll.h> struct iio_kfifo { struct iio_buffer buffer; @@ -94,7 +95,7 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length) } static int iio_store_to_kfifo(struct iio_buffer *r, - u8 *data) + const void *data) { int ret; struct iio_kfifo *kf = iio_to_kfifo(r); @@ -102,7 +103,7 @@ static int iio_store_to_kfifo(struct iio_buffer *r, if (ret != 1) return -EBUSY; r->stufftoread = true; - wake_up_interruptible(&r->pollq); + wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM); return 0; } diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index bf9fa0d7aff9..0a25ae6b132e 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -27,6 +27,18 @@ config APDS9300 To compile this driver as a module, choose M here: the module will be called apds9300. +config GP2AP020A00F + tristate "Sharp GP2AP020A00F Proximity/ALS sensor" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here if you have a Sharp GP2AP020A00F proximity/ALS combo-chip + hooked to an I2C bus. + + To compile this driver as a module, choose M here: the + module will be called gp2ap020a00f. + config HID_SENSOR_ALS depends on HID_SENSOR_HUB select IIO_BUFFER @@ -55,6 +67,16 @@ config SENSORS_LM3533 changes. The ALS-control output values can be set per zone for the three current output channels. +config TCS3472 + tristate "TAOS TCS3472 color light-to-digital converter" + depends on I2C + help + If you say yes here you get support for the TAOS TCS3472 + family of color light-to-digital converters with IR filter. + + This driver can also be built as a module. If so, the module + will be called tcs3472. + config SENSORS_TSL2563 tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" depends on I2C @@ -65,6 +87,16 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. +config TSL4531 + tristate "TAOS TSL4531 ambient light sensors" + depends on I2C + help + Say Y here if you want to build a driver for the TAOS TSL4531 family + of ambient light sensors with direct lux output. + + To compile this driver as a module, choose M here: the + module will be called tsl4531. + config VCNL4000 tristate "VCNL4000 combined ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 354ee9ab2379..cef590f2ff00 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -5,7 +5,10 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADJD_S311) += adjd_s311.o obj-$(CONFIG_APDS9300) += apds9300.o +obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o +obj-$(CONFIG_TCS3472) += tcs3472.o +obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_VCNL4000) += vcnl4000.o diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 23cff798598a..83d15c5baf64 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -114,43 +114,6 @@ static int adjd_s311_read_data(struct iio_dev *indio_dev, u8 reg, int *val) return 0; } -static ssize_t adjd_s311_read_int_time(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, char *buf) -{ - struct adjd_s311_data *data = iio_priv(indio_dev); - s32 ret; - - ret = i2c_smbus_read_word_data(data->client, - ADJD_S311_INT_REG(chan->address)); - if (ret < 0) - return ret; - - return sprintf(buf, "%d\n", ret & ADJD_S311_INT_MASK); -} - -static ssize_t adjd_s311_write_int_time(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, const char *buf, - size_t len) -{ - struct adjd_s311_data *data = iio_priv(indio_dev); - unsigned long int_time; - int ret; - - ret = kstrtoul(buf, 10, &int_time); - if (ret) - return ret; - - if (int_time > ADJD_S311_INT_MASK) - return -EINVAL; - - ret = i2c_smbus_write_word_data(data->client, - ADJD_S311_INT_REG(chan->address), int_time); - if (ret < 0) - return ret; - - return len; -} - static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -175,10 +138,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) len += 2; } - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64))) - = time_ns; - iio_push_to_buffers(indio_dev, (u8 *)data->buffer); + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns); done: iio_trigger_notify_done(indio_dev->trig); @@ -186,25 +146,16 @@ done: return IRQ_HANDLED; } -static const struct iio_chan_spec_ext_info adjd_s311_ext_info[] = { - { - .name = "integration_time", - .read = adjd_s311_read_int_time, - .write = adjd_s311_write_int_time, - }, - { } -}; - #define ADJD_S311_CHANNEL(_color, _scan_idx) { \ .type = IIO_INTENSITY, \ .modified = 1, \ .address = (IDX_##_color), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ + BIT(IIO_CHAN_INFO_INT_TIME), \ .channel2 = (IIO_MOD_LIGHT_##_color), \ .scan_index = (_scan_idx), \ .scan_type = IIO_ST('u', 10, 16, 0), \ - .ext_info = adjd_s311_ext_info, \ } static const struct iio_chan_spec adjd_s311_channels[] = { @@ -236,6 +187,18 @@ static int adjd_s311_read_raw(struct iio_dev *indio_dev, return ret; *val = ret & ADJD_S311_CAP_MASK; return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + ret = i2c_smbus_read_word_data(data->client, + ADJD_S311_INT_REG(chan->address)); + if (ret < 0) + return ret; + *val = 0; + /* + * not documented, based on measurement: + * 4095 LSBs correspond to roughly 4 ms + */ + *val2 = ret & ADJD_S311_INT_MASK; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } @@ -245,16 +208,20 @@ static int adjd_s311_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct adjd_s311_data *data = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_HARDWAREGAIN: if (val < 0 || val > ADJD_S311_CAP_MASK) return -EINVAL; - ret = i2c_smbus_write_byte_data(data->client, + return i2c_smbus_write_byte_data(data->client, ADJD_S311_CAP_REG(chan->address), val); - return ret; + case IIO_CHAN_INFO_INT_TIME: + if (val != 0 || val2 < 0 || val2 > ADJD_S311_INT_MASK) + return -EINVAL; + + return i2c_smbus_write_word_data(data->client, + ADJD_S311_INT_REG(chan->address), val2); } return -EINVAL; } diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c new file mode 100644 index 000000000000..b1e4615b87e8 --- /dev/null +++ b/drivers/iio/light/gp2ap020a00f.c @@ -0,0 +1,1617 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Author: Jacek Anaszewski <j.anaszewski@samsung.com> + * + * IIO features supported by the driver: + * + * Read-only raw channels: + * - illiminance_clear [lux] + * - illiminance_ir + * - proximity + * + * Triggered buffer: + * - illiminance_clear + * - illiminance_ir + * - proximity + * + * Events: + * - illuminance_clear (rising and falling) + * - proximity (rising and falling) + * - both falling and rising thresholds for the proximity events + * must be set to the values greater than 0. + * + * The driver supports triggered buffers for all the three + * channels as well as high and low threshold events for the + * illuminance_clear and proxmimity channels. Triggers + * can be enabled simultaneously with both illuminance_clear + * events. Proximity events cannot be enabled simultaneously + * with any triggers or illuminance events. Enabling/disabling + * one of the proximity events automatically enables/disables + * the other one. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irq_work.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define GP2A_I2C_NAME "gp2ap020a00f" + +/* Registers */ +#define GP2AP020A00F_OP_REG 0x00 /* Basic operations */ +#define GP2AP020A00F_ALS_REG 0x01 /* ALS related settings */ +#define GP2AP020A00F_PS_REG 0x02 /* PS related settings */ +#define GP2AP020A00F_LED_REG 0x03 /* LED reg */ +#define GP2AP020A00F_TL_L_REG 0x04 /* ALS: Threshold low LSB */ +#define GP2AP020A00F_TL_H_REG 0x05 /* ALS: Threshold low MSB */ +#define GP2AP020A00F_TH_L_REG 0x06 /* ALS: Threshold high LSB */ +#define GP2AP020A00F_TH_H_REG 0x07 /* ALS: Threshold high MSB */ +#define GP2AP020A00F_PL_L_REG 0x08 /* PS: Threshold low LSB */ +#define GP2AP020A00F_PL_H_REG 0x09 /* PS: Threshold low MSB */ +#define GP2AP020A00F_PH_L_REG 0x0a /* PS: Threshold high LSB */ +#define GP2AP020A00F_PH_H_REG 0x0b /* PS: Threshold high MSB */ +#define GP2AP020A00F_D0_L_REG 0x0c /* ALS result: Clear/Illuminance LSB */ +#define GP2AP020A00F_D0_H_REG 0x0d /* ALS result: Clear/Illuminance MSB */ +#define GP2AP020A00F_D1_L_REG 0x0e /* ALS result: IR LSB */ +#define GP2AP020A00F_D1_H_REG 0x0f /* ALS result: IR LSB */ +#define GP2AP020A00F_D2_L_REG 0x10 /* PS result LSB */ +#define GP2AP020A00F_D2_H_REG 0x11 /* PS result MSB */ +#define GP2AP020A00F_NUM_REGS 0x12 /* Number of registers */ + +/* OP_REG bits */ +#define GP2AP020A00F_OP3_MASK 0x80 /* Software shutdown */ +#define GP2AP020A00F_OP3_SHUTDOWN 0x00 +#define GP2AP020A00F_OP3_OPERATION 0x80 +#define GP2AP020A00F_OP2_MASK 0x40 /* Auto shutdown/Continuous mode */ +#define GP2AP020A00F_OP2_AUTO_SHUTDOWN 0x00 +#define GP2AP020A00F_OP2_CONT_OPERATION 0x40 +#define GP2AP020A00F_OP_MASK 0x30 /* Operating mode selection */ +#define GP2AP020A00F_OP_ALS_AND_PS 0x00 +#define GP2AP020A00F_OP_ALS 0x10 +#define GP2AP020A00F_OP_PS 0x20 +#define GP2AP020A00F_OP_DEBUG 0x30 +#define GP2AP020A00F_PROX_MASK 0x08 /* PS: detection/non-detection */ +#define GP2AP020A00F_PROX_NON_DETECT 0x00 +#define GP2AP020A00F_PROX_DETECT 0x08 +#define GP2AP020A00F_FLAG_P 0x04 /* PS: interrupt result */ +#define GP2AP020A00F_FLAG_A 0x02 /* ALS: interrupt result */ +#define GP2AP020A00F_TYPE_MASK 0x01 /* Output data type selection */ +#define GP2AP020A00F_TYPE_MANUAL_CALC 0x00 +#define GP2AP020A00F_TYPE_AUTO_CALC 0x01 + +/* ALS_REG bits */ +#define GP2AP020A00F_PRST_MASK 0xc0 /* Number of measurement cycles */ +#define GP2AP020A00F_PRST_ONCE 0x00 +#define GP2AP020A00F_PRST_4_CYCLES 0x40 +#define GP2AP020A00F_PRST_8_CYCLES 0x80 +#define GP2AP020A00F_PRST_16_CYCLES 0xc0 +#define GP2AP020A00F_RES_A_MASK 0x38 /* ALS: Resolution */ +#define GP2AP020A00F_RES_A_800ms 0x00 +#define GP2AP020A00F_RES_A_400ms 0x08 +#define GP2AP020A00F_RES_A_200ms 0x10 +#define GP2AP020A00F_RES_A_100ms 0x18 +#define GP2AP020A00F_RES_A_25ms 0x20 +#define GP2AP020A00F_RES_A_6_25ms 0x28 +#define GP2AP020A00F_RES_A_1_56ms 0x30 +#define GP2AP020A00F_RES_A_0_39ms 0x38 +#define GP2AP020A00F_RANGE_A_MASK 0x07 /* ALS: Max measurable range */ +#define GP2AP020A00F_RANGE_A_x1 0x00 +#define GP2AP020A00F_RANGE_A_x2 0x01 +#define GP2AP020A00F_RANGE_A_x4 0x02 +#define GP2AP020A00F_RANGE_A_x8 0x03 +#define GP2AP020A00F_RANGE_A_x16 0x04 +#define GP2AP020A00F_RANGE_A_x32 0x05 +#define GP2AP020A00F_RANGE_A_x64 0x06 +#define GP2AP020A00F_RANGE_A_x128 0x07 + +/* PS_REG bits */ +#define GP2AP020A00F_ALC_MASK 0x80 /* Auto light cancel */ +#define GP2AP020A00F_ALC_ON 0x80 +#define GP2AP020A00F_ALC_OFF 0x00 +#define GP2AP020A00F_INTTYPE_MASK 0x40 /* Interrupt type setting */ +#define GP2AP020A00F_INTTYPE_LEVEL 0x00 +#define GP2AP020A00F_INTTYPE_PULSE 0x40 +#define GP2AP020A00F_RES_P_MASK 0x38 /* PS: Resolution */ +#define GP2AP020A00F_RES_P_800ms_x2 0x00 +#define GP2AP020A00F_RES_P_400ms_x2 0x08 +#define GP2AP020A00F_RES_P_200ms_x2 0x10 +#define GP2AP020A00F_RES_P_100ms_x2 0x18 +#define GP2AP020A00F_RES_P_25ms_x2 0x20 +#define GP2AP020A00F_RES_P_6_25ms_x2 0x28 +#define GP2AP020A00F_RES_P_1_56ms_x2 0x30 +#define GP2AP020A00F_RES_P_0_39ms_x2 0x38 +#define GP2AP020A00F_RANGE_P_MASK 0x07 /* PS: Max measurable range */ +#define GP2AP020A00F_RANGE_P_x1 0x00 +#define GP2AP020A00F_RANGE_P_x2 0x01 +#define GP2AP020A00F_RANGE_P_x4 0x02 +#define GP2AP020A00F_RANGE_P_x8 0x03 +#define GP2AP020A00F_RANGE_P_x16 0x04 +#define GP2AP020A00F_RANGE_P_x32 0x05 +#define GP2AP020A00F_RANGE_P_x64 0x06 +#define GP2AP020A00F_RANGE_P_x128 0x07 + +/* LED reg bits */ +#define GP2AP020A00F_INTVAL_MASK 0xc0 /* Intermittent operating */ +#define GP2AP020A00F_INTVAL_0 0x00 +#define GP2AP020A00F_INTVAL_4 0x40 +#define GP2AP020A00F_INTVAL_8 0x80 +#define GP2AP020A00F_INTVAL_16 0xc0 +#define GP2AP020A00F_IS_MASK 0x30 /* ILED drive peak current */ +#define GP2AP020A00F_IS_13_8mA 0x00 +#define GP2AP020A00F_IS_27_5mA 0x10 +#define GP2AP020A00F_IS_55mA 0x20 +#define GP2AP020A00F_IS_110mA 0x30 +#define GP2AP020A00F_PIN_MASK 0x0c /* INT terminal setting */ +#define GP2AP020A00F_PIN_ALS_OR_PS 0x00 +#define GP2AP020A00F_PIN_ALS 0x04 +#define GP2AP020A00F_PIN_PS 0x08 +#define GP2AP020A00F_PIN_PS_DETECT 0x0c +#define GP2AP020A00F_FREQ_MASK 0x02 /* LED modulation frequency */ +#define GP2AP020A00F_FREQ_327_5kHz 0x00 +#define GP2AP020A00F_FREQ_81_8kHz 0x02 +#define GP2AP020A00F_RST 0x01 /* Software reset */ + +#define GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR 0 +#define GP2AP020A00F_SCAN_MODE_LIGHT_IR 1 +#define GP2AP020A00F_SCAN_MODE_PROXIMITY 2 +#define GP2AP020A00F_CHAN_TIMESTAMP 3 + +#define GP2AP020A00F_DATA_READY_TIMEOUT msecs_to_jiffies(1000) +#define GP2AP020A00F_DATA_REG(chan) (GP2AP020A00F_D0_L_REG + \ + (chan) * 2) +#define GP2AP020A00F_THRESH_REG(th_val_id) (GP2AP020A00F_TL_L_REG + \ + (th_val_id) * 2) +#define GP2AP020A00F_THRESH_VAL_ID(reg_addr) ((reg_addr - 4) / 2) + +#define GP2AP020A00F_SUBTRACT_MODE 0 +#define GP2AP020A00F_ADD_MODE 1 + +#define GP2AP020A00F_MAX_CHANNELS 3 + +enum gp2ap020a00f_opmode { + GP2AP020A00F_OPMODE_READ_RAW_CLEAR, + GP2AP020A00F_OPMODE_READ_RAW_IR, + GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_OPMODE_PS, + GP2AP020A00F_OPMODE_ALS_AND_PS, + GP2AP020A00F_OPMODE_PROX_DETECT, + GP2AP020A00F_OPMODE_SHUTDOWN, + GP2AP020A00F_NUM_OPMODES, +}; + +enum gp2ap020a00f_cmd { + GP2AP020A00F_CMD_READ_RAW_CLEAR, + GP2AP020A00F_CMD_READ_RAW_IR, + GP2AP020A00F_CMD_READ_RAW_PROXIMITY, + GP2AP020A00F_CMD_TRIGGER_CLEAR_EN, + GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS, + GP2AP020A00F_CMD_TRIGGER_IR_EN, + GP2AP020A00F_CMD_TRIGGER_IR_DIS, + GP2AP020A00F_CMD_TRIGGER_PROX_EN, + GP2AP020A00F_CMD_TRIGGER_PROX_DIS, + GP2AP020A00F_CMD_ALS_HIGH_EV_EN, + GP2AP020A00F_CMD_ALS_HIGH_EV_DIS, + GP2AP020A00F_CMD_ALS_LOW_EV_EN, + GP2AP020A00F_CMD_ALS_LOW_EV_DIS, + GP2AP020A00F_CMD_PROX_HIGH_EV_EN, + GP2AP020A00F_CMD_PROX_HIGH_EV_DIS, + GP2AP020A00F_CMD_PROX_LOW_EV_EN, + GP2AP020A00F_CMD_PROX_LOW_EV_DIS, +}; + +enum gp2ap020a00f_flags { + GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, + GP2AP020A00F_FLAG_ALS_IR_TRIGGER, + GP2AP020A00F_FLAG_PROX_TRIGGER, + GP2AP020A00F_FLAG_PROX_RISING_EV, + GP2AP020A00F_FLAG_PROX_FALLING_EV, + GP2AP020A00F_FLAG_ALS_RISING_EV, + GP2AP020A00F_FLAG_ALS_FALLING_EV, + GP2AP020A00F_FLAG_LUX_MODE_HI, + GP2AP020A00F_FLAG_DATA_READY, +}; + +enum gp2ap020a00f_thresh_val_id { + GP2AP020A00F_THRESH_TL, + GP2AP020A00F_THRESH_TH, + GP2AP020A00F_THRESH_PL, + GP2AP020A00F_THRESH_PH, +}; + +struct gp2ap020a00f_data { + const struct gp2ap020a00f_platform_data *pdata; + struct i2c_client *client; + struct mutex lock; + char *buffer; + struct regulator *vled_reg; + unsigned long flags; + enum gp2ap020a00f_opmode cur_opmode; + struct iio_trigger *trig; + struct regmap *regmap; + unsigned int thresh_val[4]; + u8 debug_reg_addr; + struct irq_work work; + wait_queue_head_t data_ready_queue; +}; + +static const u8 gp2ap020a00f_reg_init_tab[] = { + [GP2AP020A00F_OP_REG] = GP2AP020A00F_OP3_SHUTDOWN, + [GP2AP020A00F_ALS_REG] = GP2AP020A00F_RES_A_25ms | + GP2AP020A00F_RANGE_A_x8, + [GP2AP020A00F_PS_REG] = GP2AP020A00F_ALC_ON | + GP2AP020A00F_RES_P_1_56ms_x2 | + GP2AP020A00F_RANGE_P_x4, + [GP2AP020A00F_LED_REG] = GP2AP020A00F_INTVAL_0 | + GP2AP020A00F_IS_110mA | + GP2AP020A00F_FREQ_327_5kHz, + [GP2AP020A00F_TL_L_REG] = 0, + [GP2AP020A00F_TL_H_REG] = 0, + [GP2AP020A00F_TH_L_REG] = 0, + [GP2AP020A00F_TH_H_REG] = 0, + [GP2AP020A00F_PL_L_REG] = 0, + [GP2AP020A00F_PL_H_REG] = 0, + [GP2AP020A00F_PH_L_REG] = 0, + [GP2AP020A00F_PH_H_REG] = 0, +}; + +static bool gp2ap020a00f_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case GP2AP020A00F_OP_REG: + case GP2AP020A00F_D0_L_REG: + case GP2AP020A00F_D0_H_REG: + case GP2AP020A00F_D1_L_REG: + case GP2AP020A00F_D1_H_REG: + case GP2AP020A00F_D2_L_REG: + case GP2AP020A00F_D2_H_REG: + return true; + default: + return false; + } +} + +static const struct regmap_config gp2ap020a00f_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = GP2AP020A00F_D2_H_REG, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = gp2ap020a00f_is_volatile_reg, +}; + +static const struct gp2ap020a00f_mutable_config_regs { + u8 op_reg; + u8 als_reg; + u8 ps_reg; + u8 led_reg; +} opmode_regs_settings[GP2AP020A00F_NUM_OPMODES] = { + [GP2AP020A00F_OPMODE_READ_RAW_CLEAR] = { + GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_AUTO_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS + }, + [GP2AP020A00F_OPMODE_READ_RAW_IR] = { + GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS + }, + [GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY] = { + GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_PS + }, + [GP2AP020A00F_OPMODE_PROX_DETECT] = { + GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_4_CYCLES, + GP2AP020A00F_INTTYPE_PULSE, + GP2AP020A00F_PIN_PS_DETECT + }, + [GP2AP020A00F_OPMODE_ALS] = { + GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_AUTO_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS + }, + [GP2AP020A00F_OPMODE_PS] = { + GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_4_CYCLES, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_PS + }, + [GP2AP020A00F_OPMODE_ALS_AND_PS] = { + GP2AP020A00F_OP_ALS_AND_PS + | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_AUTO_CALC, + GP2AP020A00F_PRST_4_CYCLES, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS_OR_PS + }, + [GP2AP020A00F_OPMODE_SHUTDOWN] = { GP2AP020A00F_OP3_SHUTDOWN, }, +}; + +static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_opmode op) +{ + unsigned int op_reg_val; + int err; + + if (op != GP2AP020A00F_OPMODE_SHUTDOWN) { + err = regmap_read(data->regmap, GP2AP020A00F_OP_REG, + &op_reg_val); + if (err < 0) + return err; + /* + * Shutdown the device if the operation being executed entails + * mode transition. + */ + if ((opmode_regs_settings[op].op_reg & GP2AP020A00F_OP_MASK) != + (op_reg_val & GP2AP020A00F_OP_MASK)) { + /* set shutdown mode */ + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, GP2AP020A00F_OP3_MASK, + GP2AP020A00F_OP3_SHUTDOWN); + if (err < 0) + return err; + } + + err = regmap_update_bits(data->regmap, GP2AP020A00F_ALS_REG, + GP2AP020A00F_PRST_MASK, opmode_regs_settings[op] + .als_reg); + if (err < 0) + return err; + + err = regmap_update_bits(data->regmap, GP2AP020A00F_PS_REG, + GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op] + .ps_reg); + if (err < 0) + return err; + + err = regmap_update_bits(data->regmap, GP2AP020A00F_LED_REG, + GP2AP020A00F_PIN_MASK, opmode_regs_settings[op] + .led_reg); + if (err < 0) + return err; + } + + /* Set OP_REG and apply operation mode (power on / off) */ + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, + GP2AP020A00F_OP_MASK | GP2AP020A00F_OP2_MASK | + GP2AP020A00F_OP3_MASK | GP2AP020A00F_TYPE_MASK, + opmode_regs_settings[op].op_reg); + if (err < 0) + return err; + + data->cur_opmode = op; + + return 0; +} + +static bool gp2ap020a00f_als_enabled(struct gp2ap020a00f_data *data) +{ + return test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); +} + +static bool gp2ap020a00f_prox_detect_enabled(struct gp2ap020a00f_data *data) +{ + return test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags) || + test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); +} + +static int gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_thresh_val_id th_val_id, + bool enable) +{ + __le16 thresh_buf = 0; + unsigned int thresh_reg_val; + + if (!enable) + thresh_reg_val = 0; + else if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags) && + th_val_id != GP2AP020A00F_THRESH_PL && + th_val_id != GP2AP020A00F_THRESH_PH) + /* + * For the high lux mode ALS threshold has to be scaled down + * to allow for proper comparison with the output value. + */ + thresh_reg_val = data->thresh_val[th_val_id] / 16; + else + thresh_reg_val = data->thresh_val[th_val_id] > 16000 ? + 16000 : + data->thresh_val[th_val_id]; + + thresh_buf = cpu_to_le16(thresh_reg_val); + + return regmap_bulk_write(data->regmap, + GP2AP020A00F_THRESH_REG(th_val_id), + (u8 *)&thresh_buf, 2); +} + +static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_opmode diff_mode, int add_sub) +{ + enum gp2ap020a00f_opmode new_mode; + + if (diff_mode != GP2AP020A00F_OPMODE_ALS && + diff_mode != GP2AP020A00F_OPMODE_PS) + return -EINVAL; + + if (add_sub == GP2AP020A00F_ADD_MODE) { + if (data->cur_opmode == GP2AP020A00F_OPMODE_SHUTDOWN) + new_mode = diff_mode; + else + new_mode = GP2AP020A00F_OPMODE_ALS_AND_PS; + } else { + if (data->cur_opmode == GP2AP020A00F_OPMODE_ALS_AND_PS) + new_mode = (diff_mode == GP2AP020A00F_OPMODE_ALS) ? + GP2AP020A00F_OPMODE_PS : + GP2AP020A00F_OPMODE_ALS; + else + new_mode = GP2AP020A00F_OPMODE_SHUTDOWN; + } + + return gp2ap020a00f_set_operation_mode(data, new_mode); +} + +static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_cmd cmd) +{ + int err = 0; + + switch (cmd) { + case GP2AP020A00F_CMD_READ_RAW_CLEAR: + if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) + return -EBUSY; + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_READ_RAW_CLEAR); + break; + case GP2AP020A00F_CMD_READ_RAW_IR: + if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) + return -EBUSY; + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_READ_RAW_IR); + break; + case GP2AP020A00F_CMD_READ_RAW_PROXIMITY: + if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) + return -EBUSY; + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY); + break; + case GP2AP020A00F_CMD_TRIGGER_CLEAR_EN: + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + set_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags); + break; + case GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS: + clear_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags); + if (gp2ap020a00f_als_enabled(data)) + break; + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + break; + case GP2AP020A00F_CMD_TRIGGER_IR_EN: + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + set_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags); + break; + case GP2AP020A00F_CMD_TRIGGER_IR_DIS: + clear_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags); + if (gp2ap020a00f_als_enabled(data)) + break; + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + break; + case GP2AP020A00F_CMD_TRIGGER_PROX_EN: + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_PS, + GP2AP020A00F_ADD_MODE); + set_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags); + break; + case GP2AP020A00F_CMD_TRIGGER_PROX_DIS: + clear_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags); + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_PS, + GP2AP020A00F_SUBTRACT_MODE); + break; + case GP2AP020A00F_CMD_ALS_HIGH_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) + return 0; + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, true); + break; + case GP2AP020A00F_CMD_ALS_HIGH_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags); + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + if (err < 0) + return err; + } + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, false); + break; + case GP2AP020A00F_CMD_ALS_LOW_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) + return 0; + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, true); + break; + case GP2AP020A00F_CMD_ALS_LOW_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + if (err < 0) + return err; + } + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, false); + break; + case GP2AP020A00F_CMD_PROX_HIGH_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags)) + return 0; + if (gp2ap020a00f_als_enabled(data) || + data->cur_opmode == GP2AP020A00F_OPMODE_PS) + return -EBUSY; + if (!gp2ap020a00f_prox_detect_enabled(data)) { + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_PROX_DETECT); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PH, true); + break; + case GP2AP020A00F_CMD_PROX_HIGH_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags); + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + return err; + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PH, false); + break; + case GP2AP020A00F_CMD_PROX_LOW_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags)) + return 0; + if (gp2ap020a00f_als_enabled(data) || + data->cur_opmode == GP2AP020A00F_OPMODE_PS) + return -EBUSY; + if (!gp2ap020a00f_prox_detect_enabled(data)) { + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_PROX_DETECT); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PL, true); + break; + case GP2AP020A00F_CMD_PROX_LOW_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + return err; + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PL, false); + break; + } + + return err; +} + +static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data) +{ + int ret; + + ret = wait_event_timeout(data->data_ready_queue, + test_bit(GP2AP020A00F_FLAG_DATA_READY, + &data->flags), + GP2AP020A00F_DATA_READY_TIMEOUT); + clear_bit(GP2AP020A00F_FLAG_DATA_READY, &data->flags); + + return ret > 0 ? 0 : -ETIME; +} + +static int gp2ap020a00f_read_output(struct gp2ap020a00f_data *data, + unsigned int output_reg, int *val) +{ + u8 reg_buf[2]; + int err; + + err = wait_conversion_complete_irq(data); + if (err < 0) + dev_dbg(&data->client->dev, "data ready timeout\n"); + + err = regmap_bulk_read(data->regmap, output_reg, reg_buf, 2); + if (err < 0) + return err; + + *val = le16_to_cpup((__le16 *)reg_buf); + + return err; +} + +static bool gp2ap020a00f_adjust_lux_mode(struct gp2ap020a00f_data *data, + int output_val) +{ + u8 new_range = 0xff; + int err; + + if (!test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags)) { + if (output_val > 16000) { + set_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags); + new_range = GP2AP020A00F_RANGE_A_x128; + } + } else { + if (output_val < 1000) { + clear_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags); + new_range = GP2AP020A00F_RANGE_A_x8; + } + } + + if (new_range != 0xff) { + /* Clear als threshold registers to avoid spurious + * events caused by lux mode transition. + */ + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, false); + if (err < 0) { + dev_err(&data->client->dev, + "Clearing als threshold register failed.\n"); + return false; + } + + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, false); + if (err < 0) { + dev_err(&data->client->dev, + "Clearing als threshold register failed.\n"); + return false; + } + + /* Change lux mode */ + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, + GP2AP020A00F_OP3_MASK, + GP2AP020A00F_OP3_SHUTDOWN); + + if (err < 0) { + dev_err(&data->client->dev, + "Shutting down the device failed.\n"); + return false; + } + + err = regmap_update_bits(data->regmap, + GP2AP020A00F_ALS_REG, + GP2AP020A00F_RANGE_A_MASK, + new_range); + + if (err < 0) { + dev_err(&data->client->dev, + "Adjusting device lux mode failed.\n"); + return false; + } + + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, + GP2AP020A00F_OP3_MASK, + GP2AP020A00F_OP3_OPERATION); + + if (err < 0) { + dev_err(&data->client->dev, + "Powering up the device failed.\n"); + return false; + } + + /* Adjust als threshold register values to the new lux mode */ + if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) { + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, true); + if (err < 0) { + dev_err(&data->client->dev, + "Adjusting als threshold value failed.\n"); + return false; + } + } + + if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) { + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, true); + if (err < 0) { + dev_err(&data->client->dev, + "Adjusting als threshold value failed.\n"); + return false; + } + } + + return true; + } + + return false; +} + +static void gp2ap020a00f_output_to_lux(struct gp2ap020a00f_data *data, + int *output_val) +{ + if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags)) + *output_val *= 16; +} + +static void gp2ap020a00f_iio_trigger_work(struct irq_work *work) +{ + struct gp2ap020a00f_data *data = + container_of(work, struct gp2ap020a00f_data, work); + + iio_trigger_poll(data->trig, 0); +} + +static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct gp2ap020a00f_data *priv = iio_priv(indio_dev); + unsigned int op_reg_val; + int ret; + + /* Read interrupt flags */ + ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, &op_reg_val); + if (ret < 0) + return IRQ_HANDLED; + + if (gp2ap020a00f_prox_detect_enabled(priv)) { + if (op_reg_val & GP2AP020A00F_PROX_DETECT) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE( + IIO_PROXIMITY, + GP2AP020A00F_SCAN_MODE_PROXIMITY, + IIO_EV_TYPE_ROC, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } else { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE( + IIO_PROXIMITY, + GP2AP020A00F_SCAN_MODE_PROXIMITY, + IIO_EV_TYPE_ROC, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct gp2ap020a00f_data *priv = iio_priv(indio_dev); + u8 op_reg_flags, d0_reg_buf[2]; + unsigned int output_val, op_reg_val; + int thresh_val_id, ret; + + /* Read interrupt flags */ + ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, + &op_reg_val); + if (ret < 0) + goto done; + + op_reg_flags = op_reg_val & (GP2AP020A00F_FLAG_A | GP2AP020A00F_FLAG_P + | GP2AP020A00F_PROX_DETECT); + + op_reg_val &= (~GP2AP020A00F_FLAG_A & ~GP2AP020A00F_FLAG_P + & ~GP2AP020A00F_PROX_DETECT); + + /* Clear interrupt flags (if not in INTTYPE_PULSE mode) */ + if (priv->cur_opmode != GP2AP020A00F_OPMODE_PROX_DETECT) { + ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG, + op_reg_val); + if (ret < 0) + goto done; + } + + if (op_reg_flags & GP2AP020A00F_FLAG_A) { + /* Check D0 register to assess if the lux mode + * transition is required. + */ + ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_D0_L_REG, + d0_reg_buf, 2); + if (ret < 0) + goto done; + + output_val = le16_to_cpup((__le16 *)d0_reg_buf); + + if (gp2ap020a00f_adjust_lux_mode(priv, output_val)) + goto done; + + gp2ap020a00f_output_to_lux(priv, &output_val); + + /* + * We need to check output value to distinguish + * between high and low ambient light threshold event. + */ + if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &priv->flags)) { + thresh_val_id = + GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TH_L_REG); + if (output_val > priv->thresh_val[thresh_val_id]) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE( + IIO_LIGHT, + GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR, + IIO_MOD_LIGHT_CLEAR, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } + + if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) { + thresh_val_id = + GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TL_L_REG); + if (output_val < priv->thresh_val[thresh_val_id]) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE( + IIO_LIGHT, + GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR, + IIO_MOD_LIGHT_CLEAR, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } + } + + if (priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_CLEAR || + priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_IR || + priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY) { + set_bit(GP2AP020A00F_FLAG_DATA_READY, &priv->flags); + wake_up(&priv->data_ready_queue); + goto done; + } + + if (test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &priv->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &priv->flags) || + test_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &priv->flags)) + /* This fires off the trigger. */ + irq_work_queue(&priv->work); + +done: + return IRQ_HANDLED; +} + +static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data) +{ + struct iio_poll_func *pf = data; + struct iio_dev *indio_dev = pf->indio_dev; + struct gp2ap020a00f_data *priv = iio_priv(indio_dev); + size_t d_size = 0; + __le32 light_lux; + int i, out_val, ret; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = regmap_bulk_read(priv->regmap, + GP2AP020A00F_DATA_REG(i), + &priv->buffer[d_size], 2); + if (ret < 0) + goto done; + + if (i == GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR || + i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) { + out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]); + gp2ap020a00f_output_to_lux(priv, &out_val); + light_lux = cpu_to_le32(out_val); + memcpy(&priv->buffer[d_size], (u8 *)&light_lux, 4); + d_size += 4; + } else { + d_size += 2; + } + } + + iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer, + pf->timestamp); +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static u8 gp2ap020a00f_get_reg_by_event_code(u64 event_code) +{ + int event_dir = IIO_EVENT_CODE_EXTRACT_DIR(event_code); + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_PROXIMITY: + if (event_dir == IIO_EV_DIR_RISING) + return GP2AP020A00F_PH_L_REG; + else + return GP2AP020A00F_PL_L_REG; + case IIO_LIGHT: + if (event_dir == IIO_EV_DIR_RISING) + return GP2AP020A00F_TH_L_REG; + else + return GP2AP020A00F_TL_L_REG; + } + + return -EINVAL; +} + +static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev, + u64 event_code, int val) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + bool event_en = false; + u8 thresh_val_id; + u8 thresh_reg_l; + int err = 0; + + mutex_lock(&data->lock); + + thresh_reg_l = gp2ap020a00f_get_reg_by_event_code(event_code); + thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l); + + if (thresh_val_id > GP2AP020A00F_THRESH_PH) { + err = -EINVAL; + goto error_unlock; + } + + switch (thresh_reg_l) { + case GP2AP020A00F_TH_L_REG: + event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, + &data->flags); + break; + case GP2AP020A00F_TL_L_REG: + event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, + &data->flags); + break; + case GP2AP020A00F_PH_L_REG: + if (val == 0) { + err = -EINVAL; + goto error_unlock; + } + event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, + &data->flags); + break; + case GP2AP020A00F_PL_L_REG: + if (val == 0) { + err = -EINVAL; + goto error_unlock; + } + event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, + &data->flags); + break; + } + + data->thresh_val[thresh_val_id] = val; + err = gp2ap020a00f_write_event_threshold(data, thresh_val_id, + event_en); +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev, + u64 event_code, int *val) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + u8 thresh_reg_l; + int err = 0; + + mutex_lock(&data->lock); + + thresh_reg_l = gp2ap020a00f_get_reg_by_event_code(event_code); + + if (thresh_reg_l > GP2AP020A00F_PH_L_REG) { + err = -EINVAL; + goto error_unlock; + } + + *val = data->thresh_val[GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l)]; + +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev, + u64 event_code, int state) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + enum gp2ap020a00f_cmd cmd_high_ev, cmd_low_ev; + int err; + + cmd_high_ev = state ? GP2AP020A00F_CMD_PROX_HIGH_EV_EN : + GP2AP020A00F_CMD_PROX_HIGH_EV_DIS; + cmd_low_ev = state ? GP2AP020A00F_CMD_PROX_LOW_EV_EN : + GP2AP020A00F_CMD_PROX_LOW_EV_DIS; + + /* + * In order to enable proximity detection feature in the device + * both high and low threshold registers have to be written + * with different values, greater than zero. + */ + if (state) { + if (data->thresh_val[GP2AP020A00F_THRESH_PL] == 0) + return -EINVAL; + + if (data->thresh_val[GP2AP020A00F_THRESH_PH] == 0) + return -EINVAL; + } + + err = gp2ap020a00f_exec_cmd(data, cmd_high_ev); + if (err < 0) + return err; + + err = gp2ap020a00f_exec_cmd(data, cmd_low_ev); + if (err < 0) + return err; + + free_irq(data->client->irq, indio_dev); + + if (state) + err = request_threaded_irq(data->client->irq, NULL, + &gp2ap020a00f_prox_sensing_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "gp2ap020a00f_prox_sensing", + indio_dev); + else { + err = request_threaded_irq(data->client->irq, NULL, + &gp2ap020a00f_thresh_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "gp2ap020a00f_thresh_event", + indio_dev); + } + + return err; +} + +static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev, + u64 event_code, int state) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + enum gp2ap020a00f_cmd cmd; + int err; + + mutex_lock(&data->lock); + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_PROXIMITY: + err = gp2ap020a00f_write_prox_event_config(indio_dev, + event_code, state); + break; + case IIO_LIGHT: + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) + == IIO_EV_DIR_RISING) { + cmd = state ? GP2AP020A00F_CMD_ALS_HIGH_EV_EN : + GP2AP020A00F_CMD_ALS_HIGH_EV_DIS; + err = gp2ap020a00f_exec_cmd(data, cmd); + } else { + cmd = state ? GP2AP020A00F_CMD_ALS_LOW_EV_EN : + GP2AP020A00F_CMD_ALS_LOW_EV_DIS; + err = gp2ap020a00f_exec_cmd(data, cmd); + } + break; + default: + err = -EINVAL; + } + + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev, + u64 event_code) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int event_en = 0; + + mutex_lock(&data->lock); + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_PROXIMITY: + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) + == IIO_EV_DIR_RISING) + event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, + &data->flags); + else + event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, + &data->flags); + break; + case IIO_LIGHT: + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) + == IIO_EV_DIR_RISING) + event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, + &data->flags); + else + event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, + &data->flags); + break; + } + + mutex_unlock(&data->lock); + + return event_en; +} + +static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data, + struct iio_chan_spec const *chan, int *val) +{ + enum gp2ap020a00f_cmd cmd; + int err; + + switch (chan->scan_index) { + case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR: + cmd = GP2AP020A00F_CMD_READ_RAW_CLEAR; + break; + case GP2AP020A00F_SCAN_MODE_LIGHT_IR: + cmd = GP2AP020A00F_CMD_READ_RAW_IR; + break; + case GP2AP020A00F_SCAN_MODE_PROXIMITY: + cmd = GP2AP020A00F_CMD_READ_RAW_PROXIMITY; + break; + default: + return -EINVAL; + } + + err = gp2ap020a00f_exec_cmd(data, cmd); + if (err < 0) { + dev_err(&data->client->dev, + "gp2ap020a00f_exec_cmd failed\n"); + goto error_ret; + } + + err = gp2ap020a00f_read_output(data, chan->address, val); + if (err < 0) + dev_err(&data->client->dev, + "gp2ap020a00f_read_output failed\n"); + + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + dev_err(&data->client->dev, + "Failed to shut down the device.\n"); + + if (cmd == GP2AP020A00F_CMD_READ_RAW_CLEAR || + cmd == GP2AP020A00F_CMD_READ_RAW_IR) + gp2ap020a00f_output_to_lux(data, val); + +error_ret: + return err; +} + +static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int err = -EINVAL; + + mutex_lock(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) { + err = -EBUSY; + goto error_unlock; + } + + err = gp2ap020a00f_read_channel(data, chan, val); + break; + } + +error_unlock: + mutex_unlock(&data->lock); + + return err < 0 ? err : IIO_VAL_INT; +} + +static const struct iio_chan_spec gp2ap020a00f_channels[] = { + { + .type = IIO_LIGHT, + .channel2 = IIO_MOD_LIGHT_CLEAR, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .scan_type = { + .sign = 'u', + .realbits = 24, + .shift = 0, + .storagebits = 32, + .endianness = IIO_LE, + }, + .scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR, + .address = GP2AP020A00F_D0_L_REG, + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING) | + IIO_EV_BIT(IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + }, + { + .type = IIO_LIGHT, + .channel2 = IIO_MOD_LIGHT_IR, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .scan_type = { + .sign = 'u', + .realbits = 24, + .shift = 0, + .storagebits = 32, + .endianness = IIO_LE, + }, + .scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_IR, + .address = GP2AP020A00F_D1_L_REG, + }, + { + .type = IIO_PROXIMITY, + .modified = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .scan_type = { + .sign = 'u', + .realbits = 16, + .shift = 0, + .storagebits = 16, + .endianness = IIO_LE, + }, + .scan_index = GP2AP020A00F_SCAN_MODE_PROXIMITY, + .address = GP2AP020A00F_D2_L_REG, + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_ROC, + IIO_EV_DIR_RISING) | + IIO_EV_BIT(IIO_EV_TYPE_ROC, + IIO_EV_DIR_FALLING), + }, + IIO_CHAN_SOFT_TIMESTAMP(GP2AP020A00F_CHAN_TIMESTAMP), +}; + +static const struct iio_info gp2ap020a00f_info = { + .read_raw = &gp2ap020a00f_read_raw, + .read_event_value = &gp2ap020a00f_read_event_val, + .read_event_config = &gp2ap020a00f_read_event_config, + .write_event_value = &gp2ap020a00f_write_event_val, + .write_event_config = &gp2ap020a00f_write_event_config, + .driver_module = THIS_MODULE, +}; + +static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int i, err = 0; + + mutex_lock(&data->lock); + + /* + * Enable triggers according to the scan_mask. Enabling either + * LIGHT_CLEAR or LIGHT_IR scan mode results in enabling ALS + * module in the device, which generates samples in both D0 (clear) + * and D1 (ir) registers. As the two registers are bound to the + * two separate IIO channels they are treated in the driver logic + * as if they were controlled independently. + */ + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + switch (i) { + case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_CLEAR_EN); + break; + case GP2AP020A00F_SCAN_MODE_LIGHT_IR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_IR_EN); + break; + case GP2AP020A00F_SCAN_MODE_PROXIMITY: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_PROX_EN); + break; + } + } + + if (err < 0) + goto error_unlock; + + data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); + if (!data->buffer) { + err = -ENOMEM; + goto error_unlock; + } + + err = iio_triggered_buffer_postenable(indio_dev); + +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int i, err; + + mutex_lock(&data->lock); + + err = iio_triggered_buffer_predisable(indio_dev); + if (err < 0) + goto error_unlock; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + switch (i) { + case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS); + break; + case GP2AP020A00F_SCAN_MODE_LIGHT_IR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_IR_DIS); + break; + case GP2AP020A00F_SCAN_MODE_PROXIMITY: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_PROX_DIS); + break; + } + } + + if (err == 0) + kfree(data->buffer); + +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = { + .preenable = &iio_sw_buffer_preenable, + .postenable = &gp2ap020a00f_buffer_postenable, + .predisable = &gp2ap020a00f_buffer_predisable, +}; + +static const struct iio_trigger_ops gp2ap020a00f_trigger_ops = { + .owner = THIS_MODULE, +}; + +static int gp2ap020a00f_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct gp2ap020a00f_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int err; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + + data->vled_reg = devm_regulator_get(&client->dev, "vled"); + if (IS_ERR(data->vled_reg)) + return PTR_ERR(data->vled_reg); + + err = regulator_enable(data->vled_reg); + if (err) + return err; + + regmap = devm_regmap_init_i2c(client, &gp2ap020a00f_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Regmap initialization failed.\n"); + err = PTR_ERR(regmap); + goto error_regulator_disable; + } + + /* Initialize device registers */ + err = regmap_bulk_write(regmap, GP2AP020A00F_OP_REG, + gp2ap020a00f_reg_init_tab, + ARRAY_SIZE(gp2ap020a00f_reg_init_tab)); + + if (err < 0) { + dev_err(&client->dev, "Device initialization failed.\n"); + goto error_regulator_disable; + } + + i2c_set_clientdata(client, indio_dev); + + data->client = client; + data->cur_opmode = GP2AP020A00F_OPMODE_SHUTDOWN; + data->regmap = regmap; + init_waitqueue_head(&data->data_ready_queue); + + mutex_init(&data->lock); + indio_dev->dev.parent = &client->dev; + indio_dev->channels = gp2ap020a00f_channels; + indio_dev->num_channels = ARRAY_SIZE(gp2ap020a00f_channels); + indio_dev->info = &gp2ap020a00f_info; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + /* Allocate buffer */ + err = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &gp2ap020a00f_trigger_handler, &gp2ap020a00f_buffer_setup_ops); + if (err < 0) + goto error_regulator_disable; + + /* Allocate trigger */ + data->trig = devm_iio_trigger_alloc(&client->dev, "%s-trigger", + indio_dev->name); + if (data->trig == NULL) { + err = -ENOMEM; + dev_err(&indio_dev->dev, "Failed to allocate iio trigger.\n"); + goto error_uninit_buffer; + } + + /* This needs to be requested here for read_raw calls to work. */ + err = request_threaded_irq(client->irq, NULL, + &gp2ap020a00f_thresh_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "gp2ap020a00f_als_event", + indio_dev); + if (err < 0) { + dev_err(&client->dev, "Irq request failed.\n"); + goto error_uninit_buffer; + } + + data->trig->ops = &gp2ap020a00f_trigger_ops; + data->trig->dev.parent = &data->client->dev; + + init_irq_work(&data->work, gp2ap020a00f_iio_trigger_work); + + err = iio_trigger_register(data->trig); + if (err < 0) { + dev_err(&client->dev, "Failed to register iio trigger.\n"); + goto error_free_irq; + } + + err = iio_device_register(indio_dev); + if (err < 0) + goto error_trigger_unregister; + + return 0; + +error_trigger_unregister: + iio_trigger_unregister(data->trig); +error_free_irq: + free_irq(client->irq, indio_dev); +error_uninit_buffer: + iio_triggered_buffer_cleanup(indio_dev); +error_regulator_disable: + regulator_disable(data->vled_reg); + + return err; +} + +static int gp2ap020a00f_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int err; + + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + dev_err(&indio_dev->dev, "Failed to power off the device.\n"); + + iio_device_unregister(indio_dev); + iio_trigger_unregister(data->trig); + free_irq(client->irq, indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(data->vled_reg); + + return 0; +} + +static const struct i2c_device_id gp2ap020a00f_id[] = { + { GP2A_I2C_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id); + +#ifdef CONFIG_OF +static const struct of_device_id gp2ap020a00f_of_match[] = { + { .compatible = "sharp,gp2ap020a00f" }, + { } +}; +#endif + +static struct i2c_driver gp2ap020a00f_driver = { + .driver = { + .name = GP2A_I2C_NAME, + .of_match_table = of_match_ptr(gp2ap020a00f_of_match), + .owner = THIS_MODULE, + }, + .probe = gp2ap020a00f_probe, + .remove = gp2ap020a00f_remove, + .id_table = gp2ap020a00f_id, +}; + +module_i2c_driver(gp2ap020a00f_driver); + +MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); +MODULE_DESCRIPTION("Sharp GP2AP020A00F Proximity/ALS sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index e59d00c3139c..fa6ae8cf89ea 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -161,10 +161,11 @@ static const struct iio_info als_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -179,7 +180,7 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev, als_state->common_attributes.data_ready); if (als_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)&als_state->illum, + &als_state->illum, sizeof(als_state->illum)); return 0; diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c new file mode 100644 index 000000000000..45df2204614a --- /dev/null +++ b/drivers/iio/light/tcs3472.c @@ -0,0 +1,367 @@ +/* + * tcs3472.c - Support for TAOS TCS3472 color light-to-digital converter + * + * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net> + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * Color light sensor with 16-bit channels for red, green, blue, clear); + * 7-bit I2C slave address 0x39 (TCS34721, TCS34723) or 0x29 (TCS34725, + * TCS34727) + * + * TODO: interrupt support, thresholds, wait time + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/pm.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/triggered_buffer.h> + +#define TCS3472_DRV_NAME "tcs3472" + +#define TCS3472_COMMAND BIT(7) +#define TCS3472_AUTO_INCR BIT(5) + +#define TCS3472_ENABLE (TCS3472_COMMAND | 0x00) +#define TCS3472_ATIME (TCS3472_COMMAND | 0x01) +#define TCS3472_WTIME (TCS3472_COMMAND | 0x03) +#define TCS3472_AILT (TCS3472_COMMAND | 0x04) +#define TCS3472_AIHT (TCS3472_COMMAND | 0x06) +#define TCS3472_PERS (TCS3472_COMMAND | 0x0c) +#define TCS3472_CONFIG (TCS3472_COMMAND | 0x0d) +#define TCS3472_CONTROL (TCS3472_COMMAND | 0x0f) +#define TCS3472_ID (TCS3472_COMMAND | 0x12) +#define TCS3472_STATUS (TCS3472_COMMAND | 0x13) +#define TCS3472_CDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x14) +#define TCS3472_RDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x16) +#define TCS3472_GDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x18) +#define TCS3472_BDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x1a) + +#define TCS3472_STATUS_AVALID BIT(0) +#define TCS3472_ENABLE_AEN BIT(1) +#define TCS3472_ENABLE_PON BIT(0) +#define TCS3472_CONTROL_AGAIN_MASK (BIT(0) | BIT(1)) + +struct tcs3472_data { + struct i2c_client *client; + u8 enable; + u8 control; + u8 atime; + u16 buffer[8]; /* 4 16-bit channels + 64-bit timestamp */ +}; + +#define TCS3472_CHANNEL(_color, _si, _addr) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_INT_TIME), \ + .channel2 = IIO_MOD_LIGHT_##_color, \ + .address = _addr, \ + .scan_index = _si, \ + .scan_type = IIO_ST('u', 16, 16, 0), \ +} + +static const int tcs3472_agains[] = { 1, 4, 16, 60 }; + +static const struct iio_chan_spec tcs3472_channels[] = { + TCS3472_CHANNEL(CLEAR, 0, TCS3472_CDATA), + TCS3472_CHANNEL(RED, 1, TCS3472_RDATA), + TCS3472_CHANNEL(GREEN, 2, TCS3472_GDATA), + TCS3472_CHANNEL(BLUE, 3, TCS3472_BDATA), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static int tcs3472_req_data(struct tcs3472_data *data) +{ + int tries = 50; + int ret; + + while (tries--) { + ret = i2c_smbus_read_byte_data(data->client, TCS3472_STATUS); + if (ret < 0) + return ret; + if (ret & TCS3472_STATUS_AVALID) + break; + msleep(20); + } + + if (tries < 0) { + dev_err(&data->client->dev, "data not ready\n"); + return -EIO; + } + + return 0; +} + +static int tcs3472_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tcs3472_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = tcs3472_req_data(data); + if (ret < 0) + return ret; + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + *val = tcs3472_agains[data->control & + TCS3472_CONTROL_AGAIN_MASK]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = (256 - data->atime) * 2400; + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; +} + +static int tcs3472_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct tcs3472_data *data = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + if (val2 != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(tcs3472_agains); i++) { + if (val == tcs3472_agains[i]) { + data->control &= ~TCS3472_CONTROL_AGAIN_MASK; + data->control |= i; + return i2c_smbus_write_byte_data( + data->client, TCS3472_CONTROL, + data->control); + } + } + return -EINVAL; + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + for (i = 0; i < 256; i++) { + if (val2 == (256 - i) * 2400) { + data->atime = i; + return i2c_smbus_write_word_data( + data->client, TCS3472_ATIME, + data->atime); + } + + } + return -EINVAL; + } + return -EINVAL; +} + +static irqreturn_t tcs3472_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct tcs3472_data *data = iio_priv(indio_dev); + int len = 0; + int i, j = 0; + + int ret = tcs3472_req_data(data); + if (ret < 0) + goto done; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = i2c_smbus_read_word_data(data->client, + TCS3472_CDATA + 2*i); + if (ret < 0) + goto done; + + data->buffer[j++] = ret; + len += 2; + } + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_get_time_ns()); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static ssize_t tcs3472_show_int_time_available(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + size_t len = 0; + int i; + + for (i = 1; i <= 256; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06d ", + 2400 * i); + + /* replace trailing space by newline */ + buf[len - 1] = '\n'; + + return len; +} + +static IIO_CONST_ATTR(calibscale_available, "1 4 16 60"); +static IIO_DEV_ATTR_INT_TIME_AVAIL(tcs3472_show_int_time_available); + +static struct attribute *tcs3472_attributes[] = { + &iio_const_attr_calibscale_available.dev_attr.attr, + &iio_dev_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group tcs3472_attribute_group = { + .attrs = tcs3472_attributes, +}; + +static const struct iio_info tcs3472_info = { + .read_raw = tcs3472_read_raw, + .write_raw = tcs3472_write_raw, + .attrs = &tcs3472_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int tcs3472_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tcs3472_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &tcs3472_info; + indio_dev->name = TCS3472_DRV_NAME; + indio_dev->channels = tcs3472_channels; + indio_dev->num_channels = ARRAY_SIZE(tcs3472_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_ID); + if (ret < 0) + return ret; + + if (ret == 0x44) + dev_info(&client->dev, "TCS34721/34725 found\n"); + else if (ret == 0x4d) + dev_info(&client->dev, "TCS34723/34727 found\n"); + else + return -ENODEV; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONTROL); + if (ret < 0) + return ret; + data->control = ret; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_ATIME); + if (ret < 0) + return ret; + data->atime = ret; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_ENABLE); + if (ret < 0) + return ret; + + /* enable device */ + data->enable = ret | TCS3472_ENABLE_PON | TCS3472_ENABLE_AEN; + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable); + if (ret < 0) + return ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + tcs3472_trigger_handler, NULL); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto buffer_cleanup; + + return 0; + +buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + return ret; +} + +static int tcs3472_powerdown(struct tcs3472_data *data) +{ + return i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable & ~(TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON)); +} + +static int tcs3472_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); + tcs3472_powerdown(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tcs3472_suspend(struct device *dev) +{ + struct tcs3472_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return tcs3472_powerdown(data); +} + +static int tcs3472_resume(struct device *dev) +{ + struct tcs3472_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable | (TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON)); +} +#endif + +static SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, tcs3472_resume); + +static const struct i2c_device_id tcs3472_id[] = { + { "tcs3472", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tcs3472_id); + +static struct i2c_driver tcs3472_driver = { + .driver = { + .name = TCS3472_DRV_NAME, + .pm = &tcs3472_pm_ops, + .owner = THIS_MODULE, + }, + .probe = tcs3472_probe, + .remove = tcs3472_remove, + .id_table = tcs3472_id, +}; +module_i2c_driver(tcs3472_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("TCS3472 color light sensors driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c new file mode 100644 index 000000000000..a15006efa137 --- /dev/null +++ b/drivers/iio/light/tsl4531.c @@ -0,0 +1,258 @@ +/* + * tsl4531.c - Support for TAOS TSL4531 ambient light sensor + * + * Copyright 2013 Peter Meerwald <pmeerw@pmeerw.net> + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for the TSL4531x family + * TSL45311/TSL45313: 7-bit I2C slave address 0x39 + * TSL45315/TSL45317: 7-bit I2C slave address 0x29 + * + * TODO: single cycle measurement + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/delay.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define TSL4531_DRV_NAME "tsl4531" + +#define TCS3472_COMMAND BIT(7) + +#define TSL4531_CONTROL (TCS3472_COMMAND | 0x00) +#define TSL4531_CONFIG (TCS3472_COMMAND | 0x01) +#define TSL4531_DATA (TCS3472_COMMAND | 0x04) +#define TSL4531_ID (TCS3472_COMMAND | 0x0a) + +/* operating modes in control register */ +#define TSL4531_MODE_POWERDOWN 0x00 +#define TSL4531_MODE_SINGLE_ADC 0x02 +#define TSL4531_MODE_NORMAL 0x03 + +/* integration time control in config register */ +#define TSL4531_TCNTRL_400MS 0x00 +#define TSL4531_TCNTRL_200MS 0x01 +#define TSL4531_TCNTRL_100MS 0x02 + +/* part number in id register */ +#define TSL45311_ID 0x8 +#define TSL45313_ID 0x9 +#define TSL45315_ID 0xa +#define TSL45317_ID 0xb +#define TSL4531_ID_SHIFT 4 + +struct tsl4531_data { + struct i2c_client *client; + struct mutex lock; + int int_time; +}; + +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.2 0.4"); + +static struct attribute *tsl4531_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group tsl4531_attribute_group = { + .attrs = tsl4531_attributes, +}; + +static const struct iio_chan_spec tsl4531_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_INT_TIME) + } +}; + +static int tsl4531_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tsl4531_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_data(data->client, + TSL4531_DATA); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* 0.. 1x, 1 .. 2x, 2 .. 4x */ + *val = 1 << data->int_time; + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + if (data->int_time == 0) + *val2 = 400000; + else if (data->int_time == 1) + *val2 = 200000; + else if (data->int_time == 2) + *val2 = 100000; + else + return -EINVAL; + *val = 0; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int tsl4531_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct tsl4531_data *data = iio_priv(indio_dev); + int int_time, ret; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + if (val2 == 400000) + int_time = 0; + else if (val2 == 200000) + int_time = 1; + else if (val2 == 100000) + int_time = 2; + else + return -EINVAL; + mutex_lock(&data->lock); + ret = i2c_smbus_write_byte_data(data->client, + TSL4531_CONFIG, int_time); + if (ret >= 0) + data->int_time = int_time; + mutex_unlock(&data->lock); + return ret; + default: + return -EINVAL; + } +} + +static const struct iio_info tsl4531_info = { + .read_raw = tsl4531_read_raw, + .write_raw = tsl4531_write_raw, + .attrs = &tsl4531_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int tsl4531_check_id(struct i2c_client *client) +{ + int ret = i2c_smbus_read_byte_data(client, TSL4531_ID); + if (ret < 0) + return ret; + + switch (ret >> TSL4531_ID_SHIFT) { + case TSL45311_ID: + case TSL45313_ID: + case TSL45315_ID: + case TSL45317_ID: + return 1; + default: + return 0; + } +} + +static int tsl4531_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tsl4531_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + if (!tsl4531_check_id(client)) { + dev_err(&client->dev, "no TSL4531 sensor\n"); + return -ENODEV; + } + + ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL, + TSL4531_MODE_NORMAL); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONFIG, + TSL4531_TCNTRL_400MS); + if (ret < 0) + return ret; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &tsl4531_info; + indio_dev->channels = tsl4531_channels; + indio_dev->num_channels = ARRAY_SIZE(tsl4531_channels); + indio_dev->name = TSL4531_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + + return iio_device_register(indio_dev); +} + +static int tsl4531_powerdown(struct i2c_client *client) +{ + return i2c_smbus_write_byte_data(client, TSL4531_CONTROL, + TSL4531_MODE_POWERDOWN); +} + +static int tsl4531_remove(struct i2c_client *client) +{ + iio_device_unregister(i2c_get_clientdata(client)); + tsl4531_powerdown(client); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tsl4531_suspend(struct device *dev) +{ + return tsl4531_powerdown(to_i2c_client(dev)); +} + +static int tsl4531_resume(struct device *dev) +{ + return i2c_smbus_write_byte_data(to_i2c_client(dev), TSL4531_CONTROL, + TSL4531_MODE_NORMAL); +} +#endif + +static SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume); + +static const struct i2c_device_id tsl4531_id[] = { + { "tsl4531", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tsl4531_id); + +static struct i2c_driver tsl4531_driver = { + .driver = { + .name = TSL4531_DRV_NAME, + .pm = &tsl4531_pm_ops, + .owner = THIS_MODULE, + }, + .probe = tsl4531_probe, + .remove = tsl4531_remove, + .id_table = tsl4531_id, +}; + +module_i2c_driver(tsl4531_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("TAOS TSL4531 ambient light sensors driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index a98460b15e4b..2634920562fb 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -183,10 +183,11 @@ static const struct iio_info magn_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -201,7 +202,7 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, magn_state->common_attributes.data_ready); if (magn_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)magn_state->magn_val, + magn_state->magn_val, sizeof(magn_state->magn_val)); return 0; diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index e8d2849cc81d..82461eff995a 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -348,8 +348,9 @@ static const struct iio_info magn_info = { int st_magn_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) { - int err; 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; @@ -357,7 +358,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev, err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_magn_sensors), st_magn_sensors); if (err < 0) - goto st_magn_common_probe_error; + return err; mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; mdata->multiread_bit = mdata->sensor->multi_read_bit; @@ -370,12 +371,13 @@ int st_magn_common_probe(struct iio_dev *indio_dev, err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_magn_common_probe_error; + return err; - if (mdata->get_irq_data_ready(indio_dev) > 0) { - err = st_magn_allocate_ring(indio_dev); - if (err < 0) - goto st_magn_common_probe_error; + err = st_magn_allocate_ring(indio_dev); + if (err < 0) + return err; + + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, NULL); if (err < 0) goto st_magn_probe_trigger_error; @@ -385,15 +387,14 @@ int st_magn_common_probe(struct iio_dev *indio_dev, if (err) goto st_magn_device_register_error; - return err; + return 0; st_magn_device_register_error: - if (mdata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_magn_probe_trigger_error: - if (mdata->get_irq_data_ready(indio_dev) > 0) - st_magn_deallocate_ring(indio_dev); -st_magn_common_probe_error: + st_magn_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_magn_common_probe); @@ -403,10 +404,10 @@ void st_magn_common_remove(struct iio_dev *indio_dev) struct st_sensor_data *mdata = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (mdata->get_irq_data_ready(indio_dev) > 0) { + if (mdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_magn_deallocate_ring(indio_dev); - } + + st_magn_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_magn_common_remove); diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index b0b630688da6..049c21acf1f0 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/iio/common/st_sensors.h> +#define LPS001WP_PRESS_DEV_NAME "lps001wp" #define LPS331AP_PRESS_DEV_NAME "lps331ap" /** diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index ceebd3c27892..2da411b6925b 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -36,94 +36,200 @@ ST_PRESS_LSB_PER_CELSIUS) #define ST_PRESS_NUMBER_DATA_CHANNELS 1 -/* DEFAULT VALUE FOR SENSORS */ -#define ST_PRESS_DEFAULT_OUT_XL_ADDR 0x28 -#define ST_TEMP_DEFAULT_OUT_L_ADDR 0x2b - /* FULLSCALE */ #define ST_PRESS_FS_AVL_1260MB 1260 -/* CUSTOM VALUES FOR SENSOR 1 */ -#define ST_PRESS_1_WAI_EXP 0xbb -#define ST_PRESS_1_ODR_ADDR 0x20 -#define ST_PRESS_1_ODR_MASK 0x70 -#define ST_PRESS_1_ODR_AVL_1HZ_VAL 0x01 -#define ST_PRESS_1_ODR_AVL_7HZ_VAL 0x05 -#define ST_PRESS_1_ODR_AVL_13HZ_VAL 0x06 -#define ST_PRESS_1_ODR_AVL_25HZ_VAL 0x07 -#define ST_PRESS_1_PW_ADDR 0x20 -#define ST_PRESS_1_PW_MASK 0x80 -#define ST_PRESS_1_FS_ADDR 0x23 -#define ST_PRESS_1_FS_MASK 0x30 -#define ST_PRESS_1_FS_AVL_1260_VAL 0x00 -#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE -#define ST_PRESS_1_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE -#define ST_PRESS_1_BDU_ADDR 0x20 -#define ST_PRESS_1_BDU_MASK 0x04 -#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22 -#define ST_PRESS_1_DRDY_IRQ_INT1_MASK 0x04 -#define ST_PRESS_1_DRDY_IRQ_INT2_MASK 0x20 -#define ST_PRESS_1_MULTIREAD_BIT true -#define ST_PRESS_1_TEMP_OFFSET 42500 - -static const struct iio_chan_spec st_press_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_PRESSURE, +/* CUSTOM VALUES FOR LPS331AP SENSOR */ +#define ST_PRESS_LPS331AP_WAI_EXP 0xbb +#define ST_PRESS_LPS331AP_ODR_ADDR 0x20 +#define ST_PRESS_LPS331AP_ODR_MASK 0x70 +#define ST_PRESS_LPS331AP_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_LPS331AP_ODR_AVL_7HZ_VAL 0x05 +#define ST_PRESS_LPS331AP_ODR_AVL_13HZ_VAL 0x06 +#define ST_PRESS_LPS331AP_ODR_AVL_25HZ_VAL 0x07 +#define ST_PRESS_LPS331AP_PW_ADDR 0x20 +#define ST_PRESS_LPS331AP_PW_MASK 0x80 +#define ST_PRESS_LPS331AP_FS_ADDR 0x23 +#define ST_PRESS_LPS331AP_FS_MASK 0x30 +#define ST_PRESS_LPS331AP_FS_AVL_1260_VAL 0x00 +#define ST_PRESS_LPS331AP_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE +#define ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE +#define ST_PRESS_LPS331AP_BDU_ADDR 0x20 +#define ST_PRESS_LPS331AP_BDU_MASK 0x04 +#define ST_PRESS_LPS331AP_DRDY_IRQ_ADDR 0x22 +#define ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK 0x04 +#define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK 0x20 +#define ST_PRESS_LPS331AP_MULTIREAD_BIT true +#define ST_PRESS_LPS331AP_TEMP_OFFSET 42500 +#define ST_PRESS_LPS331AP_OUT_XL_ADDR 0x28 +#define ST_TEMP_LPS331AP_OUT_L_ADDR 0x2b + +/* CUSTOM VALUES FOR LPS001WP SENSOR */ +#define ST_PRESS_LPS001WP_WAI_EXP 0xba +#define ST_PRESS_LPS001WP_ODR_ADDR 0x20 +#define ST_PRESS_LPS001WP_ODR_MASK 0x30 +#define ST_PRESS_LPS001WP_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_LPS001WP_ODR_AVL_7HZ_VAL 0x02 +#define ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL 0x03 +#define ST_PRESS_LPS001WP_PW_ADDR 0x20 +#define ST_PRESS_LPS001WP_PW_MASK 0x40 +#define ST_PRESS_LPS001WP_BDU_ADDR 0x20 +#define ST_PRESS_LPS001WP_BDU_MASK 0x04 +#define ST_PRESS_LPS001WP_MULTIREAD_BIT true +#define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28 +#define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a + +static const struct iio_chan_spec st_press_lps331ap_channels[] = { + { + .type = IIO_PRESSURE, + .channel2 = IIO_NO_MOD, + .address = ST_PRESS_LPS331AP_OUT_XL_ADDR, + .scan_index = ST_SENSORS_SCAN_X, + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 24, + .endianness = IIO_LE, + }, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - ST_SENSORS_SCAN_X, 0, IIO_NO_MOD, 'u', IIO_LE, 24, 24, - ST_PRESS_DEFAULT_OUT_XL_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_TEMP, - BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_OFFSET), - -1, 0, IIO_NO_MOD, 's', IIO_LE, 16, 16, - ST_TEMP_DEFAULT_OUT_L_ADDR), + .modified = 0, + }, + { + .type = IIO_TEMP, + .channel2 = IIO_NO_MOD, + .address = ST_TEMP_LPS331AP_OUT_L_ADDR, + .scan_index = -1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .modified = 0, + }, + IIO_CHAN_SOFT_TIMESTAMP(1) +}; + +static const struct iio_chan_spec st_press_lps001wp_channels[] = { + { + .type = IIO_PRESSURE, + .channel2 = IIO_NO_MOD, + .address = ST_PRESS_LPS001WP_OUT_L_ADDR, + .scan_index = ST_SENSORS_SCAN_X, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .modified = 0, + }, + { + .type = IIO_TEMP, + .channel2 = IIO_NO_MOD, + .address = ST_TEMP_LPS001WP_OUT_L_ADDR, + .scan_index = -1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET), + .modified = 0, + }, IIO_CHAN_SOFT_TIMESTAMP(1) }; static const struct st_sensors st_press_sensors[] = { { - .wai = ST_PRESS_1_WAI_EXP, + .wai = ST_PRESS_LPS331AP_WAI_EXP, .sensors_supported = { [0] = LPS331AP_PRESS_DEV_NAME, }, - .ch = (struct iio_chan_spec *)st_press_channels, + .ch = (struct iio_chan_spec *)st_press_lps331ap_channels, + .num_ch = ARRAY_SIZE(st_press_lps331ap_channels), .odr = { - .addr = ST_PRESS_1_ODR_ADDR, - .mask = ST_PRESS_1_ODR_MASK, + .addr = ST_PRESS_LPS331AP_ODR_ADDR, + .mask = ST_PRESS_LPS331AP_ODR_MASK, .odr_avl = { - { 1, ST_PRESS_1_ODR_AVL_1HZ_VAL, }, - { 7, ST_PRESS_1_ODR_AVL_7HZ_VAL, }, - { 13, ST_PRESS_1_ODR_AVL_13HZ_VAL, }, - { 25, ST_PRESS_1_ODR_AVL_25HZ_VAL, }, + { 1, ST_PRESS_LPS331AP_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_LPS331AP_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_LPS331AP_ODR_AVL_13HZ_VAL, }, + { 25, ST_PRESS_LPS331AP_ODR_AVL_25HZ_VAL, }, }, }, .pw = { - .addr = ST_PRESS_1_PW_ADDR, - .mask = ST_PRESS_1_PW_MASK, + .addr = ST_PRESS_LPS331AP_PW_ADDR, + .mask = ST_PRESS_LPS331AP_PW_MASK, .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, .fs = { - .addr = ST_PRESS_1_FS_ADDR, - .mask = ST_PRESS_1_FS_MASK, + .addr = ST_PRESS_LPS331AP_FS_ADDR, + .mask = ST_PRESS_LPS331AP_FS_MASK, .fs_avl = { [0] = { .num = ST_PRESS_FS_AVL_1260MB, - .value = ST_PRESS_1_FS_AVL_1260_VAL, - .gain = ST_PRESS_1_FS_AVL_1260_GAIN, - .gain2 = ST_PRESS_1_FS_AVL_TEMP_GAIN, + .value = ST_PRESS_LPS331AP_FS_AVL_1260_VAL, + .gain = ST_PRESS_LPS331AP_FS_AVL_1260_GAIN, + .gain2 = ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN, }, }, }, .bdu = { - .addr = ST_PRESS_1_BDU_ADDR, - .mask = ST_PRESS_1_BDU_MASK, + .addr = ST_PRESS_LPS331AP_BDU_ADDR, + .mask = ST_PRESS_LPS331AP_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_PRESS_LPS331AP_DRDY_IRQ_ADDR, + .mask_int1 = ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK, + .mask_int2 = ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK, + }, + .multi_read_bit = ST_PRESS_LPS331AP_MULTIREAD_BIT, + .bootime = 2, + }, + { + .wai = ST_PRESS_LPS001WP_WAI_EXP, + .sensors_supported = { + [0] = LPS001WP_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_lps001wp_channels, + .num_ch = ARRAY_SIZE(st_press_lps001wp_channels), + .odr = { + .addr = ST_PRESS_LPS001WP_ODR_ADDR, + .mask = ST_PRESS_LPS001WP_ODR_MASK, + .odr_avl = { + { 1, ST_PRESS_LPS001WP_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_LPS001WP_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_PRESS_LPS001WP_PW_ADDR, + .mask = ST_PRESS_LPS001WP_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .addr = 0, + }, + .bdu = { + .addr = ST_PRESS_LPS001WP_BDU_ADDR, + .mask = ST_PRESS_LPS001WP_BDU_MASK, }, .drdy_irq = { - .addr = ST_PRESS_1_DRDY_IRQ_ADDR, - .mask_int1 = ST_PRESS_1_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_PRESS_1_DRDY_IRQ_INT2_MASK, + .addr = 0, }, - .multi_read_bit = ST_PRESS_1_MULTIREAD_BIT, + .multi_read_bit = ST_PRESS_LPS001WP_MULTIREAD_BIT, .bootime = 2, }, }; @@ -210,41 +316,46 @@ static const struct iio_trigger_ops st_press_trigger_ops = { int st_press_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *plat_data) { - int err; struct st_sensor_data *pdata = iio_priv(indio_dev); + int irq = pdata->get_irq_data_ready(indio_dev); + int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_press_sensors), st_press_sensors); + ARRAY_SIZE(st_press_sensors), + st_press_sensors); if (err < 0) - goto st_press_common_probe_error; + return err; pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; - pdata->multiread_bit = pdata->sensor->multi_read_bit; - indio_dev->channels = pdata->sensor->ch; - indio_dev->num_channels = ARRAY_SIZE(st_press_channels); + pdata->multiread_bit = pdata->sensor->multi_read_bit; + indio_dev->channels = pdata->sensor->ch; + indio_dev->num_channels = pdata->sensor->num_ch; + + if (pdata->sensor->fs.addr != 0) + pdata->current_fullscale = (struct st_sensor_fullscale_avl *) + &pdata->sensor->fs.fs_avl[0]; - pdata->current_fullscale = (struct st_sensor_fullscale_avl *) - &pdata->sensor->fs.fs_avl[0]; pdata->odr = pdata->sensor->odr.odr_avl[0].hz; - if (!plat_data) + /* Some devices don't support a data ready pin. */ + if (!plat_data && pdata->sensor->drdy_irq.addr) plat_data = (struct st_sensors_platform_data *)&default_press_pdata; err = st_sensors_init_sensor(indio_dev, plat_data); if (err < 0) - goto st_press_common_probe_error; + return err; - if (pdata->get_irq_data_ready(indio_dev) > 0) { - err = st_press_allocate_ring(indio_dev); - if (err < 0) - goto st_press_common_probe_error; + err = st_press_allocate_ring(indio_dev); + if (err < 0) + return err; + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, - ST_PRESS_TRIGGER_OPS); + ST_PRESS_TRIGGER_OPS); if (err < 0) goto st_press_probe_trigger_error; } @@ -256,12 +367,11 @@ int st_press_common_probe(struct iio_dev *indio_dev, return err; st_press_device_register_error: - if (pdata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: - if (pdata->get_irq_data_ready(indio_dev) > 0) - st_press_deallocate_ring(indio_dev); -st_press_common_probe_error: + st_press_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_press_common_probe); @@ -271,10 +381,10 @@ void st_press_common_remove(struct iio_dev *indio_dev) struct st_sensor_data *pdata = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (pdata->get_irq_data_ready(indio_dev) > 0) { + if (pdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_press_deallocate_ring(indio_dev); - } + + st_press_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_press_common_remove); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 08aac5e6251d..51eab7fcb194 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -49,6 +49,7 @@ static int st_press_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id st_press_id_table[] = { + { LPS001WP_PRESS_DEV_NAME }, { LPS331AP_PRESS_DEV_NAME }, {}, }; diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index 64ccde3f1f7a..4e950979f43e 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -70,12 +70,16 @@ static int tmp006_read_measurement(struct tmp006_data *data, u8 reg) return i2c_smbus_read_word_swapped(data->client, reg); } +static const int tmp006_freqs[5][2] = { {4, 0}, {2, 0}, {1, 0}, + {0, 500000}, {0, 250000} }; + static int tmp006_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask) { struct tmp006_data *data = iio_priv(indio_dev); s32 ret; + int cr; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -106,6 +110,12 @@ static int tmp006_read_raw(struct iio_dev *indio_dev, break; } return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + cr = (data->config & TMP006_CONFIG_CR_MASK) + >> TMP006_CONFIG_CR_SHIFT; + *val = tmp006_freqs[cr][0]; + *val2 = tmp006_freqs[cr][1]; + return IIO_VAL_INT_PLUS_MICRO; default: break; } @@ -113,48 +123,32 @@ static int tmp006_read_raw(struct iio_dev *indio_dev, return -EINVAL; } -static const char * const tmp006_freqs[] = { "4", "2", "1", "0.5", "0.25" }; - -static ssize_t tmp006_show_freq(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev)); - int cr = (data->config & TMP006_CONFIG_CR_MASK) - >> TMP006_CONFIG_CR_SHIFT; - return sprintf(buf, "%s\n", tmp006_freqs[cr]); -} - -static ssize_t tmp006_store_freq(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static int tmp006_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tmp006_data *data = iio_priv(indio_dev); int i; - bool found = false; for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++) - if (sysfs_streq(buf, tmp006_freqs[i])) { - found = true; - break; - } - if (!found) - return -EINVAL; + if ((val == tmp006_freqs[i][0]) && + (val2 == tmp006_freqs[i][1])) { + data->config &= ~TMP006_CONFIG_CR_MASK; + data->config |= i << TMP006_CONFIG_CR_SHIFT; - data->config &= ~TMP006_CONFIG_CR_MASK; - data->config |= i << TMP006_CONFIG_CR_SHIFT; + return i2c_smbus_write_word_swapped(data->client, + TMP006_CONFIG, + data->config); - return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, - data->config); + } + return -EINVAL; } -static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, - tmp006_show_freq, tmp006_store_freq); - static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25"); static struct attribute *tmp006_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL }; @@ -168,16 +162,19 @@ static const struct iio_chan_spec tmp006_channels[] = { .type = IIO_VOLTAGE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), } }; static const struct iio_info tmp006_info = { .read_raw = tmp006_read_raw, + .write_raw = tmp006_write_raw, .attrs = &tmp006_attribute_group, .driver_module = THIS_MODULE, }; diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index e1c5300cacfc..24e625c0b531 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -52,6 +52,7 @@ struct titsc { u32 config_inp[4]; u32 bit_xp, bit_xn, bit_yp, bit_yn; u32 inp_xp, inp_xn, inp_yp, inp_yn; + u32 step_mask; }; static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) @@ -196,7 +197,8 @@ static void titsc_step_config(struct titsc *ts_dev) /* The steps1 … end and bit 0 for TS_Charge */ stepenable = (1 << (end_step + 2)) - 1; - am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable); + ts_dev->step_mask = stepenable; + am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); } static void titsc_read_coordinates(struct titsc *ts_dev, @@ -260,6 +262,10 @@ static irqreturn_t titsc_irq(int irq, void *dev) unsigned int fsm; status = titsc_readl(ts_dev, REG_IRQSTATUS); + /* + * ADC and touchscreen share the IRQ line. + * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only + */ if (status & IRQENB_FIFO0THRES) { titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2); @@ -316,7 +322,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) if (irqclr) { titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); - am335x_tsc_se_update(ts_dev->mfd_tscadc); + am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); return IRQ_HANDLED; } return IRQ_NONE; @@ -389,7 +395,7 @@ static int titsc_probe(struct platform_device *pdev) } err = request_irq(ts_dev->irq, titsc_irq, - 0, pdev->dev.driver->name, ts_dev); + IRQF_SHARED, pdev->dev.driver->name, ts_dev); if (err) { dev_err(&pdev->dev, "failed to allocate irq.\n"); goto err_free_mem; diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 5b8f0f6c9938..aae86ddd658b 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -146,11 +146,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) len = lis3l02dq_get_buffer_element(indio_dev, data); - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)data + ALIGN(len, sizeof(s64))) - = pf->timestamp; - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp); kfree(data); done: diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 48a25ba290f5..6a9ca20ea22d 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -624,9 +624,9 @@ static ssize_t sca3000_set_frequency(struct device *dev, struct sca3000_state *st = iio_priv(indio_dev); int ret, base_freq = 0; int ctrlval; - long val; + int val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtoint(buf, 10, &val); if (ret) return ret; @@ -931,12 +931,12 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); - long val; + u8 val; int ret; u8 protect_mask = SCA3000_FREE_FALL_DETECT; mutex_lock(&st->lock); - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index 3e5e860aa38e..0f2ee3373d9a 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -177,11 +177,11 @@ static ssize_t sca3000_set_ring_int(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long val; + u8 val; int ret; mutex_lock(&st->lock); - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 3283e2829536..83bb44b38152 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -623,17 +623,17 @@ static int ad7192_probe(struct spi_device *spi) return -ENODEV; } - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; voltage_uv = regulator_get_voltage(st->reg); } @@ -677,11 +677,6 @@ error_remove_trigger: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - - iio_device_free(indio_dev); return ret; } @@ -694,10 +689,8 @@ static int ad7192_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad_sd_cleanup_buffer_and_trigger(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } return 0; } diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index c19618bc37c4..e7191e44a970 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -835,8 +835,9 @@ static int ad7280_probe(struct spi_device *spi) int ret; const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890}; const unsigned short nAVG[4] = {1, 2, 4, 8}; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -860,7 +861,7 @@ static int ad7280_probe(struct spi_device *spi) ret = ad7280_chain_setup(st); if (ret < 0) - goto error_free_device; + return ret; st->slave_num = ret; st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; @@ -891,7 +892,7 @@ static int ad7280_probe(struct spi_device *spi) ret = ad7280_channel_init(st); if (ret < 0) - goto error_free_device; + return ret; indio_dev->num_channels = ret; indio_dev->channels = st->channels; @@ -940,9 +941,6 @@ error_free_attr: error_free_channels: kfree(st->channels); -error_free_device: - iio_device_free(indio_dev); - return ret; } @@ -960,7 +958,6 @@ static int ad7280_remove(struct spi_device *spi) kfree(st->channels); kfree(st->iio_attr); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c index a2e61c2fc8d1..1dae1efe41c7 100644 --- a/drivers/staging/iio/adc/ad7291.c +++ b/drivers/staging/iio/adc/ad7291.c @@ -528,21 +528,19 @@ static int ad7291_probe(struct i2c_client *client, struct iio_dev *indio_dev; int ret = 0; - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); if (pdata && pdata->use_external_ref) { - chip->reg = regulator_get(&client->dev, "vref"); + chip->reg = devm_regulator_get(&client->dev, "vref"); if (IS_ERR(chip->reg)) - goto error_free; + return ret; ret = regulator_enable(chip->reg); if (ret) - goto error_put_reg; + return ret; } mutex_init(&chip->state_lock); @@ -601,12 +599,7 @@ error_unreg_irq: error_disable_reg: if (chip->reg) regulator_disable(chip->reg); -error_put_reg: - if (chip->reg) - regulator_put(chip->reg); -error_free: - iio_device_free(indio_dev); -error_ret: + return ret; } @@ -620,12 +613,8 @@ static int ad7291_remove(struct i2c_client *client) if (client->irq) free_irq(client->irq, indio_dev); - if (chip->reg) { + if (chip->reg) regulator_disable(chip->reg); - regulator_put(chip->reg); - } - - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 72868ceda360..f042027b5291 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -425,8 +425,7 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) struct ad7606_state *st = iio_priv(indio_dev); if (iio_buffer_enabled(indio_dev)) { - if (!work_pending(&st->poll_work)) - schedule_work(&st->poll_work); + schedule_work(&st->poll_work); } else { st->done = true; wake_up_interruptible(&st->wq_data_avail); @@ -466,12 +465,11 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, struct ad7606_platform_data *pdata = dev->platform_data; struct ad7606_state *st; int ret; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return ERR_PTR(-ENOMEM); st = iio_priv(indio_dev); @@ -489,11 +487,11 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, st->oversampling = pdata->default_os; } - st->reg = regulator_get(dev, "vcc"); + st->reg = devm_regulator_get(dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ERR_PTR(ret); } st->pdata = pdata; @@ -554,11 +552,6 @@ error_free_gpios: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - iio_device_free(indio_dev); -error_ret: return ERR_PTR(ret); } @@ -570,13 +563,10 @@ int ad7606_remove(struct iio_dev *indio_dev, int irq) ad7606_ring_cleanup(indio_dev); free_irq(irq, indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } ad7606_free_gpios(st); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index 2b25cb07fe41..3bf174cb19b1 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -46,7 +46,6 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) struct ad7606_state *st = container_of(work_s, struct ad7606_state, poll_work); struct iio_dev *indio_dev = iio_priv_to_dev(st); - s64 time_ns; __u8 *buf; int ret; @@ -78,12 +77,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) goto done; } - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - *((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns; - - iio_push_to_buffers(indio_dev, buf); + iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); done: gpio_set_value(st->pdata->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index e1f88603d7e0..4f2522a9edfb 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -171,7 +171,7 @@ static int ad7780_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, voltage_uv = 0; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -180,11 +180,11 @@ static int ad7780_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); - st->reg = regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; voltage_uv = regulator_get_voltage(st->reg); } @@ -210,8 +210,8 @@ static int ad7780_probe(struct spi_device *spi) if (pdata && gpio_is_valid(pdata->gpio_pdrst)) { - ret = gpio_request_one(pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW, - "AD7780 /PDRST"); + ret = devm_gpio_request_one(&spi->dev, pdata->gpio_pdrst, + GPIOF_OUT_INIT_LOW, "AD7780 /PDRST"); if (ret) { dev_err(&spi->dev, "failed to request GPIO PDRST\n"); goto error_disable_reg; @@ -223,7 +223,7 @@ static int ad7780_probe(struct spi_device *spi) ret = ad_sd_setup_buffer_and_trigger(indio_dev); if (ret) - goto error_free_gpio; + goto error_disable_reg; ret = iio_device_register(indio_dev); if (ret) @@ -233,17 +233,9 @@ static int ad7780_probe(struct spi_device *spi) error_cleanup_buffer_and_trigger: ad_sd_cleanup_buffer_and_trigger(indio_dev); -error_free_gpio: - if (pdata && gpio_is_valid(pdata->gpio_pdrst)) - gpio_free(pdata->gpio_pdrst); error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - - iio_device_free(indio_dev); return ret; } @@ -256,14 +248,8 @@ static int ad7780_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad_sd_cleanup_buffer_and_trigger(indio_dev); - if (gpio_is_valid(st->powerdown_gpio)) - gpio_free(st->powerdown_gpio); - - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 8470036a3378..9f48e5c74eed 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -356,11 +356,9 @@ static int ad7816_probe(struct spi_device *spi_dev) return -EINVAL; } - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); /* this is only used for device removal purposes */ dev_set_drvdata(&spi_dev->dev, indio_dev); @@ -372,25 +370,28 @@ static int ad7816_probe(struct spi_device *spi_dev) chip->convert_pin = pins[1]; chip->busy_pin = pins[2]; - ret = gpio_request(chip->rdwr_pin, spi_get_device_id(spi_dev)->name); + ret = devm_gpio_request(&spi_dev->dev, chip->rdwr_pin, + spi_get_device_id(spi_dev)->name); if (ret) { dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n", chip->rdwr_pin); - goto error_free_device; + return ret; } gpio_direction_input(chip->rdwr_pin); - ret = gpio_request(chip->convert_pin, spi_get_device_id(spi_dev)->name); + ret = devm_gpio_request(&spi_dev->dev, chip->convert_pin, + spi_get_device_id(spi_dev)->name); if (ret) { dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n", chip->convert_pin); - goto error_free_gpio_rdwr; + return ret; } gpio_direction_input(chip->convert_pin); - ret = gpio_request(chip->busy_pin, spi_get_device_id(spi_dev)->name); + ret = devm_gpio_request(&spi_dev->dev, chip->busy_pin, + spi_get_device_id(spi_dev)->name); if (ret) { dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n", chip->busy_pin); - goto error_free_gpio_convert; + return ret; } gpio_direction_input(chip->busy_pin); @@ -401,51 +402,31 @@ static int ad7816_probe(struct spi_device *spi_dev) if (spi_dev->irq) { /* Only low trigger is supported in ad7816/7/8 */ - ret = request_threaded_irq(spi_dev->irq, - NULL, - &ad7816_event_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - indio_dev->name, - indio_dev); + ret = devm_request_threaded_irq(&spi_dev->dev, spi_dev->irq, + NULL, + &ad7816_event_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + indio_dev->name, + indio_dev); if (ret) - goto error_free_gpio; + return ret; } ret = iio_device_register(indio_dev); if (ret) - goto error_free_irq; + return ret; dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n", indio_dev->name); return 0; -error_free_irq: - free_irq(spi_dev->irq, indio_dev); -error_free_gpio: - gpio_free(chip->busy_pin); -error_free_gpio_convert: - gpio_free(chip->convert_pin); -error_free_gpio_rdwr: - gpio_free(chip->rdwr_pin); -error_free_device: - iio_device_free(indio_dev); -error_ret: - return ret; } static int ad7816_remove(struct spi_device *spi_dev) { struct iio_dev *indio_dev = dev_get_drvdata(&spi_dev->dev); - struct ad7816_chip_info *chip = iio_priv(indio_dev); iio_device_unregister(indio_dev); - dev_set_drvdata(&spi_dev->dev, NULL); - if (spi_dev->irq) - free_irq(spi_dev->irq, indio_dev); - gpio_free(chip->busy_pin); - gpio_free(chip->convert_pin); - gpio_free(chip->rdwr_pin); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index 2b2049c8bc6b..3f5142b284d1 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -586,8 +586,9 @@ static int ad799x_probe(struct i2c_client *client, int ret; struct ad799x_platform_data *pdata = client->dev.platform_data; struct ad799x_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -606,11 +607,11 @@ static int ad799x_probe(struct i2c_client *client, st->int_vref_mv = pdata->vref_mv; - st->reg = regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(&client->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; } st->client = client; @@ -650,10 +651,6 @@ error_cleanup_ring: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - iio_device_free(indio_dev); return ret; } @@ -668,12 +665,9 @@ static int ad799x_remove(struct i2c_client *client) free_irq(client->irq, indio_dev); ad799x_ring_cleanup(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } kfree(st->rx_buf); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c index c2ebae12ee19..0ff6c03a483e 100644 --- a/drivers/staging/iio/adc/ad799x_ring.c +++ b/drivers/staging/iio/adc/ad799x_ring.c @@ -35,7 +35,6 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad799x_state *st = iio_priv(indio_dev); - s64 time_ns; int b_sent; u8 cmd; @@ -65,13 +64,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) if (b_sent < 0) goto out; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(st->rx_buf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - - iio_push_to_buffers(indio_dev, st->rx_buf); + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); out: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index 9a4bb0999b51..ce7ff3e6cd21 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -137,43 +137,39 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get platform I/O memory\n"); - retval = -EBUSY; - goto errout1; + return -EBUSY; } - iodev = iio_device_alloc(sizeof(struct lpc32xx_adc_info)); - if (!iodev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); - retval = -ENOMEM; - goto errout1; - } + iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); + if (!iodev) + return -ENOMEM; info = iio_priv(iodev); - info->adc_base = ioremap(res->start, resource_size(res)); + info->adc_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (!info->adc_base) { dev_err(&pdev->dev, "failed mapping memory\n"); - retval = -EBUSY; - goto errout2; + return -EBUSY; } - info->clk = clk_get(&pdev->dev, NULL); + info->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed getting clock\n"); - goto errout3; + return PTR_ERR(info->clk); } irq = platform_get_irq(pdev, 0); if ((irq < 0) || (irq >= NR_IRQS)) { dev_err(&pdev->dev, "failed getting interrupt resource\n"); - retval = -EINVAL; - goto errout4; + return -EINVAL; } - retval = request_irq(irq, lpc32xx_adc_isr, 0, MOD_NAME, info); + retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, + MOD_NAME, info); if (retval < 0) { dev_err(&pdev->dev, "failed requesting interrupt\n"); - goto errout4; + return retval; } platform_set_drvdata(pdev, iodev); @@ -189,35 +185,18 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) retval = iio_device_register(iodev); if (retval) - goto errout5; + return retval; dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq); return 0; - -errout5: - free_irq(irq, info); -errout4: - clk_put(info->clk); -errout3: - iounmap(info->adc_base); -errout2: - iio_device_free(iodev); -errout1: - return retval; } static int lpc32xx_adc_remove(struct platform_device *pdev) { struct iio_dev *iodev = platform_get_drvdata(pdev); - struct lpc32xx_adc_info *info = iio_priv(iodev); - int irq = platform_get_irq(pdev, 0); iio_device_unregister(iodev); - free_irq(irq, info); - clk_put(info->clk); - iounmap(info->adc_base); - iio_device_free(iodev); return 0; } diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index a08c1736458b..9da64bf00039 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -625,13 +625,7 @@ static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p) j++; } - if (iio->scan_timestamp) { - s64 *timestamp = (s64 *)((u8 *)lradc->buffer + - ALIGN(j, sizeof(s64))); - *timestamp = pf->timestamp; - } - - iio_push_to_buffers(iio, (u8 *)lradc->buffer); + iio_push_to_buffers_with_timestamp(iio, lradc->buffer, pf->timestamp); iio_trigger_notify_done(iio->trig); @@ -987,7 +981,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) /* Register the touchscreen input device. */ ret = mxs_lradc_ts_register(lradc); if (ret) - goto err_dev; + goto err_ts_register; /* Register IIO device. */ ret = iio_device_register(iio); @@ -1000,6 +994,8 @@ static int mxs_lradc_probe(struct platform_device *pdev) err_ts: mxs_lradc_ts_unregister(lradc); +err_ts_register: + mxs_lradc_hw_stop(lradc); err_dev: mxs_lradc_trigger_remove(iio); err_trig: @@ -1012,13 +1008,11 @@ static int mxs_lradc_remove(struct platform_device *pdev) struct iio_dev *iio = platform_get_drvdata(pdev); struct mxs_lradc *lradc = iio_priv(iio); + iio_device_unregister(iio); mxs_lradc_ts_unregister(lradc); - mxs_lradc_hw_stop(lradc); - - iio_device_unregister(iio); - iio_triggered_buffer_cleanup(iio); mxs_lradc_trigger_remove(iio); + iio_triggered_buffer_cleanup(iio); return 0; } @@ -1038,3 +1032,4 @@ module_platform_driver(mxs_lradc_driver); MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 1e1356825d6d..80266e801d56 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -412,13 +412,13 @@ static ssize_t adt7316_store_ad_channel(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config2; - unsigned long data = 0; + u8 data; int ret; if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE)) return -EPERM; - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou8(buf, 10, &data); if (ret) return -EINVAL; @@ -823,10 +823,10 @@ static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; - unsigned long data = 0; + u8 data; int ret; - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret || data > ADT7316_DA_2VREF_CH_MASK) return -EINVAL; @@ -878,13 +878,13 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; - unsigned long data; + u8 data; int ret; if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)) return -EPERM; - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou8(buf, 10, &data); if (ret || data > ADT7316_DA_EN_MODE_MASK) return -EINVAL; @@ -933,7 +933,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 ldac_config; - unsigned long data; + u8 data; int ret; if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) { @@ -941,7 +941,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, ADT7316_DA_EN_MODE_LDAC) return -EPERM; - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret || data > ADT7316_LDAC_EN_DA_MASK) return -EINVAL; @@ -1079,11 +1079,11 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 ldac_config; - unsigned long data; + u8 data; int ret; if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) { - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret || data > 3) return -EINVAL; @@ -1093,7 +1093,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, else if (data & 0x2) ldac_config |= ADT7516_DAC_CD_IN_VREF; } else { - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret) return -EINVAL; @@ -1281,11 +1281,11 @@ static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip, static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip, int offset_addr, const char *buf, size_t len) { - long data; + int data; u8 val; int ret; - ret = strict_strtol(buf, 10, &data); + ret = kstrtoint(buf, 10, &data); if (ret || data > 127 || data < -128) return -EINVAL; @@ -1442,7 +1442,7 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, int channel, const char *buf, size_t len) { u8 msb, lsb, offset; - unsigned long data; + u16 data; int ret; if (channel >= ADT7316_DA_MSB_DATA_REGS || @@ -1454,7 +1454,7 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, offset = chip->dac_bits - 8; - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou16(buf, 10, &data); if (ret || data >= (1 << chip->dac_bits)) return -EINVAL; @@ -1830,11 +1830,11 @@ static ssize_t adt7316_set_int_mask(struct device *dev, { struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - unsigned long data; + u16 data; int ret; u8 mask; - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou16(buf, 16, &data); if (ret || data >= ADT7316_VDD_INT_MASK + 1) return -EINVAL; @@ -1901,7 +1901,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - long data; + int data; u8 val; int ret; @@ -1909,7 +1909,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev, this_attr->address > ADT7316_EX_TEMP_LOW) return -EPERM; - ret = strict_strtol(buf, 10, &data); + ret = kstrtoint(buf, 10, &data); if (ret) return -EINVAL; @@ -2106,11 +2106,9 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, unsigned short *adt7316_platform_data = dev->platform_data; int ret = 0; - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); /* this is only used for device removal purposes */ dev_set_drvdata(dev, indio_dev); @@ -2146,58 +2144,44 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, if (adt7316_platform_data[0]) chip->bus.irq_flags = adt7316_platform_data[0]; - ret = request_threaded_irq(chip->bus.irq, - NULL, - &adt7316_event_handler, - chip->bus.irq_flags | IRQF_ONESHOT, - indio_dev->name, - indio_dev); + ret = devm_request_threaded_irq(dev, chip->bus.irq, + NULL, + &adt7316_event_handler, + chip->bus.irq_flags | + IRQF_ONESHOT, + indio_dev->name, + indio_dev); if (ret) - goto error_free_dev; + return ret; if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH) chip->config1 |= ADT7316_INT_POLARITY; } ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1); - if (ret) { - ret = -EIO; - goto error_unreg_irq; - } + if (ret) + return -EIO; ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, chip->config3); - if (ret) { - ret = -EIO; - goto error_unreg_irq; - } + if (ret) + return -EIO; ret = iio_device_register(indio_dev); if (ret) - goto error_unreg_irq; + return ret; dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n", indio_dev->name); return 0; - -error_unreg_irq: - free_irq(chip->bus.irq, indio_dev); -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; } EXPORT_SYMBOL(adt7316_probe); int adt7316_remove(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct adt7316_chip_info *chip = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (chip->bus.irq) - free_irq(chip->bus.irq, indio_dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/frequency/ad5930.c b/drivers/staging/iio/frequency/ad5930.c index 69e90e9e60ea..a4aeee6ffdf2 100644 --- a/drivers/staging/iio/frequency/ad5930.c +++ b/drivers/staging/iio/frequency/ad5930.c @@ -94,11 +94,9 @@ static int ad5930_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); @@ -110,24 +108,18 @@ static int ad5930_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 16; spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(idev); -error_ret: - return ret; } static int ad5930_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index 4e18380c5141..c7d0307c8e76 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -81,9 +81,9 @@ static ssize_t ad9832_write(struct device *dev, struct ad9832_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + unsigned long val; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) goto error_ret; @@ -214,14 +214,14 @@ static int ad9832_probe(struct spi_device *spi) return -ENODEV; } - reg = regulator_get(&spi->dev, "vcc"); + reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(reg)) { ret = regulator_enable(reg); if (ret) - goto error_put_reg; + return ret; } - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -279,47 +279,42 @@ static int ad9832_probe(struct spi_device *spi) ret = spi_sync(st->spi, &st->msg); if (ret) { dev_err(&spi->dev, "device init failed\n"); - goto error_free_device; + goto error_disable_reg; } ret = ad9832_write_frequency(st, AD9832_FREQ0HM, pdata->freq0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_frequency(st, AD9832_FREQ1HM, pdata->freq1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE0H, pdata->phase0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE1H, pdata->phase1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE2H, pdata->phase2); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE3H, pdata->phase3); if (ret) - goto error_free_device; + goto error_disable_reg; ret = iio_device_register(indio_dev); if (ret) - goto error_free_device; + goto error_disable_reg; return 0; -error_free_device: - iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); -error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); return ret; } @@ -330,11 +325,8 @@ static int ad9832_remove(struct spi_device *spi) struct ad9832_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 5cba3c01f417..86cda6176093 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -70,9 +70,9 @@ static ssize_t ad9834_write(struct device *dev, struct ad9834_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + unsigned long val; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) goto error_ret; @@ -327,14 +327,14 @@ static int ad9834_probe(struct spi_device *spi) return -ENODEV; } - reg = regulator_get(&spi->dev, "vcc"); + reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(reg)) { ret = regulator_enable(reg); if (ret) - goto error_put_reg; + return ret; } - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -388,39 +388,35 @@ static int ad9834_probe(struct spi_device *spi) ret = spi_sync(st->spi, &st->msg); if (ret) { dev_err(&spi->dev, "device init failed\n"); - goto error_free_device; + goto error_disable_reg; } ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = iio_device_register(indio_dev); if (ret) - goto error_free_device; + goto error_disable_reg; return 0; -error_free_device: - iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); -error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); + return ret; } @@ -430,11 +426,8 @@ static int ad9834_remove(struct spi_device *spi) struct ad9834_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/frequency/ad9850.c b/drivers/staging/iio/frequency/ad9850.c index 01a8a93031f5..af877ff680e9 100644 --- a/drivers/staging/iio/frequency/ad9850.c +++ b/drivers/staging/iio/frequency/ad9850.c @@ -80,11 +80,9 @@ static int ad9850_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); mutex_init(&st->lock); @@ -96,24 +94,18 @@ static int ad9850_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 16; spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(idev); -error_ret: - return ret; } static int ad9850_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9852.c b/drivers/staging/iio/frequency/ad9852.c index 1344031232bc..4be2cf8c2ab6 100644 --- a/drivers/staging/iio/frequency/ad9852.c +++ b/drivers/staging/iio/frequency/ad9852.c @@ -229,11 +229,9 @@ static int ad9852_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; st = iio_priv(idev); spi_set_drvdata(spi, idev); mutex_init(&st->lock); @@ -245,7 +243,7 @@ static int ad9852_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 8; @@ -253,18 +251,11 @@ static int ad9852_probe(struct spi_device *spi) ad9852_init(st); return 0; - -error_free_dev: - iio_device_free(idev); - -error_ret: - return ret; } static int ad9852_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9910.c b/drivers/staging/iio/frequency/ad9910.c index e48f874c1fc2..a7d528ef620c 100644 --- a/drivers/staging/iio/frequency/ad9910.c +++ b/drivers/staging/iio/frequency/ad9910.c @@ -367,11 +367,9 @@ static int ad9910_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); mutex_init(&st->lock); @@ -383,24 +381,18 @@ static int ad9910_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); ad9910_init(st); return 0; - -error_free_dev: - iio_device_free(idev); -error_ret: - return ret; } static int ad9910_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9951.c b/drivers/staging/iio/frequency/ad9951.c index 8234e3c915c4..0094c2f392ad 100644 --- a/drivers/staging/iio/frequency/ad9951.c +++ b/drivers/staging/iio/frequency/ad9951.c @@ -176,11 +176,9 @@ static int ad9951_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); mutex_init(&st->lock); @@ -193,25 +191,18 @@ static int ad9951_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); ad9951_init(st); return 0; - -error_free_dev: - iio_device_free(idev); - -error_ret: - return ret; } static int ad9951_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index 0e8e02a3cf5b..141ec6188dea 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -90,6 +90,11 @@ static const struct iio_chan_spec iio_dummy_channels[] = { * when converting to standard units (microvolts) */ BIT(IIO_CHAN_INFO_SCALE), + /* + * sampling_frequency + * The frequency in Hz at which the channels are sampled + */ + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), /* The ordering of elements in the buffer via an enum */ .scan_index = voltage0, .scan_type = { /* Description of storage in buffer */ @@ -130,6 +135,10 @@ static const struct iio_chan_spec iio_dummy_channels[] = { * input channels of type IIO_VOLTAGE. */ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + /* + * sampling_frequency + * The frequency in Hz at which the channels are sampled + */ .scan_index = diffvoltage1m2, .scan_type = { /* Description of storage in buffer */ .sign = 's', /* signed */ @@ -147,6 +156,7 @@ static const struct iio_chan_spec iio_dummy_channels[] = { .channel2 = 4, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), .scan_index = diffvoltage3m4, .scan_type = { .sign = 's', @@ -173,6 +183,7 @@ static const struct iio_chan_spec iio_dummy_channels[] = { */ BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), .scan_index = accelx, .scan_type = { /* Description of storage in buffer */ .sign = 's', /* signed */ @@ -272,6 +283,11 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, *val2 = st->accel_calibscale->val2; ret = IIO_VAL_INT_PLUS_MICRO; break; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = 3; + *val2 = 33; + ret = IIO_VAL_INT_PLUS_NANO; + break; default: break; } diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index 72f400c3cbcb..09c93ac7351a 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -82,11 +82,8 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) len += 2; } } - /* Store the timestamp at an 8 byte aligned offset */ - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)data + ALIGN(len, sizeof(s64))) - = iio_get_time_ns(); - iio_push_to_buffers(indio_dev, (u8 *)data); + + iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns()); kfree(data); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 6330af656a0f..712f3c22ce64 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -323,10 +323,10 @@ static ssize_t ad5933_store_frequency(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long val; + unsigned long val; int ret; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) return ret; @@ -400,12 +400,12 @@ static ssize_t ad5933_store(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long val; + u16 val; int i, ret = 0; unsigned short dat; if (this_attr->address != AD5933_IN_PGA_GAIN) { - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; } @@ -434,7 +434,7 @@ static ssize_t ad5933_store(struct device *dev, ret = ad5933_cmd(st, 0); break; case AD5933_OUT_SETTLING_CYCLES: - val = clamp(val, 0L, 0x7FFL); + val = clamp(val, (u16)0, (u16)0x7FF); st->settling_cycles = val; /* 2x, 4x handling, see datasheet */ @@ -448,7 +448,7 @@ static ssize_t ad5933_store(struct device *dev, AD5933_REG_SETTLING_CYCLES, 2, (u8 *)&dat); break; case AD5933_FREQ_POINTS: - val = clamp(val, 0L, 511L); + val = clamp(val, (u16)0, (u16)511); st->freq_points = val; dat = cpu_to_be16(val); @@ -676,7 +676,7 @@ static void ad5933_work(struct work_struct *work) } else { buf[0] = be16_to_cpu(buf[0]); } - iio_push_to_buffers(indio_dev, (u8 *)buf); + iio_push_to_buffers(indio_dev, buf); } else { /* no data available - try again later */ schedule_delayed_work(&st->work, st->poll_time_jiffies); @@ -703,7 +703,9 @@ static int ad5933_probe(struct i2c_client *client, int ret, voltage_uv = 0; struct ad5933_platform_data *pdata = client->dev.platform_data; struct ad5933_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -716,11 +718,11 @@ static int ad5933_probe(struct i2c_client *client, else st->pdata = pdata; - st->reg = regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(&client->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; voltage_uv = regulator_get_voltage(st->reg); } @@ -778,11 +780,6 @@ error_unreg_ring: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - - iio_device_free(indio_dev); return ret; } @@ -795,11 +792,8 @@ static int ad5933_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_buffer_unregister(indio_dev); iio_kfifo_free(indio_dev->buffer); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 351936c3efd6..e314d7ee29dd 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -240,7 +240,7 @@ static ssize_t store_range(struct device *dev, unsigned long lval; unsigned int new_range; - if (strict_strtoul(buf, 10, &lval)) + if (kstrtoul(buf, 10, &lval)) return -EINVAL; if (!(lval == 1000UL || lval == 4000UL || @@ -279,18 +279,18 @@ static ssize_t store_resolution(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); int status; - unsigned long lval; + unsigned int val; unsigned int new_adc_bit; - if (strict_strtoul(buf, 10, &lval)) + if (kstrtouint(buf, 10, &val)) return -EINVAL; - if (!(lval == 4 || lval == 8 || lval == 12 || lval == 16)) { + if (!(val == 4 || val == 8 || val == 12 || val == 16)) { dev_err(dev, "The resolution is not supported\n"); return -EINVAL; } mutex_lock(&chip->lock); - status = isl29018_set_resolution(chip, lval, &new_adc_bit); + status = isl29018_set_resolution(chip, val, &new_adc_bit); if (status < 0) { mutex_unlock(&chip->lock); dev_err(dev, "Error in setting resolution\n"); @@ -319,11 +319,11 @@ static ssize_t store_prox_infrared_suppression(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - unsigned long lval; + int val; - if (strict_strtoul(buf, 10, &lval)) + if (kstrtoint(buf, 10, &val)) return -EINVAL; - if (!(lval == 0UL || lval == 1UL)) { + if (!(val == 0 || val == 1)) { dev_err(dev, "The mode is not supported\n"); return -EINVAL; } @@ -331,7 +331,7 @@ static ssize_t store_prox_infrared_suppression(struct device *dev, /* get the "proximity scheme" i.e. if the chip does on chip infrared suppression (1 means perform on chip suppression) */ mutex_lock(&chip->lock); - chip->prox_scheme = (int)lval; + chip->prox_scheme = val; mutex_unlock(&chip->lock); return count; diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index b377dd3b76ad..f8c659568c38 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -493,9 +493,9 @@ static ssize_t taos_power_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value == 0) @@ -536,9 +536,9 @@ static ssize_t taos_gain_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; switch (value) { @@ -582,9 +582,9 @@ static ssize_t taos_als_time_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if ((value < 50) || (value > 650)) @@ -619,9 +619,9 @@ static ssize_t taos_als_trim_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value) @@ -644,9 +644,9 @@ static ssize_t taos_als_cal_target_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value) @@ -671,9 +671,9 @@ static ssize_t taos_do_calibrate(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value == 1) @@ -815,12 +815,9 @@ static int taos_probe(struct i2c_client *clientp, return -EOPNOTSUPP; } - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - dev_err(&clientp->dev, "iio allocation failed\n"); - goto fail1; - } + indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); chip->client = clientp; i2c_set_clientdata(clientp, indio_dev); @@ -835,14 +832,14 @@ static int taos_probe(struct i2c_client *clientp, if (ret < 0) { dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd " "reg failed in taos_probe(), err = %d\n", ret); - goto fail2; + return ret; } ret = i2c_smbus_read_byte(clientp); if (ret < 0) { dev_err(&clientp->dev, "i2c_smbus_read_byte from " "reg failed in taos_probe(), err = %d\n", ret); - goto fail2; + return ret; } buf[i] = ret; } @@ -850,14 +847,14 @@ static int taos_probe(struct i2c_client *clientp, if (!taos_tsl258x_device(buf)) { dev_info(&clientp->dev, "i2c device found but does not match " "expected id in taos_probe()\n"); - goto fail2; + return -EINVAL; } ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL)); if (ret < 0) { dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " "failed in taos_probe(), err = %d\n", ret); - goto fail2; + return ret; } indio_dev->info = &tsl2583_info; @@ -867,7 +864,7 @@ static int taos_probe(struct i2c_client *clientp, ret = iio_device_register(indio_dev); if (ret) { dev_err(&clientp->dev, "iio registration failed\n"); - goto fail2; + return ret; } /* Load up the V2 defaults (these are hard coded defaults for now) */ @@ -878,10 +875,6 @@ static int taos_probe(struct i2c_client *clientp, dev_info(&clientp->dev, "Light sensor found.\n"); return 0; -fail1: - iio_device_free(indio_dev); -fail2: - return ret; } #ifdef CONFIG_PM_SLEEP @@ -926,7 +919,6 @@ static SIMPLE_DEV_PM_OPS(taos_pm_ops, taos_suspend, taos_resume); static int taos_remove(struct i2c_client *client) { iio_device_unregister(i2c_get_clientdata(client)); - iio_device_free(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index c99f890cc6c6..9c43dcf444c2 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -550,7 +550,7 @@ prox_poll_err: static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) { /* If Operational settings defined elsewhere.. */ - if (chip->pdata && chip->pdata->platform_default_settings != 0) + if (chip->pdata && chip->pdata->platform_default_settings) memcpy(&(chip->tsl2x7x_settings), chip->pdata->platform_default_settings, sizeof(tsl2x7x_default_settings)); @@ -951,7 +951,6 @@ static ssize_t tsl2x7x_gain_available_show(struct device *dev, case tsl2771: case tmd2771: return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); - break; } return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); @@ -1346,7 +1345,6 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev, break; default: return -EINVAL; - break; } break; case IIO_CHAN_INFO_RAW: @@ -1366,7 +1364,6 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev, break; default: return -EINVAL; - break; } break; case IIO_CHAN_INFO_CALIBSCALE: @@ -1419,7 +1416,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, case tsl2772: case tmd2772: return -EINVAL; - break; } chip->tsl2x7x_settings.als_gain = 3; break; @@ -1431,7 +1427,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, case tsl2771: case tmd2771: return -EINVAL; - break; } chip->tsl2x7x_settings.als_gain = 3; break; @@ -1508,18 +1503,15 @@ static int tsl2x7x_device_id(unsigned char *id, int target) case tsl2671: case tsl2771: return ((*id & 0xf0) == TRITON_ID); - break; case tmd2671: case tmd2771: return ((*id & 0xf0) == HALIBUT_ID); - break; case tsl2572: case tsl2672: case tmd2672: case tsl2772: case tmd2772: return ((*id & 0xf0) == SWORDFISH_ID); - break; } return -EINVAL; @@ -1851,7 +1843,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp, struct iio_dev *indio_dev; struct tsl2X7X_chip *chip; - indio_dev = iio_device_alloc(sizeof(*chip)); + indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); if (!indio_dev) return -ENOMEM; @@ -1862,22 +1854,21 @@ static int tsl2x7x_probe(struct i2c_client *clientp, ret = tsl2x7x_i2c_read(chip->client, TSL2X7X_CHIPID, &device_id); if (ret < 0) - goto fail1; + return ret; if ((!tsl2x7x_device_id(&device_id, id->driver_data)) || (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) { dev_info(&chip->client->dev, "%s: i2c device found does not match expected id\n", __func__); - ret = -EINVAL; - goto fail1; + return -EINVAL; } ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); if (ret < 0) { dev_err(&clientp->dev, "%s: write to cmd reg failed. err = %d\n", __func__, ret); - goto fail1; + return ret; } /* ALS and PROX functions can be invoked via user space poll @@ -1899,16 +1890,17 @@ static int tsl2x7x_probe(struct i2c_client *clientp, indio_dev->num_channels = chip->chip_info->chan_table_elements; if (clientp->irq) { - ret = request_threaded_irq(clientp->irq, - NULL, - &tsl2x7x_event_handler, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "TSL2X7X_event", - indio_dev); + ret = devm_request_threaded_irq(&clientp->dev, clientp->irq, + NULL, + &tsl2x7x_event_handler, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "TSL2X7X_event", + indio_dev); if (ret) { dev_err(&clientp->dev, "%s: irq request failed", __func__); - goto fail1; + return ret; } } @@ -1921,20 +1913,12 @@ static int tsl2x7x_probe(struct i2c_client *clientp, if (ret) { dev_err(&clientp->dev, "%s: iio registration failed\n", __func__); - goto fail2; + return ret; } dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); return 0; - -fail2: - if (clientp->irq) - free_irq(clientp->irq, indio_dev); -fail1: - iio_device_free(indio_dev); - - return ret; } static int tsl2x7x_suspend(struct device *dev) @@ -1980,10 +1964,6 @@ static int tsl2x7x_remove(struct i2c_client *client) tsl2x7x_chip_off(indio_dev); iio_device_unregister(indio_dev); - if (client->irq) - free_irq(client->irq, indio_dev); - - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index d2748c329eae..c7c5e82bcf31 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -643,11 +643,9 @@ static int hmc5843_probe(struct i2c_client *client, struct iio_dev *indio_dev; int err = 0; - indio_dev = iio_device_alloc(sizeof(*data)); - if (indio_dev == NULL) { - err = -ENOMEM; - goto exit; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; /* default settings at probe */ data = iio_priv(indio_dev); @@ -665,24 +663,16 @@ static int hmc5843_probe(struct i2c_client *client, err = iio_device_register(indio_dev); if (err) - goto exit_free2; + return err; return 0; - -exit_free2: - iio_device_free(indio_dev); -exit: - return err; } static int hmc5843_remove(struct i2c_client *client) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); + iio_device_unregister(i2c_get_clientdata(client)); /* sleep mode to save power */ hmc5843_configure(client, HMC5843_MODE_SLEEP); - iio_device_free(indio_dev); return 0; } @@ -691,14 +681,14 @@ static int hmc5843_remove(struct i2c_client *client) static int hmc5843_suspend(struct device *dev) { hmc5843_configure(to_i2c_client(dev), HMC5843_MODE_SLEEP); + return 0; } static int hmc5843_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct hmc5843_data *data = iio_priv(indio_dev); + struct hmc5843_data *data = iio_priv(i2c_get_clientdata(client)); hmc5843_configure(client, data->operating_mode); @@ -730,6 +720,6 @@ static struct i2c_driver hmc5843_driver = { }; module_i2c_driver(hmc5843_driver); -MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com"); +MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com>"); MODULE_DESCRIPTION("HMC5843/5883/5883L driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 74025fbae679..6200335d12f7 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -186,9 +186,9 @@ static ssize_t ade7753_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7753_spi_write_reg_8(dev, this_attr->address, val); @@ -204,9 +204,9 @@ static ssize_t ade7753_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7753_spi_write_reg_16(dev, this_attr->address, val); @@ -399,11 +399,11 @@ static ssize_t ade7753_write_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); - unsigned long val; + u16 val; int ret; u16 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; if (val == 0) @@ -497,11 +497,9 @@ static int ade7753_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -517,19 +515,13 @@ static int ade7753_probe(struct spi_device *spi) /* Get the device into a sane initial state */ ret = ade7753_initial_setup(indio_dev); if (ret) - goto error_free_dev; + return ret; ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; return 0; - -error_free_dev: - iio_device_free(indio_dev); - -error_ret: - return ret; } /* fixme, confirm ordering in this function */ @@ -539,7 +531,6 @@ static int ade7753_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ade7753_stop_device(&indio_dev->dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index f649ebe55a04..2e046f6e4fb4 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -186,9 +186,9 @@ static ssize_t ade7754_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7754_spi_write_reg_8(dev, this_attr->address, val); @@ -204,9 +204,9 @@ static ssize_t ade7754_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7754_spi_write_reg_16(dev, this_attr->address, val); @@ -419,11 +419,11 @@ static ssize_t ade7754_write_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); - unsigned long val; + u16 val; int ret; u8 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; if (val == 0) @@ -520,11 +520,9 @@ static int ade7754_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -540,18 +538,12 @@ static int ade7754_probe(struct spi_device *spi) /* Get the device into a sane initial state */ ret = ade7754_initial_setup(indio_dev); if (ret) - goto error_free_dev; + return ret; ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; return 0; - -error_free_dev: - iio_device_free(indio_dev); - -error_ret: - return ret; } /* fixme, confirm ordering in this function */ @@ -561,7 +553,6 @@ static int ade7754_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ade7754_stop_device(&indio_dev->dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 6005d4aab0c3..cba183e24838 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -269,9 +269,9 @@ static ssize_t ade7758_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7758_spi_write_reg_8(dev, this_attr->address, val); @@ -287,9 +287,9 @@ static ssize_t ade7758_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7758_spi_write_reg_16(dev, this_attr->address, val); @@ -502,11 +502,11 @@ static ssize_t ade7758_write_frequency(struct device *dev, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned long val; + u16 val; int ret; u8 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; @@ -849,12 +849,11 @@ static int ade7758_probe(struct spi_device *spi) { int ret; struct ade7758_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); /* this is only used for removal purposes */ @@ -862,10 +861,8 @@ static int ade7758_probe(struct spi_device *spi) /* Allocate the comms buffers */ st->rx = kcalloc(ADE7758_MAX_RX, sizeof(*st->rx), GFP_KERNEL); - if (st->rx == NULL) { - ret = -ENOMEM; - goto error_free_dev; - } + if (!st->rx) + return -ENOMEM; st->tx = kcalloc(ADE7758_MAX_TX, sizeof(*st->tx), GFP_KERNEL); if (st->tx == NULL) { ret = -ENOMEM; @@ -920,9 +917,6 @@ error_free_tx: kfree(st->tx); error_free_rx: kfree(st->rx); -error_free_dev: - iio_device_free(indio_dev); -error_ret: return ret; } @@ -939,8 +933,6 @@ static int ade7758_remove(struct spi_device *spi) kfree(st->tx); kfree(st->rx); - iio_device_free(indio_dev); - return 0; } diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 7d5db7175578..4080995c99b6 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -69,11 +69,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) if (ade7758_spi_read_burst(indio_dev) >= 0) *dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF; - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - dat64[1] = pf->timestamp; - - iio_push_to_buffers(indio_dev, (u8 *)dat64); + iio_push_to_buffers_with_timestamp(indio_dev, dat64, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index d214ac4932cb..145f896aae2b 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -185,9 +185,9 @@ static ssize_t ade7759_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7759_spi_write_reg_8(dev, this_attr->address, val); @@ -203,9 +203,9 @@ static ssize_t ade7759_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7759_spi_write_reg_16(dev, this_attr->address, val); @@ -360,11 +360,11 @@ static ssize_t ade7759_write_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); - unsigned long val; + u16 val; int ret; u16 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; if (val == 0) @@ -444,11 +444,9 @@ static int ade7759_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -463,18 +461,13 @@ static int ade7759_probe(struct spi_device *spi) /* Get the device into a sane initial state */ ret = ade7759_initial_setup(indio_dev); if (ret) - goto error_free_dev; + return ret; ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; } /* fixme, confirm ordering in this function */ @@ -484,7 +477,6 @@ static int ade7759_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ade7759_stop_device(&indio_dev->dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c index db9ef6c86c1e..5b33c7f1aa91 100644 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -208,7 +208,7 @@ static int ade7854_i2c_probe(struct i2c_client *client, struct ade7854_state *st; struct iio_dev *indio_dev; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); @@ -225,8 +225,6 @@ static int ade7854_i2c_probe(struct i2c_client *client, st->irq = client->irq; ret = ade7854_probe(indio_dev, &client->dev); - if (ret) - iio_device_free(indio_dev); return ret; } diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index a802cf2491d6..7cb8d931625c 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -278,7 +278,7 @@ static int ade7854_spi_probe(struct spi_device *spi) struct ade7854_state *st; struct iio_dev *indio_dev; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); @@ -296,8 +296,6 @@ static int ade7854_spi_probe(struct spi_device *spi) ret = ade7854_probe(indio_dev, &spi->dev); - if (ret) - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c index e8379c0f1173..d620bbd603a3 100644 --- a/drivers/staging/iio/meter/ade7854.c +++ b/drivers/staging/iio/meter/ade7854.c @@ -100,9 +100,9 @@ static ssize_t ade7854_write_8bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_8(dev, this_attr->address, val); @@ -121,9 +121,9 @@ static ssize_t ade7854_write_16bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_16(dev, this_attr->address, val); @@ -142,9 +142,9 @@ static ssize_t ade7854_write_24bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u32 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou32(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_24(dev, this_attr->address, val); @@ -163,9 +163,9 @@ static ssize_t ade7854_write_32bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u32 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou32(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_32(dev, this_attr->address, val); @@ -550,7 +550,7 @@ int ade7854_probe(struct iio_dev *indio_dev, struct device *dev) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; /* Get the device into a sane initial state */ ret = ade7854_initial_setup(indio_dev); @@ -561,9 +561,6 @@ int ade7854_probe(struct iio_dev *indio_dev, struct device *dev) error_unreg_dev: iio_device_unregister(indio_dev); -error_free_dev: - iio_device_free(indio_dev); - return ret; } EXPORT_SYMBOL(ade7854_probe); @@ -571,7 +568,6 @@ EXPORT_SYMBOL(ade7854_probe); int ade7854_remove(struct iio_dev *indio_dev) { iio_device_unregister(indio_dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c index 71221161aa6b..62d30179301f 100644 --- a/drivers/staging/iio/resolver/ad2s1200.c +++ b/drivers/staging/iio/resolver/ad2s1200.c @@ -107,16 +107,16 @@ static int ad2s1200_probe(struct spi_device *spi) unsigned short *pins = spi->dev.platform_data; for (pn = 0; pn < AD2S1200_PN; pn++) - if (gpio_request_one(pins[pn], GPIOF_DIR_OUT, DRV_NAME)) { - pr_err("%s: request gpio pin %d failed\n", - DRV_NAME, pins[pn]); - goto error_ret; + ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT, + DRV_NAME); + if (ret) { + dev_err(&spi->dev, "request gpio pin %d failed\n", + pins[pn]); + return ret; } - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); mutex_init(&st->lock); @@ -133,26 +133,18 @@ static int ad2s1200_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = AD2S1200_HZ; spi->mode = SPI_MODE_3; spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - for (--pn; pn >= 0; pn--) - gpio_free(pins[pn]); - return ret; } static int ad2s1200_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index dcdadbbcf7e8..6966d5f76648 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -206,10 +206,10 @@ static ssize_t ad2s1210_store_fclkin(struct device *dev, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long fclkin; + unsigned int fclkin; int ret; - ret = strict_strtoul(buf, 10, &fclkin); + ret = kstrtouint(buf, 10, &fclkin); if (ret) return ret; if (fclkin < AD2S1210_MIN_CLKIN || fclkin > AD2S1210_MAX_CLKIN) { @@ -243,10 +243,10 @@ static ssize_t ad2s1210_store_fexcit(struct device *dev, const char *buf, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long fexcit; + unsigned int fexcit; int ret; - ret = strict_strtoul(buf, 10, &fexcit); + ret = kstrtouint(buf, 10, &fexcit); if (ret < 0) return ret; if (fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) { @@ -282,11 +282,11 @@ static ssize_t ad2s1210_store_control(struct device *dev, const char *buf, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long udata; + unsigned char udata; unsigned char data; int ret; - ret = strict_strtoul(buf, 16, &udata); + ret = kstrtou8(buf, 16, &udata); if (ret) return -EINVAL; @@ -337,10 +337,10 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned char data; - unsigned long udata; + unsigned char udata; int ret; - ret = strict_strtoul(buf, 10, &udata); + ret = kstrtou8(buf, 10, &udata); if (ret || udata < 10 || udata > 16) { pr_err("ad2s1210: resolution out of range\n"); return -EINVAL; @@ -438,11 +438,11 @@ static ssize_t ad2s1210_store_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long data; + unsigned char data; int ret; struct iio_dev_attr *iattr = to_iio_dev_attr(attr); - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou8(buf, 10, &data); if (ret) return -EINVAL; mutex_lock(&st->lock); @@ -669,16 +669,14 @@ static int ad2s1210_probe(struct spi_device *spi) if (spi->dev.platform_data == NULL) return -EINVAL; - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); st->pdata = spi->dev.platform_data; ret = ad2s1210_setup_gpios(st); if (ret < 0) - goto error_free_dev; + return ret; spi_set_drvdata(spi, indio_dev); @@ -709,9 +707,6 @@ static int ad2s1210_probe(struct spi_device *spi) error_free_gpios: ad2s1210_free_gpios(st); -error_free_dev: - iio_device_free(indio_dev); -error_ret: return ret; } @@ -721,7 +716,6 @@ static int ad2s1210_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad2s1210_free_gpios(iio_priv(indio_dev)); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c index 40b825286d4a..e24c5890652f 100644 --- a/drivers/staging/iio/resolver/ad2s90.c +++ b/drivers/staging/iio/resolver/ad2s90.c @@ -64,11 +64,9 @@ static int ad2s90_probe(struct spi_device *spi) struct ad2s90_state *st; int ret = 0; - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); @@ -83,7 +81,7 @@ static int ad2s90_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; /* need 600ns between CS and the first falling edge of SCLK */ spi->max_speed_hz = 830000; @@ -91,17 +89,11 @@ static int ad2s90_probe(struct spi_device *spi) spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; } static int ad2s90_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c index 38a158b77b1d..ebb189c68d88 100644 --- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c @@ -83,32 +83,28 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct bfin_tmr_state *st = iio_trigger_get_drvdata(trig); - unsigned long val; + unsigned int val; bool enabled; int ret; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtouint(buf, 10, &val); if (ret) - goto error_ret; + return ret; if (val > 100000) { - ret = -EINVAL; - goto error_ret; - } + return -EINVAL; enabled = get_enabled_gptimers() & st->t->bit; if (enabled) disable_gptimers(st->t->bit); - if (!val) - goto error_ret; + if (val == 0) + return count; val = get_sclk() / val; - if (val <= 4 || val <= st->duty) { - ret = -EINVAL; - goto error_ret; - } + if (val <= 4 || val <= st->duty) + return -EINVAL; set_gptimer_period(st->t->id, val); set_gptimer_pwidth(st->t->id, val - st->duty); @@ -116,8 +112,7 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, if (enabled) enable_gptimers(st->t->bit); -error_ret: - return ret ? ret : count; + return count; } static ssize_t iio_bfin_tmr_frequency_show(struct device *dev, diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 79695974b1d4..48a6afa84088 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -53,10 +53,10 @@ static ssize_t iio_trig_periodic_write_freq(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); - unsigned long val; + int val; int ret; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoint(buf, 10, &val); if (ret) goto error_ret; diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 2bac0eb8948d..a1124bdc4cac 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -36,7 +36,7 @@ struct iio_buffer; * any of them not existing. **/ struct iio_buffer_access_funcs { - int (*store_to)(struct iio_buffer *buffer, u8 *data); + int (*store_to)(struct iio_buffer *buffer, const void *data); int (*read_first_n)(struct iio_buffer *buffer, size_t n, char __user *buf); @@ -81,7 +81,7 @@ struct iio_buffer { bool stufftoread; const struct attribute_group *attrs; struct list_head demux_list; - unsigned char *demux_bounce; + void *demux_bounce; struct list_head buffer_list; }; @@ -120,7 +120,32 @@ int iio_scan_mask_set(struct iio_dev *indio_dev, * @indio_dev: iio_dev structure for device. * @data: Full scan. */ -int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data); +int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data); + +/* + * iio_push_to_buffers_with_timestamp() - push data and timestamp to buffers + * @indio_dev: iio_dev structure for device. + * @data: sample data + * @timestamp: timestamp for the sample data + * + * Pushes data to the IIO device's buffers. If timestamps are enabled for the + * device the function will store the supplied timestamp as the last element in + * the sample data buffer before pushing it to the device buffers. The sample + * data buffer needs to be large enough to hold the additional timestamp + * (usually the buffer should be indio->scan_bytes bytes large). + * + * Returns 0 on success, a negative error code otherwise. + */ +static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, + void *data, int64_t timestamp) +{ + if (indio_dev->scan_timestamp) { + size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1; + ((int64_t *)data)[ts_offset] = timestamp; + } + + return iio_push_to_buffers(indio_dev, data); +} int iio_update_demux(struct iio_dev *indio_dev); diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index e51f65480ea5..e732fda6c8e6 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -184,6 +184,7 @@ struct st_sensors { u8 wai; char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME]; struct iio_chan_spec *ch; + int num_ch; struct st_sensor_odr odr; struct st_sensor_power pw; struct st_sensor_axis enable_axis; diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 833926c91aa8..2752b1fd12be 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -77,7 +77,7 @@ struct iio_cb_buffer; * fail. */ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, - int (*cb)(u8 *data, + int (*cb)(const void *data, void *private), void *private); /** diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 2103cc32a5fb..ac1cb8f1858c 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -36,6 +36,14 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_PHASE, IIO_CHAN_INFO_HARDWAREGAIN, IIO_CHAN_INFO_HYSTERESIS, + IIO_CHAN_INFO_INT_TIME, +}; + +enum iio_shared_by { + IIO_SEPARATE, + IIO_SHARED_BY_TYPE, + IIO_SHARED_BY_DIR, + IIO_SHARED_BY_ALL }; enum iio_endian { @@ -57,7 +65,7 @@ struct iio_dev; */ struct iio_chan_spec_ext_info { const char *name; - bool shared; + enum iio_shared_by shared; ssize_t (*read)(struct iio_dev *, uintptr_t private, struct iio_chan_spec const *, char *buf); ssize_t (*write)(struct iio_dev *, uintptr_t private, @@ -125,7 +133,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, #define IIO_ENUM_AVAILABLE(_name, _e) \ { \ .name = (_name "_available"), \ - .shared = true, \ + .shared = IIO_SHARED_BY_TYPE, \ .read = iio_enum_available_read, \ .private = (uintptr_t)(_e), \ } @@ -146,12 +154,14 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, * shift: Shift right by this before masking out * realbits. * endianness: little or big endian - * @info_mask: What information is to be exported about this channel. - * This includes calibbias, scale etc. * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_shared_by_type: What information is to be exported that is shared -* by all channels of the same type. + * by all channels of the same type. + * @info_mask_shared_by_dir: What information is to be exported that is shared + * by all channels of the same direction. + * @info_mask_shared_by_all: What information is to be exported that is shared + * by all channels. * @event_mask: What events can this channel produce. * @ext_info: Array of extended info attributes for this channel. * The array is NULL terminated, the last element should @@ -186,9 +196,10 @@ struct iio_chan_spec { u8 shift; enum iio_endian endianness; } scan_type; - long info_mask; long info_mask_separate; long info_mask_shared_by_type; + long info_mask_shared_by_dir; + long info_mask_shared_by_all; long event_mask; const struct iio_chan_spec_ext_info *ext_info; const char *extend_name; @@ -212,7 +223,9 @@ static inline bool iio_channel_has_info(const struct iio_chan_spec *chan, enum iio_chan_info_enum type) { return (chan->info_mask_separate & BIT(type)) | - (chan->info_mask_shared_by_type & BIT(type)); + (chan->info_mask_shared_by_type & BIT(type)) | + (chan->info_mask_shared_by_dir & BIT(type)) | + (chan->info_mask_shared_by_all & BIT(type)); } #define IIO_ST(si, rb, sb, sh) \ @@ -457,7 +470,7 @@ static inline void iio_device_put(struct iio_dev *indio_dev) { if (indio_dev) put_device(&indio_dev->dev); -}; +} /** * dev_to_iio_dev() - Get IIO device struct from a device struct @@ -593,7 +606,7 @@ static inline bool iio_buffer_enabled(struct iio_dev *indio_dev) { return indio_dev->currentmode & (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE); -}; +} /** * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry @@ -603,12 +616,12 @@ static inline bool iio_buffer_enabled(struct iio_dev *indio_dev) static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) { return indio_dev->debugfs_dentry; -}; +} #else static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) { return NULL; -}; +} #endif int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h index 2958c960003a..8a1d18640ab9 100644 --- a/include/linux/iio/sysfs.h +++ b/include/linux/iio/sysfs.h @@ -100,6 +100,21 @@ struct iio_const_attr { #define IIO_CONST_ATTR_SAMP_FREQ_AVAIL(_string) \ IIO_CONST_ATTR(sampling_frequency_available, _string) +/** + * IIO_DEV_ATTR_INT_TIME_AVAIL - list available integration times + * @_show: output method for the attribute + **/ +#define IIO_DEV_ATTR_INT_TIME_AVAIL(_show) \ + IIO_DEVICE_ATTR(integration_time_available, S_IRUGO, _show, NULL, 0) +/** + * IIO_CONST_ATTR_INT_TIME_AVAIL - list available integration times + * @_string: frequency string for the attribute + * + * Constant version + **/ +#define IIO_CONST_ATTR_INT_TIME_AVAIL(_string) \ + IIO_CONST_ATTR(integration_time_available, _string) + #define IIO_DEV_ATTR_TEMP_RAW(_show) \ IIO_DEVICE_ATTR(in_temp_raw, S_IRUGO, _show, NULL, 0) diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 25f2c611ab01..08cce7f96ab9 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -46,16 +46,24 @@ /* Step Enable */ #define STEPENB_MASK (0x1FFFF << 0) #define STEPENB(val) ((val) << 0) +#define ENB(val) (1 << (val)) +#define STPENB_STEPENB STEPENB(0x1FFFF) +#define STPENB_STEPENB_TC STEPENB(0x1FFF) /* IRQ enable */ #define IRQENB_HW_PEN BIT(0) #define IRQENB_FIFO0THRES BIT(2) +#define IRQENB_FIFO0OVRRUN BIT(3) +#define IRQENB_FIFO0UNDRFLW BIT(4) #define IRQENB_FIFO1THRES BIT(5) +#define IRQENB_FIFO1OVRRUN BIT(6) +#define IRQENB_FIFO1UNDRFLW BIT(7) #define IRQENB_PENUP BIT(9) /* Step Configuration */ #define STEPCONFIG_MODE_MASK (3 << 0) #define STEPCONFIG_MODE(val) ((val) << 0) +#define STEPCONFIG_MODE_SWCNT STEPCONFIG_MODE(1) #define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) #define STEPCONFIG_AVG_MASK (7 << 2) #define STEPCONFIG_AVG(val) ((val) << 2) @@ -123,6 +131,7 @@ #define ADC_CLK 3000000 #define TOTAL_STEPS 16 #define TOTAL_CHANNELS 8 +#define FIFO1_THRESHOLD 19 /* * ADC runs at 3MHz, and it takes |