1
0
Fork 0

Second set of new device support, cleanups and features for IIO in the 5.8 cycle

Usual mixed back but with a few subsystem wide or device type
 wide cleanups.
 
 New device support
 
 * adis16475
   - New driver supporting adis16470, adis16475, adis16477, adis16465,
     adis16467, adis16500, adis16505 and adis16507.
     Includes some rework of the adis library to simplify using it
     for this new driver.
 * ak8974
   - Add support for Alps hscdt008a. ID only. Related patches add support
     for scale.
 * atlas-sensor
   - Add support for RTD-SM OEM temperature sensor.
 * cm32181
   - Add support for CM3218 including support for SMBUS alert via
     ACPI resources.
 * ltc2632
   - Add support for ltc2634-12/10/8 DACS including handling per
     device type numbers of channels.
 
 Major Features
 
 * cm32181
   - ACPI bindings including parsing CPM0 and CPM1 custom ACPI tables.
     Includes minor tidy ups and fixes.
 * vcnl4000
   - Add event support
   - Add buffered data capture support
   - Add control of sampling frequency
 
 Cleanups and minor fixes.
 
 * core
   - Trivial rework of iio_device_alloc to use an early return and
     improve readability.
   - Precursors to addition of multiple buffer support. So far
     minor refactoring.
 * subsystem wide
   - Use get_unaligned_be24 slightly improve readability over open
     coding it.
 * adis drivers
   - Use iio_get_debugfs_dentry access function.
 * bh1780, cm32181, cm3232, gp2ap02a00f, opt3001, st_uvis25, vl6180,
   dmard06, kxsd9
   - Drop use of of_match_ptr to allow ACPI based probing via PRP0001.
     Part of clear out of this to avoid cut and paste into new drivers.
 * ad5592r, ad5593r
   - Fix typos
 * ad5933
   - Use managed interfaces to automate error handling and remove.
 * ak8974
   - Fix wrong number of 'real bits' for buffered data.
   - Refactor to pull measurement code out as separate function.
     bmp280
   - Fix lack of clamp on range during data capture.
 * at91-sama5d2_adc
   - Handle unfinished conversions correctly.
   - Allow use of triggers other than it's own.
   - Reorganize buffer setup and tear down as part of long running
     subsystem wide rework.
 * ccs811
   - Add DT binding docs and match table.
   - Support external reset and wakeup pins.
 * hid-sensors
   - Reorganize buffer setup and tear down as part of long running
     subsystem wide rework.
 * ltr501
   - Constify some structs.
 * vcnl4000
   - Fix an endian issue by using explicit byte swapped i2c accessors.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAl666PYRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FohMRQ//ZvDdYRB883lW11iRZJhnzpFhClNbzEp1
 2wxEqMOaLQmf6MntRX6LWmN15EGmQw1Eu2SBCt3G5XRMWKvtxaLnERKYxds67qtP
 uhTJDnfcDUYa6ACEHYs0FSfdmUL3S/7qmdKsABU+86o4LGzyb/jblWruB+6jOWyJ
 vRtMGUC8QP2RA2hq5UNJ3au1tlIS3IYqkmh1A1IXD8OtNW/EGpwFUMsmtRGd99gI
 lJb9VtlAF2bxqUBJuvludrRs8HMHafKRm9WM7+pJX7w2waSsiMMFojB7jDlJTAW/
 J2Zb5UGSUHMwJNLmhr+t1BjeAtO9AVzQsK80e+GXxjyb7rv1IKSt9eFUfev1jCuR
 lws3+QhwamGrxh7sFG4NFaWkZmmj5SSPTMqI+GCjm1VTL+vb3rh0MBjgn9/RNPux
 lEhscgEmq0w3BJPX08G8tZ4yipZbO4ZMmuQC3Gx2iPqO80xJqD+XpD5jz4MciGBC
 MDfWMamlnGk3n1sb4TIm0vPCtkz471DX5TyVLPLatcPnwWtu1zH380BD9HGVfnBN
 Fommp6YKvlpOCHOgl4vNg9pLKyUAukQbM8V0lPfk3NWQdswABmzDYJqh4HJWADxT
 uLiW8VgDfeq7CVPL+wwfWV3S9edu/REZa2f9y6qV/3eCyK0XId2CVHr8WpqbQIOR
 p6jjJHfzPNU=
 =mYqq
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-5.8b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

Second set of new device support, cleanups and features for IIO in the 5.8 cycle

Usual mixed back but with a few subsystem wide or device type
wide cleanups.

New device support

* adis16475
  - New driver supporting adis16470, adis16475, adis16477, adis16465,
    adis16467, adis16500, adis16505 and adis16507.
    Includes some rework of the adis library to simplify using it
    for this new driver.
* ak8974
  - Add support for Alps hscdt008a. ID only. Related patches add support
    for scale.
* atlas-sensor
  - Add support for RTD-SM OEM temperature sensor.
* cm32181
  - Add support for CM3218 including support for SMBUS alert via
    ACPI resources.
* ltc2632
  - Add support for ltc2634-12/10/8 DACS including handling per
    device type numbers of channels.

Major Features

* cm32181
  - ACPI bindings including parsing CPM0 and CPM1 custom ACPI tables.
    Includes minor tidy ups and fixes.
* vcnl4000
  - Add event support
  - Add buffered data capture support
  - Add control of sampling frequency

Cleanups and minor fixes.

* core
  - Trivial rework of iio_device_alloc to use an early return and
    improve readability.
  - Precursors to addition of multiple buffer support. So far
    minor refactoring.
* subsystem wide
  - Use get_unaligned_be24 slightly improve readability over open
    coding it.
* adis drivers
  - Use iio_get_debugfs_dentry access function.
* bh1780, cm32181, cm3232, gp2ap02a00f, opt3001, st_uvis25, vl6180,
  dmard06, kxsd9
  - Drop use of of_match_ptr to allow ACPI based probing via PRP0001.
    Part of clear out of this to avoid cut and paste into new drivers.
* ad5592r, ad5593r
  - Fix typos
* ad5933
  - Use managed interfaces to automate error handling and remove.
* ak8974
  - Fix wrong number of 'real bits' for buffered data.
  - Refactor to pull measurement code out as separate function.
    bmp280
  - Fix lack of clamp on range during data capture.
* at91-sama5d2_adc
  - Handle unfinished conversions correctly.
  - Allow use of triggers other than it's own.
  - Reorganize buffer setup and tear down as part of long running
    subsystem wide rework.
* ccs811
  - Add DT binding docs and match table.
  - Support external reset and wakeup pins.
* hid-sensors
  - Reorganize buffer setup and tear down as part of long running
    subsystem wide rework.
* ltr501
  - Constify some structs.
* vcnl4000
  - Fix an endian issue by using explicit byte swapped i2c accessors.

* tag 'iio-for-5.8b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (74 commits)
  iio: light: ltr501: Constify structs
  staging: iio: ad5933: attach life-cycle of kfifo buffer to parent device and use managed calls throughout
  iio: bmp280: fix compensation of humidity
  iio: light: cm32181: Fix integartion time typo
  iio: light: cm32181: Add support for parsing CPM0 and CPM1 ACPI tables
  iio: light: cm32181: Make lux_per_bit and lux_per_bit_base_it runtime settings
  iio: light: cm32181: Use units of 1/100000th for calibscale and lux_per_bit
  iio: light: cm32181: Change reg_init to use a bitmap of which registers to init
  iio: light: cm32181: Handle CM3218 ACPI devices with 2 I2C resources
  iio: light: cm32181: Clean up the probe function a bit
  iio: light: cm32181: Add support for the CM3218
  iio: light: cm32181: Add some extra register defines
  iio: light: cm32181: Add support for ACPI enumeration
  iio: light: cm32181: Switch to new style i2c-driver probe function
  iio: hid-sensors: move triggered buffer setup into hid_sensor_setup_trigger
  iio: vcnl4000: Add buffer support for VCNL4010/20.
  iio: vcnl4000: Add sampling frequency support for VCNL4010/20.
  iio: vcnl4000: Add event support for VCNL4010/20.
  iio: vcnl4000: Factorize data reading and writing.
  iio: vcnl4000: Fix i2c swapped word reading.
  ...
alistair/sunxi64-5.8
Greg Kroah-Hartman 2020-05-15 16:03:28 +02:00
commit cef077e6aa
72 changed files with 3471 additions and 662 deletions

View File

@ -0,0 +1,53 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/chemical/ams,ccs811.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: AMS CCS811 VOC Sensor
maintainers:
- Narcisa Vasile <narcisaanamaria12@gmail.com>
description: |
Ultra-Low Power Digital Gas Sensor for Monitoring Indoor Air Quality.
properties:
compatible:
enum:
- ams,ccs811
reg:
maxItems: 1
reset-gpios:
description: GPIO connected to the nRESET line. This is an active low
input to CCS811.
maxItems: 1
wakeup-gpios:
description: GPIO connected to the nWAKE line. This is an active low
input to CCS811.
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
voc@5b {
compatible = "ams,ccs811";
reg = <0x5b>;
reset-gpios = <&gpioa 11 GPIO_ACTIVE_LOW>;
wakeup-gpios = <&gpioa 12 GPIO_ACTIVE_LOW>;
};
};
...

View File

@ -17,6 +17,7 @@ description: |
http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/RTD_oem_datasheet.pdf
properties:
compatible:
@ -25,6 +26,7 @@ properties:
- atlas,ec-sm
- atlas,orp-sm
- atlas,ph-sm
- atlas,rtd-sm
reg:
maxItems: 1

View File

@ -1,4 +1,4 @@
Linear Technology LTC2632/2636 DAC
Linear Technology LTC2632/2634/2636 DAC
Required properties:
- compatible: Has to contain one of the following:
@ -8,6 +8,12 @@ Required properties:
lltc,ltc2632-h12
lltc,ltc2632-h10
lltc,ltc2632-h8
lltc,ltc2634-l12
lltc,ltc2634-l10
lltc,ltc2634-l8
lltc,ltc2634-h12
lltc,ltc2634-h10
lltc,ltc2634-h8
lltc,ltc2636-l12
lltc,ltc2636-l10
lltc,ltc2636-l8

View File

@ -0,0 +1,137 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADIS16475 and similar IMUs
maintainers:
- Nuno Sá <nuno.sa@analog.com>
description: |
Analog Devices ADIS16475 and similar IMUs
https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
properties:
compatible:
enum:
- adi,adis16475-1
- adi,adis16475-2
- adi,adis16475-3
- adi,adis16477-1
- adi,adis16477-2
- adi,adis16477-3
- adi,adis16470
- adi,adis16465-1
- adi,adis16465-2
- adi,adis16465-3
- adi,adis16467-1
- adi,adis16467-2
- adi,adis16467-3
- adi,adis16500
- adi,adis16505-1
- adi,adis16505-2
- adi,adis16505-3
- adi,adis16507-1
- adi,adis16507-2
- adi,adis16507-3
reg:
maxItems: 1
spi-cpha: true
spi-cpol: true
spi-max-frequency:
maximum: 2000000
interrupts:
maxItems: 1
clocks:
maxItems: 1
reset-gpios:
description:
Must be the device tree identifier of the RESET pin. If specified,
it will be asserted during driver probe. As the line is active low,
it should be marked GPIO_ACTIVE_LOW.
maxItems: 1
adi,sync-mode:
description:
Configures the device SYNC pin. The following modes are supported
0 - output_sync
1 - direct_sync
2 - scaled_sync
3 - pulse_sync
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 3
adi,scaled-output-hz:
description:
This property must be present if the clock mode is scaled-sync through
clock-names property. In this mode, the input clock can have a range
of 1Hz to 128HZ which must be scaled to originate an allowable sample
rate. This property specifies that rate.
minimum: 1900
maximum: 2100
required:
- compatible
- reg
- interrupts
- spi-cpha
- spi-cpol
allOf:
- if:
properties:
compatible:
contains:
enum:
- adi,adis16500
- adi,adis16505-1
- adi,adis16505-2
- adi,adis16505-3
- adi,adis16507-1
- adi,adis16507-2
- adi,adis16507-3
then:
properties:
adi,sync-mode:
minimum: 0
maximum: 2
- if:
properties:
adi,sync-mode:
enum: [1, 2, 3]
then:
dependencies:
adi,sync-mode: [ clocks ]
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adis16475: adis16475-3@0 {
compatible = "adi,adis16475-3";
reg = <0>;
spi-cpha;
spi-cpol;
spi-max-frequency = <2000000>;
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio>;
};
};
...

View File

@ -2,7 +2,9 @@
Required properties:
- compatible : should be "asahi-kasei,ak8974"
- compatible:
* "asahi-kasei,ak8974"
* "alps,hscdtd008a"
- reg : the I2C address of the magnetometer
Optional properties:

View File

@ -1031,6 +1031,14 @@ W: http://ez.analog.com/community/linux-device-drivers
F: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
F: drivers/iio/imu/adis16460.c
ANALOG DEVICES INC ADIS16475 DRIVER
M: Nuno Sa <nuno.sa@analog.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/imu/adis16475.c
F: Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
ANALOG DEVICES INC ADM1177 DRIVER
M: Beniamin Bia <beniamin.bia@analog.com>
M: Michael Hennerich <Michael.Hennerich@analog.com>

View File

@ -6,6 +6,7 @@
*/
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@ -226,7 +227,7 @@ static struct i2c_driver dmard06_driver = {
.id_table = dmard06_id,
.driver = {
.name = DMARD06_DRV_NAME,
.of_match_table = of_match_ptr(dmard06_of_match),
.of_match_table = dmard06_of_match,
.pm = DMARD06_PM_OPS,
},
};

View File

@ -14,8 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum accel_3d_channel {
@ -391,18 +389,13 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&accel_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&accel_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
goto error_free_dev_mem;
}
ret = iio_device_register(indio_dev);
@ -426,9 +419,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&accel_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
@ -443,8 +434,7 @@ static int hid_accel_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&accel_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
kfree(indio_dev->channels);
return 0;

View File

