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.
  ...
This commit is contained in:
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/EC_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_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/pH_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/RTD_oem_datasheet.pdf
properties: properties:
compatible: compatible:
@ -25,6 +26,7 @@ properties:
- atlas,ec-sm - atlas,ec-sm
- atlas,orp-sm - atlas,orp-sm
- atlas,ph-sm - atlas,ph-sm
- atlas,rtd-sm
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -1,4 +1,4 @@
Linear Technology LTC2632/2636 DAC Linear Technology LTC2632/2634/2636 DAC
Required properties: Required properties:
- compatible: Has to contain one of the following: - compatible: Has to contain one of the following:
@ -8,6 +8,12 @@ Required properties:
lltc,ltc2632-h12 lltc,ltc2632-h12
lltc,ltc2632-h10 lltc,ltc2632-h10
lltc,ltc2632-h8 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-l12
lltc,ltc2636-l10 lltc,ltc2636-l10
lltc,ltc2636-l8 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: Required properties:
- compatible : should be "asahi-kasei,ak8974" - compatible:
* "asahi-kasei,ak8974"
* "alps,hscdtd008a"
- reg : the I2C address of the magnetometer - reg : the I2C address of the magnetometer
Optional properties: 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: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
F: drivers/iio/imu/adis16460.c 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 ANALOG DEVICES INC ADM1177 DRIVER
M: Beniamin Bia <beniamin.bia@analog.com> M: Beniamin Bia <beniamin.bia@analog.com>
M: Michael Hennerich <Michael.Hennerich@analog.com> M: Michael Hennerich <Michael.Hennerich@analog.com>

View File

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

View File

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

View File

@ -2,6 +2,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/delay.h> #include <linux/delay.h>
@ -36,15 +37,11 @@ static int kxsd9_i2c_remove(struct i2c_client *client)
return kxsd9_common_remove(&client->dev); return kxsd9_common_remove(&client->dev);
} }
#ifdef CONFIG_OF
static const struct of_device_id kxsd9_of_match[] = { static const struct of_device_id kxsd9_of_match[] = {
{ .compatible = "kionix,kxsd9", }, { .compatible = "kionix,kxsd9", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, kxsd9_of_match); MODULE_DEVICE_TABLE(of, kxsd9_of_match);
#else
#define kxsd9_of_match NULL
#endif
static const struct i2c_device_id kxsd9_i2c_id[] = { static const struct i2c_device_id kxsd9_i2c_id[] = {
{"kxsd9", 0}, {"kxsd9", 0},
@ -55,7 +52,7 @@ MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id);
static struct i2c_driver kxsd9_i2c_driver = { static struct i2c_driver kxsd9_i2c_driver = {
.driver = { .driver = {
.name = "kxsd9", .name = "kxsd9",
.of_match_table = of_match_ptr(kxsd9_of_match), .of_match_table = kxsd9_of_match,
.pm = &kxsd9_dev_pm_ops, .pm = &kxsd9_dev_pm_ops,
}, },
.probe = kxsd9_i2c_probe, .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->num_channels = 2;
indio_dev->info = &ad7476_info; 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; indio_dev->channels = st->chip_info->convst_channel;
/* Setup default message */ /* 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) { switch (size) {
case 3: case 3:
data[1] = val >> 16; put_unaligned_be24(val, &data[1]);
data[2] = val >> 8;
data[3] = val;
break; break;
case 2: case 2:
put_unaligned_be16(val, &data[1]); 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); *val = get_unaligned_be32(sigma_delta->data);
break; break;
case 3: case 3:
*val = (sigma_delta->data[0] << 16) | *val = get_unaligned_be24(&sigma_delta->data[0]);
(sigma_delta->data[1] << 8) |
sigma_delta->data[2];
break; break;
case 2: case 2:
*val = get_unaligned_be16(sigma_delta->data); *val = get_unaligned_be16(sigma_delta->data);

View File

@ -8,6 +8,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
@ -100,6 +101,8 @@
#define AT91_SAMA5D2_IER_YRDY BIT(21) #define AT91_SAMA5D2_IER_YRDY BIT(21)
/* Interrupt Enable Register - TS pressure measurement ready */ /* Interrupt Enable Register - TS pressure measurement ready */
#define AT91_SAMA5D2_IER_PRDY BIT(22) #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 */ /* Interrupt Enable Register - general overrun error */
#define AT91_SAMA5D2_IER_GOVRE BIT(25) #define AT91_SAMA5D2_IER_GOVRE BIT(25)
/* Interrupt Enable Register - Pen detect */ /* 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]); 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) static void at91_adc_config_emr(struct at91_adc_state *st)
{ {
/* configure the extended mode register */ /* 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 iio_dev *indio = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(indio); struct at91_adc_state *st = iio_priv(indio);
u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR); u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR);
u8 bit;
/* clear TRGMOD */ /* clear TRGMOD */
status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK; 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 */ /* set/unset hw trigger */
at91_adc_writel(st, AT91_SAMA5D2_TRGR, status); 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; return 0;
} }
@ -781,6 +754,7 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig)
/* Needed to ACK the DRDY interruption */ /* Needed to ACK the DRDY interruption */
at91_adc_readl(st, AT91_SAMA5D2_LCDR); at91_adc_readl(st, AT91_SAMA5D2_LCDR);
return 0; return 0;
} }
@ -888,18 +862,37 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev)
return 0; 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; int ret;
u8 bit;
struct at91_adc_state *st = iio_priv(indio_dev); struct at91_adc_state *st = iio_priv(indio_dev);
/* check if we are enabling triggered buffer or the touchscreen */ /* check if we are enabling triggered buffer or the touchscreen */
if (bitmap_subset(indio_dev->active_scan_mask, if (at91_adc_current_chan_is_touch(indio_dev))
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen enabling */
return at91_adc_configure_touch(st, true); return at91_adc_configure_touch(st, true);
}
/* if we are not in triggered mode, we cannot enable the buffer. */ /* if we are not in triggered mode, we cannot enable the buffer. */
if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES)) if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
return -EINVAL; return -EINVAL;
@ -911,41 +904,65 @@ static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
return ret; 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); 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); struct at91_adc_state *st = iio_priv(indio_dev);
int ret;
u8 bit; u8 bit;
/* check if we are disabling triggered buffer or the touchscreen */ /* check if we are disabling triggered buffer or the touchscreen */
if (bitmap_subset(indio_dev->active_scan_mask, if (at91_adc_current_chan_is_touch(indio_dev))
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen disable */
return at91_adc_configure_touch(st, false); return at91_adc_configure_touch(st, false);
}
/* if we are not in triggered mode, nothing to do here */ /* if we are not in triggered mode, nothing to do here */
if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES)) if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
return -EINVAL; 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. * 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, for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) { indio_dev->num_channels) {
@ -958,16 +975,37 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
if (chan->type == IIO_POSITIONRELATIVE || if (chan->type == IIO_POSITIONRELATIVE ||
chan->type == IIO_PRESSURE) chan->type == IIO_PRESSURE)
continue; continue;
at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
if (st->dma_st.dma_chan) if (st->dma_st.dma_chan)
at91_adc_readl(st, chan->address); 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 */ /* read overflow register to clear possible overflow status */
at91_adc_readl(st, AT91_SAMA5D2_OVER); 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 = { 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, .postenable = &at91_adc_buffer_postenable,
.predisable = &at91_adc_buffer_predisable, .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 i = 0;
int val; int val;
u8 bit; 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, for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) { 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 iio_dev *indio_dev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(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) if (st->dma_st.dma_chan)
at91_adc_trigger_handler_dma(indio_dev); at91_adc_trigger_handler_dma(indio_dev);
else 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) static int at91_adc_buffer_init(struct iio_dev *indio)
{ {
struct at91_adc_state *st = iio_priv(indio); return devm_iio_triggered_buffer_setup(&indio->dev, indio,
&iio_pollfunc_store_time,
if (st->selected_trig->hw_trig) { &at91_adc_trigger_handler, &at91_buffer_setup_ops);
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;
} }
static unsigned at91_adc_startup_time(unsigned startup_time_min, 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_XPOSR);
status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR); status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR);
status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR); 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 */ /* triggered buffer without DMA */
disable_irq_nosync(irq); disable_irq_nosync(irq);
iio_trigger_poll(indio->trig); iio_trigger_poll(indio->trig);
@ -1901,14 +1952,10 @@ static __maybe_unused int at91_adc_resume(struct device *dev)
return 0; return 0;
/* check if we are enabling triggered buffer or the touchscreen */ /* check if we are enabling triggered buffer or the touchscreen */
if (bitmap_subset(indio_dev->active_scan_mask, if (at91_adc_current_chan_is_touch(indio_dev))
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen enabling */
return at91_adc_configure_touch(st, true); return at91_adc_configure_touch(st, true);
} else { else
return at91_adc_configure_trigger(st->trig, true); return at91_adc_configure_trigger(st->trig, true);
}
/* not needed but more explicit */ /* not needed but more explicit */
return 0; return 0;

View File

@ -19,6 +19,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/of.h> #include <linux/of.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.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) { if (sample_rate == MCP3422_SRATE_3) {
ret = i2c_master_recv(adc->i2c, buf, 4); 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]; *config = buf[3];
} else { } else {
ret = i2c_master_recv(adc->i2c, buf, 3); ret = i2c_master_recv(adc->i2c, buf, 3);
temp = buf[0] << 8 | buf[1]; temp = get_unaligned_be16(&buf[0]);
*config = buf[2]; *config = buf[2];
} }

