mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
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:
commit
cef077e6aa
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
@ -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
|
||||||
|
@ -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
|
||||||
|
137
Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
Normal file
137
Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
Normal 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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
...
|
@ -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:
|
||||||
|
@ -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>
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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");
|
||||||
|
@ -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,
|
||||||
|
@ -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)<c2632_chip_info_tbl[ID_LTC2632H12] },
|
{ "ltc2632-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H12] },
|
||||||
{ "ltc2632-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H10] },
|
{ "ltc2632-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H10] },
|
||||||
{ "ltc2632-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H8] },
|
{ "ltc2632-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H8] },
|
||||||
|
{ "ltc2634-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L12] },
|
||||||
|
{ "ltc2634-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L10] },
|
||||||
|
{ "ltc2634-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L8] },
|
||||||
|
{ "ltc2634-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H12] },
|
||||||
|
{ "ltc2634-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H10] },
|
||||||
|
{ "ltc2634-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H8] },
|
||||||
{ "ltc2636-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L12] },
|
{ "ltc2636-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L12] },
|
||||||
{ "ltc2636-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L10] },
|
{ "ltc2636-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L10] },
|
||||||
{ "ltc2636-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L8] },
|
{ "ltc2636-l8", (kernel_ulong_t)<c2632_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 = <c2632_chip_info_tbl[ID_LTC2632H8]
|
.data = <c2632_chip_info_tbl[ID_LTC2632H8]
|
||||||
|
}, {
|
||||||
|
.compatible = "lltc,ltc2634-l12",
|
||||||
|
.data = <c2632_chip_info_tbl[ID_LTC2634L12]
|
||||||
|
}, {
|
||||||
|
.compatible = "lltc,ltc2634-l10",
|
||||||
|
.data = <c2632_chip_info_tbl[ID_LTC2634L10]
|
||||||
|
}, {
|
||||||
|
.compatible = "lltc,ltc2634-l8",
|
||||||
|
.data = <c2632_chip_info_tbl[ID_LTC2634L8]
|
||||||
|
}, {
|
||||||
|
.compatible = "lltc,ltc2634-h12",
|
||||||
|
.data = <c2632_chip_info_tbl[ID_LTC2634H12]
|
||||||
|
}, {
|
||||||
|
.compatible = "lltc,ltc2634-h10",
|
||||||
|
.data = <c2632_chip_info_tbl[ID_LTC2634H10]
|
||||||
|
}, {
|
||||||
|
.compatible = "lltc,ltc2634-h8",
|
||||||
|
.data = <c2632_chip_info_tbl[ID_LTC2634H8]
|
||||||
}, {
|
}, {
|
||||||
.compatible = "lltc,ltc2636-l12",
|
.compatible = "lltc,ltc2636-l12",
|
||||||
.data = <c2632_chip_info_tbl[ID_LTC2636L12]
|
.data = <c2632_chip_info_tbl[ID_LTC2636L12]
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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, ®, 1, rx, 3);
|
ret = spi_write_then_read(afe->spi, ®, 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 */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
1338
drivers/iio/imu/adis16475.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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 = {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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");
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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. */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(®_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(®_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 */
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user