@ -2,6 +2,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
@ -36,15 +37,11 @@ static int kxsd9_i2c_remove(struct i2c_client *client)
return kxsd9_common_remove(&client->dev);
}
#ifdef CONFIG_OF
static const struct of_device_id kxsd9_of_match[] = {
{ .compatible = "kionix,kxsd9", },
{ },
};
MODULE_DEVICE_TABLE(of, kxsd9_of_match);
#else
#define kxsd9_of_match NULL
#endif
static const struct i2c_device_id kxsd9_i2c_id[] = {
{"kxsd9", 0},
@ -55,7 +52,7 @@ MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id);
static struct i2c_driver kxsd9_i2c_driver = {
.driver = {
.name = "kxsd9",
.of_match_table = of_match_ptr(kxsd9_of_match),
.of_match_table = kxsd9_of_match,
.pm = &kxsd9_dev_pm_ops,
},
.probe = kxsd9_i2c_probe,

View File

@ -309,7 +309,7 @@ static int ad7476_probe(struct spi_device *spi)
indio_dev->num_channels = 2;
indio_dev->info = &ad7476_info;
if (st->convst_gpio && st->chip_info->convst_channel)
if (st->convst_gpio)
indio_dev->channels = st->chip_info->convst_channel;
/* Setup default message */

View File

@ -70,9 +70,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
switch (size) {
case 3:
data[1] = val >> 16;
data[2] = val >> 8;
data[3] = val;
put_unaligned_be24(val, &data[1]);
break;
case 2:
put_unaligned_be16(val, &data[1]);
@ -157,9 +155,7 @@ int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
*val = get_unaligned_be32(sigma_delta->data);
break;
case 3:
*val = (sigma_delta->data[0] << 16) |
(sigma_delta->data[1] << 8) |
sigma_delta->data[2];
*val = get_unaligned_be24(&sigma_delta->data[0]);
break;
case 2:
*val = get_unaligned_be16(sigma_delta->data);

View File

@ -8,6 +8,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
@ -100,6 +101,8 @@
#define AT91_SAMA5D2_IER_YRDY BIT(21)
/* Interrupt Enable Register - TS pressure measurement ready */
#define AT91_SAMA5D2_IER_PRDY BIT(22)
/* Interrupt Enable Register - Data ready */
#define AT91_SAMA5D2_IER_DRDY BIT(24)
/* Interrupt Enable Register - general overrun error */
#define AT91_SAMA5D2_IER_GOVRE BIT(25)
/* Interrupt Enable Register - Pen detect */
@ -486,6 +489,21 @@ static inline int at91_adc_of_xlate(struct iio_dev *indio_dev,
return at91_adc_chan_xlate(indio_dev, iiospec->args[0]);
}
static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev)
{
u32 mask = 0;
u8 bit;
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
struct iio_chan_spec const *chan =
at91_adc_chan_get(indio_dev, bit);
mask |= BIT(chan->channel);
}
return mask & GENMASK(11, 0);
}
static void at91_adc_config_emr(struct at91_adc_state *st)
{
/* configure the extended mode register */
@ -710,7 +728,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(indio);
u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR);
u8 bit;
/* clear TRGMOD */
status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK;
@ -721,50 +738,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
/* set/unset hw trigger */
at91_adc_writel(st, AT91_SAMA5D2_TRGR, status);
for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit);
u32 cor;
if (!chan)
continue;
/* these channel types cannot be handled by this trigger */
if (chan->type == IIO_POSITIONRELATIVE ||
chan->type == IIO_PRESSURE)
continue;
if (state) {
cor = at91_adc_readl(st, AT91_SAMA5D2_COR);
if (chan->differential)
cor |= (BIT(chan->channel) |
BIT(chan->channel2)) <<
AT91_SAMA5D2_COR_DIFF_OFFSET;
else
cor &= ~(BIT(chan->channel) <<
AT91_SAMA5D2_COR_DIFF_OFFSET);
at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
}
if (state) {
at91_adc_writel(st, AT91_SAMA5D2_CHER,
BIT(chan->channel));
/* enable irq only if not using DMA */
if (!st->dma_st.dma_chan) {
at91_adc_writel(st, AT91_SAMA5D2_IER,
BIT(chan->channel));
}
} else {
/* disable irq only if not using DMA */
if (!st->dma_st.dma_chan) {
at91_adc_writel(st, AT91_SAMA5D2_IDR,
BIT(chan->channel));
}
at91_adc_writel(st, AT91_SAMA5D2_CHDR,
BIT(chan->channel));
}
}
return 0;
}
@ -781,6 +754,7 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig)
/* Needed to ACK the DRDY interruption */
at91_adc_readl(st, AT91_SAMA5D2_LCDR);
return 0;
}
@ -888,18 +862,37 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev)
return 0;
}
static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
static bool at91_adc_buffer_check_use_irq(struct iio_dev *indio,
struct at91_adc_state *st)
{
/* if using DMA, we do not use our own IRQ (we use DMA-controller) */
if (st->dma_st.dma_chan)
return false;
/* if the trigger is not ours, then it has its own IRQ */
if (iio_trigger_validate_own_device(indio->trig, indio))
return false;
return true;
}
static bool at91_adc_current_chan_is_touch(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
return !!bitmap_subset(indio_dev->active_scan_mask,
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1);
}
static int at91_adc_buffer_preenable(struct iio_dev *indio_dev)
{
int ret;
u8 bit;
struct at91_adc_state *st = iio_priv(indio_dev);
/* check if we are enabling triggered buffer or the touchscreen */
if (bitmap_subset(indio_dev->active_scan_mask,
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen enabling */
if (at91_adc_current_chan_is_touch(indio_dev))
return at91_adc_configure_touch(st, true);
}
/* if we are not in triggered mode, we cannot enable the buffer. */
if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
return -EINVAL;
@ -911,41 +904,65 @@ static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
return ret;
}
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
struct iio_chan_spec const *chan =
at91_adc_chan_get(indio_dev, bit);
u32 cor;
if (!chan)
continue;
/* these channel types cannot be handled by this trigger */
if (chan->type == IIO_POSITIONRELATIVE ||
chan->type == IIO_PRESSURE)
continue;
cor = at91_adc_readl(st, AT91_SAMA5D2_COR);
if (chan->differential)
cor |= (BIT(chan->channel) | BIT(chan->channel2)) <<
AT91_SAMA5D2_COR_DIFF_OFFSET;
else
cor &= ~(BIT(chan->channel) <<
AT91_SAMA5D2_COR_DIFF_OFFSET);
at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
}
if (at91_adc_buffer_check_use_irq(indio_dev, st))
at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_DRDY);
return 0;
}
static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
{
if (at91_adc_current_chan_is_touch(indio_dev))
return 0;
return iio_triggered_buffer_postenable(indio_dev);
}
static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
int ret;
u8 bit;
/* check if we are disabling triggered buffer or the touchscreen */
if (bitmap_subset(indio_dev->active_scan_mask,
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen disable */
if (at91_adc_current_chan_is_touch(indio_dev))
return at91_adc_configure_touch(st, false);
}
/* if we are not in triggered mode, nothing to do here */
if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
return -EINVAL;
/* continue with the triggered buffer */
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret < 0)
dev_err(&indio_dev->dev, "buffer predisable failed\n");
if (!st->dma_st.dma_chan)
return ret;
/* if we are using DMA we must clear registers and end DMA */
dmaengine_terminate_sync(st->dma_st.dma_chan);
/*
* For each enabled channel we must read the last converted value
* For each enable channel we must disable it in hardware.
* In the case of DMA, we must read the last converted value
* to clear EOC status and not get a possible interrupt later.
* This value is being read by DMA from LCDR anyway
* This value is being read by DMA from LCDR anyway, so it's not lost.
*/
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
@ -958,16 +975,37 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
if (chan->type == IIO_POSITIONRELATIVE ||
chan->type == IIO_PRESSURE)
continue;
at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
if (st->dma_st.dma_chan)
at91_adc_readl(st, chan->address);
}
if (at91_adc_buffer_check_use_irq(indio_dev, st))
at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_DRDY);
/* read overflow register to clear possible overflow status */
at91_adc_readl(st, AT91_SAMA5D2_OVER);
return ret;
/* if we are using DMA we must clear registers and end DMA */
if (st->dma_st.dma_chan)
dmaengine_terminate_sync(st->dma_st.dma_chan);
return 0;
}
static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
{
if (at91_adc_current_chan_is_touch(indio_dev))
return 0;
return iio_triggered_buffer_predisable(indio_dev);
}
static const struct iio_buffer_setup_ops at91_buffer_setup_ops = {
.preenable = &at91_adc_buffer_preenable,
.postdisable = &at91_adc_buffer_postdisable,
.postenable = &at91_adc_buffer_postenable,
.predisable = &at91_adc_buffer_predisable,
};
@ -1015,6 +1053,22 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
int i = 0;
int val;
u8 bit;
u32 mask = at91_adc_active_scan_mask_to_reg(indio_dev);
unsigned int timeout = 50;
/*
* Check if the conversion is ready. If not, wait a little bit, and
* in case of timeout exit with an error.
*/
while ((at91_adc_readl(st, AT91_SAMA5D2_ISR) & mask) != mask &&
timeout) {
usleep_range(50, 100);
timeout--;
}
/* Cannot read data, not ready. Continue without reporting data */
if (!timeout)
return;
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
@ -1102,6 +1156,13 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(indio_dev);
/*
* If it's not our trigger, start a conversion now, as we are
* actually polling the trigger now.
*/
if (iio_trigger_validate_own_device(indio_dev->trig, indio_dev))
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
if (st->dma_st.dma_chan)
at91_adc_trigger_handler_dma(indio_dev);
else
@ -1114,20 +1175,9 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
static int at91_adc_buffer_init(struct iio_dev *indio)
{
struct at91_adc_state *st = iio_priv(indio);
if (st->selected_trig->hw_trig) {
return devm_iio_triggered_buffer_setup(&indio->dev, indio,
&iio_pollfunc_store_time,
&at91_adc_trigger_handler, &at91_buffer_setup_ops);
}
/*
* we need to prepare the buffer ops in case we will get
* another buffer attached (like a callback buffer for the touchscreen)
*/
indio->setup_ops = &at91_buffer_setup_ops;
return 0;
return devm_iio_triggered_buffer_setup(&indio->dev, indio,
&iio_pollfunc_store_time,
&at91_adc_trigger_handler, &at91_buffer_setup_ops);
}
static unsigned at91_adc_startup_time(unsigned startup_time_min,
@ -1281,7 +1331,8 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
status = at91_adc_readl(st, AT91_SAMA5D2_XPOSR);
status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR);
status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
} else if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) {
} else if (iio_buffer_enabled(indio) &&
(status & AT91_SAMA5D2_IER_DRDY)) {
/* triggered buffer without DMA */
disable_irq_nosync(irq);
iio_trigger_poll(indio->trig);
@ -1901,14 +1952,10 @@ static __maybe_unused int at91_adc_resume(struct device *dev)
return 0;
/* check if we are enabling triggered buffer or the touchscreen */
if (bitmap_subset(indio_dev->active_scan_mask,
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen enabling */
if (at91_adc_current_chan_is_touch(indio_dev))
return at91_adc_configure_touch(st, true);
} else {
else
return at91_adc_configure_trigger(st->trig, true);
}
/* not needed but more explicit */
return 0;

View File

@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/sysfs.h>
#include <linux/of.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -117,11 +118,11 @@ static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config)
if (sample_rate == MCP3422_SRATE_3) {
ret = i2c_master_recv(adc->i2c, buf, 4);
temp = buf[0] << 16 | buf[1] << 8 | buf[2];
temp = get_unaligned_be24(&buf[0]);
*config = buf[3];
} else {
ret = i2c_master_recv(adc->i2c, buf, 3);
temp = buf[0] << 8 | buf[1];
temp = get_unaligned_be16(&buf[0]);
*config = buf[2];
}

View File

@ -22,6 +22,8 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h>
#include <asm/unaligned.h>
/* Commands */
#define ADS124S08_CMD_NOP 0x00
#define ADS124S08_CMD_WAKEUP 0x02
@ -188,7 +190,6 @@ static int ads124s_read(struct iio_dev *indio_dev, unsigned int chan)
{
struct ads124s_private *priv = iio_priv(indio_dev);
int ret;
u32 tmp;
struct spi_transfer t[] = {
{
.tx_buf = &priv->data[0],
@ -208,9 +209,7 @@ static int ads124s_read(struct iio_dev *indio_dev, unsigned int chan)
if (ret < 0)
return ret;
tmp = priv->data[2] << 16 | priv->data[3] << 8 | priv->data[4];
return tmp;
return get_unaligned_be24(&priv->data[2]);
}
static int ads124s_read_raw(struct iio_dev *indio_dev,

View File

@ -53,6 +53,8 @@
#define ATLAS_REG_DO_CALIB_STATUS_PRESSURE BIT(0)
#define ATLAS_REG_DO_CALIB_STATUS_DO BIT(1)
#define ATLAS_REG_RTD_DATA 0x0e
#define ATLAS_REG_PH_TEMP_DATA 0x0e
#define ATLAS_REG_PH_DATA 0x16
@ -72,12 +74,14 @@
#define ATLAS_EC_INT_TIME_IN_MS 650
#define ATLAS_ORP_INT_TIME_IN_MS 450
#define ATLAS_DO_INT_TIME_IN_MS 450
#define ATLAS_RTD_INT_TIME_IN_MS 450
enum {
ATLAS_PH_SM,
ATLAS_EC_SM,
ATLAS_ORP_SM,
ATLAS_DO_SM,
ATLAS_RTD_SM,
};
struct atlas_data {
@ -206,6 +210,22 @@ static const struct iio_chan_spec atlas_do_channels[] = {
},
};
static const struct iio_chan_spec atlas_rtd_channels[] = {
{
.type = IIO_TEMP,
.address = ATLAS_REG_RTD_DATA,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static int atlas_check_ph_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
@ -350,6 +370,12 @@ static struct atlas_device atlas_devices[] = {
.calibration = &atlas_check_do_calibration,
.delay = ATLAS_DO_INT_TIME_IN_MS,
},
[ATLAS_RTD_SM] = {
.channels = atlas_rtd_channels,
.num_channels = 2,
.data_reg = ATLAS_REG_RTD_DATA,
.delay = ATLAS_RTD_INT_TIME_IN_MS,
},
};
static int atlas_set_powermode(struct atlas_data *data, int on)
@ -477,6 +503,7 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
struct atlas_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
case IIO_CHAN_INFO_RAW: {
int ret;
__be32 reg;
@ -565,6 +592,7 @@ static const struct i2c_device_id atlas_id[] = {
{ "atlas-ec-sm", ATLAS_EC_SM},
{ "atlas-orp-sm", ATLAS_ORP_SM},
{ "atlas-do-sm", ATLAS_DO_SM},
{ "atlas-rtd-sm", ATLAS_RTD_SM},
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
@ -574,6 +602,7 @@ static const struct of_device_id atlas_dt_ids[] = {
{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
{ .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
{ .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, },
{ .compatible = "atlas,rtd-sm", .data = (void *)ATLAS_RTD_SM, },
{ }
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);

View File

@ -16,6 +16,7 @@
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@ -36,6 +37,7 @@
#define CCS811_ERR 0xE0
/* Used to transition from boot to application mode */
#define CCS811_APP_START 0xF4
#define CCS811_SW_RESET 0xFF
/* Status register flags */
#define CCS811_STATUS_ERROR BIT(0)
@ -74,6 +76,7 @@ struct ccs811_data {
struct mutex lock; /* Protect readings */
struct ccs811_reading buffer;
struct iio_trigger *drdy_trig;
struct gpio_desc *wakeup_gpio;
bool drdy_trig_on;
};
@ -166,10 +169,25 @@ static int ccs811_setup(struct i2c_client *client)
CCS811_MODE_IAQ_1SEC);
}
static void ccs811_set_wakeup(struct ccs811_data *data, bool enable)
{
if (!data->wakeup_gpio)
return;
gpiod_set_value(data->wakeup_gpio, enable);
if (enable)
usleep_range(50, 60);
else
usleep_range(20, 30);
}
static int ccs811_get_measurement(struct ccs811_data *data)
{
int ret, tries = 11;
ccs811_set_wakeup(data, true);
/* Maximum waiting time: 1s, as measurements are made every second */
while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS);
@ -183,9 +201,12 @@ static int ccs811_get_measurement(struct ccs811_data *data)
if (!(ret & CCS811_STATUS_DATA_READY))
return -EIO;
return i2c_smbus_read_i2c_block_data(data->client,
ret = i2c_smbus_read_i2c_block_data(data->client,
CCS811_ALG_RESULT_DATA, 8,
(char *)&data->buffer);
ccs811_set_wakeup(data, false);
return ret;
}
static int ccs811_read_raw(struct iio_dev *indio_dev,
@ -336,6 +357,45 @@ static irqreturn_t ccs811_data_rdy_trigger_poll(int irq, void *private)
return IRQ_HANDLED;
}
static int ccs811_reset(struct i2c_client *client)
{
struct gpio_desc *reset_gpio;
int ret;
reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
/* Try to reset using nRESET pin if available else do SW reset */
if (reset_gpio) {
gpiod_set_value(reset_gpio, 1);
usleep_range(20, 30);
gpiod_set_value(reset_gpio, 0);
} else {
/*
* As per the datasheet, this sequence of values needs to be
* written to the SW_RESET register for triggering the soft
* reset in the device and placing it in boot mode.
*/
static const u8 reset_seq[] = {
0x11, 0xE5, 0x72, 0x8A,
};
ret = i2c_smbus_write_i2c_block_data(client, CCS811_SW_RESET,
sizeof(reset_seq), reset_seq);
if (ret < 0) {
dev_err(&client->dev, "Failed to reset sensor\n");
return ret;
}
}
/* tSTART delay required after reset */
usleep_range(1000, 2000);
return 0;
}
static int ccs811_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -348,37 +408,60 @@ static int ccs811_probe(struct i2c_client *client,
| I2C_FUNC_SMBUS_READ_I2C_BLOCK))
return -EOPNOTSUPP;
/* Check hardware id (should be 0x81 for this family of devices) */
ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
if (ret < 0)
return ret;
if (ret != CCS811_HW_ID_VALUE) {
dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
return -ENODEV;
}
ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
if (ret < 0)
return ret;
if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
dev_err(&client->dev, "no CCS811 sensor\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
ret = ccs811_setup(client);
if (ret < 0)
return ret;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->wakeup_gpio = devm_gpiod_get_optional(&client->dev, "wakeup",
GPIOD_OUT_HIGH);
if (IS_ERR(data->wakeup_gpio))
return PTR_ERR(data->wakeup_gpio);
ccs811_set_wakeup(data, true);
ret = ccs811_reset(client);
if (ret) {
ccs811_set_wakeup(data, false);
return ret;
}
/* Check hardware id (should be 0x81 for this family of devices) */
ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
if (ret < 0) {
ccs811_set_wakeup(data, false);
return ret;
}
if (ret != CCS811_HW_ID_VALUE) {
dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
ccs811_set_wakeup(data, false);
return -ENODEV;
}
ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
if (ret < 0) {
ccs811_set_wakeup(data, false);
return ret;
}
if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
dev_err(&client->dev, "no CCS811 sensor\n");
ccs811_set_wakeup(data, false);
return -ENODEV;
}
ret = ccs811_setup(client);
if (ret < 0) {
ccs811_set_wakeup(data, false);
return ret;
}
ccs811_set_wakeup(data, false);
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
@ -466,9 +549,16 @@ static const struct i2c_device_id ccs811_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ccs811_id);
static const struct of_device_id ccs811_dt_ids[] = {
{ .compatible = "ams,ccs811" },
{ }
};
MODULE_DEVICE_TABLE(of, ccs811_dt_ids);
static struct i2c_driver ccs811_driver = {
.driver = {
.name = "ccs811",
.of_match_table = ccs811_dt_ids,
},
.probe = ccs811_probe,
.remove = ccs811_remove,

View File

@ -13,6 +13,8 @@
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include "hid-sensor-trigger.h"
@ -222,7 +224,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state);
}
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
struct hid_sensor_common *attrb)
{
if (atomic_read(&attrb->runtime_pm_enable))
pm_runtime_disable(&attrb->pdev->dev);
@ -233,6 +236,7 @@ void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
cancel_work_sync(&attrb->work);
iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger);
iio_triggered_buffer_cleanup(indio_dev);
}
EXPORT_SYMBOL(hid_sensor_remove_trigger);
@ -246,11 +250,18 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
int ret;
struct iio_trigger *trig;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n");
return ret;
}
trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
if (trig == NULL) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
ret = -ENOMEM;
goto error_ret;
goto error_triggered_buffer_cleanup;
}
trig->dev.parent = indio_dev->dev.parent;
@ -284,7 +295,8 @@ error_unreg_trigger:
iio_trigger_unregister(trig);
error_free_trig:
iio_trigger_free(trig);
error_ret:
error_triggered_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
EXPORT_SYMBOL(hid_sensor_setup_trigger);

View File

@ -13,7 +13,8 @@ extern const struct dev_pm_ops hid_sensor_pm_ops;
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
struct hid_sensor_common *attrb);
int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
#endif