View File

@ -22,6 +22,8 @@
#include <linux/iio/triggered_buffer.h> #include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <asm/unaligned.h>
/* Commands */ /* Commands */
#define ADS124S08_CMD_NOP 0x00 #define ADS124S08_CMD_NOP 0x00
#define ADS124S08_CMD_WAKEUP 0x02 #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); struct ads124s_private *priv = iio_priv(indio_dev);
int ret; int ret;
u32 tmp;
struct spi_transfer t[] = { struct spi_transfer t[] = {
{ {
.tx_buf = &priv->data[0], .tx_buf = &priv->data[0],
@ -208,9 +209,7 @@ static int ads124s_read(struct iio_dev *indio_dev, unsigned int chan)
if (ret < 0) if (ret < 0)
return ret; return ret;
tmp = priv->data[2] << 16 | priv->data[3] << 8 | priv->data[4]; return get_unaligned_be24(&priv->data[2]);
return tmp;
} }
static int ads124s_read_raw(struct iio_dev *indio_dev, 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_PRESSURE BIT(0)
#define ATLAS_REG_DO_CALIB_STATUS_DO BIT(1) #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_TEMP_DATA 0x0e
#define ATLAS_REG_PH_DATA 0x16 #define ATLAS_REG_PH_DATA 0x16
@ -72,12 +74,14 @@
#define ATLAS_EC_INT_TIME_IN_MS 650 #define ATLAS_EC_INT_TIME_IN_MS 650
#define ATLAS_ORP_INT_TIME_IN_MS 450 #define ATLAS_ORP_INT_TIME_IN_MS 450
#define ATLAS_DO_INT_TIME_IN_MS 450 #define ATLAS_DO_INT_TIME_IN_MS 450
#define ATLAS_RTD_INT_TIME_IN_MS 450
enum { enum {
ATLAS_PH_SM, ATLAS_PH_SM,
ATLAS_EC_SM, ATLAS_EC_SM,
ATLAS_ORP_SM, ATLAS_ORP_SM,
ATLAS_DO_SM, ATLAS_DO_SM,
ATLAS_RTD_SM,
}; };
struct atlas_data { 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) static int atlas_check_ph_calibration(struct atlas_data *data)
{ {
struct device *dev = &data->client->dev; struct device *dev = &data->client->dev;
@ -350,6 +370,12 @@ static struct atlas_device atlas_devices[] = {
.calibration = &atlas_check_do_calibration, .calibration = &atlas_check_do_calibration,
.delay = ATLAS_DO_INT_TIME_IN_MS, .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) 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); struct atlas_data *data = iio_priv(indio_dev);
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
case IIO_CHAN_INFO_RAW: { case IIO_CHAN_INFO_RAW: {
int ret; int ret;
__be32 reg; __be32 reg;
@ -565,6 +592,7 @@ static const struct i2c_device_id atlas_id[] = {
{ "atlas-ec-sm", ATLAS_EC_SM}, { "atlas-ec-sm", ATLAS_EC_SM},
{ "atlas-orp-sm", ATLAS_ORP_SM}, { "atlas-orp-sm", ATLAS_ORP_SM},
{ "atlas-do-sm", ATLAS_DO_SM}, { "atlas-do-sm", ATLAS_DO_SM},
{ "atlas-rtd-sm", ATLAS_RTD_SM},
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, atlas_id); 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,ec-sm", .data = (void *)ATLAS_EC_SM, },
{ .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, }, { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
{ .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_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); MODULE_DEVICE_TABLE(of, atlas_dt_ids);

View File

@ -16,6 +16,7 @@
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
@ -36,6 +37,7 @@
#define CCS811_ERR 0xE0 #define CCS811_ERR 0xE0
/* Used to transition from boot to application mode */ /* Used to transition from boot to application mode */
#define CCS811_APP_START 0xF4 #define CCS811_APP_START 0xF4
#define CCS811_SW_RESET 0xFF
/* Status register flags */ /* Status register flags */
#define CCS811_STATUS_ERROR BIT(0) #define CCS811_STATUS_ERROR BIT(0)
@ -74,6 +76,7 @@ struct ccs811_data {
struct mutex lock; /* Protect readings */ struct mutex lock; /* Protect readings */
struct ccs811_reading buffer; struct ccs811_reading buffer;
struct iio_trigger *drdy_trig; struct iio_trigger *drdy_trig;
struct gpio_desc *wakeup_gpio;
bool drdy_trig_on; bool drdy_trig_on;
}; };
@ -166,10 +169,25 @@ static int ccs811_setup(struct i2c_client *client)
CCS811_MODE_IAQ_1SEC); 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) static int ccs811_get_measurement(struct ccs811_data *data)
{ {
int ret, tries = 11; int ret, tries = 11;
ccs811_set_wakeup(data, true);
/* Maximum waiting time: 1s, as measurements are made every second */ /* Maximum waiting time: 1s, as measurements are made every second */
while (tries-- > 0) { while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS); 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)) if (!(ret & CCS811_STATUS_DATA_READY))
return -EIO; 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, CCS811_ALG_RESULT_DATA, 8,
(char *)&data->buffer); (char *)&data->buffer);
ccs811_set_wakeup(data, false);
return ret;
} }
static int ccs811_read_raw(struct iio_dev *indio_dev, 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; 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, static int ccs811_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -348,37 +408,60 @@ static int ccs811_probe(struct i2c_client *client,
| I2C_FUNC_SMBUS_READ_I2C_BLOCK)) | I2C_FUNC_SMBUS_READ_I2C_BLOCK))
return -EOPNOTSUPP; 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)); indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) if (!indio_dev)
return -ENOMEM; return -ENOMEM;
ret = ccs811_setup(client);
if (ret < 0)
return ret;
data = iio_priv(indio_dev); data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev); i2c_set_clientdata(client, indio_dev);
data->client = client; 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); mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = &client->dev;
@ -466,9 +549,16 @@ static const struct i2c_device_id ccs811_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, 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 = { static struct i2c_driver ccs811_driver = {
.driver = { .driver = {
.name = "ccs811", .name = "ccs811",
.of_match_table = ccs811_dt_ids,
}, },
.probe = ccs811_probe, .probe = ccs811_probe,
.remove = ccs811_remove, .remove = ccs811_remove,

View File

@ -13,6 +13,8 @@
#include <linux/hid-sensor-hub.h> #include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/trigger.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/buffer.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include "hid-sensor-trigger.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); 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)) if (atomic_read(&attrb->runtime_pm_enable))
pm_runtime_disable(&attrb->pdev->dev); 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); cancel_work_sync(&attrb->work);
iio_trigger_unregister(attrb->trigger); iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger); iio_trigger_free(attrb->trigger);
iio_triggered_buffer_cleanup(indio_dev);
} }
EXPORT_SYMBOL(hid_sensor_remove_trigger); 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; int ret;
struct iio_trigger *trig; 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); trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
if (trig == NULL) { if (trig == NULL) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
ret = -ENOMEM; ret = -ENOMEM;
goto error_ret; goto error_triggered_buffer_cleanup;
} }
trig->dev.parent = indio_dev->dev.parent; trig->dev.parent = indio_dev->dev.parent;
@ -284,7 +295,8 @@ error_unreg_trigger:
iio_trigger_unregister(trig); iio_trigger_unregister(trig);
error_free_trig: error_free_trig:
iio_trigger_free(trig); iio_trigger_free(trig);
error_ret: error_triggered_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret; return ret;
} }
EXPORT_SYMBOL(hid_sensor_setup_trigger); 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, int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb); 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); int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
#endif #endif