View File

@ -20,11 +20,6 @@
#include "st_sensors_core.h"
static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
}
int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
u8 reg_addr, u8 mask, u8 data)
{
@ -543,7 +538,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
else if (byte_for_channel == 2)
*data = (s16)get_unaligned_le16(outdata);
else if (byte_for_channel == 3)
*data = (s32)st_sensors_get_unaligned_le24(outdata);
*data = (s32)sign_extend32(get_unaligned_le24(outdata), 23);
st_sensors_free_memory:
kfree(outdata);

View File

@ -279,12 +279,12 @@ config LTC1660
module will be called ltc1660.
config LTC2632
tristate "Linear Technology LTC2632-12/10/8 and LTC2636-12/10/8 DAC spi driver"
tristate "Linear Technology LTC2632-12/10/8 and similar DAC spi driver"
depends on SPI
help
Say yes here to build support for Linear Technology
LTC2632-12, LTC2632-10, LTC2632-8, LTC2636-12, LTC2636-10 and
LTC2636-8 converters (DAC).
LTC2632, LTC2634 and LTC2636 DAC resolution 12/10/8 bit
low 0-2.5V and high 0-4.096V range converters.
To compile this driver as a module, choose M here: the
module will be called ltc2632.

View File

@ -21,6 +21,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <asm/unaligned.h>
#define MODE_PWRDWN_1k 0x1
#define MODE_PWRDWN_100k 0x2
#define MODE_PWRDWN_TRISTATE 0x3
@ -302,9 +304,7 @@ static int ad5660_write(struct ad5446_state *st, unsigned val)
struct spi_device *spi = to_spi_device(st->dev);
uint8_t data[3];
data[0] = (val >> 16) & 0xFF;
data[1] = (val >> 8) & 0xFF;
data[2] = val & 0xFF;
put_unaligned_be24(val, &data[0]);
return spi_write(spi, data, sizeof(data));
}

View File

@ -98,7 +98,7 @@ static int ad5592r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
return 0;
}
static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
static int ad5592r_gpio_read(struct ad5592r_state *st, u8 *value)
{
int ret;
@ -121,7 +121,7 @@ static const struct ad5592r_rw_ops ad5592r_rw_ops = {
.read_adc = ad5592r_read_adc,
.reg_write = ad5592r_reg_write,
.reg_read = ad5592r_reg_read,
.gpio_read = ad5593r_gpio_read,
.gpio_read = ad5592r_gpio_read,
};
static int ad5592r_spi_probe(struct spi_device *spi)

View File

@ -134,5 +134,5 @@ static struct i2c_driver ad5593r_driver = {
module_i2c_driver(ad5593r_driver);
MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
MODULE_DESCRIPTION("Analog Devices AD5593R multi-channel converters");
MODULE_LICENSE("GPL v2");

View File

@ -18,6 +18,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <asm/unaligned.h>
#include "ad5624r.h"
static int ad5624r_spi_write(struct spi_device *spi,
@ -35,11 +37,9 @@ static int ad5624r_spi_write(struct spi_device *spi,
* for the AD5664R, AD5644R, and AD5624R, respectively.
*/
data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << shift);
msg[0] = data >> 16;
msg[1] = data >> 8;
msg[2] = data;
put_unaligned_be24(data, &msg[0]);
return spi_write(spi, msg, 3);
return spi_write(spi, msg, sizeof(msg));
}
static int ad5624r_read_raw(struct iio_dev *indio_dev,

View File

@ -12,6 +12,8 @@
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
#define LTC2632_CMD_WRITE_INPUT_N 0x0
#define LTC2632_CMD_UPDATE_DAC_N 0x1
#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2
@ -24,6 +26,7 @@
/**
* struct ltc2632_chip_info - chip specific information
* @channels: channel spec for the DAC
* @num_channels: DAC channel count of the chip
* @vref_mv: internal reference voltage
*/
struct ltc2632_chip_info {
@ -53,6 +56,12 @@ enum ltc2632_supported_device_ids {
ID_LTC2632H12,
ID_LTC2632H10,
ID_LTC2632H8,
ID_LTC2634L12,
ID_LTC2634L10,
ID_LTC2634L8,
ID_LTC2634H12,
ID_LTC2634H10,
ID_LTC2634H8,
ID_LTC2636L12,
ID_LTC2636L10,
ID_LTC2636L8,
@ -75,9 +84,7 @@ static int ltc2632_spi_write(struct spi_device *spi,
* 10-, 8-bit input code followed by 4, 6, or 8 don't care bits.
*/
data = (cmd << 20) | (addr << 16) | (val << shift);
msg[0] = data >> 16;
msg[1] = data >> 8;
msg[2] = data;
put_unaligned_be24(data, &msg[0]);
return spi_write(spi, msg, sizeof(msg));
}
@ -235,6 +242,36 @@ static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = {
.num_channels = 2,
.vref_mv = 4096,
},
[ID_LTC2634L12] = {
.channels = ltc2632x12_channels,
.num_channels = 4,
.vref_mv = 2500,
},
[ID_LTC2634L10] = {
.channels = ltc2632x10_channels,
.num_channels = 4,
.vref_mv = 2500,
},
[ID_LTC2634L8] = {
.channels = ltc2632x8_channels,
.num_channels = 4,
.vref_mv = 2500,
},
[ID_LTC2634H12] = {
.channels = ltc2632x12_channels,
.num_channels = 4,
.vref_mv = 4096,
},
[ID_LTC2634H10] = {
.channels = ltc2632x10_channels,
.num_channels = 4,
.vref_mv = 4096,
},
[ID_LTC2634H8] = {
.channels = ltc2632x8_channels,
.num_channels = 4,
.vref_mv = 4096,
},
[ID_LTC2636L12] = {
.channels = ltc2632x12_channels,
.num_channels = 8,
@ -356,6 +393,12 @@ static const struct spi_device_id ltc2632_id[] = {
{ "ltc2632-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H12] },
{ "ltc2632-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H10] },
{ "ltc2632-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H8] },
{ "ltc2634-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L12] },
{ "ltc2634-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L10] },
{ "ltc2634-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L8] },
{ "ltc2634-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H12] },
{ "ltc2634-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H10] },
{ "ltc2634-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H8] },
{ "ltc2636-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L12] },
{ "ltc2636-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L10] },
{ "ltc2636-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L8] },
@ -385,6 +428,24 @@ static const struct of_device_id ltc2632_of_match[] = {
}, {
.compatible = "lltc,ltc2632-h8",
.data = &ltc2632_chip_info_tbl[ID_LTC2632H8]
}, {
.compatible = "lltc,ltc2634-l12",
.data = &ltc2632_chip_info_tbl[ID_LTC2634L12]
}, {
.compatible = "lltc,ltc2634-l10",
.data = &ltc2632_chip_info_tbl[ID_LTC2634L10]
}, {
.compatible = "lltc,ltc2634-l8",
.data = &ltc2632_chip_info_tbl[ID_LTC2634L8]
}, {
.compatible = "lltc,ltc2634-h12",
.data = &ltc2632_chip_info_tbl[ID_LTC2634H12]
}, {
.compatible = "lltc,ltc2634-h10",
.data = &ltc2632_chip_info_tbl[ID_LTC2634H10]
}, {
.compatible = "lltc,ltc2634-h8",
.data = &ltc2632_chip_info_tbl[ID_LTC2634H8]
}, {
.compatible = "lltc,ltc2636-l12",
.data = &ltc2632_chip_info_tbl[ID_LTC2636L12]

View File

@ -12,6 +12,8 @@
#include <linux/iio/iio.h>
#include <asm/unaligned.h>
#define ADIS16130_CON 0x0
#define ADIS16130_CON_RD (1 << 6)
#define ADIS16130_IOP 0x1
@ -59,7 +61,7 @@ static int adis16130_spi_read(struct iio_dev *indio_dev, u8 reg_addr, u32 *val)
ret = spi_sync_transfer(st->us, &xfer, 1);
if (ret == 0)
*val = (st->buf[1] << 16) | (st->buf[2] << 8) | st->buf[3];
*val = get_unaligned_be24(&st->buf[1]);
mutex_unlock(&st->buf_lock);
return ret;

View File

@ -148,16 +148,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(adis16136_flash_count_fops,
static int adis16136_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
struct dentry *d = iio_get_debugfs_dentry(indio_dev);
debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, adis16136,
&adis16136_serial_fops);
d, adis16136, &adis16136_serial_fops);
debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry,
adis16136, &adis16136_product_id_fops);
d, adis16136, &adis16136_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry,
adis16136, &adis16136_flash_count_fops);
d, adis16136, &adis16136_flash_count_fops);
return 0;
}

View File

@ -14,8 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum gyro_3d_channel {
@ -326,18 +324,13 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&gyro_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&gyro_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
goto error_free_dev_mem;
}
ret = iio_device_register(indio_dev);
@ -361,9 +354,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&gyro_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
@ -378,8 +369,7 @@ static int hid_gyro_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&gyro_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
kfree(indio_dev->channels);
return 0;

View File

@ -23,6 +23,8 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <asm/unaligned.h>
#include "afe440x.h"
#define AFE4403_DRIVER_NAME "afe4403"
@ -220,13 +222,11 @@ static int afe4403_read(struct afe4403_data *afe, unsigned int reg, u32 *val)
if (ret)
return ret;
ret = spi_write_then_read(afe->spi, &reg, 1, rx, 3);
ret = spi_write_then_read(afe->spi, &reg, 1, rx, sizeof(rx));
if (ret)
return ret;
*val = (rx[0] << 16) |
(rx[1] << 8) |
(rx[2]);
*val = get_unaligned_be24(&rx[0]);
/* Disable reading from the device */
tx[3] = AFE440X_CONTROL0_WRITE;
@ -322,13 +322,11 @@ static irqreturn_t afe4403_trigger_handler(int irq, void *private)
indio_dev->masklength) {
ret = spi_write_then_read(afe->spi,
&afe4403_channel_values[bit], 1,
rx, 3);
rx, sizeof(rx));
if (ret)
goto err;
buffer[i++] = (rx[0] << 16) |
(rx[1] << 8) |
(rx[2]);
buffer[i++] = get_unaligned_be24(&rx[0]);
}
/* Disable reading from the device */

View File

@ -7,8 +7,6 @@
#include <linux/hid-sensor-hub.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@ -233,12 +231,8 @@ static int hid_humidity_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev,
&iio_pollfunc_store_time, NULL, NULL);
if (ret)
return ret;
atomic_set(&humid_st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&humid_st->common_attributes);
if (ret)
@ -261,7 +255,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
error_remove_callback:
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
error_remove_trigger:
hid_sensor_remove_trigger(&humid_st->common_attributes);
hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes);
return ret;
}
@ -274,7 +268,7 @@ static int hid_humidity_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
hid_sensor_remove_trigger(&humid_st->common_attributes);
hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes);
return 0;
}

View File

@ -29,6 +29,19 @@ config ADIS16460
To compile this driver as a module, choose M here: the module will be
called adis16460.
config ADIS16475
tristate "Analog Devices ADIS16475 and similar IMU driver"
depends on SPI
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices ADIS16470, ADIS16475,
ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505, ADIS16507 inertial
sensors.
To compile this driver as a module, choose M here: the module will be
called adis16475.
config ADIS16480
tristate "Analog Devices ADIS16480 and similar IMU driver"
depends on SPI

View File

@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ADIS16400) += adis16400.o
obj-$(CONFIG_ADIS16460) += adis16460.o
obj-$(CONFIG_ADIS16475) += adis16475.o
obj-$(CONFIG_ADIS16480) += adis16480.o
adis_lib-y += adis.o

View File

@ -223,6 +223,31 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
return ret;
}
EXPORT_SYMBOL_GPL(__adis_read_reg);
/**
* __adis_update_bits_base() - ADIS Update bits function - Unlocked version
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @mask: Bitmask to change
* @val: Value to be written
* @size: Size of the register to update
*
* Updates the desired bits of @reg in accordance with @mask and @val.
*/
int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
const u32 val, u8 size)
{
int ret;
u32 __val;
ret = __adis_read_reg(adis, reg, &__val, size);
if (ret)
return ret;
__val = (__val & ~mask) | (val & mask);
return __adis_write_reg(adis, reg, __val, size);
}
EXPORT_SYMBOL_GPL(__adis_update_bits_base);
#ifdef CONFIG_DEBUG_FS

View File

@ -281,18 +281,16 @@ DEFINE_DEBUGFS_ATTRIBUTE(adis16400_flash_count_fops,
static int adis16400_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16400_state *st = iio_priv(indio_dev);
struct dentry *d = iio_get_debugfs_dentry(indio_dev);
if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER)
debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, st,
&adis16400_serial_number_fops);
d, st, &adis16400_serial_number_fops);
if (st->variant->flags & ADIS16400_HAS_PROD_ID)
debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry, st,
&adis16400_product_id_fops);
d, st, &adis16400_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry, st,
&adis16400_flash_count_fops);
d, st, &adis16400_flash_count_fops);
return 0;
}
@ -1195,7 +1193,7 @@ static int adis16400_probe(struct spi_device *spi)
indio_dev->available_scan_masks = st->avail_scan_mask;
st->adis.burst = &adis16400_burst;
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
st->adis.burst->extra_len = sizeof(u16);
st->adis.burst_extra_len = sizeof(u16);
}
adis16400_data = &st->variant->adis_data;

View File

@ -129,16 +129,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(adis16460_flash_count_fops,
static int adis16460_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16460 *adis16460 = iio_priv(indio_dev);
struct dentry *d = iio_get_debugfs_dentry(indio_dev);
debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, adis16460,
&adis16460_serial_number_fops);
d, adis16460, &adis16460_serial_number_fops);
debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry, adis16460,
&adis16460_product_id_fops);
d, adis16460, &adis16460_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry, adis16460,
&adis16460_flash_count_fops);
d, adis16460, &adis16460_flash_count_fops);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -284,22 +284,18 @@ DEFINE_DEBUGFS_ATTRIBUTE(adis16480_flash_count_fops,
static int adis16480_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16480 *adis16480 = iio_priv(indio_dev);
struct dentry *d = iio_get_debugfs_dentry(indio_dev);
debugfs_create_file_unsafe("firmware_revision", 0400,
indio_dev->debugfs_dentry, adis16480,
&adis16480_firmware_revision_fops);
d, adis16480, &adis16480_firmware_revision_fops);
debugfs_create_file_unsafe("firmware_date", 0400,
indio_dev->debugfs_dentry, adis16480,
&adis16480_firmware_date_fops);
d, adis16480, &adis16480_firmware_date_fops);
debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, adis16480,
&adis16480_serial_number_fops);
d, adis16480, &adis16480_serial_number_fops);
debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry, adis16480,
&adis16480_product_id_fops);
d, adis16480, &adis16480_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry, adis16480,
&adis16480_flash_count_fops);
d, adis16480, &adis16480_flash_count_fops);
return 0;
}

View File