View File

@ -20,11 +20,6 @@
#include "st_sensors_core.h" #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, int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
u8 reg_addr, u8 mask, u8 data) 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) else if (byte_for_channel == 2)
*data = (s16)get_unaligned_le16(outdata); *data = (s16)get_unaligned_le16(outdata);
else if (byte_for_channel == 3) 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: st_sensors_free_memory:
kfree(outdata); kfree(outdata);

View File

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

View File

@ -21,6 +21,8 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <asm/unaligned.h>
#define MODE_PWRDWN_1k 0x1 #define MODE_PWRDWN_1k 0x1
#define MODE_PWRDWN_100k 0x2 #define MODE_PWRDWN_100k 0x2
#define MODE_PWRDWN_TRISTATE 0x3 #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); struct spi_device *spi = to_spi_device(st->dev);
uint8_t data[3]; uint8_t data[3];
data[0] = (val >> 16) & 0xFF; put_unaligned_be24(val, &data[0]);
data[1] = (val >> 8) & 0xFF;
data[2] = val & 0xFF;
return spi_write(spi, data, sizeof(data)); 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; 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; int ret;
@ -121,7 +121,7 @@ static const struct ad5592r_rw_ops ad5592r_rw_ops = {
.read_adc = ad5592r_read_adc, .read_adc = ad5592r_read_adc,
.reg_write = ad5592r_reg_write, .reg_write = ad5592r_reg_write,
.reg_read = ad5592r_reg_read, .reg_read = ad5592r_reg_read,
.gpio_read = ad5593r_gpio_read, .gpio_read = ad5592r_gpio_read,
}; };
static int ad5592r_spi_probe(struct spi_device *spi) 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_i2c_driver(ad5593r_driver);
MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>"); 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"); MODULE_LICENSE("GPL v2");

View File

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

View File

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

View File

@ -12,6 +12,8 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <asm/unaligned.h>
#define ADIS16130_CON 0x0 #define ADIS16130_CON 0x0
#define ADIS16130_CON_RD (1 << 6) #define ADIS16130_CON_RD (1 << 6)
#define ADIS16130_IOP 0x1 #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); ret = spi_sync_transfer(st->us, &xfer, 1);
if (ret == 0) 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); mutex_unlock(&st->buf_lock);
return ret; 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) static int adis16136_debugfs_init(struct iio_dev *indio_dev)
{ {
struct adis16136 *adis16136 = iio_priv(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, debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, adis16136, d, adis16136, &adis16136_serial_fops);
&adis16136_serial_fops);
debugfs_create_file_unsafe("product_id", 0400, debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry, d, adis16136, &adis16136_product_id_fops);
adis16136, &adis16136_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400, debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry, d, adis16136, &adis16136_flash_count_fops);
adis16136, &adis16136_flash_count_fops);
return 0; return 0;
} }

View File

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

View File

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

View File

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

View File

@ -29,6 +29,19 @@ config ADIS16460
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called adis16460. 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 config ADIS16480
tristate "Analog Devices ADIS16480 and similar IMU driver" tristate "Analog Devices ADIS16480 and similar IMU driver"
depends on SPI depends on SPI

View File

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

View File

@ -223,6 +223,31 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(__adis_read_reg); 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 #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) static int adis16400_debugfs_init(struct iio_dev *indio_dev)
{ {
struct adis16400_state *st = iio_priv(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) if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER)
debugfs_create_file_unsafe("serial_number", 0400, debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, st, d, st, &adis16400_serial_number_fops);
&adis16400_serial_number_fops);
if (st->variant->flags & ADIS16400_HAS_PROD_ID) if (st->variant->flags & ADIS16400_HAS_PROD_ID)
debugfs_create_file_unsafe("product_id", 0400, debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry, st, d, st, &adis16400_product_id_fops);
&adis16400_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400, debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry, st, d, st, &adis16400_flash_count_fops);
&adis16400_flash_count_fops);
return 0; return 0;
} }
@ -1195,7 +1193,7 @@ static int adis16400_probe(struct spi_device *spi)
indio_dev->available_scan_masks = st->avail_scan_mask; indio_dev->available_scan_masks = st->avail_scan_mask;
st->adis.burst = &adis16400_burst; st->adis.burst = &adis16400_burst;
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) 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; 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) static int adis16460_debugfs_init(struct iio_dev *indio_dev)
{ {
struct adis16460 *adis16460 = iio_priv(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, debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, adis16460, d, adis16460, &adis16460_serial_number_fops);
&adis16460_serial_number_fops);
debugfs_create_file_unsafe("product_id", 0400, debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry, adis16460, d, adis16460, &adis16460_product_id_fops);
&adis16460_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400, debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry, adis16460, d, adis16460, &adis16460_flash_count_fops);
&adis16460_flash_count_fops);
return 0; return 0;
} }

1338
drivers/iio/imu/adis16475.c Normal file

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) static int adis16480_debugfs_init(struct iio_dev *indio_dev)
{ {
struct adis16480 *adis16480 = iio_priv(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, debugfs_create_file_unsafe("firmware_revision", 0400,
indio_dev->debugfs_dentry, adis16480, d, adis16480, &adis16480_firmware_revision_fops);
&adis16480_firmware_revision_fops);
debugfs_create_file_unsafe("firmware_date", 0400, debugfs_create_file_unsafe("firmware_date", 0400,
indio_dev->debugfs_dentry, adis16480, d, adis16480, &adis16480_firmware_date_fops);
&adis16480_firmware_date_fops);
debugfs_create_file_unsafe("serial_number", 0400, debugfs_create_file_unsafe("serial_number", 0400,
indio_dev->debugfs_dentry, adis16480, d, adis16480, &adis16480_serial_number_fops);
&adis16480_serial_number_fops);
debugfs_create_file_unsafe("product_id", 0400, debugfs_create_file_unsafe("product_id", 0400,
indio_dev->debugfs_dentry, adis16480, d, adis16480, &adis16480_product_id_fops);
&adis16480_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400, debugfs_create_file_unsafe("flash_count", 0400,
indio_dev->debugfs_dentry, adis16480, d, adis16480, &adis16480_flash_count_fops);
&adis16480_flash_count_fops);
return 0; 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) const unsigned long *scan_mask)
{ {
struct adis *adis = iio_device_get_drvdata(indio_dev); struct adis *adis = iio_device_get_drvdata(indio_dev);
unsigned int burst_length; unsigned int burst_length, burst_max_length;
u8 *tx; u8 *tx;
/* All but the timestamp channel */ /* All but the timestamp channel */
burst_length = (indio_dev->num_channels - 1) * sizeof(u16); 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); adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
if (!adis->xfer) if (!adis->xfer)
return -ENOMEM; return -ENOMEM;
adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL); adis->buffer = kzalloc(burst_max_length + sizeof(u16), GFP_KERNEL);
if (!adis->buffer) { if (!adis->buffer) {
kfree(adis->xfer); kfree(adis->xfer);
adis->xfer = NULL; adis->xfer = NULL;
return -ENOMEM; return -ENOMEM;
} }
tx = adis->buffer + burst_length; tx = adis->buffer + burst_max_length;
tx[0] = ADIS_READ_REG(adis->burst->reg_cmd); tx[0] = ADIS_READ_REG(adis->burst->reg_cmd);
tx[1] = 0; tx[1] = 0;
@ -156,6 +161,14 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
return IRQ_HANDLED; 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_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device
* @adis: The adis device. * @adis: The adis device.
@ -198,6 +211,43 @@ error_buffer_cleanup:
} }
EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger); 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_cleanup_buffer_and_trigger() - Free buffer and trigger resources
* @adis: The adis device. * @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, .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_probe_trigger() - Sets up trigger for a adis device
* @adis: The 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) if (adis->trig == NULL)
return -ENOMEM; return -ENOMEM;
adis->trig->dev.parent = &adis->spi->dev; adis_trigger_setup(adis);
adis->trig->ops = &adis_trigger_ops;
iio_trigger_set_drvdata(adis->trig, adis); ret = adis_validate_irq_flag(adis);
if (ret)
return ret;
ret = request_irq(adis->spi->irq, ret = request_irq(adis->spi->irq,
&iio_trigger_generic_data_rdy_poll, &iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING, adis->irq_flag,
indio_dev->name, indio_dev->name,
adis->trig); adis->trig);
if (ret) if (ret)
@ -73,6 +103,40 @@ error_free_trig:
} }
EXPORT_SYMBOL_GPL(adis_probe_trigger); 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_remove_trigger() - Remove trigger for a adis devices
* @adis: The adis device * @adis: The adis device