@ -23,25 +23,30 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
unsigned int burst_length;
unsigned int burst_length, burst_max_length;
u8 *tx;
/* All but the timestamp channel */
burst_length = (indio_dev->num_channels - 1) * sizeof(u16);
burst_length += adis->burst->extra_len;
burst_length += adis->burst->extra_len + adis->burst_extra_len;
if (adis->burst->burst_max_len)
burst_max_length = adis->burst->burst_max_len;
else
burst_max_length = burst_length;
adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
if (!adis->xfer)
return -ENOMEM;
adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL);
adis->buffer = kzalloc(burst_max_length + sizeof(u16), GFP_KERNEL);
if (!adis->buffer) {
kfree(adis->xfer);
adis->xfer = NULL;
return -ENOMEM;
}
tx = adis->buffer + burst_length;
tx = adis->buffer + burst_max_length;
tx[0] = ADIS_READ_REG(adis->burst->reg_cmd);
tx[1] = 0;
@ -156,6 +161,14 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
return IRQ_HANDLED;
}
static void adis_buffer_cleanup(void *arg)
{
struct adis *adis = arg;
kfree(adis->buffer);
kfree(adis->xfer);
}
/**
* adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device
* @adis: The adis device.
@ -198,6 +211,43 @@ error_buffer_cleanup:
}
EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger);
/**
* devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for
* the managed adis device
* @adis: The adis device
* @indio_dev: The IIO device
* @trigger_handler: Optional trigger handler, may be NULL.
*
* Returns 0 on success, a negative error code otherwise.
*
* This function perfoms exactly the same as adis_setup_buffer_and_trigger()
*/
int
devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
irq_handler_t trigger_handler)
{
int ret;
if (!trigger_handler)
trigger_handler = adis_trigger_handler;
ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev,
&iio_pollfunc_store_time,
trigger_handler, NULL);
if (ret)
return ret;
if (adis->spi->irq) {
ret = devm_adis_probe_trigger(adis, indio_dev);
if (ret)
return ret;
}
return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup,
adis);
}
EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger);
/**
* adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources
* @adis: The adis device.

View File

@ -27,6 +27,34 @@ static const struct iio_trigger_ops adis_trigger_ops = {
.set_trigger_state = &adis_data_rdy_trigger_set_state,
};
static void adis_trigger_setup(struct adis *adis)
{
adis->trig->dev.parent = &adis->spi->dev;
adis->trig->ops = &adis_trigger_ops;
iio_trigger_set_drvdata(adis->trig, adis);
}
static int adis_validate_irq_flag(struct adis *adis)
{
/*
* Typically this devices have data ready either on the rising edge or
* on the falling edge of the data ready pin. This checks enforces that
* one of those is set in the drivers... It defaults to
* IRQF_TRIGGER_RISING for backward compatibility wiht devices that
* don't support changing the pin polarity.
*/
if (!adis->irq_flag) {
adis->irq_flag = IRQF_TRIGGER_RISING;
return 0;
} else if (adis->irq_flag != IRQF_TRIGGER_RISING &&
adis->irq_flag != IRQF_TRIGGER_FALLING) {
dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n",
adis->irq_flag);
return -EINVAL;
}
return 0;
}
/**
* adis_probe_trigger() - Sets up trigger for a adis device
* @adis: The adis device
@ -45,13 +73,15 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
if (adis->trig == NULL)
return -ENOMEM;
adis->trig->dev.parent = &adis->spi->dev;
adis->trig->ops = &adis_trigger_ops;
iio_trigger_set_drvdata(adis->trig, adis);
adis_trigger_setup(adis);
ret = adis_validate_irq_flag(adis);
if (ret)
return ret;
ret = request_irq(adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
adis->irq_flag,
indio_dev->name,
adis->trig);
if (ret)
@ -73,6 +103,40 @@ error_free_trig:
}
EXPORT_SYMBOL_GPL(adis_probe_trigger);
/**
* devm_adis_probe_trigger() - Sets up trigger for a managed adis device
* @adis: The adis device
* @indio_dev: The IIO device
*
* Returns 0 on success or a negative error code
*/
int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
{
int ret;
adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-dev%d",
indio_dev->name, indio_dev->id);
if (!adis->trig)
return -ENOMEM;
adis_trigger_setup(adis);
ret = adis_validate_irq_flag(adis);
if (ret)
return ret;
ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
adis->irq_flag,
indio_dev->name,
adis->trig);
if (ret)
return ret;
return devm_iio_trigger_register(&adis->spi->dev, adis->trig);
}
EXPORT_SYMBOL_GPL(devm_adis_probe_trigger);
/**
* adis_remove_trigger() - Remove trigger for a adis devices
* @adis: The adis device

View File

@ -27,7 +27,8 @@
* - FIFO size: 4KB
*
* - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX:
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416,
* 833
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 3KB
@ -791,7 +792,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
.odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
@ -804,7 +806,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
.odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
},
},
.fs_table = {
@ -994,7 +997,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
.odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
@ -1007,7 +1011,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
.odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
},
},
.fs_table = {
@ -1171,7 +1176,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
.odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
@ -1184,7 +1190,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
.odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
},
},
.fs_table = {

View File

@ -189,10 +189,12 @@ __poll_t iio_buffer_poll(struct file *filp,
*/
void iio_buffer_wakeup_poll(struct iio_dev *indio_dev)
{
if (!indio_dev->buffer)
struct iio_buffer *buffer = indio_dev->buffer;
if (!buffer)
return;
wake_up(&indio_dev->buffer->pollq);
wake_up(&buffer->pollq);
}
void iio_buffer_init(struct iio_buffer *buffer)
@ -262,10 +264,11 @@ static ssize_t iio_scan_el_show(struct device *dev,
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
/* Ensure ret is 0 or 1. */
ret = !!test_bit(to_iio_dev_attr(attr)->address,
indio_dev->buffer->scan_mask);
buffer->scan_mask);
return sprintf(buf, "%d\n", ret);
}
@ -381,7 +384,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->buffer)) {
if (iio_buffer_is_active(buffer)) {
ret = -EBUSY;
goto error_ret;
}
@ -410,7 +413,9 @@ static ssize_t iio_scan_el_ts_show(struct device *dev,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%d\n", indio_dev->buffer->scan_timestamp);
struct iio_buffer *buffer = indio_dev->buffer;
return sprintf(buf, "%d\n", buffer->scan_timestamp);
}
static ssize_t iio_scan_el_ts_store(struct device *dev,
@ -420,6 +425,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
bool state;
ret = strtobool(buf, &state);
@ -427,11 +433,11 @@ 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->buffer)) {
if (iio_buffer_is_active(buffer)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
buffer->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@ -439,10 +445,10 @@ error_ret:
}
static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
struct iio_buffer *buffer,
const struct iio_chan_spec *chan)
{
int ret, attrcount = 0;
struct iio_buffer *buffer = indio_dev->buffer;
ret = __iio_add_chan_devattr("index",
chan,
@ -518,7 +524,7 @@ static ssize_t iio_buffer_write_length(struct device *dev,
return len;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_is_active(indio_dev->buffer)) {
if (iio_buffer_is_active(buffer)) {
ret = -EBUSY;
} else {
buffer->access->set_length(buffer, val);
@ -539,7 +545,9 @@ static 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->buffer));
struct iio_buffer *buffer = indio_dev->buffer;
return sprintf(buf, "%d\n", iio_buffer_is_active(buffer));
}
static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
@ -1129,6 +1137,7 @@ static 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 *buffer = indio_dev->buffer;
bool inlist;
ret = strtobool(buf, &requested_state);
@ -1138,17 +1147,15 @@ static 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->buffer);
inlist = iio_buffer_is_active(buffer);
/* Already in desired state */
if (inlist == requested_state)
goto done;
if (requested_state)
ret = __iio_update_buffers(indio_dev,
indio_dev->buffer, NULL);
ret = __iio_update_buffers(indio_dev, buffer, NULL);
else
ret = __iio_update_buffers(indio_dev,
NULL, indio_dev->buffer);
ret = __iio_update_buffers(indio_dev, NULL, buffer);
done:
mutex_unlock(&indio_dev->mlock);
@ -1190,7 +1197,7 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
goto out;
}
if (iio_buffer_is_active(indio_dev->buffer)) {
if (iio_buffer_is_active(buffer)) {
ret = -EBUSY;
goto out;
}
@ -1207,11 +1214,9 @@ static ssize_t iio_dma_show_data_available(struct device *dev,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
size_t bytes;
struct iio_buffer *buffer = indio_dev->buffer;
bytes = iio_buffer_data_available(indio_dev->buffer);
return sprintf(buf, "%zu\n", bytes);
return sprintf(buf, "%zu\n", iio_buffer_data_available(buffer));
}
static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
@ -1292,7 +1297,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
if (channels[i].scan_index < 0)
continue;
ret = iio_buffer_add_channel_sysfs(indio_dev,
ret = iio_buffer_add_channel_sysfs(indio_dev, buffer,
&channels[i]);
if (ret < 0)
goto error_cleanup_dynamic;
@ -1332,20 +1337,22 @@ error_free_scan_mask:
bitmap_free(buffer->scan_mask);
error_cleanup_dynamic:
iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
kfree(indio_dev->buffer->buffer_group.attrs);
kfree(buffer->buffer_group.attrs);
return ret;
}
void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
{
if (!indio_dev->buffer)
struct iio_buffer *buffer = indio_dev->buffer;
if (!buffer)
return;
bitmap_free(indio_dev->buffer->scan_mask);
kfree(indio_dev->buffer->buffer_group.attrs);
kfree(indio_dev->buffer->scan_el_group.attrs);
iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
bitmap_free(buffer->scan_mask);
kfree(buffer->buffer_group.attrs);
kfree(buffer->scan_el_group.attrs);
iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
}
/**

View File

@ -1507,27 +1507,27 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
alloc_size += IIO_ALIGN - 1;
dev = kzalloc(alloc_size, GFP_KERNEL);
if (!dev)
return NULL;
if (dev) {
dev->dev.groups = dev->groups;
dev->dev.type = &iio_device_type;
dev->dev.bus = &iio_bus_type;
device_initialize(&dev->dev);
dev_set_drvdata(&dev->dev, (void *)dev);
mutex_init(&dev->mlock);
mutex_init(&dev->info_exist_lock);
INIT_LIST_HEAD(&dev->channel_attr_list);
dev->dev.groups = dev->groups;
dev->dev.type = &iio_device_type;
dev->dev.bus = &iio_bus_type;
device_initialize(&dev->dev);
dev_set_drvdata(&dev->dev, (void *)dev);
mutex_init(&dev->mlock);
mutex_init(&dev->info_exist_lock);
INIT_LIST_HEAD(&dev->channel_attr_list);
dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
if (dev->id < 0) {
/* cannot use a dev_err as the name isn't available */
pr_err("failed to get device id\n");
kfree(dev);
return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
INIT_LIST_HEAD(&dev->buffer_list);
dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
if (dev->id < 0) {
/* cannot use a dev_err as the name isn't available */
pr_err("failed to get device id\n");
kfree(dev);
return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
INIT_LIST_HEAD(&dev->buffer_list);
return dev;
}

View File

@ -516,6 +516,8 @@ config US5182D
config VCNL4000
tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VCNL4000,

View File

@ -13,7 +13,7 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -273,13 +273,11 @@ static const struct i2c_device_id bh1780_id[] = {
MODULE_DEVICE_TABLE(i2c, bh1780_id);
#ifdef CONFIG_OF
static const struct of_device_id of_bh1780_match[] = {
{ .compatible = "rohm,bh1780gli", },
{},
};
MODULE_DEVICE_TABLE(of, of_bh1780_match);
#endif
static struct i2c_driver bh1780_driver = {
.probe = bh1780_probe,
@ -288,7 +286,7 @@ static struct i2c_driver bh1780_driver = {
.driver = {
.name = "bh1780",
.pm = &bh1780_dev_pm_ops,
.of_match_table = of_match_ptr(of_bh1780_match),
.of_match_table = of_bh1780_match,
},
};

View File

@ -4,11 +4,13 @@
* Author: Kevin Tsai <ktsai@capellamicro.com>
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
@ -18,17 +20,24 @@
/* Registers Address */
#define CM32181_REG_ADDR_CMD 0x00
#define CM32181_REG_ADDR_WH 0x01
#define CM32181_REG_ADDR_WL 0x02
#define CM32181_REG_ADDR_TEST 0x03
#define CM32181_REG_ADDR_ALS 0x04
#define CM32181_REG_ADDR_STATUS 0x06
#define CM32181_REG_ADDR_ID 0x07
/* Number of Configurable Registers */
#define CM32181_CONF_REG_NUM 0x01
#define CM32181_CONF_REG_NUM 4
/* CMD register */
#define CM32181_CMD_ALS_ENABLE 0x00
#define CM32181_CMD_ALS_DISABLE 0x01
#define CM32181_CMD_ALS_INT_EN 0x02
#define CM32181_CMD_ALS_DISABLE BIT(0)
#define CM32181_CMD_ALS_INT_EN BIT(1)
#define CM32181_CMD_ALS_THRES_WINDOW BIT(2)
#define CM32181_CMD_ALS_PERS_SHIFT 4
#define CM32181_CMD_ALS_PERS_MASK (0x03 << CM32181_CMD_ALS_PERS_SHIFT)
#define CM32181_CMD_ALS_PERS_DEFAULT (0x01 << CM32181_CMD_ALS_PERS_SHIFT)
#define CM32181_CMD_ALS_IT_SHIFT 6
#define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT)
@ -38,27 +47,133 @@
#define CM32181_CMD_ALS_SM_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT)
#define CM32181_CMD_ALS_SM_DEFAULT (0x01 << CM32181_CMD_ALS_SM_SHIFT)
#define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
#define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
#define CM32181_CALIBSCALE_DEFAULT 1000
#define CM32181_CALIBSCALE_RESOLUTION 1000
#define MLUX_PER_LUX 1000
#define CM32181_LUX_PER_BIT 500 /* ALS_SM=01 IT=800ms */
#define CM32181_LUX_PER_BIT_RESOLUTION 100000
#define CM32181_LUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
#define CM32181_CALIBSCALE_DEFAULT 100000
#define CM32181_CALIBSCALE_RESOLUTION 100000
static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
CM32181_REG_ADDR_CMD,
#define SMBUS_ALERT_RESPONSE_ADDRESS 0x0c
/* CPM0 Index 0: device-id (3218 or 32181), 1: Unknown, 2: init_regs_bitmap */
#define CPM0_REGS_BITMAP 2
#define CPM0_HEADER_SIZE 3
/* CPM1 Index 0: lux_per_bit, 1: calibscale, 2: resolution (100000) */
#define CPM1_LUX_PER_BIT 0
#define CPM1_CALIBSCALE 1
#define CPM1_SIZE 3
/* CM3218 Family */
static const int cm3218_als_it_bits[] = { 0, 1, 2, 3 };
static const int cm3218_als_it_values[] = { 100000, 200000, 400000, 800000 };
/* CM32181 Family */
static const int cm32181_als_it_bits[] = { 12, 8, 0, 1, 2, 3 };
static const int cm32181_als_it_values[] = {
25000, 50000, 100000, 200000, 400000, 800000
};
static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
800000};
struct cm32181_chip {
struct i2c_client *client;
struct device *dev;
struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM];
unsigned long init_regs_bitmap;
int calibscale;
int lux_per_bit;
int lux_per_bit_base_it;
int num_als_it;
const int *als_it_bits;
const int *als_it_values;
};
static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2);
#ifdef CONFIG_ACPI
/**
* cm32181_acpi_get_cpm() - Get CPM object from ACPI
* @client pointer of struct i2c_client.
* @obj_name pointer of ACPI object name.
* @count maximum size of return array.
* @vals pointer of array for return elements.
*
* Convert ACPI CPM table to array.
*
* Return: -ENODEV for fail. Otherwise is number of elements.
*/
static int cm32181_acpi_get_cpm(struct device *dev, char *obj_name,
u64 *values, int count)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *cpm, *elem;
acpi_handle handle;
acpi_status status;
int i;
handle = ACPI_HANDLE(dev);
if (!handle)
return -ENODEV;
status = acpi_evaluate_object(handle, obj_name, NULL, &buffer);
if (ACPI_FAILURE(status)) {
dev_err(dev, "object %s not found\n", obj_name);
return -ENODEV;
}
cpm = buffer.pointer;
if (cpm->package.count > count)
dev_warn(dev, "%s table contains %u values, only using first %d values\n",
obj_name, cpm->package.count, count);
count = min_t(int, cpm->package.count, count);
for (i = 0; i < count; i++) {
elem = &(cpm->package.elements[i]);
values[i] = elem->integer.value;
}
kfree(buffer.pointer);
return count;
}
static void cm32181_acpi_parse_cpm_tables(struct cm32181_chip *cm32181)
{
u64 vals[CPM0_HEADER_SIZE + CM32181_CONF_REG_NUM];
struct device *dev = cm32181->dev;
int i, count;
count = cm32181_acpi_get_cpm(dev, "CPM0", vals, ARRAY_SIZE(vals));
if (count <= CPM0_HEADER_SIZE)
return;
count -= CPM0_HEADER_SIZE;
cm32181->init_regs_bitmap = vals[CPM0_REGS_BITMAP];
cm32181->init_regs_bitmap &= GENMASK(count - 1, 0);
for_each_set_bit(i, &cm32181->init_regs_bitmap, count)
cm32181->conf_regs[i] = vals[CPM0_HEADER_SIZE + i];
count = cm32181_acpi_get_cpm(dev, "CPM1", vals, ARRAY_SIZE(vals));
if (count != CPM1_SIZE)
return;
cm32181->lux_per_bit = vals[CPM1_LUX_PER_BIT];
/* Check for uncalibrated devices */
if (vals[CPM1_CALIBSCALE] == CM32181_CALIBSCALE_DEFAULT)
return;
cm32181->calibscale = vals[CPM1_CALIBSCALE];
/* CPM1 lux_per_bit is for the current it value */
cm32181_read_als_it(cm32181, &cm32181->lux_per_bit_base_it);
}
#else
static void cm32181_acpi_parse_cpm_tables(struct cm32181_chip *cm32181)
{
}
#endif /* CONFIG_ACPI */
/**
* cm32181_reg_init() - Initialize CM32181 registers
* @cm32181: pointer of struct cm32181.
@ -78,18 +193,37 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret;
/* check device ID */
if ((ret & 0xFF) != 0x81)
switch (ret & 0xFF) {
case 0x18: /* CM3218 */
cm32181->num_als_it = ARRAY_SIZE(cm3218_als_it_bits);
cm32181->als_it_bits = cm3218_als_it_bits;
cm32181->als_it_values = cm3218_als_it_values;
break;
case 0x81: /* CM32181 */
case 0x82: /* CM32182, fully compat. with CM32181 */
cm32181->num_als_it = ARRAY_SIZE(cm32181_als_it_bits);
cm32181->als_it_bits = cm32181_als_it_bits;
cm32181->als_it_values = cm32181_als_it_values;
break;
default:
return -ENODEV;
}
/* Default Values */
cm32181->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_ALS_ENABLE |
cm32181->conf_regs[CM32181_REG_ADDR_CMD] =
CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT;
cm32181->init_regs_bitmap = BIT(CM32181_REG_ADDR_CMD);
cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT;
cm32181->lux_per_bit = CM32181_LUX_PER_BIT;
cm32181->lux_per_bit_base_it = CM32181_LUX_PER_BIT_BASE_IT;
if (ACPI_HANDLE(cm32181->dev))
cm32181_acpi_parse_cpm_tables(cm32181);
/* Initialize registers*/
for (i = 0; i < CM32181_CONF_REG_NUM; i++) {
ret = i2c_smbus_write_word_data(client, cm32181_reg[i],
cm32181->conf_regs[i]);
for_each_set_bit(i, &cm32181->init_regs_bitmap, CM32181_CONF_REG_NUM) {
ret = i2c_smbus_write_word_data(client, i,
cm32181->conf_regs[i]);
if (ret < 0)
return ret;
}
@ -102,7 +236,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
* @cm32181: pointer of struct cm32181
* @val2: pointer of int to load the als_it value.
*
* Report the current integartion time by millisecond.
* Report the current integration time in milliseconds.
*
* Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
*/
@ -114,9 +248,9 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
if (als_it == als_it_bits[i]) {
*val2 = als_it_value[i];
for (i = 0; i < cm32181->num_als_it; i++) {
if (als_it == cm32181->als_it_bits[i]) {
*val2 = cm32181->als_it_values[i];
return IIO_VAL_INT_PLUS_MICRO;
}
}
@ -139,14 +273,14 @@ static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
u16 als_it;
int ret, i, n;
n = ARRAY_SIZE(als_it_value);
n = cm32181->num_als_it;
for (i = 0; i < n; i++)
if (val <= als_it_value[i])
if (val <= cm32181->als_it_values[i])
break;
if (i >= n)
i = n - 1;
als_it = als_it_bits[i];
als_it = cm32181->als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT;
mutex_lock(&cm32181->lock);
@ -175,15 +309,15 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
struct i2c_client *client = cm32181->client;
int ret;
int als_it;
unsigned long lux;
u64 lux;
ret = cm32181_read_als_it(cm32181, &als_it);
if (ret < 0)
return -EINVAL;
lux = CM32181_MLUX_PER_BIT;
lux *= CM32181_MLUX_PER_BIT_BASE_IT;
lux /= als_it;
lux = cm32181->lux_per_bit;
lux *= cm32181->lux_per_bit_base_it;
lux = div_u64(lux, als_it);
ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
if (ret < 0)
@ -191,8 +325,8 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
lux *= ret;
lux *= cm32181->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
lux /= MLUX_PER_LUX;
lux = div_u64(lux, CM32181_CALIBSCALE_RESOLUTION);
lux = div_u64(lux, CM32181_LUX_PER_BIT_RESOLUTION);
if (lux > 0xFFFF)
lux = 0xFFFF;
@ -258,11 +392,12 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
static ssize_t cm32181_get_it_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cm32181_chip *cm32181 = iio_priv(dev_to_iio_dev(dev));
int i, n, len;
n = ARRAY_SIZE(als_it_value);
n = cm32181->num_als_it;
for (i = 0, len = 0; i < n; i++)
len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
len += sprintf(buf + len, "0.%06u ", cm32181->als_it_values[i]);
return len + sprintf(buf + len, "\n");
}
@ -294,70 +429,86 @@ static const struct iio_info cm32181_info = {
.attrs = &cm32181_attribute_group,
};
static int cm32181_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int cm32181_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct cm32181_chip *cm32181;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
if (!indio_dev) {
dev_err(&client->dev, "devm_iio_device_alloc failed\n");
indio_dev = devm_iio_device_alloc(dev, sizeof(*cm32181));
if (!indio_dev)
return -ENOMEM;
/*
* Some ACPI systems list 2 I2C resources for the CM3218 sensor, the
* SMBus Alert Response Address (ARA, 0x0c) and the actual I2C address.
* Detect this and take the following step to deal with it:
* 1. When a SMBus Alert capable sensor has an Alert asserted, it will
* not respond on its actual I2C address. Read a byte from the ARA
* to clear any pending Alerts.
* 2. Create a "dummy" client for the actual I2C address and
* use that client to communicate with the sensor.
*/
if (ACPI_HANDLE(dev) && client->addr == SMBUS_ALERT_RESPONSE_ADDRESS) {
struct i2c_board_info board_info = { .type = "dummy" };
i2c_smbus_read_byte(client);
client = i2c_acpi_new_device(dev, 1, &board_info);
if (IS_ERR(client))
return PTR_ERR(client);
}
cm32181 = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
cm32181->client = client;
cm32181->dev = dev;
mutex_init(&cm32181->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->dev.parent = dev;
indio_dev->channels = cm32181_channels;
indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
indio_dev->info = &cm32181_info;
indio_dev->name = id->name;
indio_dev->name = dev_name(dev);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = cm32181_reg_init(cm32181);
if (ret) {
dev_err(&client->dev,
"%s: register init failed\n",
__func__);
dev_err(dev, "%s: register init failed\n", __func__);
return ret;
}
ret = devm_iio_device_register(&client->dev, indio_dev);
ret = devm_iio_device_register(dev, indio_dev);
if (ret) {
dev_err(&client->dev,
"%s: regist device failed\n",
__func__);
dev_err(dev, "%s: regist device failed\n", __func__);
return ret;
}
return 0;
}
static const struct i2c_device_id cm32181_id[] = {
{ "cm32181", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cm32181_id);
static const struct of_device_id cm32181_of_match[] = {
{ .compatible = "capella,cm3218" },
{ .compatible = "capella,cm32181" },
{ }
};
MODULE_DEVICE_TABLE(of, cm32181_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id cm32181_acpi_match[] = {
{ "CPLM3218", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, cm32181_acpi_match);
#endif
static struct i2c_driver cm32181_driver = {
.driver = {
.name = "cm32181",
.of_match_table = of_match_ptr(cm32181_of_match),
.acpi_match_table = ACPI_PTR(cm32181_acpi_match),
.of_match_table = cm32181_of_match,
},
.id_table = cm32181_id,
.probe = cm32181_probe,
.probe_new = cm32181_probe,
};
module_i2c_driver(cm32181_driver);

View File

@ -10,6 +10,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/init.h>
@ -418,7 +419,7 @@ MODULE_DEVICE_TABLE(of, cm3232_of_match);
static struct i2c_driver cm3232_driver = {
.driver = {
.name = "cm3232",
.of_match_table = of_match_ptr(cm3232_of_match),
.of_match_table = cm3232_of_match,
#ifdef CONFIG_PM_SLEEP
.pm = &cm3232_pm_ops,
#endif

View File

@ -38,8 +38,8 @@
#include <linux/irq.h>
#include <linux/irq_work.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@ -1617,18 +1617,16 @@ static const struct i2c_device_id gp2ap020a00f_id[] = {
MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id);
#ifdef CONFIG_OF
static const struct of_device_id gp2ap020a00f_of_match[] = {
{ .compatible = "sharp,gp2ap020a00f" },
{ }
};
MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);
#endif
static struct i2c_driver gp2ap020a00f_driver = {
.driver = {
.name = GP2A_I2C_NAME,
.of_match_table = of_match_ptr(gp2ap020a00f_of_match),
.of_match_table = gp2ap020a00f_of_match,
},
.probe = gp2ap020a00f_probe,
.remove = gp2ap020a00f_remove,

View File

@ -14,8 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum {
@ -308,18 +306,13 @@ static int hid_als_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&als_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&als_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
goto error_free_dev_mem;
}
ret = iio_device_register(indio_dev);
@ -343,9 +336,7 @@ static int hid_als_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&als_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
@ -360,8 +351,7 @@ static int hid_als_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&als_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
kfree(indio_dev->channels);
return 0;

View File

@ -14,8 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
#define CHANNEL_SCAN_INDEX_PRESENCE 0
@ -286,18 +284,13 @@ static int hid_prox_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&prox_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&prox_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
goto error_free_dev_mem;
}
ret = iio_device_register(indio_dev);
@ -321,9 +314,7 @@ static int hid_prox_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&prox_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
@ -338,8 +329,7 @@ static int hid_prox_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&prox_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
kfree(indio_dev->channels);
return 0;

View File

@ -101,12 +101,12 @@ struct ltr501_gain {
int uscale;
};
static struct ltr501_gain ltr501_als_gain_tbl[] = {
static const struct ltr501_gain ltr501_als_gain_tbl[] = {
{1, 0},
{0, 5000},
};
static struct ltr501_gain ltr559_als_gain_tbl[] = {
static const struct ltr501_gain ltr559_als_gain_tbl[] = {
{1, 0},
{0, 500000},
{0, 250000},
@ -117,14 +117,14 @@ static struct ltr501_gain ltr559_als_gain_tbl[] = {
{0, 10000},
};
static struct ltr501_gain ltr501_ps_gain_tbl[] = {
static const struct ltr501_gain ltr501_ps_gain_tbl[] = {
{1, 0},
{0, 250000},
{0, 125000},
{0, 62500},
};
static struct ltr501_gain ltr559_ps_gain_tbl[] = {
static const struct ltr501_gain ltr559_ps_gain_tbl[] = {
{0, 62500}, /* x16 gain */
{0, 31250}, /* x32 gain */
{0, 15625}, /* bits X1 are for x64 gain */
@ -133,9 +133,9 @@ static struct ltr501_gain ltr559_ps_gain_tbl[] = {
struct ltr501_chip_info {
u8 partid;
struct ltr501_gain *als_gain;
const struct ltr501_gain *als_gain;
int als_gain_tbl_size;
struct ltr501_gain *ps_gain;
const struct ltr501_gain *ps_gain;
int ps_gain_tbl_size;
u8 als_mode_active;
u8 als_gain_mask;
@ -192,7 +192,7 @@ static int ltr501_match_samp_freq(const struct ltr501_samp_table *tab,
return -EINVAL;
}
static int ltr501_als_read_samp_freq(struct ltr501_data *data,
static int ltr501_als_read_samp_freq(const struct ltr501_data *data,
int *val, int *val2)
{
int ret, i;
@ -210,7 +210,7 @@ static int ltr501_als_read_samp_freq(struct ltr501_data *data,
return IIO_VAL_INT_PLUS_MICRO;
}
static int ltr501_ps_read_samp_freq(struct ltr501_data *data,
static int ltr501_ps_read_samp_freq(const struct ltr501_data *data,
int *val, int *val2)
{
int ret, i;
@ -266,7 +266,7 @@ static int ltr501_ps_write_samp_freq(struct ltr501_data *data,
return ret;
}
static int ltr501_als_read_samp_period(struct ltr501_data *data, int *val)
static int ltr501_als_read_samp_period(const struct ltr501_data *data, int *val)
{
int ret, i;
@ -282,7 +282,7 @@ static int ltr501_als_read_samp_period(struct ltr501_data *data, int *val)
return IIO_VAL_INT;
}
static int ltr501_ps_read_samp_period(struct ltr501_data *data, int *val)
static int ltr501_ps_read_samp_period(const struct ltr501_data *data, int *val)
{
int ret, i;
@ -321,7 +321,7 @@ static unsigned long ltr501_calculate_lux(u16 vis_data, u16 ir_data)
return lux / 1000;
}
static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
static int ltr501_drdy(const struct ltr501_data *data, u8 drdy_mask)
{
int tries = 100;
int ret, status;
@ -373,7 +373,8 @@ static int ltr501_set_it_time(struct ltr501_data *data, int it)
}
/* read int time in micro seconds */
static int ltr501_read_it_time(struct ltr501_data *data, int *val, int *val2)
static int ltr501_read_it_time(const struct ltr501_data *data,
int *val, int *val2)
{
int ret, index;
@ -391,7 +392,7 @@ static int ltr501_read_it_time(struct ltr501_data *data, int *val, int *val2)
return IIO_VAL_INT_PLUS_MICRO;
}
static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
static int ltr501_read_als(const struct ltr501_data *data, __le16 buf[2])
{
int ret;
@ -403,7 +404,7 @@ static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
buf, 2 * sizeof(__le16));
}
static int ltr501_read_ps(struct ltr501_data *data)
static int ltr501_read_ps(const struct ltr501_data *data)
{
int ret, status;
@ -419,7 +420,7 @@ static int ltr501_read_ps(struct ltr501_data *data)
return status;
}
static int ltr501_read_intr_prst(struct ltr501_data *data,
static int ltr501_read_intr_prst(const struct ltr501_data *data,
enum iio_chan_type type,
int *val2)
{
@ -716,7 +717,7 @@ static int ltr501_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
static int ltr501_get_gain_index(struct ltr501_gain *gain, int size,
static int ltr501_get_gain_index(const struct ltr501_gain *gain, int size,
int val, int val2)
{
int i;
@ -848,14 +849,14 @@ static int ltr501_write_raw(struct iio_dev *indio_dev,
return ret;
}
static int ltr501_read_thresh(struct iio_dev *indio_dev,
static int ltr501_read_thresh(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
struct ltr501_data *data = iio_priv(indio_dev);
const struct ltr501_data *data = iio_priv(indio_dev);
int ret, thresh_data;
switch (chan->type) {
@ -1359,7 +1360,7 @@ static bool ltr501_is_volatile_reg(struct device *dev, unsigned int reg)
}
}
static struct regmap_config ltr501_regmap_config = {
static const struct regmap_config ltr501_regmap_config = {
.name = LTR501_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,

View File

@ -16,6 +16,7 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
@ -844,7 +845,7 @@ static struct i2c_driver opt3001_driver = {
.driver = {
.name = "opt3001",
.of_match_table = of_match_ptr(opt3001_of_match),
.of_match_table = opt3001_of_match,
},
};

View File

@ -17,6 +17,8 @@
#include <linux/util_macros.h>
#include <asm/unaligned.h>
#define SI1133_REG_PART_ID 0x00
#define SI1133_REG_REV_ID 0x01
#define SI1133_REG_MFR_ID 0x02
@ -104,8 +106,6 @@
#define SI1133_LUX_BUFFER_SIZE 9
#define SI1133_MEASURE_BUFFER_SIZE 3
#define SI1133_SIGN_BIT_INDEX 23
static const int si1133_scale_available[] = {
1, 2, 4, 8, 16, 32, 64, 128};
@ -633,8 +633,7 @@ static int si1133_measure(struct si1133_data *data,
if (err)
return err;
*val = sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
SI1133_SIGN_BIT_INDEX);
*val = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
return err;
}
@ -723,16 +722,11 @@ static int si1133_get_lux(struct si1133_data *data, int *val)
if (err)
return err;
high_vis =
sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
SI1133_SIGN_BIT_INDEX);
high_vis = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
low_vis =
sign_extend32((buffer[3] << 16) | (buffer[4] << 8) | buffer[5],
SI1133_SIGN_BIT_INDEX);
low_vis = sign_extend32(get_unaligned_be24(&buffer[3]), 23);
ir = sign_extend32((buffer[6] << 16) | (buffer[7] << 8) | buffer[8],
SI1133_SIGN_BIT_INDEX);
ir = sign_extend32(get_unaligned_be24(&buffer[6]), 23);
if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD)
lux = si1133_calc_polynomial(high_vis, ir,

View File

@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@ -55,7 +56,7 @@ static struct i2c_driver st_uvis25_driver = {
.driver = {
.name = "st_uvis25_i2c",
.pm = &st_uvis25_pm_ops,
.of_match_table = of_match_ptr(st_uvis25_i2c_of_match),
.of_match_table = st_uvis25_i2c_of_match,
},
.probe = st_uvis25_i2c_probe,
.id_table = st_uvis25_i2c_id_table,

View File

@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@ -55,7 +56,7 @@ static struct spi_driver st_uvis25_driver = {
.driver = {
.name = "st_uvis25_spi",
.pm = &st_uvis25_pm_ops,
.of_match_table = of_match_ptr(st_uvis25_spi_of_match),
.of_match_table = st_uvis25_spi_of_match,
},
.probe = st_uvis25_spi_probe,
.id_table = st_uvis25_spi_id_table,

View File

@ -5,6 +5,7 @@
*
* Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
* Copyright 2019 Pursim SPC
* Copyright 2020 Mathieu Othacehe <m.othacehe@gmail.com>
*
* IIO driver for:
* VCNL4000/10/20 (7-bit I2C slave address 0x13)
@ -13,9 +14,7 @@
*
* TODO:
* allow to adjust IR current
* proximity threshold and event handling
* periodic ALS/proximity measurement (VCNL4010/20)
* interrupts (VCNL4010/20/40, VCNL4200)
* interrupts (VCNL4040, VCNL4200)
*/
#include <linux/module.h>
@ -23,9 +22,15 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.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 VCNL4000_DRV_NAME "vcnl4000"
#define VCNL4000_PROD_ID 0x01
@ -35,14 +40,22 @@
#define VCNL4000_COMMAND 0x80 /* Command register */
#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
#define VCNL4010_PROX_RATE 0x82 /* Proximity rate */
#define VCNL4000_LED_CURRENT 0x83 /* IR LED current for proximity mode */
#define VCNL4000_AL_PARAM 0x84 /* Ambient light parameter register */
#define VCNL4010_ALS_PARAM 0x84 /* ALS rate */
#define VCNL4000_AL_RESULT_HI 0x85 /* Ambient light result register, MSB */
#define VCNL4000_AL_RESULT_LO 0x86 /* Ambient light result register, LSB */
#define VCNL4000_PS_RESULT_HI 0x87 /* Proximity result register, MSB */
#define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */
#define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */
#define VCNL4010_INT_CTRL 0x89 /* Interrupt control */
#define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
#define VCNL4010_LOW_THR_HI 0x8a /* Low threshold, MSB */
#define VCNL4010_LOW_THR_LO 0x8b /* Low threshold, LSB */
#define VCNL4010_HIGH_THR_HI 0x8c /* High threshold, MSB */
#define VCNL4010_HIGH_THR_LO 0x8d /* High threshold, LSB */
#define VCNL4010_ISR 0x8e /* Interrupt status */
#define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
@ -57,6 +70,36 @@
#define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
#define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
#define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
#define VCNL4000_ALS_EN BIT(2) /* start ALS measurement */
#define VCNL4000_PROX_EN BIT(1) /* start proximity measurement */
#define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed measurement */
/* Bit masks for interrupt registers. */
#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */
#define VCNL4010_INT_THR_EN BIT(1) /* Threshold interrupt type */
#define VCNL4010_INT_ALS_EN BIT(2) /* Enable on ALS data ready */
#define VCNL4010_INT_PROX_EN BIT(3) /* Enable on proximity data ready */
#define VCNL4010_INT_THR_HIGH 0 /* High threshold exceeded */
#define VCNL4010_INT_THR_LOW 1 /* Low threshold exceeded */
#define VCNL4010_INT_ALS 2 /* ALS data ready */
#define VCNL4010_INT_PROXIMITY 3 /* Proximity data ready */
#define VCNL4010_INT_THR \
(BIT(VCNL4010_INT_THR_LOW) | BIT(VCNL4010_INT_THR_HIGH))
#define VCNL4010_INT_DRDY \
(BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))
static const int vcnl4010_prox_sampling_frequency[][2] = {
{1, 950000},
{3, 906250},
{7, 812500},
{16, 625000},
{31, 250000},
{62, 500000},
{125, 0},
{250, 0},
};
#define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
@ -88,6 +131,10 @@ struct vcnl4000_data {
struct vcnl4000_chip_spec {
const char *prod;
struct iio_chan_spec const *channels;
const int num_channels;
const struct iio_info *info;
bool irq_support;
int (*init)(struct vcnl4000_data *data);
int (*measure_light)(struct vcnl4000_data *data, int *val);
int (*measure_proximity)(struct vcnl4000_data *data, int *val);
@ -216,11 +263,31 @@ static int vcnl4200_init(struct vcnl4000_data *data)
return 0;
};
static int vcnl4000_read_data(struct vcnl4000_data *data, u8 data_reg, int *val)
{
s32 ret;
ret = i2c_smbus_read_word_swapped(data->client, data_reg);
if (ret < 0)
return ret;
*val = ret;
return 0;
}
static int vcnl4000_write_data(struct vcnl4000_data *data, u8 data_reg, int val)
{
if (val > U16_MAX)
return -ERANGE;
return i2c_smbus_write_word_swapped(data->client, data_reg, val);
}
static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
u8 rdy_mask, u8 data_reg, int *val)
{
int tries = 20;
__be16 buf;
int ret;
mutex_lock(&data->vcnl4000_lock);
@ -247,13 +314,11 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
goto fail;
}
ret = i2c_smbus_read_i2c_block_data(data->client,
data_reg, sizeof(buf), (u8 *) &buf);
ret = vcnl4000_read_data(data, data_reg, val);
if (ret < 0)
goto fail;
mutex_unlock(&data->vcnl4000_lock);
*val = be16_to_cpu(buf);
return 0;
@ -313,67 +378,34 @@ static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
return vcnl4200_measure(data, &data->vcnl4200_ps, val);
}
static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
[VCNL4000] = {
.prod = "VCNL4000",
.init = vcnl4000_init,
.measure_light = vcnl4000_measure_light,
.measure_proximity = vcnl4000_measure_proximity,
.set_power_state = vcnl4000_set_power_state,
},
[VCNL4010] = {
.prod = "VCNL4010/4020",
.init = vcnl4000_init,
.measure_light = vcnl4000_measure_light,
.measure_proximity = vcnl4000_measure_proximity,
.set_power_state = vcnl4000_set_power_state,
},
[VCNL4040] = {
.prod = "VCNL4040",
.init = vcnl4200_init,
.measure_light = vcnl4200_measure_light,
.measure_proximity = vcnl4200_measure_proximity,
.set_power_state = vcnl4200_set_power_state,
},
[VCNL4200] = {
.prod = "VCNL4200",
.init = vcnl4200_init,
.measure_light = vcnl4200_measure_light,
.measure_proximity = vcnl4200_measure_proximity,
.set_power_state = vcnl4200_set_power_state,
},
};
static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
uintptr_t priv,
const struct iio_chan_spec *chan,
char *buf)
static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,
int *val2)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
return sprintf(buf, "%u\n", data->near_level);
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_PROX_RATE);
if (ret < 0)
return ret;
if (ret >= ARRAY_SIZE(vcnl4010_prox_sampling_frequency))
return -EINVAL;
*val = vcnl4010_prox_sampling_frequency[ret][0];
*val2 = vcnl4010_prox_sampling_frequency[ret][1];
return 0;
}
static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
{
.name = "nearlevel",
.shared = IIO_SEPARATE,
.read = vcnl4000_read_near_level,
},
{ /* sentinel */ }
};
static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
{
int ret;
static const struct iio_chan_spec vcnl4000_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.ext_info = vcnl4000_ext_info,
}
};
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
if (ret < 0)
return false;
return !!(ret & VCNL4000_SELF_TIMED_EN);
}
static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
{
@ -433,10 +465,571 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
}
}
static int vcnl4010_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_SCALE:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
/* Protect against event capture. */
if (vcnl4010_is_in_periodic_mode(data)) {
ret = -EBUSY;
} else {
ret = vcnl4000_read_raw(indio_dev, chan, val, val2,
mask);
}
iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
case IIO_PROXIMITY:
ret = vcnl4010_read_proxy_samp_freq(data, val, val2);
if (ret < 0)
return ret;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int vcnl4010_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*vals = (int *)vcnl4010_prox_sampling_frequency;
*type = IIO_VAL_INT_PLUS_MICRO;
*length = 2 * ARRAY_SIZE(vcnl4010_prox_sampling_frequency);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int vcnl4010_write_proxy_samp_freq(struct vcnl4000_data *data, int val,
int val2)
{
unsigned int i;
int index = -1;
for (i = 0; i < ARRAY_SIZE(vcnl4010_prox_sampling_frequency); i++) {
if (val == vcnl4010_prox_sampling_frequency[i][0] &&
val2 == vcnl4010_prox_sampling_frequency[i][1]) {
index = i;
break;
}
}
if (index < 0)
return -EINVAL;
return i2c_smbus_write_byte_data(data->client, VCNL4010_PROX_RATE,
index);
}
static int vcnl4010_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
/* Protect against event capture. */
if (vcnl4010_is_in_periodic_mode(data)) {
ret = -EBUSY;
goto end;
}
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
case IIO_PROXIMITY:
ret = vcnl4010_write_proxy_samp_freq(data, val, val2);
goto end;
default:
ret = -EINVAL;
goto end;
}
default:
ret = -EINVAL;
goto end;
}
end:
iio_device_release_direct_mode(indio_dev);
return ret;
}
static int vcnl4010_read_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
switch (info) {
case IIO_EV_INFO_VALUE:
switch (dir) {
case IIO_EV_DIR_RISING:
ret = vcnl4000_read_data(data, VCNL4010_HIGH_THR_HI,
val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_EV_DIR_FALLING:
ret = vcnl4000_read_data(data, VCNL4010_LOW_THR_HI,
val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int vcnl4010_write_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
switch (info) {
case IIO_EV_INFO_VALUE:
switch (dir) {
case IIO_EV_DIR_RISING:
ret = vcnl4000_write_data(data, VCNL4010_HIGH_THR_HI,
val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_EV_DIR_FALLING:
ret = vcnl4000_write_data(data, VCNL4010_LOW_THR_HI,
val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
{
int ret;
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_INT_CTRL);
if (ret < 0)
return false;
return !!(ret & VCNL4010_INT_THR_EN);
}
static int vcnl4010_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
switch (chan->type) {
case IIO_PROXIMITY:
return vcnl4010_is_thr_enabled(data);
default:
return -EINVAL;
}
}
static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
int icr;
int command;
if (state) {
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
/* Enable periodic measurement of proximity data. */
command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
/*
* Enable interrupts on threshold, for proximity data by
* default.
*/
icr = VCNL4010_INT_THR_EN;
} else {
if (!vcnl4010_is_thr_enabled(data))
return 0;
command = 0;
icr = 0;
}
ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
command);
if (ret < 0)
goto end;
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr);
end:
if (state)
iio_device_release_direct_mode(indio_dev);
return ret;
}
static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
{
switch (chan->type) {
case IIO_PROXIMITY:
return vcnl4010_config_threshold(indio_dev, state);
default:
return -EINVAL;
}
}
static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
uintptr_t priv,
const struct iio_chan_spec *chan,
char *buf)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
return sprintf(buf, "%u\n", data->near_level);
}
static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
{
.name = "nearlevel",
.shared = IIO_SEPARATE,
.read = vcnl4000_read_near_level,
},
{ /* sentinel */ }
};
static const struct iio_event_spec vcnl4000_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
}
};
static const struct iio_chan_spec vcnl4000_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.ext_info = vcnl4000_ext_info,
}
};
static const struct iio_chan_spec vcnl4010_channels[] = {
{
.type = IIO_LIGHT,
.scan_index = -1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_PROXIMITY,
.scan_index = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.event_spec = vcnl4000_event_spec,
.num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
.ext_info = vcnl4000_ext_info,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static const struct iio_info vcnl4000_info = {
.read_raw = vcnl4000_read_raw,
};
static const struct iio_info vcnl4010_info = {
.read_raw = vcnl4010_read_raw,
.read_avail = vcnl4010_read_avail,
.write_raw = vcnl4010_write_raw,
.read_event_value = vcnl4010_read_event,
.write_event_value = vcnl4010_write_event,
.read_event_config = vcnl4010_read_event_config,
.write_event_config = vcnl4010_write_event_config,
};
static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
[VCNL4000] = {
.prod = "VCNL4000",
.init = vcnl4000_init,
.measure_light = vcnl4000_measure_light,
.measure_proximity = vcnl4000_measure_proximity,
.set_power_state = vcnl4000_set_power_state,
.channels = vcnl4000_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
.info = &vcnl4000_info,
.irq_support = false,
},
[VCNL4010] = {
.prod = "VCNL4010/4020",
.init = vcnl4000_init,
.measure_light = vcnl4000_measure_light,
.measure_proximity = vcnl4000_measure_proximity,
.set_power_state = vcnl4000_set_power_state,
.channels = vcnl4010_channels,
.num_channels = ARRAY_SIZE(vcnl4010_channels),
.info = &vcnl4010_info,
.irq_support = true,
},
[VCNL4040] = {
.prod = "VCNL4040",
.init = vcnl4200_init,
.measure_light = vcnl4200_measure_light,
.measure_proximity = vcnl4200_measure_proximity,
.set_power_state = vcnl4200_set_power_state,
.channels = vcnl4000_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
.info = &vcnl4000_info,
.irq_support = false,
},
[VCNL4200] = {
.prod = "VCNL4200",
.init = vcnl4200_init,
.measure_light = vcnl4200_measure_light,
.measure_proximity = vcnl4200_measure_proximity,
.set_power_state = vcnl4200_set_power_state,
.channels = vcnl4000_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
.info = &vcnl4000_info,
.irq_support = false,
},
};
static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct vcnl4000_data *data = iio_priv(indio_dev);
unsigned long isr;
int ret;
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
if (ret < 0)
goto end;
isr = ret;
if (isr & VCNL4010_INT_THR) {
if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(
IIO_PROXIMITY,
1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns(indio_dev));
}
if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(
IIO_PROXIMITY,
1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns(indio_dev));
}
i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
isr & VCNL4010_INT_THR);
}
if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
iio_trigger_poll_chained(indio_dev->trig);
end:
return IRQ_HANDLED;
}
static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4000_data *data = iio_priv(indio_dev);
const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
u16 buffer[8] = {0}; /* 1x16-bit + ts */
bool data_read = false;
unsigned long isr;
int val = 0;
int ret;
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
if (ret < 0)
goto end;
isr = ret;
if (test_bit(0, active_scan_mask)) {
if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
ret = vcnl4000_read_data(data,
VCNL4000_PS_RESULT_HI,
&val);
if (ret < 0)
goto end;
buffer[0] = val;
data_read = true;
}
}
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
isr & VCNL4010_INT_DRDY);
if (ret < 0)
goto end;
if (!data_read)
goto end;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
iio_get_time_ns(indio_dev));
end:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
int cmd;
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret)
return ret;
/* Do not enable the buffer if we are already capturing events. */
if (vcnl4010_is_in_periodic_mode(data)) {
ret = -EBUSY;
goto end;
}
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
VCNL4010_INT_PROX_EN);
if (ret < 0)
goto end;
cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
if (ret < 0)
goto end;
return 0;
end:
iio_triggered_buffer_predisable(indio_dev);
return ret;
}
static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret, ret_disable;
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
if (ret < 0)
goto end;
ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
end:
ret_disable = iio_triggered_buffer_predisable(indio_dev);
if (ret == 0)
ret = ret_disable;
return ret;
}
static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
.postenable = &vcnl4010_buffer_postenable,
.predisable = &vcnl4010_buffer_predisable,
};
static const struct iio_trigger_ops vcnl4010_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
struct iio_trigger *trigger;
trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
indio_dev->name, indio_dev->id);
if (!trigger)
return -ENOMEM;
trigger->dev.parent = &client->dev;
trigger->ops = &vcnl4010_trigger_ops;
iio_trigger_set_drvdata(trigger, indio_dev);
return devm_iio_trigger_register(&client->dev, trigger);
}
static int vcnl4000_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -466,12 +1059,39 @@ static int vcnl4000_probe(struct i2c_client *client,
data->near_level = 0;
indio_dev->dev.parent = &client->dev;
indio_dev->info = &vcnl4000_info;
indio_dev->channels = vcnl4000_channels;
indio_dev->num_channels = ARRAY_SIZE(vcnl4000_channels);
indio_dev->info = data->chip_spec->info;
indio_dev->channels = data->chip_spec->channels;
indio_dev->num_channels = data->chip_spec->num_channels;
indio_dev->name = VCNL4000_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->irq && data->chip_spec->irq_support) {
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
NULL,
vcnl4010_trigger_handler,
&vcnl4010_buffer_ops);
if (ret < 0) {
dev_err(&client->dev,
"unable to setup iio triggered buffer\n");
return ret;
}
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, vcnl4010_irq_thread,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"vcnl4010_irq",
indio_dev);
if (ret < 0) {
dev_err(&client->dev, "irq request failed\n");
return ret;
}
ret = vcnl4010_probe_trigger(indio_dev);
if (ret < 0)
return ret;
}
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
goto fail_poweroff;
@ -565,5 +1185,6 @@ static struct i2c_driver vcnl4000_driver = {
module_i2c_driver(vcnl4000_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
MODULE_LICENSE("GPL");

View File

@ -16,6 +16,7 @@
*/
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/err.h>
@ -537,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, vl6180_id);
static struct i2c_driver vl6180_driver = {
.driver = {
.name = VL6180_DRV_NAME,
.of_match_table = of_match_ptr(vl6180_of_match),
.of_match_table = vl6180_of_match,
},
.probe = vl6180_probe,
.id_table = vl6180_id,

View File

@ -19,6 +19,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <asm/unaligned.h>
#define ZOPT2201_DRV_NAME "zopt2201"
/* Registers */
@ -219,7 +221,7 @@ static int zopt2201_read(struct zopt2201_data *data, u8 reg)
goto fail;
mutex_unlock(&data->lock);
return (buf[2] << 16) | (buf[1] << 8) | buf[0];
return get_unaligned_le24(&buf[0]);
fail:
mutex_unlock(&data->lock);

View File

@ -49,6 +49,7 @@
#define AK8974_WHOAMI_VALUE_AMI306 0x46
#define AK8974_WHOAMI_VALUE_AMI305 0x47
#define AK8974_WHOAMI_VALUE_AK8974 0x48
#define AK8974_WHOAMI_VALUE_HSCDTD008A 0x49
#define AK8974_DATA_X 0x10
#define AK8974_DATA_Y 0x12
@ -140,6 +141,12 @@
#define AK8974_INT_CTRL_PULSE BIT(1) /* 0 = latched; 1 = pulse (50 usec) */
#define AK8974_INT_CTRL_RESDEF (AK8974_INT_CTRL_XYZEN | AK8974_INT_CTRL_POL)
/* HSCDTD008A-specific control register */
#define HSCDTD008A_CTRL4 0x1E
#define HSCDTD008A_CTRL4_MMD BIT(7) /* must be set to 1 */
#define HSCDTD008A_CTRL4_RANGE BIT(4) /* 0 = 14-bit output; 1 = 15-bit output */
#define HSCDTD008A_CTRL4_RESDEF (HSCDTD008A_CTRL4_MMD | HSCDTD008A_CTRL4_RANGE)
/* The AMI305 has elaborate FW version and serial number registers */
#define AMI305_VER 0xE8
#define AMI305_SN 0xEA
@ -241,10 +248,17 @@ static int ak8974_reset(struct ak8974 *ak8974)
ret = regmap_write(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_RESDEF);
if (ret)
return ret;
ret = regmap_write(ak8974->map, AK8974_INT_CTRL,
AK8974_INT_CTRL_RESDEF);
if (ret)
return ret;
if (ak8974->variant != AK8974_WHOAMI_VALUE_HSCDTD008A) {
ret = regmap_write(ak8974->map, AK8974_INT_CTRL,
AK8974_INT_CTRL_RESDEF);
if (ret)
return ret;
} else {
ret = regmap_write(ak8974->map, HSCDTD008A_CTRL4,
HSCDTD008A_CTRL4_RESDEF);
if (ret)
return ret;
}
/* After reset, power off is default state */
return ak8974_set_power(ak8974, AK8974_PWR_OFF);
@ -267,6 +281,8 @@ static int ak8974_configure(struct ak8974 *ak8974)
if (ret)
return ret;
}
if (ak8974->variant == AK8974_WHOAMI_VALUE_HSCDTD008A)
return 0;
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL);
if (ret)
return ret;
@ -495,6 +511,10 @@ static int ak8974_detect(struct ak8974 *ak8974)
name = "ak8974";
dev_info(&ak8974->i2c->dev, "detected AK8974\n");
break;
case AK8974_WHOAMI_VALUE_HSCDTD008A:
name = "hscdtd008a";
dev_info(&ak8974->i2c->dev, "detected hscdtd008a\n");
break;
default:
dev_err(&ak8974->i2c->dev, "unsupported device (%02x) ",
whoami);
@ -534,47 +554,103 @@ static int ak8974_detect(struct ak8974 *ak8974)
return 0;
}
static int ak8974_measure_channel(struct ak8974 *ak8974, unsigned long address,
int *val)
{
__le16 hw_values[3];
int ret;
pm_runtime_get_sync(&ak8974->i2c->dev);
mutex_lock(&ak8974->lock);
/*
* We read all axes and discard all but one, for optimized
* reading, use the triggered buffer.
*/
ret = ak8974_trigmeas(ak8974);
if (ret)
goto out_unlock;
ret = ak8974_getresult(ak8974, hw_values);
if (ret)
goto out_unlock;
/*
* This explicit cast to (s16) is necessary as the measurement
* is done in 2's complement with positive and negative values.
* The follwing assignment to *val will then convert the signed
* s16 value to a signed int value.
*/
*val = (s16)le16_to_cpu(hw_values[address]);
out_unlock:
mutex_unlock(&ak8974->lock);
pm_runtime_mark_last_busy(&ak8974->i2c->dev);
pm_runtime_put_autosuspend(&ak8974->i2c->dev);
return ret;
}
static int ak8974_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
struct ak8974 *ak8974 = iio_priv(indio_dev);
__le16 hw_values[3];
int ret = -EINVAL;
pm_runtime_get_sync(&ak8974->i2c->dev);
mutex_lock(&ak8974->lock);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->address > 2) {
dev_err(&ak8974->i2c->dev, "faulty channel address\n");
ret = -EIO;
goto out_unlock;
return -EIO;
}
ret = ak8974_trigmeas(ak8974);
ret = ak8974_measure_channel(ak8974, chan->address, val);
if (ret)
goto out_unlock;
ret = ak8974_getresult(ak8974, hw_values);
if (ret)
goto out_unlock;
/*
* We read all axes and discard all but one, for optimized
* reading, use the triggered buffer.
*/
*val = (s16)le16_to_cpu(hw_values[chan->address]);
ret = IIO_VAL_INT;
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (ak8974->variant) {
case AK8974_WHOAMI_VALUE_AMI306:
case AK8974_WHOAMI_VALUE_AMI305:
/*
* The datasheet for AMI305 and AMI306, page 6
* specifies the range of the sensor to be
* +/- 12 Gauss.
*/
*val = 12;
/*
* 12 bits are used, +/- 2^11
* [ -2048 .. 2047 ] (manual page 20)
* [ 0xf800 .. 0x07ff ]
*/
*val2 = 11;
return IIO_VAL_FRACTIONAL_LOG2;
case AK8974_WHOAMI_VALUE_HSCDTD008A:
/*
* The datasheet for HSCDTF008A, page 3 specifies the
* range of the sensor as +/- 2.4 mT per axis, which
* corresponds to +/- 2400 uT = +/- 24 Gauss.
*/
*val = 24;
/*
* 15 bits are used (set up in CTRL4), +/- 2^14
* [ -16384 .. 16383 ] (manual page 24)
* [ 0xc000 .. 0x3fff ]
*/
*val2 = 14;
return IIO_VAL_FRACTIONAL_LOG2;
default:
/* GUESSING +/- 12 Gauss */
*val = 12;
/* GUESSING 12 bits ADC +/- 2^11 */
*val2 = 11;
return IIO_VAL_FRACTIONAL_LOG2;
}
break;
default:
/* Unknown request */
break;
}
out_unlock:
mutex_unlock(&ak8974->lock);
pm_runtime_mark_last_busy(&ak8974->i2c->dev);
pm_runtime_put_autosuspend(&ak8974->i2c->dev);
return ret;
return -EINVAL;
}
static void ak8974_fill_buffer(struct iio_dev *indio_dev)
@ -631,27 +707,44 @@ static const struct iio_chan_spec_ext_info ak8974_ext_info[] = {
{ },
};
#define AK8974_AXIS_CHANNEL(axis, index) \
#define AK8974_AXIS_CHANNEL(axis, index, bits) \
{ \
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.ext_info = ak8974_ext_info, \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.realbits = bits, \
.storagebits = 16, \
.endianness = IIO_LE \
}, \
}
static const struct iio_chan_spec ak8974_channels[] = {
AK8974_AXIS_CHANNEL(X, 0),
AK8974_AXIS_CHANNEL(Y, 1),
AK8974_AXIS_CHANNEL(Z, 2),
/*
* We have no datasheet for the AK8974 but we guess that its
* ADC is 12 bits. The AMI305 and AMI306 certainly has 12bit
* ADC.
*/
static const struct iio_chan_spec ak8974_12_bits_channels[] = {
AK8974_AXIS_CHANNEL(X, 0, 12),
AK8974_AXIS_CHANNEL(Y, 1, 12),
AK8974_AXIS_CHANNEL(Z, 2, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
/*
* The HSCDTD008A has 15 bits resolution the way we set it up
* in CTRL4.
*/
static const struct iio_chan_spec ak8974_15_bits_channels[] = {
AK8974_AXIS_CHANNEL(X, 0, 15),
AK8974_AXIS_CHANNEL(Y, 1, 15),
AK8974_AXIS_CHANNEL(Z, 2, 15),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
@ -674,18 +767,18 @@ static bool ak8974_writeable_reg(struct device *dev, unsigned int reg)
case AK8974_INT_CTRL:
case AK8974_INT_THRES:
case AK8974_INT_THRES + 1:
return true;
case AK8974_PRESET:
case AK8974_PRESET + 1:
return true;
return ak8974->variant != AK8974_WHOAMI_VALUE_HSCDTD008A;
case AK8974_OFFSET_X:
case AK8974_OFFSET_X + 1:
case AK8974_OFFSET_Y:
case AK8974_OFFSET_Y + 1:
case AK8974_OFFSET_Z:
case AK8974_OFFSET_Z + 1:
if (ak8974->variant == AK8974_WHOAMI_VALUE_AK8974)
return true;
return false;
return ak8974->variant == AK8974_WHOAMI_VALUE_AK8974 ||
ak8974->variant == AK8974_WHOAMI_VALUE_HSCDTD008A;
case AMI305_OFFSET_X:
case AMI305_OFFSET_X + 1:
case AMI305_OFFSET_Y:
@ -800,8 +893,21 @@ static int ak8974_probe(struct i2c_client *i2c,
pm_runtime_put(&i2c->dev);
indio_dev->dev.parent = &i2c->dev;
indio_dev->channels = ak8974_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8974_channels);
switch (ak8974->variant) {
case AK8974_WHOAMI_VALUE_AMI306:
case AK8974_WHOAMI_VALUE_AMI305:
indio_dev->channels = ak8974_12_bits_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8974_12_bits_channels);
break;
case AK8974_WHOAMI_VALUE_HSCDTD008A:
indio_dev->channels = ak8974_15_bits_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8974_15_bits_channels);
break;
default:
indio_dev->channels = ak8974_12_bits_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8974_12_bits_channels);
break;
}
indio_dev->info = &ak8974_info;
indio_dev->available_scan_masks = ak8974_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;
@ -931,12 +1037,14 @@ static const struct i2c_device_id ak8974_id[] = {
{"ami305", 0 },
{"ami306", 0 },
{"ak8974", 0 },
{"hscdtd008a", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ak8974_id);
static const struct of_device_id ak8974_of_match[] = {
{ .compatible = "asahi-kasei,ak8974", },
{ .compatible = "alps,hscdtd008a", },
{}
};
MODULE_DEVICE_TABLE(of, ak8974_of_match);

View File

@ -14,8 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum magn_3d_channel {
@ -519,18 +517,13 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
return ret;
}
atomic_set(&magn_state->magn_flux_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&magn_state->magn_flux_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
return ret;
}
ret = iio_device_register(indio_dev);
@ -554,9 +547,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&magn_state->magn_flux_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
return ret;
}
@ -569,8 +560,7 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&magn_state->magn_flux_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
return 0;
}

View File

@ -22,6 +22,8 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <asm/unaligned.h>
#include "rm3100.h"
/* Cycle Count Registers. */
@ -223,8 +225,7 @@ static int rm3100_read_mag(struct rm3100_data *data, int idx, int *val)
goto unlock_return;
mutex_unlock(&data->lock);
*val = sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
23);
*val = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
return IIO_VAL_INT;

View File

@ -15,8 +15,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum incl_3d_channel {
@ -346,18 +344,13 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&incl_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&incl_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
goto error_free_dev_mem;
}
ret = iio_device_register(indio_dev);
@ -382,9 +375,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&incl_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
@ -399,8 +390,7 @@ static int hid_incl_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&incl_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
kfree(indio_dev->channels);
return 0;

View File

@ -14,8 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
struct dev_rot_state {
@ -288,18 +286,13 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
return ret;
}
atomic_set(&rot_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&rot_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
return ret;
}
ret = iio_device_register(indio_dev);
@ -323,9 +316,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&rot_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
return ret;
}
@ -338,8 +329,7 @@ static int hid_dev_rot_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&rot_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
return 0;
}

View File

@ -271,6 +271,8 @@ static u32 bmp280_compensate_humidity(struct bmp280_data *data,
+ (s32)2097152) * calib->H2 + 8192) >> 14);
var -= ((((var >> 15) * (var >> 15)) >> 7) * (s32)calib->H1) >> 4;
var = clamp_val(var, 0, 419430400);
return var >> 12;
};