View File

@ -27,7 +27,8 @@
* - FIFO size: 4KB * - FIFO size: 4KB
* *
* - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: * - 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 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 3KB * - FIFO size: 3KB
@ -791,7 +792,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 }, .odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 }, .odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 }, .odr_avl[5] = { 416000, 0x06 },
.odr_len = 6, .odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
}, },
[ST_LSM6DSX_ID_GYRO] = { [ST_LSM6DSX_ID_GYRO] = {
.reg = { .reg = {
@ -804,7 +806,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 }, .odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 }, .odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 }, .odr_avl[5] = { 416000, 0x06 },
.odr_len = 6, .odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
}, },
}, },
.fs_table = { .fs_table = {
@ -994,7 +997,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 }, .odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 }, .odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 }, .odr_avl[5] = { 416000, 0x06 },
.odr_len = 6, .odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
}, },
[ST_LSM6DSX_ID_GYRO] = { [ST_LSM6DSX_ID_GYRO] = {
.reg = { .reg = {
@ -1007,7 +1011,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 }, .odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 }, .odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 }, .odr_avl[5] = { 416000, 0x06 },
.odr_len = 6, .odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
}, },
}, },
.fs_table = { .fs_table = {
@ -1171,7 +1176,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 }, .odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 }, .odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 }, .odr_avl[5] = { 416000, 0x06 },
.odr_len = 6, .odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
}, },
[ST_LSM6DSX_ID_GYRO] = { [ST_LSM6DSX_ID_GYRO] = {
.reg = { .reg = {
@ -1184,7 +1190,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.odr_avl[3] = { 104000, 0x04 }, .odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 }, .odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 }, .odr_avl[5] = { 416000, 0x06 },
.odr_len = 6, .odr_avl[6] = { 833000, 0x07 },
.odr_len = 7,
}, },
}, },
.fs_table = { .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) void iio_buffer_wakeup_poll(struct iio_dev *indio_dev)
{ {
if (!indio_dev->buffer) struct iio_buffer *buffer = indio_dev->buffer;
if (!buffer)
return; return;
wake_up(&indio_dev->buffer->pollq); wake_up(&buffer->pollq);
} }
void iio_buffer_init(struct iio_buffer *buffer) void iio_buffer_init(struct iio_buffer *buffer)
@ -262,10 +264,11 @@ static ssize_t iio_scan_el_show(struct device *dev,
{ {
int ret; int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
/* Ensure ret is 0 or 1. */ /* Ensure ret is 0 or 1. */
ret = !!test_bit(to_iio_dev_attr(attr)->address, ret = !!test_bit(to_iio_dev_attr(attr)->address,
indio_dev->buffer->scan_mask); buffer->scan_mask);
return sprintf(buf, "%d\n", ret); return sprintf(buf, "%d\n", ret);
} }
@ -381,7 +384,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; return ret;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
if (iio_buffer_is_active(indio_dev->buffer)) { if (iio_buffer_is_active(buffer)) {
ret = -EBUSY; ret = -EBUSY;
goto error_ret; goto error_ret;
} }
@ -410,7 +413,9 @@ static ssize_t iio_scan_el_ts_show(struct device *dev,
char *buf) char *buf)
{ {
struct iio_dev *indio_dev = dev_to_iio_dev(dev); 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, 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; int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
bool state; bool state;
ret = strtobool(buf, &state); ret = strtobool(buf, &state);
@ -427,11 +433,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
return ret; return ret;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
if (iio_buffer_is_active(indio_dev->buffer)) { if (iio_buffer_is_active(buffer)) {
ret = -EBUSY; ret = -EBUSY;
goto error_ret; goto error_ret;
} }
indio_dev->buffer->scan_timestamp = state; buffer->scan_timestamp = state;
error_ret: error_ret:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
@ -439,10 +445,10 @@ error_ret:
} }
static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
struct iio_buffer *buffer,
const struct iio_chan_spec *chan) const struct iio_chan_spec *chan)
{ {
int ret, attrcount = 0; int ret, attrcount = 0;
struct iio_buffer *buffer = indio_dev->buffer;
ret = __iio_add_chan_devattr("index", ret = __iio_add_chan_devattr("index",
chan, chan,
@ -518,7 +524,7 @@ static ssize_t iio_buffer_write_length(struct device *dev,
return len; return len;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
if (iio_buffer_is_active(indio_dev->buffer)) { if (iio_buffer_is_active(buffer)) {
ret = -EBUSY; ret = -EBUSY;
} else { } else {
buffer->access->set_length(buffer, val); buffer->access->set_length(buffer, val);
@ -539,7 +545,9 @@ static ssize_t iio_buffer_show_enable(struct device *dev,
char *buf) char *buf)
{ {
struct iio_dev *indio_dev = dev_to_iio_dev(dev); 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, 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; int ret;
bool requested_state; bool requested_state;
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
bool inlist; bool inlist;
ret = strtobool(buf, &requested_state); ret = strtobool(buf, &requested_state);
@ -1138,17 +1147,15 @@ static ssize_t iio_buffer_store_enable(struct device *dev,
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
/* Find out if it is in the list */ /* 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 */ /* Already in desired state */
if (inlist == requested_state) if (inlist == requested_state)
goto done; goto done;
if (requested_state) if (requested_state)
ret = __iio_update_buffers(indio_dev, ret = __iio_update_buffers(indio_dev, buffer, NULL);
indio_dev->buffer, NULL);
else else
ret = __iio_update_buffers(indio_dev, ret = __iio_update_buffers(indio_dev, NULL, buffer);
NULL, indio_dev->buffer);
done: done:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
@ -1190,7 +1197,7 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
goto out; goto out;
} }
if (iio_buffer_is_active(indio_dev->buffer)) { if (iio_buffer_is_active(buffer)) {
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
@ -1207,11 +1214,9 @@ static ssize_t iio_dma_show_data_available(struct device *dev,
char *buf) char *buf)
{ {
struct iio_dev *indio_dev = dev_to_iio_dev(dev); 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", iio_buffer_data_available(buffer));
return sprintf(buf, "%zu\n", bytes);
} }
static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length, 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) if (channels[i].scan_index < 0)
continue; continue;
ret = iio_buffer_add_channel_sysfs(indio_dev, ret = iio_buffer_add_channel_sysfs(indio_dev, buffer,
&channels[i]); &channels[i]);
if (ret < 0) if (ret < 0)
goto error_cleanup_dynamic; goto error_cleanup_dynamic;
@ -1332,20 +1337,22 @@ error_free_scan_mask:
bitmap_free(buffer->scan_mask); bitmap_free(buffer->scan_mask);
error_cleanup_dynamic: error_cleanup_dynamic:
iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); 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; return ret;
} }
void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) 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; return;
bitmap_free(indio_dev->buffer->scan_mask); bitmap_free(buffer->scan_mask);
kfree(indio_dev->buffer->buffer_group.attrs); kfree(buffer->buffer_group.attrs);
kfree(indio_dev->buffer->scan_el_group.attrs); kfree(buffer->scan_el_group.attrs);
iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list); 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; alloc_size += IIO_ALIGN - 1;
dev = kzalloc(alloc_size, GFP_KERNEL); dev = kzalloc(alloc_size, GFP_KERNEL);
if (!dev)
return NULL;
if (dev) { dev->dev.groups = dev->groups;
dev->dev.groups = dev->groups; dev->dev.type = &iio_device_type;
dev->dev.type = &iio_device_type; dev->dev.bus = &iio_bus_type;
dev->dev.bus = &iio_bus_type; device_initialize(&dev->dev);
device_initialize(&dev->dev); dev_set_drvdata(&dev->dev, (void *)dev);
dev_set_drvdata(&dev->dev, (void *)dev); mutex_init(&dev->mlock);
mutex_init(&dev->mlock); mutex_init(&dev->info_exist_lock);
mutex_init(&dev->info_exist_lock); INIT_LIST_HEAD(&dev->channel_attr_list);
INIT_LIST_HEAD(&dev->channel_attr_list);
dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
if (dev->id < 0) { if (dev->id < 0) {
/* cannot use a dev_err as the name isn't available */ /* cannot use a dev_err as the name isn't available */
pr_err("failed to get device id\n"); pr_err("failed to get device id\n");
kfree(dev); kfree(dev);
return NULL; return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
INIT_LIST_HEAD(&dev->buffer_list);
} }
dev_set_name(&dev->dev, "iio:device%d", dev->id);
INIT_LIST_HEAD(&dev->buffer_list);
return dev; return dev;
} }

View File

@ -516,6 +516,8 @@ config US5182D
config VCNL4000 config VCNL4000
tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor" tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
depends on I2C depends on I2C
help help
Say Y here if you want to build a driver for the Vishay VCNL4000, 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/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
@ -273,13 +273,11 @@ static const struct i2c_device_id bh1780_id[] = {
MODULE_DEVICE_TABLE(i2c, bh1780_id); MODULE_DEVICE_TABLE(i2c, bh1780_id);
#ifdef CONFIG_OF
static const struct of_device_id of_bh1780_match[] = { static const struct of_device_id of_bh1780_match[] = {
{ .compatible = "rohm,bh1780gli", }, { .compatible = "rohm,bh1780gli", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, of_bh1780_match); MODULE_DEVICE_TABLE(of, of_bh1780_match);
#endif
static struct i2c_driver bh1780_driver = { static struct i2c_driver bh1780_driver = {
.probe = bh1780_probe, .probe = bh1780_probe,
@ -288,7 +286,7 @@ static struct i2c_driver bh1780_driver = {
.driver = { .driver = {
.name = "bh1780", .name = "bh1780",
.pm = &bh1780_dev_pm_ops, .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> * Author: Kevin Tsai <ktsai@capellamicro.com>
*/ */
#include <linux/acpi.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
@ -18,17 +20,24 @@
/* Registers Address */ /* Registers Address */
#define CM32181_REG_ADDR_CMD 0x00 #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_ALS 0x04
#define CM32181_REG_ADDR_STATUS 0x06 #define CM32181_REG_ADDR_STATUS 0x06
#define CM32181_REG_ADDR_ID 0x07 #define CM32181_REG_ADDR_ID 0x07
/* Number of Configurable Registers */ /* Number of Configurable Registers */
#define CM32181_CONF_REG_NUM 0x01 #define CM32181_CONF_REG_NUM 4
/* CMD register */ /* CMD register */
#define CM32181_CMD_ALS_ENABLE 0x00 #define CM32181_CMD_ALS_DISABLE BIT(0)
#define CM32181_CMD_ALS_DISABLE 0x01 #define CM32181_CMD_ALS_INT_EN BIT(1)
#define CM32181_CMD_ALS_INT_EN 0x02 #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_SHIFT 6
#define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT) #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_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT)
#define CM32181_CMD_ALS_SM_DEFAULT (0x01 << 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_LUX_PER_BIT 500 /* ALS_SM=01 IT=800ms */
#define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */ #define CM32181_LUX_PER_BIT_RESOLUTION 100000
#define CM32181_CALIBSCALE_DEFAULT 1000 #define CM32181_LUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
#define CM32181_CALIBSCALE_RESOLUTION 1000 #define CM32181_CALIBSCALE_DEFAULT 100000
#define MLUX_PER_LUX 1000 #define CM32181_CALIBSCALE_RESOLUTION 100000
static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = { #define SMBUS_ALERT_RESPONSE_ADDRESS 0x0c
CM32181_REG_ADDR_CMD,
/* 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 cm32181_chip {
struct i2c_client *client; struct i2c_client *client;
struct device *dev;
struct mutex lock; struct mutex lock;
u16 conf_regs[CM32181_CONF_REG_NUM]; u16 conf_regs[CM32181_CONF_REG_NUM];
unsigned long init_regs_bitmap;
int calibscale; 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_reg_init() - Initialize CM32181 registers
* @cm32181: pointer of struct cm32181. * @cm32181: pointer of struct cm32181.
@ -78,18 +193,37 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return ret; return ret;
/* check device ID */ /* 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; return -ENODEV;
}
/* Default Values */ /* 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_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT;
cm32181->init_regs_bitmap = BIT(CM32181_REG_ADDR_CMD);
cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT; 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*/ /* Initialize registers*/
for (i = 0; i < CM32181_CONF_REG_NUM; i++) { for_each_set_bit(i, &cm32181->init_regs_bitmap, CM32181_CONF_REG_NUM) {
ret = i2c_smbus_write_word_data(client, cm32181_reg[i], ret = i2c_smbus_write_word_data(client, i,
cm32181->conf_regs[i]); cm32181->conf_regs[i]);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
@ -102,7 +236,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
* @cm32181: pointer of struct cm32181 * @cm32181: pointer of struct cm32181
* @val2: pointer of int to load the als_it value. * @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. * 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->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK; als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT; als_it >>= CM32181_CMD_ALS_IT_SHIFT;
for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) { for (i = 0; i < cm32181->num_als_it; i++) {
if (als_it == als_it_bits[i]) { if (als_it == cm32181->als_it_bits[i]) {
*val2 = als_it_value[i]; *val2 = cm32181->als_it_values[i];
return IIO_VAL_INT_PLUS_MICRO; 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; u16 als_it;
int ret, i, n; int ret, i, n;
n = ARRAY_SIZE(als_it_value); n = cm32181->num_als_it;
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
if (val <= als_it_value[i]) if (val <= cm32181->als_it_values[i])
break; break;
if (i >= n) if (i >= n)
i = n - 1; i = n - 1;
als_it = als_it_bits[i]; als_it = cm32181->als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT; als_it <<= CM32181_CMD_ALS_IT_SHIFT;
mutex_lock(&cm32181->lock); mutex_lock(&cm32181->lock);
@ -175,15 +309,15 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
struct i2c_client *client = cm32181->client; struct i2c_client *client = cm32181->client;
int ret; int ret;
int als_it; int als_it;
unsigned long lux; u64 lux;
ret = cm32181_read_als_it(cm32181, &als_it); ret = cm32181_read_als_it(cm32181, &als_it);
if (ret < 0) if (ret < 0)
return -EINVAL; return -EINVAL;
lux = CM32181_MLUX_PER_BIT; lux = cm32181->lux_per_bit;
lux *= CM32181_MLUX_PER_BIT_BASE_IT; lux *= cm32181->lux_per_bit_base_it;
lux /= als_it; lux = div_u64(lux, als_it);
ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS); ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
if (ret < 0) if (ret < 0)
@ -191,8 +325,8 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
lux *= ret; lux *= ret;
lux *= cm32181->calibscale; lux *= cm32181->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION; lux = div_u64(lux, CM32181_CALIBSCALE_RESOLUTION);
lux /= MLUX_PER_LUX; lux = div_u64(lux, CM32181_LUX_PER_BIT_RESOLUTION);
if (lux > 0xFFFF) if (lux > 0xFFFF)
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, static ssize_t cm32181_get_it_available(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct cm32181_chip *cm32181 = iio_priv(dev_to_iio_dev(dev));
int i, n, len; int i, n, len;
n = ARRAY_SIZE(als_it_value); n = cm32181->num_als_it;
for (i = 0, len = 0; i < n; i++) 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"); return len + sprintf(buf + len, "\n");
} }
@ -294,70 +429,86 @@ static const struct iio_info cm32181_info = {
.attrs = &cm32181_attribute_group, .attrs = &cm32181_attribute_group,
}; };
static int cm32181_probe(struct i2c_client *client, static int cm32181_probe(struct i2c_client *client)
const struct i2c_device_id *id)
{ {
struct device *dev = &client->dev;
struct cm32181_chip *cm32181; struct cm32181_chip *cm32181;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
int ret; int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181)); indio_dev = devm_iio_device_alloc(dev, sizeof(*cm32181));
if (!indio_dev) { if (!indio_dev)
dev_err(&client->dev, "devm_iio_device_alloc failed\n");
return -ENOMEM; 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); cm32181 = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
cm32181->client = client; cm32181->client = client;
cm32181->dev = dev;
mutex_init(&cm32181->lock); mutex_init(&cm32181->lock);
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = dev;
indio_dev->channels = cm32181_channels; indio_dev->channels = cm32181_channels;
indio_dev->num_channels = ARRAY_SIZE(cm32181_channels); indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
indio_dev->info = &cm32181_info; indio_dev->info = &cm32181_info;
indio_dev->name = id->name; indio_dev->name = dev_name(dev);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = cm32181_reg_init(cm32181); ret = cm32181_reg_init(cm32181);
if (ret) { if (ret) {
dev_err(&client->dev, dev_err(dev, "%s: register init failed\n", __func__);
"%s: register init failed\n",
__func__);
return ret; return ret;
} }
ret = devm_iio_device_register(&client->dev, indio_dev); ret = devm_iio_device_register(dev, indio_dev);
if (ret) { if (ret) {
dev_err(&client->dev, dev_err(dev, "%s: regist device failed\n", __func__);
"%s: regist device failed\n",
__func__);
return ret; return ret;
} }
return 0; 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[] = { static const struct of_device_id cm32181_of_match[] = {
{ .compatible = "capella,cm3218" },
{ .compatible = "capella,cm32181" }, { .compatible = "capella,cm32181" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, cm32181_of_match); 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 = { static struct i2c_driver cm32181_driver = {
.driver = { .driver = {
.name = "cm32181", .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_new = cm32181_probe,
.probe = cm32181_probe,
}; };
module_i2c_driver(cm32181_driver); module_i2c_driver(cm32181_driver);

View File

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

View File

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

View File

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

View File

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

View File

@ -101,12 +101,12 @@ struct ltr501_gain {
int uscale; int uscale;
}; };
static struct ltr501_gain ltr501_als_gain_tbl[] = { static const struct ltr501_gain ltr501_als_gain_tbl[] = {
{1, 0}, {1, 0},
{0, 5000}, {0, 5000},
}; };
static struct ltr501_gain ltr559_als_gain_tbl[] = { static const struct ltr501_gain ltr559_als_gain_tbl[] = {
{1, 0}, {1, 0},
{0, 500000}, {0, 500000},
{0, 250000}, {0, 250000},
@ -117,14 +117,14 @@ static struct ltr501_gain ltr559_als_gain_tbl[] = {
{0, 10000}, {0, 10000},
}; };
static struct ltr501_gain ltr501_ps_gain_tbl[] = { static const struct ltr501_gain ltr501_ps_gain_tbl[] = {
{1, 0}, {1, 0},
{0, 250000}, {0, 250000},
{0, 125000}, {0, 125000},
{0, 62500}, {0, 62500},
}; };
static struct ltr501_gain ltr559_ps_gain_tbl[] = { static const struct ltr501_gain ltr559_ps_gain_tbl[] = {
{0, 62500}, /* x16 gain */ {0, 62500}, /* x16 gain */
{0, 31250}, /* x32 gain */ {0, 31250}, /* x32 gain */
{0, 15625}, /* bits X1 are for x64 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 { struct ltr501_chip_info {
u8 partid; u8 partid;
struct ltr501_gain *als_gain; const struct ltr501_gain *als_gain;
int als_gain_tbl_size; int als_gain_tbl_size;
struct ltr501_gain *ps_gain; const struct ltr501_gain *ps_gain;
int ps_gain_tbl_size; int ps_gain_tbl_size;
u8 als_mode_active; u8 als_mode_active;
u8 als_gain_mask; u8 als_gain_mask;
@ -192,7 +192,7 @@ static int ltr501_match_samp_freq(const struct ltr501_samp_table *tab,
return -EINVAL; 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 *val, int *val2)
{ {
int ret, i; int ret, i;
@ -210,7 +210,7 @@ static int ltr501_als_read_samp_freq(struct ltr501_data *data,
return IIO_VAL_INT_PLUS_MICRO; 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 *val, int *val2)
{ {
int ret, i; int ret, i;
@ -266,7 +266,7 @@ static int ltr501_ps_write_samp_freq(struct ltr501_data *data,
return ret; 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; int ret, i;
@ -282,7 +282,7 @@ static int ltr501_als_read_samp_period(struct ltr501_data *data, int *val)
return IIO_VAL_INT; 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; int ret, i;
@ -321,7 +321,7 @@ static unsigned long ltr501_calculate_lux(u16 vis_data, u16 ir_data)
return lux / 1000; 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 tries = 100;
int ret, status; 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 */ /* 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; 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; 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; int ret;
@ -403,7 +404,7 @@ static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
buf, 2 * sizeof(__le16)); 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; int ret, status;
@ -419,7 +420,7 @@ static int ltr501_read_ps(struct ltr501_data *data)
return status; 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, enum iio_chan_type type,
int *val2) int *val2)
{ {
@ -716,7 +717,7 @@ static int ltr501_read_raw(struct iio_dev *indio_dev,
return -EINVAL; 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 val, int val2)
{ {
int i; int i;
@ -848,14 +849,14 @@ static int ltr501_write_raw(struct iio_dev *indio_dev,
return ret; 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, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_direction dir,
enum iio_event_info info, enum iio_event_info info,
int *val, int *val2) 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; int ret, thresh_data;
switch (chan->type) { 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, .name = LTR501_REGMAP_NAME,
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@
* *
* Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net> * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
* Copyright 2019 Pursim SPC * Copyright 2019 Pursim SPC
* Copyright 2020 Mathieu Othacehe <m.othacehe@gmail.com>
* *
* IIO driver for: * IIO driver for:
* VCNL4000/10/20 (7-bit I2C slave address 0x13) * VCNL4000/10/20 (7-bit I2C slave address 0x13)
@ -13,9 +14,7 @@
* *
* TODO: * TODO:
* allow to adjust IR current * allow to adjust IR current
* proximity threshold and event handling * interrupts (VCNL4040, VCNL4200)
* periodic ALS/proximity measurement (VCNL4010/20)
* interrupts (VCNL4010/20/40, VCNL4200)
*/ */
#include <linux/module.h> #include <linux/module.h>
@ -23,9 +22,15 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm_runtime.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/iio.h>
#include <linux/iio/sysfs.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_DRV_NAME "vcnl4000"
#define VCNL4000_PROD_ID 0x01 #define VCNL4000_PROD_ID 0x01
@ -35,14 +40,22 @@
#define VCNL4000_COMMAND 0x80 /* Command register */ #define VCNL4000_COMMAND 0x80 /* Command register */
#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */ #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_LED_CURRENT 0x83 /* IR LED current for proximity mode */
#define VCNL4000_AL_PARAM 0x84 /* Ambient light parameter register */ #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_HI 0x85 /* Ambient light result register, MSB */
#define VCNL4000_AL_RESULT_LO 0x86 /* Ambient light result register, LSB */ #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_HI 0x87 /* Proximity result register, MSB */
#define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */ #define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */
#define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */ #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 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_AL_CONF 0x00 /* Ambient light configuration */
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */ #define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
@ -57,6 +70,36 @@
#define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */ #define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
#define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */ #define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
#define VCNL4000_PS_OD BIT(3) /* start on-demand proximity 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 */ #define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
@ -88,6 +131,10 @@ struct vcnl4000_data {
struct vcnl4000_chip_spec { struct vcnl4000_chip_spec {
const char *prod; 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 (*init)(struct vcnl4000_data *data);
int (*measure_light)(struct vcnl4000_data *data, int *val); int (*measure_light)(struct vcnl4000_data *data, int *val);
int (*measure_proximity)(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; 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, static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
u8 rdy_mask, u8 data_reg, int *val) u8 rdy_mask, u8 data_reg, int *val)
{ {
int tries = 20; int tries = 20;
__be16 buf;
int ret; int ret;
mutex_lock(&data->vcnl4000_lock); mutex_lock(&data->vcnl4000_lock);
@ -247,13 +314,11 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
goto fail; goto fail;
} }
ret = i2c_smbus_read_i2c_block_data(data->client, ret = vcnl4000_read_data(data, data_reg, val);
data_reg, sizeof(buf), (u8 *) &buf);
if (ret < 0) if (ret < 0)
goto fail; goto fail;
mutex_unlock(&data->vcnl4000_lock); mutex_unlock(&data->vcnl4000_lock);
*val = be16_to_cpu(buf);
return 0; 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); return vcnl4200_measure(data, &data->vcnl4200_ps, val);
} }
static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,
[VCNL4000] = { int *val2)
.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)
{ {
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[] = { static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
{ {
.name = "nearlevel", int ret;
.shared = IIO_SEPARATE,
.read = vcnl4000_read_near_level,
},
{ /* sentinel */ }
};
static const struct iio_chan_spec vcnl4000_channels[] = { ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
{ if (ret < 0)
.type = IIO_LIGHT, return false;
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE), return !!(ret & VCNL4000_SELF_TIMED_EN);
}, { }
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.ext_info = vcnl4000_ext_info,
}
};
static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on) 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 = { static const struct iio_info vcnl4000_info = {
.read_raw = vcnl4000_read_raw, .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, static int vcnl4000_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -466,12 +1059,39 @@ static int vcnl4000_probe(struct i2c_client *client,
data->near_level = 0; data->near_level = 0;
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = &client->dev;
indio_dev->info = &vcnl4000_info; indio_dev->info = data->chip_spec->info;
indio_dev->channels = vcnl4000_channels; indio_dev->channels = data->chip_spec->channels;
indio_dev->num_channels = ARRAY_SIZE(vcnl4000_channels); indio_dev->num_channels = data->chip_spec->num_channels;
indio_dev->name = VCNL4000_DRV_NAME; indio_dev->name = VCNL4000_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE; 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); ret = pm_runtime_set_active(&client->dev);
if (ret < 0) if (ret < 0)
goto fail_poweroff; goto fail_poweroff;
@ -565,5 +1185,6 @@ static struct i2c_driver vcnl4000_driver = {
module_i2c_driver(vcnl4000_driver); module_i2c_driver(vcnl4000_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 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_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

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

View File

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

View File

@ -49,6 +49,7 @@
#define AK8974_WHOAMI_VALUE_AMI306 0x46 #define AK8974_WHOAMI_VALUE_AMI306 0x46
#define AK8974_WHOAMI_VALUE_AMI305 0x47 #define AK8974_WHOAMI_VALUE_AMI305 0x47
#define AK8974_WHOAMI_VALUE_AK8974 0x48 #define AK8974_WHOAMI_VALUE_AK8974 0x48
#define AK8974_WHOAMI_VALUE_HSCDTD008A 0x49
#define AK8974_DATA_X 0x10 #define AK8974_DATA_X 0x10
#define AK8974_DATA_Y 0x12 #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_PULSE BIT(1) /* 0 = latched; 1 = pulse (50 usec) */
#define AK8974_INT_CTRL_RESDEF (AK8974_INT_CTRL_XYZEN | AK8974_INT_CTRL_POL) #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 */ /* The AMI305 has elaborate FW version and serial number registers */
#define AMI305_VER 0xE8 #define AMI305_VER 0xE8
#define AMI305_SN 0xEA #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); ret = regmap_write(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_RESDEF);
if (ret) if (ret)
return ret; return ret;
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, if (ak8974->variant != AK8974_WHOAMI_VALUE_HSCDTD008A) {
AK8974_INT_CTRL_RESDEF); ret = regmap_write(ak8974->map, AK8974_INT_CTRL,
if (ret) AK8974_INT_CTRL_RESDEF);
return ret; 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 */ /* After reset, power off is default state */
return ak8974_set_power(ak8974, AK8974_PWR_OFF); return ak8974_set_power(ak8974, AK8974_PWR_OFF);
@ -267,6 +281,8 @@ static int ak8974_configure(struct ak8974 *ak8974)
if (ret) if (ret)
return ret; return ret;
} }
if (ak8974->variant == AK8974_WHOAMI_VALUE_HSCDTD008A)
return 0;
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL); ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL);
if (ret) if (ret)
return ret; return ret;
@ -495,6 +511,10 @@ static int ak8974_detect(struct ak8974 *ak8974)
name = "ak8974"; name = "ak8974";
dev_info(&ak8974->i2c->dev, "detected AK8974\n"); dev_info(&ak8974->i2c->dev, "detected AK8974\n");
break; break;
case AK8974_WHOAMI_VALUE_HSCDTD008A:
name = "hscdtd008a";
dev_info(&ak8974->i2c->dev, "detected hscdtd008a\n");
break;
default: default:
dev_err(&ak8974->i2c->dev, "unsupported device (%02x) ", dev_err(&ak8974->i2c->dev, "unsupported device (%02x) ",
whoami); whoami);
@ -534,47 +554,103 @@ static int ak8974_detect(struct ak8974 *ak8974)
return 0; 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, static int ak8974_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, struct iio_chan_spec const *chan,
int *val, int *val2, int *val, int *val2,
long mask) long mask)
{ {
struct ak8974 *ak8974 = iio_priv(indio_dev); struct ak8974 *ak8974 = iio_priv(indio_dev);
__le16 hw_values[3]; int ret;
int ret = -EINVAL;
pm_runtime_get_sync(&ak8974->i2c->dev);
mutex_lock(&ak8974->lock);
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
if (chan->address > 2) { if (chan->address > 2) {
dev_err(&ak8974->i2c->dev, "faulty channel address\n"); dev_err(&ak8974->i2c->dev, "faulty channel address\n");
ret = -EIO; return -EIO;
goto out_unlock;
} }
ret = ak8974_trigmeas(ak8974); ret = ak8974_measure_channel(ak8974, chan->address, val);
if (ret) if (ret)
goto out_unlock; return ret;
ret = ak8974_getresult(ak8974, hw_values); return IIO_VAL_INT;
if (ret) case IIO_CHAN_INFO_SCALE:
goto out_unlock; switch (ak8974->variant) {
case AK8974_WHOAMI_VALUE_AMI306:
/* case AK8974_WHOAMI_VALUE_AMI305:
* We read all axes and discard all but one, for optimized /*
* reading, use the triggered buffer. * The datasheet for AMI305 and AMI306, page 6
*/ * specifies the range of the sensor to be
*val = (s16)le16_to_cpu(hw_values[chan->address]); * +/- 12 Gauss.
*/
ret = IIO_VAL_INT; *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: return -EINVAL;
mutex_unlock(&ak8974->lock);
pm_runtime_mark_last_busy(&ak8974->i2c->dev);
pm_runtime_put_autosuspend(&ak8974->i2c->dev);
return ret;
} }
static void ak8974_fill_buffer(struct iio_dev *indio_dev) 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, \ .type = IIO_MAGN, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_##axis, \ .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, \ .ext_info = ak8974_ext_info, \
.address = index, \ .address = index, \
.scan_index = index, \ .scan_index = index, \
.scan_type = { \ .scan_type = { \
.sign = 's', \ .sign = 's', \
.realbits = 16, \ .realbits = bits, \
.storagebits = 16, \ .storagebits = 16, \
.endianness = IIO_LE \ .endianness = IIO_LE \
}, \ }, \
} }
static const struct iio_chan_spec ak8974_channels[] = { /*
AK8974_AXIS_CHANNEL(X, 0), * We have no datasheet for the AK8974 but we guess that its
AK8974_AXIS_CHANNEL(Y, 1), * ADC is 12 bits. The AMI305 and AMI306 certainly has 12bit
AK8974_AXIS_CHANNEL(Z, 2), * 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), 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_CTRL:
case AK8974_INT_THRES: case AK8974_INT_THRES:
case AK8974_INT_THRES + 1: case AK8974_INT_THRES + 1:
return true;
case AK8974_PRESET: case AK8974_PRESET:
case AK8974_PRESET + 1: case AK8974_PRESET + 1:
return true; return ak8974->variant != AK8974_WHOAMI_VALUE_HSCDTD008A;
case AK8974_OFFSET_X: case AK8974_OFFSET_X:
case AK8974_OFFSET_X + 1: case AK8974_OFFSET_X + 1:
case AK8974_OFFSET_Y: case AK8974_OFFSET_Y:
case AK8974_OFFSET_Y + 1: case AK8974_OFFSET_Y + 1:
case AK8974_OFFSET_Z: case AK8974_OFFSET_Z:
case AK8974_OFFSET_Z + 1: case AK8974_OFFSET_Z + 1:
if (ak8974->variant == AK8974_WHOAMI_VALUE_AK8974) return ak8974->variant == AK8974_WHOAMI_VALUE_AK8974 ||
return true; ak8974->variant == AK8974_WHOAMI_VALUE_HSCDTD008A;
return false;
case AMI305_OFFSET_X: case AMI305_OFFSET_X:
case AMI305_OFFSET_X + 1: case AMI305_OFFSET_X + 1:
case AMI305_OFFSET_Y: case AMI305_OFFSET_Y:
@ -800,8 +893,21 @@ static int ak8974_probe(struct i2c_client *i2c,
pm_runtime_put(&i2c->dev); pm_runtime_put(&i2c->dev);
indio_dev->dev.parent = &i2c->dev; indio_dev->dev.parent = &i2c->dev;
indio_dev->channels = ak8974_channels; switch (ak8974->variant) {
indio_dev->num_channels = ARRAY_SIZE(ak8974_channels); 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->info = &ak8974_info;
indio_dev->available_scan_masks = ak8974_scan_masks; indio_dev->available_scan_masks = ak8974_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
@ -931,12 +1037,14 @@ static const struct i2c_device_id ak8974_id[] = {
{"ami305", 0 }, {"ami305", 0 },
{"ami306", 0 }, {"ami306", 0 },
{"ak8974", 0 }, {"ak8974", 0 },
{"hscdtd008a", 0 },
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, ak8974_id); MODULE_DEVICE_TABLE(i2c, ak8974_id);
static const struct of_device_id ak8974_of_match[] = { static const struct of_device_id ak8974_of_match[] = {
{ .compatible = "asahi-kasei,ak8974", }, { .compatible = "asahi-kasei,ak8974", },
{ .compatible = "alps,hscdtd008a", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, ak8974_of_match); MODULE_DEVICE_TABLE(of, ak8974_of_match);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,6 +14,7 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/util_macros.h> #include <linux/util_macros.h>
#include <asm/unaligned.h>
#include <dt-bindings/iio/temperature/thermocouple.h> #include <dt-bindings/iio/temperature/thermocouple.h>
/* /*
* The MSB of the register value determines whether the following byte will * 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) if (ret)
return ret; return ret;
/* Skip last 5 dead bits of LTCBL */ /* 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*/ /* Check 7th bit of LTCBH reg. value for sign*/
if (reg_val[0] & 0x80) if (reg_val[0] & 0x80)
*val -= 0x80000; *val -= 0x80000;
@ -185,7 +186,7 @@ static int max31856_thermocouple_read(struct max31856_data *data,
/* Get Cold Junction Temp. offset register value */ /* Get Cold Junction Temp. offset register value */
offset_cjto = reg_val[0]; offset_cjto = reg_val[0];
/* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */ /* 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 */ /* As per datasheet add offset into CJTH and CJTL */
*val += offset_cjto; *val += offset_cjto;
/* Check 7th bit of CJTH reg. value for sign */ /* 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, .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; struct iio_buffer *buffer;
buffer = iio_kfifo_allocate(); buffer = devm_iio_kfifo_allocate(dev);
if (!buffer) if (!buffer)
return -ENOMEM; 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, static int ad5933_probe(struct i2c_client *client,
const struct i2c_device_id *id) 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"); dev_err(&client->dev, "Failed to enable specified VDD supply\n");
return ret; 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) if (ret < 0)
goto error_disable_reg; return ret;
st->vref_mv = ret / 1000; st->vref_mv = ret / 1000;
st->mclk = devm_clk_get(&client->dev, "mclk"); st->mclk = devm_clk_get(&client->dev, "mclk");
if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) { if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT)
ret = PTR_ERR(st->mclk); return PTR_ERR(st->mclk);
goto error_disable_reg;
}
if (!IS_ERR(st->mclk)) { if (!IS_ERR(st->mclk)) {
ret = clk_prepare_enable(st->mclk); ret = clk_prepare_enable(st->mclk);
if (ret < 0) 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); 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->channels = ad5933_channels;
indio_dev->num_channels = ARRAY_SIZE(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) if (ret)
goto error_disable_mclk; return ret;
ret = ad5933_setup(st); ret = ad5933_setup(st);
if (ret) if (ret)
goto error_unreg_ring; return ret;
ret = iio_device_register(indio_dev); return devm_iio_device_register(&client->dev, 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;
} }
static const struct i2c_device_id ad5933_id[] = { static const struct i2c_device_id ad5933_id[] = {
@ -801,7 +799,6 @@ static struct i2c_driver ad5933_driver = {
.of_match_table = ad5933_of_match, .of_match_table = ad5933_of_match,
}, },
.probe = ad5933_probe, .probe = ad5933_probe,
.remove = ad5933_remove,
.id_table = ad5933_id, .id_table = ad5933_id,
}; };
module_i2c_driver(ad5933_driver); module_i2c_driver(ad5933_driver);

View File

@ -83,10 +83,13 @@ struct adis_data {
* @trig: IIO trigger object data * @trig: IIO trigger object data
* @data: ADIS chip variant specific data * @data: ADIS chip variant specific data
* @burst: ADIS burst transfer information * @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 * @state_lock: Lock used by the device to protect state
* @msg: SPI message object * @msg: SPI message object
* @xfer: SPI transfer objects to be used for a @msg * @xfer: SPI transfer objects to be used for a @msg
* @current_page: Some ADIS devices have registers, this selects current page * @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 * @buffer: Data buffer for information read from the device
* @tx: DMA safe TX buffer for SPI transfers * @tx: DMA safe TX buffer for SPI transfers
* @rx: DMA safe RX buffer for SPI transfers * @rx: DMA safe RX buffer for SPI transfers
@ -97,7 +100,7 @@ struct adis {
const struct adis_data *data; const struct adis_data *data;
struct adis_burst *burst; struct adis_burst *burst;
unsigned int burst_extra_len;
/** /**
* The state_lock is meant to be used during operations that require * 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 * 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_message msg;
struct spi_transfer *xfer; struct spi_transfer *xfer;
unsigned int current_page; unsigned int current_page;
unsigned long irq_flag;
void *buffer; void *buffer;
uint8_t tx[10] ____cacheline_aligned; 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; 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_enable_irq(struct adis *adis, bool enable);
int __adis_check_status(struct adis *adis); int __adis_check_status(struct adis *adis);
int __adis_initial_startup(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 * @en burst mode enabled
* @reg_cmd register command that triggers burst * @reg_cmd register command that triggers burst
* @extra_len extra length to account in the SPI RX buffer * @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 { struct adis_burst {
bool en; bool en;
unsigned int reg_cmd; 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, int adis_setup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *)); struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *));
void adis_cleanup_buffer_and_trigger(struct adis *adis, void adis_cleanup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev); 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); int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
void adis_remove_trigger(struct adis *adis); 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 */ #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, static inline int adis_setup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *)) 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, static inline int adis_probe_trigger(struct adis *adis,
struct iio_dev *indio_dev) struct iio_dev *indio_dev)
{ {