View File

@ -14,8 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
#define CHANNEL_SCAN_INDEX_PRESSURE 0
@ -290,18 +288,13 @@ static int hid_press_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&press_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&press_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
goto error_free_dev_mem;
}
ret = iio_device_register(indio_dev);
@ -325,9 +318,7 @@ static int hid_press_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&press_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
@ -342,8 +333,7 @@ static int hid_press_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&press_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
kfree(indio_dev->channels);
return 0;

View File

@ -18,6 +18,8 @@
#include <linux/util_macros.h>
#include <linux/acpi.h>
#include <asm/unaligned.h>
/* I2C commands: */
#define HP206C_CMD_SOFT_RST 0x06
@ -93,12 +95,12 @@ static int hp206c_read_20bit(struct i2c_client *client, u8 cmd)
int ret;
u8 values[3];
ret = i2c_smbus_read_i2c_block_data(client, cmd, 3, values);
ret = i2c_smbus_read_i2c_block_data(client, cmd, sizeof(values), values);
if (ret < 0)
return ret;
if (ret != 3)
if (ret != sizeof(values))
return -EIO;
return ((values[0] & 0xF) << 16) | (values[1] << 8) | (values[2]);
return get_unaligned_be24(&values[0]) & GENMASK(19, 0);
}
/* Spin for max 160ms until DEV_RDY is 1, or return error. */

View File

@ -16,6 +16,8 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <asm/unaligned.h>
#include "ms5611.h"
static int ms5611_i2c_reset(struct device *dev)
@ -50,7 +52,7 @@ static int ms5611_i2c_read_adc(struct ms5611_state *st, s32 *val)
if (ret < 0)
return ret;
*val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
*val = get_unaligned_be24(&buf[0]);
return 0;
}

View File

@ -11,6 +11,8 @@
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <asm/unaligned.h>
#include "ms5611.h"
static int ms5611_spi_reset(struct device *dev)
@ -45,7 +47,7 @@ static int ms5611_spi_read_adc(struct device *dev, s32 *val)
if (ret < 0)
return ret;
*val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
*val = get_unaligned_be24(&buf[0]);
return 0;
}

View File

@ -64,6 +64,7 @@
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <asm/unaligned.h>
#include "zpa2326.h"
/* 200 ms should be enough for the longest conversion time in one-shot mode. */
@ -1005,22 +1006,20 @@ static int zpa2326_fetch_raw_sample(const struct iio_dev *indio_dev,
struct regmap *regs = ((struct zpa2326_private *)
iio_priv(indio_dev))->regmap;
int err;
u8 v[3];
switch (type) {
case IIO_PRESSURE:
zpa2326_dbg(indio_dev, "fetching raw pressure sample");
err = regmap_bulk_read(regs, ZPA2326_PRESS_OUT_XL_REG, value,
3);
err = regmap_bulk_read(regs, ZPA2326_PRESS_OUT_XL_REG, v, sizeof(v));
if (err) {
zpa2326_warn(indio_dev, "failed to fetch pressure (%d)",
err);
return err;
}
/* Pressure is a 24 bits wide little-endian unsigned int. */
*value = (((u8 *)value)[2] << 16) | (((u8 *)value)[1] << 8) |
((u8 *)value)[0];
*value = get_unaligned_le24(&v[0]);
return IIO_VAL_INT;

View File

@ -7,8 +7,6 @@
#include <linux/hid-sensor-hub.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@ -230,12 +228,8 @@ static int hid_temperature_probe(struct platform_device *pdev)
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev,
&iio_pollfunc_store_time, NULL, NULL);
if (ret)
return ret;
atomic_set(&temp_st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&temp_st->common_attributes);
if (ret)
@ -258,7 +252,7 @@ static int hid_temperature_probe(struct platform_device *pdev)
error_remove_callback:
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
error_remove_trigger:
hid_sensor_remove_trigger(&temp_st->common_attributes);
hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
return ret;
}
@ -270,7 +264,7 @@ static int hid_temperature_remove(struct platform_device *pdev)
struct temperature_state *temp_st = iio_priv(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
hid_sensor_remove_trigger(&temp_st->common_attributes);
hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
return 0;
}

View File

@ -14,6 +14,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/util_macros.h>
#include <asm/unaligned.h>
#include <dt-bindings/iio/temperature/thermocouple.h>
/*
* The MSB of the register value determines whether the following byte will
@ -168,7 +169,7 @@ static int max31856_thermocouple_read(struct max31856_data *data,
if (ret)
return ret;
/* Skip last 5 dead bits of LTCBL */
*val = (reg_val[0] << 16 | reg_val[1] << 8 | reg_val[2]) >> 5;
*val = get_unaligned_be24(&reg_val[0]) >> 5;
/* Check 7th bit of LTCBH reg. value for sign*/
if (reg_val[0] & 0x80)
*val -= 0x80000;
@ -185,7 +186,7 @@ static int max31856_thermocouple_read(struct max31856_data *data,
/* Get Cold Junction Temp. offset register value */
offset_cjto = reg_val[0];
/* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */
*val = (reg_val[1] << 8 | reg_val[2]) >> 2;
*val = get_unaligned_be16(&reg_val[1]) >> 2;
/* As per datasheet add offset into CJTH and CJTL */
*val += offset_cjto;
/* Check 7th bit of CJTH reg. value for sign */

View File

@ -602,11 +602,12 @@ static const struct iio_buffer_setup_ops ad5933_ring_setup_ops = {
.postdisable = ad5933_ring_postdisable,
};
static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
static int ad5933_register_ring_funcs_and_init(struct device *dev,
struct iio_dev *indio_dev)
{
struct iio_buffer *buffer;
buffer = iio_kfifo_allocate();
buffer = devm_iio_kfifo_allocate(dev);
if (!buffer)
return -ENOMEM;
@ -676,6 +677,20 @@ static void ad5933_work(struct work_struct *work)
}
}
static void ad5933_reg_disable(void *data)
{
struct ad5933_state *st = data;
regulator_disable(st->reg);
}
static void ad5933_clk_disable(void *data)
{
struct ad5933_state *st = data;
clk_disable_unprepare(st->mclk);
}
static int ad5933_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -703,23 +718,32 @@ static int ad5933_probe(struct i2c_client *client,
dev_err(&client->dev, "Failed to enable specified VDD supply\n");
return ret;
}
ret = regulator_get_voltage(st->reg);
ret = devm_add_action_or_reset(&client->dev, ad5933_reg_disable, st);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
return ret;
st->vref_mv = ret / 1000;
st->mclk = devm_clk_get(&client->dev, "mclk");
if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) {
ret = PTR_ERR(st->mclk);
goto error_disable_reg;
}
if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT)
return PTR_ERR(st->mclk);
if (!IS_ERR(st->mclk)) {
ret = clk_prepare_enable(st->mclk);
if (ret < 0)
goto error_disable_reg;
return ret;
ret = devm_add_action_or_reset(&client->dev,
ad5933_clk_disable,
st);
if (ret)
return ret;
ext_clk_hz = clk_get_rate(st->mclk);
}
@ -742,41 +766,15 @@ static int ad5933_probe(struct i2c_client *client,
indio_dev->channels = ad5933_channels;
indio_dev->num_channels = ARRAY_SIZE(ad5933_channels);
ret = ad5933_register_ring_funcs_and_init(indio_dev);
ret = ad5933_register_ring_funcs_and_init(&client->dev, indio_dev);
if (ret)
goto error_disable_mclk;
return ret;
ret = ad5933_setup(st);
if (ret)
goto error_unreg_ring;
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto error_unreg_ring;
return 0;
error_unreg_ring:
iio_kfifo_free(indio_dev->buffer);
error_disable_mclk:
clk_disable_unprepare(st->mclk);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int ad5933_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ad5933_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_kfifo_free(indio_dev->buffer);
regulator_disable(st->reg);
clk_disable_unprepare(st->mclk);
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ad5933_id[] = {
@ -801,7 +799,6 @@ static struct i2c_driver ad5933_driver = {
.of_match_table = ad5933_of_match,
},
.probe = ad5933_probe,
.remove = ad5933_remove,
.id_table = ad5933_id,
};
module_i2c_driver(ad5933_driver);

View File

@ -83,10 +83,13 @@ struct adis_data {
* @trig: IIO trigger object data
* @data: ADIS chip variant specific data
* @burst: ADIS burst transfer information
* @burst_extra_len: Burst extra length. Should only be used by devices that can
* dynamically change their burst mode length.
* @state_lock: Lock used by the device to protect state
* @msg: SPI message object
* @xfer: SPI transfer objects to be used for a @msg
* @current_page: Some ADIS devices have registers, this selects current page
* @irq_flag: IRQ handling flags as passed to request_irq()
* @buffer: Data buffer for information read from the device
* @tx: DMA safe TX buffer for SPI transfers
* @rx: DMA safe RX buffer for SPI transfers
@ -97,7 +100,7 @@ struct adis {
const struct adis_data *data;
struct adis_burst *burst;
unsigned int burst_extra_len;
/**
* The state_lock is meant to be used during operations that require
* a sequence of SPI R/W in order to protect the SPI transfer
@ -113,6 +116,7 @@ struct adis {
struct spi_message msg;
struct spi_transfer *xfer;
unsigned int current_page;
unsigned long irq_flag;
void *buffer;
uint8_t tx[10] ____cacheline_aligned;
@ -331,6 +335,65 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
return ret;
}
int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
const u32 val, u8 size);
/**
* adis_update_bits_base() - ADIS Update bits function - Locked version
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @mask: Bitmask to change
* @val: Value to be written
* @size: Size of the register to update
*
* Updates the desired bits of @reg in accordance with @mask and @val.
*/
static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
const u32 mask, const u32 val, u8 size)
{
int ret;
mutex_lock(&adis->state_lock);
ret = __adis_update_bits_base(adis, reg, mask, val, size);
mutex_unlock(&adis->state_lock);
return ret;
}
/**
* adis_update_bits() - Wrapper macro for adis_update_bits_base - Locked version
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @mask: Bitmask to change
* @val: Value to be written
*
* This macro evaluates the sizeof of @val at compile time and calls
* adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
* @val can lead to undesired behavior if the register to update is 16bit.
*/
#define adis_update_bits(adis, reg, mask, val) ({ \
BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \
__builtin_choose_expr(sizeof(val) == 4, \
adis_update_bits_base(adis, reg, mask, val, 4), \
adis_update_bits_base(adis, reg, mask, val, 2)); \
})
/**
* adis_update_bits() - Wrapper macro for adis_update_bits_base
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @mask: Bitmask to change
* @val: Value to be written
*
* This macro evaluates the sizeof of @val at compile time and calls
* adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
* @val can lead to undesired behavior if the register to update is 16bit.
*/
#define __adis_update_bits(adis, reg, mask, val) ({ \
BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \
__builtin_choose_expr(sizeof(val) == 4, \
__adis_update_bits_base(adis, reg, mask, val, 4), \
__adis_update_bits_base(adis, reg, mask, val, 2)); \
})
int adis_enable_irq(struct adis *adis, bool enable);
int __adis_check_status(struct adis *adis);
int __adis_initial_startup(struct adis *adis);
@ -441,18 +504,25 @@ int adis_single_conversion(struct iio_dev *indio_dev,
* @en burst mode enabled
* @reg_cmd register command that triggers burst
* @extra_len extra length to account in the SPI RX buffer
* @burst_max_len holds the maximum burst size when the device supports
* more than one burst mode with different sizes
*/
struct adis_burst {
bool en;
unsigned int reg_cmd;
unsigned int extra_len;
const u32 extra_len;
const u32 burst_max_len;
};
int
devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
irq_handler_t trigger_handler);
int adis_setup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *));
void adis_cleanup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev);
int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
void adis_remove_trigger(struct adis *adis);
@ -461,6 +531,13 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
#else /* CONFIG_IIO_BUFFER */
static inline int
devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
irq_handler_t trigger_handler)
{
return 0;
}
static inline int adis_setup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *))
{
@ -472,6 +549,12 @@ static inline void adis_cleanup_buffer_and_trigger(struct adis *adis,
{
}
static inline int devm_adis_probe_trigger(struct adis *adis,
struct iio_dev *indio_dev)
{
return 0;
}
static inline int adis_probe_trigger(struct adis *adis,
struct iio_dev *indio_dev)
{