First set of new device support, features and fixes for IIO in the 5.2 cycle
Staging graduations * ad7780 - Move this ADC driver out of staging. Included adding some new features along the way (see below). Also added DT bindings. New device support * adis16480 - Support the ADIS16495 and ADIS16497 IMU devices making heavy use of refactoring of various aspects of the driver in precursor patches. * lsm6dsx - Support for the ASM330LHH 6-axis (accelerometer + gyro) sensor. - Support for the LSM6DS0X * matbotix mb1232 - New driver for this ultrasound ranging device family. Including bindings. - Supports mb1202, mb1212, mb1222, mb1232, mb1242, mb7040 and mb7137. * max31856 - New driver for this thermocouple temperature sensor. * meson saradc - Support the Meson-G12A (ID addition only). * stmpe-adc - New driver supporting generic ADC alongside touchscreen support which previously existed. Includes DT bindings. * vcnl4000 - Support for the vcln4040 proximity and light sensor, including adding DT bindings for this and parts previously supported. Features * core - Allow reading of mount matrices from ACPI in addition to DT. - Common binding for theromcouple types. * ad5933 - Add ABI docs as there are a few 'unsual' elements about this device - perhaps because it's our only impedance analyser. * ad7780 - Add gain and filter gpio support + readback of current gain and filter. * adis16480 - Allow selection fo the dataready pin to be used. - Device tree ID table and binding documentation. - Support external clock modes, including new bindings. * bma180 - Mount matrix support. * bmc150 - Mount matrix support. * bmg160 - Mount matrix support. - DT id table and bindings doc. * bmp280 - Put calibration data into the entropy pool. * hmc5843 - Mount matrix support. * itg3200 - Mount matrix support. * kxcjk1013 - Device tree id table, and binding docs. * lpc32xx - Add scale when regulator specified including DT docs for regulator. * pms7003 - Add device IDs for all supported parts to driver and binding. * stm32-dfsdm - Enable hw consumer support, scan mode control and a complex set of triggered buffer modes. - Power management. * stm32-lptimer-counter - power management. - Document the pinctrl sleep state binding. * ti-ads7950 - GPIO pin support. Cleanups, minor fixes * core - Use bitmap_zalloc to make it explicit that is what we are doing. - Tidy up all the Kconfig files (which had slowly gotten messy) - Fix a forwards definition missing issue in iio/driver.h * ad sigma delta core - Improve handling of SPI bus locking vs CS assertion. This has been wrong a long time so not rushing this in. * ad5064 - Mlock to local lock. * ad5933 (staging cleanup) - Multiline comment fixes. - Include ordering. - SPDX. - Tidy up Kconfig help which was a bit missleading. - Change some non standard attributes to ABI defined ones. * ad7124 - White space fix. * ad7192 - White space. - Use DT clock binding. - Improve error reporting. - Platform data to DT conversion. - Use read_avail callback, mostly to avoid the endless series of patches from new contributors trying to falsely put spaces around the negative sign. * ad7280a - Add brackets to macros to avoid potential precedence isseus. - Add temp vars for event codes to reduce indent and improved readability. - Clean out som CamelCase notation. - White space. * ad7606 - Fix broken file naming in MAINTAINERS. * ad7780 - Missing switch defaults to supress warnings and harden the code slightly. - Set pattern masks more directly. - Add ID values and masks for all supported chips. - SPDX + add Renato as a copyright holder as he has done a lot of work on this driver. - Add brackets to macros to avoid potential precedence issues. * ad7923 - White space fixes. - Use BIT macro to improve readability. - Add brackets to macros to avoid potential precedence issues. - Tidy up a null comparisom. * ad9523 - Fix a typo in naming of variables. * adis16400 - Combine trigger file into main code as no advantage in separate files. Rename core file to just adis16400. - Squash the header into the c file now there is only one file. - Generalize burst mode to support new variants. * ak8975 - Local variable to improve readability around mount matrix support. * as3935 - Avoid potential race by ensuring remove does exact opposite of probe rather than a slightly different order. * cross_ec - Drop some unnecessary includes. - Fix some warning and the slightly 'unusual' code. - Add some docs for non obvious function. - SPDX * hmc5843 - Potential unhandled error case. * iio trigger core - Print an error if there is no available irq due to max consumers per trigger being set to low. * iio loop trigger - Drop an unlikely on IS_ERR as IS_ERR already has the annotation. * ingenic-adc - Drop a redundant dev_err call as devm_ioremap_resource reports the same internally. * lmp91000 - Drop some unncessary parentheses and white space tidy up. - Invert and if statement to improve readability. - Fix a wrong error message. * lpc32xx - Header sorting + drop some unused ones. * mma8542 - Mark a switch fallthrough. * mpu6050 - Add a local variable to improve code readability around mount matrix support. * mxs-lradc-adc - Handle devm_iio_trigger_alloc failure. * sps30 - Fix up a kernel version in the ABI docs. * srf04 - DT binding doc converted to yaml. * ssp_sensors - Supress a clang build warning due to lack of visibility of conditional within a iio_push_to_buffers_with_timestamp. (reasonable false warning!) * st_accel - Drop pointless less than 0 comparisom of unsigned int. * stm32-dfsdm - Improve accuracy of spi_master_frequency calculation. - Improve calculation fo sampling frequency. - Rework various internals to simplify adding triggered buffer support. - Claim direct mode to avoid racing around read_raw and being in buffered mode. * stmpe - Fix a clang false positive warning. * ti-ads7950 - Use local lock rather than using the core mlock when not locking around the device mode. * vcnl4000 - Use word writes instead of byte writes. It seems byte writes are fine for some parts (undocument) but not others that the driver will shortly support. Other * mailmap - Add email address change for Sean Nyekjaer. Update in relevant drivers -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAlymX7ERHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FogLdw//TC1JMzZMly5KsPc+kBj+sgStPrCs933B dCmxaae0dd5Kr3MYzy3EQ2Nl95CxjemYt7/Bj+eSsAA0coDnqnc5aIgwQWIl36oS tDAxtYO6zsqLputmymSpiKXE/SRONwmYXcv2XdopBDnE2V9rEAx7Ihu6yxpqCMVt HDu0ArwtAxkPqZREAyPI/GjCWAbqS7Nlzp8cyiPpEzrByVJA0+M6a0V+aNWblL/U i0NQRrzb8UfaRiCE+/UqBaiBWUXM4NHGoAj6DRYn0YLX7ryswdZ8kYnNbkc3Nlvm eZLZykL0xqijBRHLkSppkT4MdY15XOB6/d1BRSWcg4Yk2nJwBbqfg3p6ROEJj0nG H6wF09P5sbo42lFEZZAQkd5j2mvTl/94Y/GhA5OxjmUQWSGmtKxW7XK/CPu/FrcR 6f3xMV0qm/RfmFG/YwpV8GvMYnNWwG4uHN7oFNCC8Gza9RyNYmXyeJillwwHRwEu CHpc/sL76U707m5WBhLKgvBFrzemQDH11Z+3hYuro1TkWQVEhs/JvACvazDs6LGj 5u2Q99U0/0XaygHO4mfr9vQAmIgRqQstu8rq85lzAxQ1xCmmomfWBq32cu/gaBIw swpPuAIVbJEH0u/avfikbSAX/YH890ynWvhXjjjJ6j6Zika8mucW0aNbe7wDyjdL I1cj5/1kXFU= =GnjE -----END PGP SIGNATURE----- Merge tag 'iio-for-5.2a-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: First set of new device support, features and fixes for IIO in the 5.2 cycle Staging graduations * ad7780 - Move this ADC driver out of staging. Included adding some new features along the way (see below). Also added DT bindings. New device support * adis16480 - Support the ADIS16495 and ADIS16497 IMU devices making heavy use of refactoring of various aspects of the driver in precursor patches. * lsm6dsx - Support for the ASM330LHH 6-axis (accelerometer + gyro) sensor. - Support for the LSM6DS0X * matbotix mb1232 - New driver for this ultrasound ranging device family. Including bindings. - Supports mb1202, mb1212, mb1222, mb1232, mb1242, mb7040 and mb7137. * max31856 - New driver for this thermocouple temperature sensor. * meson saradc - Support the Meson-G12A (ID addition only). * stmpe-adc - New driver supporting generic ADC alongside touchscreen support which previously existed. Includes DT bindings. * vcnl4000 - Support for the vcln4040 proximity and light sensor, including adding DT bindings for this and parts previously supported. Features * core - Allow reading of mount matrices from ACPI in addition to DT. - Common binding for theromcouple types. * ad5933 - Add ABI docs as there are a few 'unsual' elements about this device - perhaps because it's our only impedance analyser. * ad7780 - Add gain and filter gpio support + readback of current gain and filter. * adis16480 - Allow selection fo the dataready pin to be used. - Device tree ID table and binding documentation. - Support external clock modes, including new bindings. * bma180 - Mount matrix support. * bmc150 - Mount matrix support. * bmg160 - Mount matrix support. - DT id table and bindings doc. * bmp280 - Put calibration data into the entropy pool. * hmc5843 - Mount matrix support. * itg3200 - Mount matrix support. * kxcjk1013 - Device tree id table, and binding docs. * lpc32xx - Add scale when regulator specified including DT docs for regulator. * pms7003 - Add device IDs for all supported parts to driver and binding. * stm32-dfsdm - Enable hw consumer support, scan mode control and a complex set of triggered buffer modes. - Power management. * stm32-lptimer-counter - power management. - Document the pinctrl sleep state binding. * ti-ads7950 - GPIO pin support. Cleanups, minor fixes * core - Use bitmap_zalloc to make it explicit that is what we are doing. - Tidy up all the Kconfig files (which had slowly gotten messy) - Fix a forwards definition missing issue in iio/driver.h * ad sigma delta core - Improve handling of SPI bus locking vs CS assertion. This has been wrong a long time so not rushing this in. * ad5064 - Mlock to local lock. * ad5933 (staging cleanup) - Multiline comment fixes. - Include ordering. - SPDX. - Tidy up Kconfig help which was a bit missleading. - Change some non standard attributes to ABI defined ones. * ad7124 - White space fix. * ad7192 - White space. - Use DT clock binding. - Improve error reporting. - Platform data to DT conversion. - Use read_avail callback, mostly to avoid the endless series of patches from new contributors trying to falsely put spaces around the negative sign. * ad7280a - Add brackets to macros to avoid potential precedence isseus. - Add temp vars for event codes to reduce indent and improved readability. - Clean out som CamelCase notation. - White space. * ad7606 - Fix broken file naming in MAINTAINERS. * ad7780 - Missing switch defaults to supress warnings and harden the code slightly. - Set pattern masks more directly. - Add ID values and masks for all supported chips. - SPDX + add Renato as a copyright holder as he has done a lot of work on this driver. - Add brackets to macros to avoid potential precedence issues. * ad7923 - White space fixes. - Use BIT macro to improve readability. - Add brackets to macros to avoid potential precedence issues. - Tidy up a null comparisom. * ad9523 - Fix a typo in naming of variables. * adis16400 - Combine trigger file into main code as no advantage in separate files. Rename core file to just adis16400. - Squash the header into the c file now there is only one file. - Generalize burst mode to support new variants. * ak8975 - Local variable to improve readability around mount matrix support. * as3935 - Avoid potential race by ensuring remove does exact opposite of probe rather than a slightly different order. * cross_ec - Drop some unnecessary includes. - Fix some warning and the slightly 'unusual' code. - Add some docs for non obvious function. - SPDX * hmc5843 - Potential unhandled error case. * iio trigger core - Print an error if there is no available irq due to max consumers per trigger being set to low. * iio loop trigger - Drop an unlikely on IS_ERR as IS_ERR already has the annotation. * ingenic-adc - Drop a redundant dev_err call as devm_ioremap_resource reports the same internally. * lmp91000 - Drop some unncessary parentheses and white space tidy up. - Invert and if statement to improve readability. - Fix a wrong error message. * lpc32xx - Header sorting + drop some unused ones. * mma8542 - Mark a switch fallthrough. * mpu6050 - Add a local variable to improve code readability around mount matrix support. * mxs-lradc-adc - Handle devm_iio_trigger_alloc failure. * sps30 - Fix up a kernel version in the ABI docs. * srf04 - DT binding doc converted to yaml. * ssp_sensors - Supress a clang build warning due to lack of visibility of conditional within a iio_push_to_buffers_with_timestamp. (reasonable false warning!) * st_accel - Drop pointless less than 0 comparisom of unsigned int. * stm32-dfsdm - Improve accuracy of spi_master_frequency calculation. - Improve calculation fo sampling frequency. - Rework various internals to simplify adding triggered buffer support. - Claim direct mode to avoid racing around read_raw and being in buffered mode. * stmpe - Fix a clang false positive warning. * ti-ads7950 - Use local lock rather than using the core mlock when not locking around the device mode. * vcnl4000 - Use word writes instead of byte writes. It seems byte writes are fine for some parts (undocument) but not others that the driver will shortly support. Other * mailmap - Add email address change for Sean Nyekjaer. Update in relevant drivers * tag 'iio-for-5.2a-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (129 commits) iio: ad_sigma_delta: Properly handle SPI bus locking vs CS assertion iio: adc: stm32-dfsdm: add PM support iio: adc: stm32-dfsdm: improve sampling frequency accuracy staging: iio: adc: ad7280a: Tab alignment MAINTAINERS: Fix the link to ad7606 dt-bindings iio:temperature: Add MAX31856 thermocouple support iio:temperature:max31856:Add device tree bind info dt-bindings: iio/temperature: Add thermocouple types (and doc) devantech-srf04.yaml: transform DT binding to YAML iio: frequency: ad9523: Fix typo in ad9523_platform_data iio: Make possible to include driver.h first dt-bindings: iio: add Bosch BMG160 gyroscope sensor iio: gyro: bmg160: add device tree compatibility table staging: iio: adc: ad7192: Use read_avail for available attributes dt-bindings: iio: light: add vcnl4040 devicetree bindings iio: light: vcnl4000 add support for the VCNL4040 proximity and light sensor dt-bindings: iio: light: add vcnl4000 devicetree bindings iio: light: vcnl4000 add devicetree hooks iio: light: vcnl4000 use word writes instead of byte writes iio: adc: stm32-dfsdm: claim direct mode for raw read and settings ...
This commit is contained in:
commit
932f98922f
1
.mailmap
1
.mailmap
|
@ -187,6 +187,7 @@ Santosh Shilimkar <ssantosh@kernel.org>
|
|||
Santosh Shilimkar <santosh.shilimkar@oracle.org>
|
||||
Sascha Hauer <s.hauer@pengutronix.de>
|
||||
S.Çağlar Onur <caglar@pardus.org.tr>
|
||||
Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
|
||||
Sebastian Reichel <sre@kernel.org> <sre@debian.org>
|
||||
Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
|
||||
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
|
||||
|
|
|
@ -1,26 +1,31 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/outY_freq_start
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_start
|
||||
Date: March 2019
|
||||
KernelVersion: 3.1.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Frequency sweep start frequency in Hz.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/outY_freq_increment
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_increment
|
||||
Date: March 2019
|
||||
KernelVersion: 3.1.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Frequency increment in Hz (step size) between consecutive
|
||||
frequency points along the sweep.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/outY_freq_points
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_points
|
||||
Date: March 2019
|
||||
KernelVersion: 3.1.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Number of frequency points (steps) in the frequency sweep.
|
||||
This value, in conjunction with the outY_freq_start and the
|
||||
outY_freq_increment, determines the frequency sweep range
|
||||
for the sweep operation.
|
||||
This value, in conjunction with the
|
||||
out_altvoltageY_frequency_start and the
|
||||
out_altvoltageY_frequency_increment, determines the frequency
|
||||
sweep range for the sweep operation.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/outY_settling_cycles
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_settling_cycles
|
||||
Date: March 2019
|
||||
KernelVersion: 3.1.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
|
@ -1,6 +1,6 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/start_cleaning
|
||||
Date: December 2018
|
||||
KernelVersion: 4.22
|
||||
KernelVersion: 5.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Writing 1 starts sensor self cleaning. Internal fan accelerates
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/fault_oc
|
||||
KernelVersion: 5.1
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Open-circuit fault. The detection of open-circuit faults,
|
||||
such as those caused by broken thermocouple wires.
|
||||
Reading returns either '1' or '0'.
|
||||
'1' = An open circuit such as broken thermocouple wires
|
||||
has been detected.
|
||||
'0' = No open circuit or broken thermocouple wires are detected
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/fault_ovuv
|
||||
KernelVersion: 5.1
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Overvoltage or Undervoltage Input Fault. The internal circuitry
|
||||
is protected from excessive voltages applied to the thermocouple
|
||||
cables by integrated MOSFETs at the T+ and T- inputs, and the
|
||||
BIAS output. These MOSFETs turn off when the input voltage is
|
||||
negative or greater than VDD.
|
||||
Reading returns either '1' or '0'.
|
||||
'1' = The input voltage is negative or greater than VDD.
|
||||
'0' = The input voltage is positive and less than VDD (normal
|
||||
state).
|
|
@ -0,0 +1,17 @@
|
|||
Kionix KXCJK-1013 Accelerometer device tree bindings
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be one of:
|
||||
"kionix,kxcjk1013"
|
||||
"kionix,kxcj91008"
|
||||
"kionix,kxtj21009"
|
||||
"kionix,kxtf9"
|
||||
- reg: i2c slave address
|
||||
|
||||
Example:
|
||||
|
||||
kxtf9@f {
|
||||
compatible = "kionix,kxtf9";
|
||||
reg = <0x0F>;
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
* Analog Devices AD7170/AD7171/AD7780/AD7781
|
||||
|
||||
Data sheets:
|
||||
|
||||
- AD7170:
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/AD7170.pdf
|
||||
- AD7171:
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/AD7171.pdf
|
||||
- AD7780:
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/ad7780.pdf
|
||||
- AD7781:
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/AD7781.pdf
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of
|
||||
* "adi,ad7170"
|
||||
* "adi,ad7171"
|
||||
* "adi,ad7780"
|
||||
* "adi,ad7781"
|
||||
- reg: spi chip select number for the device
|
||||
- vref-supply: the regulator supply for the ADC reference voltage
|
||||
|
||||
Optional properties:
|
||||
|
||||
- powerdown-gpios: must be the device tree identifier of the PDRST pin. If
|
||||
specified, it will be asserted during driver probe. As the
|
||||
line is active high, it should be marked GPIO_ACTIVE_HIGH.
|
||||
- adi,gain-gpios: must be the device tree identifier of the GAIN pin. Only for
|
||||
the ad778x chips. If specified, it will be asserted during
|
||||
driver probe. As the line is active low, it should be marked
|
||||
GPIO_ACTIVE_LOW.
|
||||
- adi,filter-gpios: must be the device tree identifier of the FILTER pin. Only
|
||||
for the ad778x chips. If specified, it will be asserted
|
||||
during driver probe. As the line is active low, it should be
|
||||
marked GPIO_ACTIVE_LOW.
|
||||
|
||||
Example:
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad7780";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>
|
||||
|
||||
powerdown-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
|
||||
adi,gain-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
|
||||
adi,filter-gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
|
||||
};
|
|
@ -9,6 +9,7 @@ Required properties:
|
|||
- "amlogic,meson-gxl-saradc" for GXL
|
||||
- "amlogic,meson-gxm-saradc" for GXM
|
||||
- "amlogic,meson-axg-saradc" for AXG
|
||||
- "amlogic,meson-g12a-saradc" for AXG
|
||||
along with the generic "amlogic,meson-saradc"
|
||||
- reg: the physical base address and length of the registers
|
||||
- interrupts: the interrupt indicating end of sampling
|
||||
|
|
|
@ -6,6 +6,10 @@ Required properties:
|
|||
region.
|
||||
- interrupts: The ADC interrupt
|
||||
|
||||
Optional:
|
||||
- vref-supply: The regulator supply ADC reference voltage, optional
|
||||
for legacy reason, but highly encouraging to us in new device tree
|
||||
|
||||
Example:
|
||||
|
||||
adc@40048000 {
|
||||
|
@ -13,4 +17,5 @@ Example:
|
|||
reg = <0x40048000 0x1000>;
|
||||
interrupt-parent = <&mic>;
|
||||
interrupts = <39 0>;
|
||||
vref-supply = <&vcc>;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
* Plantower PMS7003 particulate matter sensor
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "plantower,pms7003"
|
||||
- compatible: must one of:
|
||||
"plantower,pms1003"
|
||||
"plantower,pms3003"
|
||||
"plantower,pms5003"
|
||||
"plantower,pms6003"
|
||||
"plantower,pms7003"
|
||||
"plantower,pmsa003"
|
||||
- vcc-supply: phandle to the regulator that provides power to the sensor
|
||||
|
||||
Optional properties:
|
||||
|
|
|
@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node.
|
|||
|
||||
Required properties:
|
||||
- compatible: Must be "st,stm32-lptimer-counter".
|
||||
- pinctrl-names: Set to "default".
|
||||
- pinctrl-0: List of phandles pointing to pin configuration nodes,
|
||||
- pinctrl-names: Set to "default". An additional "sleep" state can be
|
||||
defined to set pins in sleep state.
|
||||
- pinctrl-n: List of phandles pointing to pin configuration nodes,
|
||||
to set IN1/IN2 pins in mode of operation for Low-Power
|
||||
Timer input on external pin.
|
||||
|
||||
|
@ -21,7 +22,8 @@ Example:
|
|||
...
|
||||
counter {
|
||||
compatible = "st,stm32-lptimer-counter";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&lptim1_in_pins>;
|
||||
pinctrl-1 = <&lptim1_sleep_in_pins>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
* Bosch BMG160 triaxial rotation sensor (gyroscope)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "bosch,bmg160" or "bosch,bmi055_gyro"
|
||||
- reg : the I2C address of the sensor (0x69)
|
||||
|
||||
Optional properties:
|
||||
|
||||
- interrupts : interrupt mapping for GPIO IRQ, it should by configured with
|
||||
flags IRQ_TYPE_EDGE_RISING
|
||||
|
||||
Example:
|
||||
|
||||
bmg160@69 {
|
||||
compatible = "bosch,bmg160";
|
||||
reg = <0x69>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <18 (IRQ_TYPE_EDGE_RISING)>;
|
||||
};
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
Analog Devices ADIS16480 and similar IMUs
|
||||
|
||||
Required properties for the ADIS16480:
|
||||
|
||||
- compatible: Must be one of
|
||||
* "adi,adis16375"
|
||||
* "adi,adis16480"
|
||||
* "adi,adis16485"
|
||||
* "adi,adis16488"
|
||||
* "adi,adis16495-1"
|
||||
* "adi,adis16495-2"
|
||||
* "adi,adis16495-3"
|
||||
* "adi,adis16497-1"
|
||||
* "adi,adis16497-2"
|
||||
* "adi,adis16497-3"
|
||||
- reg: SPI chip select number for the device
|
||||
- spi-max-frequency: Max SPI frequency to use
|
||||
see: Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
- spi-cpol: See Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
- interrupts: interrupt mapping for IRQ, accepted values are:
|
||||
* IRQF_TRIGGER_RISING
|
||||
* IRQF_TRIGGER_FALLING
|
||||
|
||||
Optional properties:
|
||||
|
||||
- interrupt-names: Data ready line selection. Valid values are:
|
||||
* DIO1
|
||||
* DIO2
|
||||
* DIO3
|
||||
* DIO4
|
||||
If this field is left empty, DIO1 is assigned as default data ready
|
||||
signal.
|
||||
- reset-gpios: must be the device tree identifier of the RESET pin. As the line
|
||||
is active low, it should be marked GPIO_ACTIVE_LOW.
|
||||
- clocks: phandle to the external clock. Should be set according to
|
||||
"clock-names".
|
||||
If this field is left empty together with the "clock-names" field, then
|
||||
the internal clock is used.
|
||||
- clock-names: The name of the external clock to be used. Valid values are:
|
||||
* sync: In sync mode, the internal clock is disabled and the frequency
|
||||
of the external clock signal establishes therate of data
|
||||
collection and processing. See Fig 14 and 15 in the datasheet.
|
||||
The clock-frequency must be:
|
||||
* 3000 to 4500 Hz for adis1649x devices.
|
||||
* 700 to 2400 Hz for adis1648x devices.
|
||||
* pps: In Pulse Per Second (PPS) Mode, the rate of data collection and
|
||||
production is equal to the product of the external clock
|
||||
frequency and the scale factor in the SYNC_SCALE register, see
|
||||
Table 154 in the datasheet.
|
||||
The clock-frequency must be:
|
||||
* 1 to 128 Hz for adis1649x devices.
|
||||
* This mode is not supported by adis1648x devices.
|
||||
If this field is left empty together with the "clocks" field, then the
|
||||
internal clock is used.
|
||||
- adi,ext-clk-pin: The DIOx line to be used as an external clock input.
|
||||
Valid values are:
|
||||
* DIO1
|
||||
* DIO2
|
||||
* DIO3
|
||||
* DIO4
|
||||
Each DIOx pin supports only one function at a time (data ready line
|
||||
selection or external clock input). When a single pin has two
|
||||
two assignments, the enable bit for the lower priority function
|
||||
automatically resets to zero (disabling the lower priority function).
|
||||
Data ready has highest priority.
|
||||
If this field is left empty, DIO2 is assigned as default external clock
|
||||
input pin.
|
||||
|
||||
Example:
|
||||
|
||||
imu@0 {
|
||||
compatible = "adi,adis16495-1";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <3200000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
interrupts = <25 IRQF_TRIGGER_FALLING>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupt-names = "DIO2";
|
||||
clocks = <&adis16495_sync>;
|
||||
clock-names = "sync";
|
||||
adi,ext-clk-pin = "DIO1";
|
||||
};
|
|
@ -8,6 +8,8 @@ Required properties:
|
|||
"st,lsm6dsm"
|
||||
"st,ism330dlc"
|
||||
"st,lsm6dso"
|
||||
"st,asm330lhh"
|
||||
"st,lsm6dsox"
|
||||
- reg: i2c address of the sensor / spi cs line
|
||||
|
||||
Optional properties:
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
VISHAY VCNL4000 - Ambient Light and proximity sensor
|
||||
|
||||
This driver supports the VCNL4000/10/20/40 and VCNL4200 chips
|
||||
|
||||
Required properties:
|
||||
|
||||
-compatible: must be one of :
|
||||
vishay,vcnl4000
|
||||
vishay,vcnl4010
|
||||
vishay,vcnl4020
|
||||
vishay,vcnl4040
|
||||
vishay,vcnl4200
|
||||
|
||||
-reg: I2C address of the sensor, should be one from below based on the model:
|
||||
0x13
|
||||
0x51
|
||||
0x60
|
||||
|
||||
Example:
|
||||
|
||||
light-sensor@51 {
|
||||
compatible = "vishay,vcnl4200";
|
||||
reg = <0x51>;
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
* Devantech SRF04 ultrasonic range finder
|
||||
Bit-banging driver using two GPIOs
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "devantech,srf04"
|
||||
|
||||
- trig-gpios: Definition of the GPIO for the triggering (output)
|
||||
This GPIO is set for about 10 us by the driver to tell the
|
||||
device it should initiate the measurement cycle.
|
||||
|
||||
- echo-gpios: Definition of the GPIO for the echo (input)
|
||||
This GPIO is set by the device as soon as an ultrasonic
|
||||
burst is sent out and reset when the first echo is
|
||||
received.
|
||||
Thus this GPIO is set while the ultrasonic waves are doing
|
||||
one round trip.
|
||||
It needs to be an GPIO which is able to deliver an
|
||||
interrupt because the time between two interrupts is
|
||||
measured in the driver.
|
||||
See Documentation/devicetree/bindings/gpio/gpio.txt for
|
||||
information on how to specify a consumer gpio.
|
||||
|
||||
Example:
|
||||
srf04@0 {
|
||||
compatible = "devantech,srf04";
|
||||
trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
|
||||
echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/proximity/devantech-srf04.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Devantech SRF04 ultrasonic range finder
|
||||
|
||||
maintainers:
|
||||
- Andreas Klinger <ak@it-klinger.de>
|
||||
|
||||
description: |
|
||||
Bit-banging driver using two GPIOs:
|
||||
- trigger-gpio is raised by the driver to start sending out an ultrasonic
|
||||
burst
|
||||
- echo-gpio is held high by the sensor after sending ultrasonic burst
|
||||
until it is received once again
|
||||
|
||||
Specifications about the driver can be found at:
|
||||
http://www.robot-electronics.co.uk/htm/srf04tech.htm
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: devantech,srf04
|
||||
|
||||
trig-gpios:
|
||||
description:
|
||||
Definition of the GPIO for the triggering (output) This GPIO is set
|
||||
for about 10 us by the driver to tell the device it should initiate
|
||||
the measurement cycle.
|
||||
maxItems: 1
|
||||
|
||||
echo-gpios:
|
||||
description:
|
||||
Definition of the GPIO for the echo (input)
|
||||
This GPIO is set by the device as soon as an ultrasonic burst is sent
|
||||
out and reset when the first echo is received.
|
||||
Thus this GPIO is set while the ultrasonic waves are doing one round
|
||||
trip.
|
||||
It needs to be an GPIO which is able to deliver an interrupt because
|
||||
the time between two interrupts is measured in the driver.
|
||||
See Documentation/devicetree/bindings/gpio/gpio.txt for information
|
||||
on how to specify a consumer gpio.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- trig-gpios
|
||||
- echo-gpios
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
proximity {
|
||||
compatible = "devantech,srf04";
|
||||
trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
|
||||
echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
* MaxBotix I2CXL-MaxSonar ultrasonic distance sensor of type mb1202,
|
||||
mb1212, mb1222, mb1232, mb1242, mb7040 or mb7137 using the i2c interface
|
||||
for ranging
|
||||
|
||||
Required properties:
|
||||
- compatible: "maxbotix,mb1202",
|
||||
"maxbotix,mb1212",
|
||||
"maxbotix,mb1222",
|
||||
"maxbotix,mb1232",
|
||||
"maxbotix,mb1242",
|
||||
"maxbotix,mb7040" or
|
||||
"maxbotix,mb7137"
|
||||
|
||||
- reg: i2c address of the device, see also i2c/i2c.txt
|
||||
|
||||
Optional properties:
|
||||
- interrupts: Interrupt used to announce the preceding reading
|
||||
request has finished and that data is available.
|
||||
If no interrupt is specified the device driver
|
||||
falls back to wait a fixed amount of time until
|
||||
data can be retrieved.
|
||||
|
||||
Example:
|
||||
proximity@70 {
|
||||
compatible = "maxbotix,mb1232";
|
||||
reg = <0x70>;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
Maxim MAX31856 thermocouple support
|
||||
|
||||
https://datasheets.maximintegrated.com/en/ds/MAX31856.pdf
|
||||
|
||||
Optional property:
|
||||
- thermocouple-type: Type of thermocouple (THERMOCOUPLE_TYPE_K if
|
||||
omitted). Supported types are B, E, J, K, N, R, S, T.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "maxim,max31856"
|
||||
- reg: SPI chip select number for the device
|
||||
- spi-max-frequency: As per datasheet max. supported freq is 5000000
|
||||
- spi-cpha: must be defined for max31856 to enable SPI mode 1
|
||||
|
||||
Refer to spi/spi-bus.txt for generic SPI slave bindings.
|
||||
|
||||
Example:
|
||||
temp-sensor@0 {
|
||||
compatible = "maxim,max31856";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <5000000>;
|
||||
spi-cpha;
|
||||
thermocouple-type = <THERMOCOUPLE_TYPE_K>;
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
If the temperature sensor device can be configured to use some specific
|
||||
thermocouple type, you can use the defined types provided in the file
|
||||
"include/dt-bindings/iio/temperature/thermocouple.h".
|
||||
|
||||
Property:
|
||||
thermocouple-type: A single cell representing the type of the thermocouple
|
||||
used by the device.
|
|
@ -210,6 +210,7 @@ kiebackpeter Kieback & Peter GmbH
|
|||
kinetic Kinetic Technologies
|
||||
kingdisplay King & Display Technology Co., Ltd.
|
||||
kingnovel Kingnovel Technology Co., Ltd.
|
||||
kionix Kionix, Inc.
|
||||
koe Kaohsiung Opto-Electronics Inc.
|
||||
kosagi Sutajio Ko-Usagi PTE Ltd.
|
||||
kyo Kyocera Corporation
|
||||
|
@ -233,6 +234,7 @@ lsi LSI Corp. (LSI Logic)
|
|||
lwn Liebherr-Werk Nenzing GmbH
|
||||
macnica Macnica Americas
|
||||
marvell Marvell Technology Group Ltd.
|
||||
maxbotix MaxBotix Inc.
|
||||
maxim Maxim Integrated Products
|
||||
mbvl Mobiveil Inc.
|
||||
mcube mCube
|
||||
|
|
10
MAINTAINERS
10
MAINTAINERS
|
@ -868,7 +868,7 @@ L: linux-iio@vger.kernel.org
|
|||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
S: Supported
|
||||
F: drivers/iio/adc/ad7606.c
|
||||
F: Documentation/devicetree/bindings/iio/adc/ad7606.txt
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt
|
||||
|
||||
ANALOG DEVICES INC AD7768-1 DRIVER
|
||||
M: Stefan Popa <stefan.popa@analog.com>
|
||||
|
@ -950,6 +950,7 @@ F: drivers/dma/dma-axi-dmac.c
|
|||
ANALOG DEVICES INC IIO DRIVERS
|
||||
M: Lars-Peter Clausen <lars@metafoo.de>
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
M: Stefan Popa <stefan.popa@analog.com>
|
||||
W: http://wiki.analog.com/
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
S: Supported
|
||||
|
@ -9406,6 +9407,13 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/sound/max9860.txt
|
||||
F: sound/soc/codecs/max9860.*
|
||||
|
||||
MAXBOTIX ULTRASONIC RANGER IIO DRIVER
|
||||
M: Andreas Klinger <ak@it-klinger.de>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt
|
||||
F: drivers/iio/proximity/mb1232.c
|
||||
|
||||
MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
|
||||
M: Javier Martinez Canillas <javier@dowhile0.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
|
|
@ -39,28 +39,28 @@ config IIO_TRIGGER
|
|||
data now' interrupt.
|
||||
|
||||
config IIO_CONSUMERS_PER_TRIGGER
|
||||
int "Maximum number of consumers per trigger"
|
||||
depends on IIO_TRIGGER
|
||||
default "2"
|
||||
help
|
||||
This value controls the maximum number of consumers that a
|
||||
given trigger may handle. Default is 2.
|
||||
int "Maximum number of consumers per trigger"
|
||||
depends on IIO_TRIGGER
|
||||
default "2"
|
||||
help
|
||||
This value controls the maximum number of consumers that a
|
||||
given trigger may handle. Default is 2.
|
||||
|
||||
config IIO_SW_DEVICE
|
||||
tristate "Enable software IIO device support"
|
||||
select IIO_CONFIGFS
|
||||
help
|
||||
Provides IIO core support for software devices. A software
|
||||
device can be created via configfs or directly by a driver
|
||||
using the API provided.
|
||||
Provides IIO core support for software devices. A software
|
||||
device can be created via configfs or directly by a driver
|
||||
using the API provided.
|
||||
|
||||
config IIO_SW_TRIGGER
|
||||
tristate "Enable software triggers support"
|
||||
select IIO_CONFIGFS
|
||||
help
|
||||
Provides IIO core support for software triggers. A software
|
||||
trigger can be created via configfs or directly by a driver
|
||||
using the API provided.
|
||||
Provides IIO core support for software triggers. A software
|
||||
trigger can be created via configfs or directly by a driver
|
||||
using the API provided.
|
||||
|
||||
config IIO_TRIGGERED_EVENT
|
||||
tristate
|
||||
|
|
|
@ -6,28 +6,28 @@
|
|||
menu "Accelerometers"
|
||||
|
||||
config ADIS16201
|
||||
tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
|
||||
depends on SPI
|
||||
select IIO_ADIS_LIB
|
||||
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
|
||||
help
|
||||
Say Y here to build support for Analog Devices adis16201 dual-axis
|
||||
digital inclinometer and accelerometer.
|
||||
tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
|
||||
depends on SPI
|
||||
select IIO_ADIS_LIB
|
||||
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
|
||||
help
|
||||
Say Y here to build support for Analog Devices adis16201 dual-axis
|
||||
digital inclinometer and accelerometer.
|
||||
|
||||
To compile this driver as a module, say M here: the module will
|
||||
be called adis16201.
|
||||
To compile this driver as a module, say M here: the module will
|
||||
be called adis16201.
|
||||
|
||||
config ADIS16209
|
||||
tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
|
||||
depends on SPI
|
||||
select IIO_ADIS_LIB
|
||||
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
|
||||
help
|
||||
Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer
|
||||
and accelerometer.
|
||||
tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
|
||||
depends on SPI
|
||||
select IIO_ADIS_LIB
|
||||
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
|
||||
help
|
||||
Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer
|
||||
and accelerometer.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called adis16209.
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called adis16209.
|
||||
|
||||
config ADXL345
|
||||
tristate
|
||||
|
@ -100,16 +100,16 @@ config BMA180
|
|||
module will be called bma180.
|
||||
|
||||
config BMA220
|
||||
tristate "Bosch BMA220 3-Axis Accelerometer Driver"
|
||||
tristate "Bosch BMA220 3-Axis Accelerometer Driver"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to add support for the Bosch BMA220 triaxial
|
||||
acceleration sensor.
|
||||
help
|
||||
Say yes here to add support for the Bosch BMA220 triaxial
|
||||
acceleration sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bma220_spi.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bma220_spi.
|
||||
|
||||
config BMC150_ACCEL
|
||||
tristate "Bosch BMC150 Accelerometer Driver"
|
||||
|
|
|
@ -116,6 +116,7 @@ struct bma180_data {
|
|||
struct i2c_client *client;
|
||||
struct iio_trigger *trig;
|
||||
const struct bma180_part_info *part_info;
|
||||
struct iio_mount_matrix orientation;
|
||||
struct mutex mutex;
|
||||
bool sleep_state;
|
||||
int scale;
|
||||
|
@ -561,6 +562,15 @@ static int bma180_set_power_mode(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
bma180_accel_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct bma180_data *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_enum bma180_power_mode_enum = {
|
||||
.items = bma180_power_modes,
|
||||
.num_items = ARRAY_SIZE(bma180_power_modes),
|
||||
|
@ -571,7 +581,8 @@ static const struct iio_enum bma180_power_mode_enum = {
|
|||
static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
|
||||
IIO_ENUM("power_mode", true, &bma180_power_mode_enum),
|
||||
IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum),
|
||||
{ },
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma180_accel_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
#define BMA180_ACC_CHANNEL(_axis, _bits) { \
|
||||
|
@ -722,6 +733,11 @@ static int bma180_probe(struct i2c_client *client,
|
|||
chip = id->driver_data;
|
||||
data->part_info = &bma180_part_info[chip];
|
||||
|
||||
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = data->part_info->chip_config(data);
|
||||
if (ret < 0)
|
||||
goto err_chip_disable;
|
||||
|
|
|
@ -204,6 +204,7 @@ struct bmc150_accel_data {
|
|||
int ev_enable_state;
|
||||
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
|
||||
const struct bmc150_accel_chip_info *chip_info;
|
||||
struct iio_mount_matrix orientation;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -796,6 +797,20 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
|
|||
return sprintf(buf, "%d\n", state);
|
||||
}
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
bmc150_accel_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_accel_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
|
||||
static IIO_CONST_ATTR(hwfifo_watermark_max,
|
||||
__stringify(BMC150_ACCEL_FIFO_LENGTH));
|
||||
|
@ -978,6 +993,7 @@ static const struct iio_event_spec bmc150_accel_event = {
|
|||
.shift = 16 - (bits), \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
.ext_info = bmc150_accel_ext_info, \
|
||||
.event_spec = &bmc150_accel_event, \
|
||||
.num_event_specs = 1 \
|
||||
}
|
||||
|
@ -1555,6 +1571,11 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
|
||||
data->regmap = regmap;
|
||||
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bmc150_accel_chip_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
@ -1,17 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for older Chrome OS EC accelerometer
|
||||
*
|
||||
* Copyright 2017 Google, Inc
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver uses the memory mapper cros-ec interface to communicate
|
||||
* with the Chrome OS EC about accelerometer data.
|
||||
* Accelerometer access is presented through iio sysfs.
|
||||
|
@ -29,7 +21,6 @@
|
|||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-accel-legacy"
|
||||
|
@ -353,7 +344,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
|
|||
struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
|
||||
struct iio_dev *indio_dev;
|
||||
struct cros_ec_accel_legacy_state *state;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
if (!ec || !ec->ec_dev) {
|
||||
dev_warn(&pdev->dev, "No EC device found.\n");
|
||||
|
@ -381,20 +372,17 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
|
|||
* Present the channel using HTML5 standard:
|
||||
* need to invert X and Y and invert some lid axis.
|
||||
*/
|
||||
for (i = X ; i < MAX_AXIS; i++) {
|
||||
switch (i) {
|
||||
case X:
|
||||
ec_accel_channels[X].scan_index = Y;
|
||||
case Y:
|
||||
ec_accel_channels[Y].scan_index = X;
|
||||
case Z:
|
||||
ec_accel_channels[Z].scan_index = Z;
|
||||
}
|
||||
if (state->sensor_num == MOTIONSENSE_LOC_LID && i != Y)
|
||||
state->sign[i] = -1;
|
||||
else
|
||||
state->sign[i] = 1;
|
||||
}
|
||||
ec_accel_channels[X].scan_index = Y;
|
||||
ec_accel_channels[Y].scan_index = X;
|
||||
ec_accel_channels[Z].scan_index = Z;
|
||||
|
||||
state->sign[Y] = 1;
|
||||
|
||||
if (state->sensor_num == MOTIONSENSE_LOC_LID)
|
||||
state->sign[X] = state->sign[Z] = -1;
|
||||
else
|
||||
state->sign[X] = state->sign[Z] = 1;
|
||||
|
||||
indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &cros_ec_accel_legacy_info;
|
||||
|
@ -419,5 +407,5 @@ module_platform_driver(cros_ec_accel_platform_driver);
|
|||
|
||||
MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver");
|
||||
MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
|
|
@ -1510,10 +1510,20 @@ static const struct i2c_device_id kxcjk1013_id[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(i2c, kxcjk1013_id);
|
||||
|
||||
static const struct of_device_id kxcjk1013_of_match[] = {
|
||||
{ .compatible = "kionix,kxcjk1013", },
|
||||
{ .compatible = "kionix,kxcj91008", },
|
||||
{ .compatible = "kionix,kxtj21009", },
|
||||
{ .compatible = "kionix,kxtf9", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kxcjk1013_of_match);
|
||||
|
||||
static struct i2c_driver kxcjk1013_driver = {
|
||||
.driver = {
|
||||
.name = KXCJK1013_DRV_NAME,
|
||||
.acpi_match_table = ACPI_PTR(kx_acpi_match),
|
||||
.of_match_table = kxcjk1013_of_match,
|
||||
.pm = &kxcjk1013_pm_ops,
|
||||
},
|
||||
.probe = kxcjk1013_probe,
|
||||
|
|
|
@ -420,9 +420,7 @@ int kxsd9_common_probe(struct device *dev,
|
|||
indio_dev->available_scan_masks = kxsd9_scan_masks;
|
||||
|
||||
/* Read the mounting matrix, if present */
|
||||
ret = of_iio_read_mount_matrix(dev,
|
||||
"mount-matrix",
|
||||
&st->orientation);
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -1580,7 +1580,7 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
case FXLS8471_DEVICE_ID:
|
||||
if (ret == data->chip_info->chip_id)
|
||||
break;
|
||||
/* else: fall through */
|
||||
/* fall through */
|
||||
default:
|
||||
ret = -ENODEV;
|
||||
goto disable_regulators;
|
||||
|
|
|
@ -992,7 +992,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
|
|||
goto out;
|
||||
|
||||
val = elements[i].integer.value;
|
||||
if (val < 0 || val > 2)
|
||||
if (val > 2)
|
||||
goto out;
|
||||
|
||||
/* Avoiding full matrix multiplication, we simply reorder the
|
||||
|
|
|
@ -124,6 +124,18 @@ config AD7768_1
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad7768-1.
|
||||
|
||||
config AD7780
|
||||
tristate "Analog Devices AD7780 and similar ADCs driver"
|
||||
depends on SPI
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
select AD_SIGMA_DELTA
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7170, AD7171,
|
||||
AD7780 and AD7781 SPI analog to digital converters (ADC).
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7780.
|
||||
|
||||
config AD7791
|
||||
tristate "Analog Devices AD7791 ADC driver"
|
||||
depends on SPI
|
||||
|
@ -390,7 +402,7 @@ config HX711
|
|||
|
||||
This driver uses two GPIOs, one acts as the clock and controls the
|
||||
channel selection and gain, the other one is used for the measurement
|
||||
data
|
||||
data
|
||||
|
||||
Currently the raw value is read from the chip and delivered.
|
||||
To get an actual weight one needs to subtract the
|
||||
|
@ -585,17 +597,17 @@ config MCP3911
|
|||
called mcp3911.
|
||||
|
||||
config MEDIATEK_MT6577_AUXADC
|
||||
tristate "MediaTek AUXADC driver"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say yes here to enable support for MediaTek mt65xx AUXADC.
|
||||
tristate "MediaTek AUXADC driver"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say yes here to enable support for MediaTek mt65xx AUXADC.
|
||||
|
||||
The driver supports immediate mode operation to read from one of sixteen
|
||||
channels (external or internal).
|
||||
The driver supports immediate mode operation to read from one of sixteen
|
||||
channels (external or internal).
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called mt6577_auxadc.
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called mt6577_auxadc.
|
||||
|
||||
config MEN_Z188_ADC
|
||||
tristate "MEN 16z188 ADC IP Core support"
|
||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
|
|||
obj-$(CONFIG_AD7606) += ad7606.o
|
||||
obj-$(CONFIG_AD7766) += ad7766.o
|
||||
obj-$(CONFIG_AD7768_1) += ad7768-1.o
|
||||
obj-$(CONFIG_AD7780) += ad7780.o
|
||||
obj-$(CONFIG_AD7791) += ad7791.o
|
||||
obj-$(CONFIG_AD7793) += ad7793.o
|
||||
obj-$(CONFIG_AD7887) += ad7887.o
|
||||
|
|
|
@ -411,7 +411,7 @@ static int ad7124_init_channel_vref(struct ad7124_state *st,
|
|||
dev_err(&st->sd.spi->dev,
|
||||
"Error, trying to use external voltage reference without a %s regulator.\n",
|
||||
ad7124_ref_names[refsel]);
|
||||
return PTR_ERR(st->vref[refsel]);
|
||||
return PTR_ERR(st->vref[refsel]);
|
||||
}
|
||||
st->channel_config[channel_number].vref_mv =
|
||||
regulator_get_voltage(st->vref[refsel]);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* AD7170/AD7171 and AD7780/AD7781 SPI ADC driver
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Copyright 2019 Renato Lui Geh
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -16,6 +17,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bits.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
@ -27,16 +29,25 @@
|
|||
#define AD7780_ID1 BIT(4)
|
||||
#define AD7780_ID0 BIT(3)
|
||||
#define AD7780_GAIN BIT(2)
|
||||
#define AD7780_PAT1 BIT(1)
|
||||
#define AD7780_PAT0 BIT(0)
|
||||
|
||||
#define AD7780_PATTERN (AD7780_PAT0)
|
||||
#define AD7780_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1)
|
||||
#define AD7170_ID 0
|
||||
#define AD7171_ID 1
|
||||
#define AD7780_ID 1
|
||||
#define AD7781_ID 0
|
||||
|
||||
#define AD7170_PAT2 BIT(2)
|
||||
#define AD7780_ID_MASK (AD7780_ID0 | AD7780_ID1)
|
||||
|
||||
#define AD7170_PATTERN (AD7780_PAT0 | AD7170_PAT2)
|
||||
#define AD7170_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1 | AD7170_PAT2)
|
||||
#define AD7780_PATTERN_GOOD 1
|
||||
#define AD7780_PATTERN_MASK GENMASK(1, 0)
|
||||
|
||||
#define AD7170_PATTERN_GOOD 5
|
||||
#define AD7170_PATTERN_MASK GENMASK(2, 0)
|
||||
|
||||
#define AD7780_GAIN_MIDPOINT 64
|
||||
#define AD7780_FILTER_MIDPOINT 13350
|
||||
|
||||
static const unsigned int ad778x_gain[2] = { 1, 128 };
|
||||
static const unsigned int ad778x_odr_avail[2] = { 10000, 16700 };
|
||||
|
||||
struct ad7780_chip_info {
|
||||
struct iio_chan_spec channel;
|
||||
|
@ -49,7 +60,11 @@ struct ad7780_state {
|
|||
const struct ad7780_chip_info *chip_info;
|
||||
struct regulator *reg;
|
||||
struct gpio_desc *powerdown_gpio;
|
||||
unsigned int gain;
|
||||
struct gpio_desc *gain_gpio;
|
||||
struct gpio_desc *filter_gpio;
|
||||
unsigned int gain;
|
||||
unsigned int odr;
|
||||
unsigned int int_vref_mv;
|
||||
|
||||
struct ad_sigma_delta sd;
|
||||
};
|
||||
|
@ -103,17 +118,69 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
|
|||
voltage_uv = regulator_get_voltage(st->reg);
|
||||
if (voltage_uv < 0)
|
||||
return voltage_uv;
|
||||
*val = (voltage_uv / 1000) * st->gain;
|
||||
voltage_uv /= 1000;
|
||||
*val = voltage_uv * st->gain;
|
||||
*val2 = chan->scan_type.realbits - 1;
|
||||
st->int_vref_mv = voltage_uv;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = -(1 << (chan->scan_type.realbits - 1));
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = st->odr;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ad7780_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
int val2,
|
||||
long m)
|
||||
{
|
||||
struct ad7780_state *st = iio_priv(indio_dev);
|
||||
const struct ad7780_chip_info *chip_info = st->chip_info;
|
||||
unsigned long long vref;
|
||||
unsigned int full_scale, gain;
|
||||
|
||||
if (!chip_info->is_ad778x)
|
||||
return -EINVAL;
|
||||
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
vref = st->int_vref_mv * 1000000LL;
|
||||
full_scale = 1 << (chip_info->channel.scan_type.realbits - 1);
|
||||
gain = DIV_ROUND_CLOSEST_ULL(vref, full_scale);
|
||||
gain = DIV_ROUND_CLOSEST(gain, val2);
|
||||
st->gain = gain;
|
||||
if (gain < AD7780_GAIN_MIDPOINT)
|
||||
gain = 0;
|
||||
else
|
||||
gain = 1;
|
||||
gpiod_set_value(st->gain_gpio, gain);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (1000*val + val2/1000 < AD7780_FILTER_MIDPOINT)
|
||||
val = 0;
|
||||
else
|
||||
val = 1;
|
||||
st->odr = ad778x_odr_avail[val];
|
||||
gpiod_set_value(st->filter_gpio, val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
|
||||
unsigned int raw_sample)
|
||||
{
|
||||
|
@ -125,10 +192,8 @@ static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
|
|||
return -EIO;
|
||||
|
||||
if (chip_info->is_ad778x) {
|
||||
if (raw_sample & AD7780_GAIN)
|
||||
st->gain = 1;
|
||||
else
|
||||
st->gain = 128;
|
||||
st->gain = ad778x_gain[raw_sample & AD7780_GAIN];
|
||||
st->odr = ad778x_odr_avail[raw_sample & AD7780_FILTER];
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -141,30 +206,32 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
|
|||
};
|
||||
|
||||
#define AD7780_CHANNEL(bits, wordsize) \
|
||||
AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits)
|
||||
AD_SD_CHANNEL(1, 0, 0, bits, 32, (wordsize) - (bits))
|
||||
#define AD7170_CHANNEL(bits, wordsize) \
|
||||
AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, (wordsize) - (bits))
|
||||
|
||||
static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
|
||||
[ID_AD7170] = {
|
||||
.channel = AD7780_CHANNEL(12, 24),
|
||||
.pattern = AD7170_PATTERN,
|
||||
.channel = AD7170_CHANNEL(12, 24),
|
||||
.pattern = AD7170_PATTERN_GOOD,
|
||||
.pattern_mask = AD7170_PATTERN_MASK,
|
||||
.is_ad778x = false,
|
||||
},
|
||||
[ID_AD7171] = {
|
||||
.channel = AD7780_CHANNEL(16, 24),
|
||||
.pattern = AD7170_PATTERN,
|
||||
.channel = AD7170_CHANNEL(16, 24),
|
||||
.pattern = AD7170_PATTERN_GOOD,
|
||||
.pattern_mask = AD7170_PATTERN_MASK,
|
||||
.is_ad778x = false,
|
||||
},
|
||||
[ID_AD7780] = {
|
||||
.channel = AD7780_CHANNEL(24, 32),
|
||||
.pattern = AD7780_PATTERN,
|
||||
.pattern = AD7780_PATTERN_GOOD,
|
||||
.pattern_mask = AD7780_PATTERN_MASK,
|
||||
.is_ad778x = true,
|
||||
},
|
||||
[ID_AD7781] = {
|
||||
.channel = AD7780_CHANNEL(20, 32),
|
||||
.pattern = AD7780_PATTERN,
|
||||
.pattern = AD7780_PATTERN_GOOD,
|
||||
.pattern_mask = AD7780_PATTERN_MASK,
|
||||
.is_ad778x = true,
|
||||
},
|
||||
|
@ -172,8 +239,47 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
|
|||
|
||||
static const struct iio_info ad7780_info = {
|
||||
.read_raw = ad7780_read_raw,
|
||||
.write_raw = ad7780_write_raw,
|
||||
};
|
||||
|
||||
static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
st->powerdown_gpio = devm_gpiod_get_optional(dev,
|
||||
"powerdown",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->powerdown_gpio)) {
|
||||
ret = PTR_ERR(st->powerdown_gpio);
|
||||
dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!st->chip_info->is_ad778x)
|
||||
return 0;
|
||||
|
||||
|
||||
st->gain_gpio = devm_gpiod_get_optional(dev,
|
||||
"adi,gain",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->gain_gpio)) {
|
||||
ret = PTR_ERR(st->gain_gpio);
|
||||
dev_err(dev, "Failed to request gain GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->filter_gpio = devm_gpiod_get_optional(dev,
|
||||
"adi,filter",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->filter_gpio)) {
|
||||
ret = PTR_ERR(st->filter_gpio);
|
||||
dev_err(dev, "Failed to request filter GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7780_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7780_state *st;
|
||||
|
@ -189,16 +295,6 @@ static int ad7780_probe(struct spi_device *spi)
|
|||
|
||||
ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info);
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "avdd");
|
||||
if (IS_ERR(st->reg))
|
||||
return PTR_ERR(st->reg);
|
||||
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->chip_info =
|
||||
&ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
|
@ -211,14 +307,18 @@ static int ad7780_probe(struct spi_device *spi)
|
|||
indio_dev->num_channels = 1;
|
||||
indio_dev->info = &ad7780_info;
|
||||
|
||||
st->powerdown_gpio = devm_gpiod_get_optional(&spi->dev,
|
||||
"powerdown",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->powerdown_gpio)) {
|
||||
ret = PTR_ERR(st->powerdown_gpio);
|
||||
dev_err(&spi->dev, "Failed to request powerdown GPIO: %d\n",
|
||||
ret);
|
||||
goto error_disable_reg;
|
||||
ret = ad7780_init_gpios(&spi->dev, st);
|
||||
if (ret)
|
||||
goto error_cleanup_buffer_and_trigger;
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "avdd");
|
||||
if (IS_ERR(st->reg))
|
||||
return PTR_ERR(st->reg);
|
||||
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
|
|
@ -24,9 +24,9 @@
|
|||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define AD7923_WRITE_CR (1 << 11) /* write control register */
|
||||
#define AD7923_RANGE (1 << 1) /* range to REFin */
|
||||
#define AD7923_CODING (1 << 0) /* coding is straight binary */
|
||||
#define AD7923_WRITE_CR BIT(11) /* write control register */
|
||||
#define AD7923_RANGE BIT(1) /* range to REFin */
|
||||
#define AD7923_CODING BIT(0) /* coding is straight binary */
|
||||
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
|
||||
#define AD7923_PM_MODE_FS (2) /* full shutdown */
|
||||
#define AD7923_PM_MODE_OPS (3) /* normal operation */
|
||||
|
@ -40,16 +40,16 @@
|
|||
|
||||
#define AD7923_MAX_CHAN 4
|
||||
|
||||
#define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */
|
||||
#define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */
|
||||
#define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \
|
||||
+ ((sequence & 2) << 9))
|
||||
#define AD7923_PM_MODE_WRITE(mode) ((mode) << 4) /* write mode */
|
||||
#define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */
|
||||
#define AD7923_SEQUENCE_WRITE(sequence) ((((sequence) & 1) << 3) \
|
||||
+ (((sequence) & 2) << 9))
|
||||
/* write sequence fonction */
|
||||
/* left shift for CR : bit 11 transmit in first */
|
||||
#define AD7923_SHIFT_REGISTER 4
|
||||
|
||||
/* val = value, dec = left shift, bits = number of bits of the mask */
|
||||
#define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1))
|
||||
#define EXTRACT(val, dec, bits) (((val) >> (dec)) & ((1 << (bits)) - 1))
|
||||
|
||||
struct ad7923_state {
|
||||
struct spi_device *spi;
|
||||
|
@ -130,7 +130,7 @@ static const struct ad7923_chip_info ad7923_chip_info[] = {
|
|||
* ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask
|
||||
**/
|
||||
static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *active_scan_mask)
|
||||
const unsigned long *active_scan_mask)
|
||||
{
|
||||
struct ad7923_state *st = iio_priv(indio_dev);
|
||||
int i, cmd, len;
|
||||
|
@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p)
|
|||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -272,7 +272,7 @@ static int ad7923_probe(struct spi_device *spi)
|
|||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (indio_dev == NULL)
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
@ -314,7 +314,7 @@ static int ad7923_probe(struct spi_device *spi)
|
|||
return ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&ad7923_trigger_handler, NULL);
|
||||
&ad7923_trigger_handler, NULL);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
|
|||
struct spi_transfer t = {
|
||||
.tx_buf = data,
|
||||
.len = size + 1,
|
||||
.cs_change = sigma_delta->bus_locked,
|
||||
.cs_change = sigma_delta->keep_cs_asserted,
|
||||
};
|
||||
struct spi_message m;
|
||||
int ret;
|
||||
|
@ -217,6 +217,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
|
|||
|
||||
spi_bus_lock(sigma_delta->spi->master);
|
||||
sigma_delta->bus_locked = true;
|
||||
sigma_delta->keep_cs_asserted = true;
|
||||
reinit_completion(&sigma_delta->completion);
|
||||
|
||||
ret = ad_sigma_delta_set_mode(sigma_delta, mode);
|
||||
|
@ -234,9 +235,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
|
|||
ret = 0;
|
||||
}
|
||||
out:
|
||||
sigma_delta->keep_cs_asserted = false;
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
||||
sigma_delta->bus_locked = false;
|
||||
spi_bus_unlock(sigma_delta->spi->master);
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -289,6 +291,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
|
|||
|
||||
spi_bus_lock(sigma_delta->spi->master);
|
||||
sigma_delta->bus_locked = true;
|
||||
sigma_delta->keep_cs_asserted = true;
|
||||
reinit_completion(&sigma_delta->completion);
|
||||
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
|
||||
|
@ -298,9 +301,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
|
|||
ret = wait_for_completion_interruptible_timeout(
|
||||
&sigma_delta->completion, HZ);
|
||||
|
||||
sigma_delta->bus_locked = false;
|
||||
spi_bus_unlock(sigma_delta->spi->master);
|
||||
|
||||
if (ret == 0)
|
||||
ret = -EIO;
|
||||
if (ret < 0)
|
||||
|
@ -321,7 +321,10 @@ out:
|
|||
sigma_delta->irq_dis = true;
|
||||
}
|
||||
|
||||
sigma_delta->keep_cs_asserted = false;
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
||||
sigma_delta->bus_locked = false;
|
||||
spi_bus_unlock(sigma_delta->spi->master);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
if (ret)
|
||||
|
@ -358,6 +361,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
|||
|
||||
spi_bus_lock(sigma_delta->spi->master);
|
||||
sigma_delta->bus_locked = true;
|
||||
sigma_delta->keep_cs_asserted = true;
|
||||
|
||||
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
@ -386,6 +391,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
|
|||
sigma_delta->irq_dis = true;
|
||||
}
|
||||
|
||||
sigma_delta->keep_cs_asserted = false;
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
||||
|
||||
sigma_delta->bus_locked = false;
|
||||
|
|
|
@ -302,10 +302,8 @@ static int ingenic_adc_probe(struct platform_device *pdev)
|
|||
|
||||
mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
adc->base = devm_ioremap_resource(dev, mem_base);
|
||||
if (IS_ERR(adc->base)) {
|
||||
dev_err(dev, "Unable to ioremap mmio resource\n");
|
||||
if (IS_ERR(adc->base))
|
||||
return PTR_ERR(adc->base);
|
||||
}
|
||||
|
||||
adc->clk = devm_clk_get(dev, "adc");
|
||||
if (IS_ERR(adc->clk)) {
|
||||
|
|
|
@ -7,20 +7,15 @@
|
|||
* Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/*
|
||||
* LPC32XX registers definitions
|
||||
|
@ -52,6 +47,7 @@ struct lpc32xx_adc_state {
|
|||
void __iomem *adc_base;
|
||||
struct clk *clk;
|
||||
struct completion completion;
|
||||
struct regulator *vref;
|
||||
|
||||
u32 value;
|
||||
};
|
||||
|
@ -64,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
|
|||
{
|
||||
struct lpc32xx_adc_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
if (mask == IIO_CHAN_INFO_RAW) {
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = clk_prepare_enable(st->clk);
|
||||
if (ret) {
|
||||
|
@ -84,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
|
|||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = regulator_get_voltage(st->vref) / 1000;
|
||||
*val2 = 10;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info lpc32xx_adc_iio_info = {
|
||||
.read_raw = &lpc32xx_read_raw,
|
||||
};
|
||||
|
||||
#define LPC32XX_ADC_CHANNEL(_index) { \
|
||||
#define LPC32XX_ADC_CHANNEL_BASE(_index) \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = _index, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.address = LPC32XXAD_IN * _index, \
|
||||
.scan_index = _index, \
|
||||
.scan_index = _index,
|
||||
|
||||
#define LPC32XX_ADC_CHANNEL(_index) { \
|
||||
LPC32XX_ADC_CHANNEL_BASE(_index) \
|
||||
}
|
||||
|
||||
#define LPC32XX_ADC_SCALE_CHANNEL(_index) { \
|
||||
LPC32XX_ADC_CHANNEL_BASE(_index) \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
|
||||
|
@ -108,6 +120,12 @@ static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
|
|||
LPC32XX_ADC_CHANNEL(2),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec lpc32xx_adc_iio_scale_channels[] = {
|
||||
LPC32XX_ADC_SCALE_CHANNEL(0),
|
||||
LPC32XX_ADC_SCALE_CHANNEL(1),
|
||||
LPC32XX_ADC_SCALE_CHANNEL(2),
|
||||
};
|
||||
|
||||
static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct lpc32xx_adc_state *st = dev_id;
|
||||
|
@ -166,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
|
|||
return retval;
|
||||
}
|
||||
|
||||
st->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(st->vref)) {
|
||||
iodev->channels = lpc32xx_adc_iio_channels;
|
||||
dev_info(&pdev->dev,
|
||||
"Missing vref regulator: No scaling available\n");
|
||||
} else {
|
||||
iodev->channels = lpc32xx_adc_iio_scale_channels;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, iodev);
|
||||
|
||||
init_completion(&st->completion);
|
||||
|
@ -174,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
|
|||
iodev->dev.parent = &pdev->dev;
|
||||
iodev->info = &lpc32xx_adc_iio_info;
|
||||
iodev->modes = INDIO_DIRECT_MODE;
|
||||
iodev->channels = lpc32xx_adc_iio_channels;
|
||||
iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
|
||||
|
||||
retval = devm_iio_device_register(&pdev->dev, iodev);
|
||||
|
|
|
@ -1150,6 +1150,11 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = {
|
|||
.name = "meson-axg-saradc",
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_data meson_sar_adc_g12a_data = {
|
||||
.param = &meson_sar_adc_gxl_param,
|
||||
.name = "meson-g12a-saradc",
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_sar_adc_of_match[] = {
|
||||
{
|
||||
.compatible = "amlogic,meson8-saradc",
|
||||
|
@ -1175,6 +1180,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
|
|||
}, {
|
||||
.compatible = "amlogic,meson-axg-saradc",
|
||||
.data = &meson_sar_adc_axg_data,
|
||||
}, {
|
||||
.compatible = "amlogic,meson-g12a-saradc",
|
||||
.data = &meson_sar_adc_g12a_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
|
|
@ -465,6 +465,8 @@ static int mxs_lradc_adc_trigger_init(struct iio_dev *iio)
|
|||
|
||||
trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name,
|
||||
iio->id);
|
||||
if (!trig)
|
||||
return -ENOMEM;
|
||||
|
||||
trig->dev.parent = adc->dev;
|
||||
iio_trigger_set_drvdata(trig, iio);
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/hw-consumer.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/timer/stm32-lptim-trigger.h>
|
||||
#include <linux/iio/timer/stm32-timer-trigger.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
@ -38,6 +43,11 @@
|
|||
#define DFSDM_MAX_RES BIT(31)
|
||||
#define DFSDM_DATA_RES BIT(23)
|
||||
|
||||
/* Filter configuration */
|
||||
#define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \
|
||||
DFSDM_CR1_RSYNC_MASK | DFSDM_CR1_JSYNC_MASK | \
|
||||
DFSDM_CR1_JSCAN_MASK)
|
||||
|
||||
enum sd_converter_type {
|
||||
DFSDM_AUDIO,
|
||||
DFSDM_IIO,
|
||||
|
@ -54,6 +64,8 @@ struct stm32_dfsdm_adc {
|
|||
struct stm32_dfsdm *dfsdm;
|
||||
const struct stm32_dfsdm_dev_data *dev_data;
|
||||
unsigned int fl_id;
|
||||
unsigned int nconv;
|
||||
unsigned long smask;
|
||||
|
||||
/* ADC specific */
|
||||
unsigned int oversamp;
|
||||
|
@ -114,6 +126,61 @@ static int stm32_dfsdm_str2val(const char *str,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct stm32_dfsdm_trig_info - DFSDM trigger info
|
||||
* @name: name of the trigger, corresponding to its source
|
||||
* @jextsel: trigger signal selection
|
||||
*/
|
||||
struct stm32_dfsdm_trig_info {
|
||||
const char *name;
|
||||
unsigned int jextsel;
|
||||
};
|
||||
|
||||
/* hardware injected trigger enable, edge selection */
|
||||
enum stm32_dfsdm_jexten {
|
||||
STM32_DFSDM_JEXTEN_DISABLED,
|
||||
STM32_DFSDM_JEXTEN_RISING_EDGE,
|
||||
STM32_DFSDM_JEXTEN_FALLING_EDGE,
|
||||
STM32_DFSDM_EXTEN_BOTH_EDGES,
|
||||
};
|
||||
|
||||
static const struct stm32_dfsdm_trig_info stm32_dfsdm_trigs[] = {
|
||||
{ TIM1_TRGO, 0 },
|
||||
{ TIM1_TRGO2, 1 },
|
||||
{ TIM8_TRGO, 2 },
|
||||
{ TIM8_TRGO2, 3 },
|
||||
{ TIM3_TRGO, 4 },
|
||||
{ TIM4_TRGO, 5 },
|
||||
{ TIM16_OC1, 6 },
|
||||
{ TIM6_TRGO, 7 },
|
||||
{ TIM7_TRGO, 8 },
|
||||
{ LPTIM1_OUT, 26 },
|
||||
{ LPTIM2_OUT, 27 },
|
||||
{ LPTIM3_OUT, 28 },
|
||||
{},
|
||||
};
|
||||
|
||||
static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* lookup triggers registered by stm32 timer trigger driver */
|
||||
for (i = 0; stm32_dfsdm_trigs[i].name; i++) {
|
||||
/**
|
||||
* Checking both stm32 timer trigger type and trig name
|
||||
* should be safe against arbitrary trigger names.
|
||||
*/
|
||||
if ((is_stm32_timer_trigger(trig) ||
|
||||
is_stm32_lptim_trigger(trig)) &&
|
||||
!strcmp(stm32_dfsdm_trigs[i].name, trig->name)) {
|
||||
return stm32_dfsdm_trigs[i].jextsel;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
|
||||
unsigned int fast, unsigned int oversamp)
|
||||
{
|
||||
|
@ -200,19 +267,39 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_start_channel(struct stm32_dfsdm *dfsdm,
|
||||
unsigned int ch_id)
|
||||
static int stm32_dfsdm_start_channel(struct stm32_dfsdm_adc *adc)
|
||||
{
|
||||
return regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id),
|
||||
DFSDM_CHCFGR1_CHEN_MASK,
|
||||
DFSDM_CHCFGR1_CHEN(1));
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
struct regmap *regmap = adc->dfsdm->regmap;
|
||||
const struct iio_chan_spec *chan;
|
||||
unsigned int bit;
|
||||
int ret;
|
||||
|
||||
for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) {
|
||||
chan = indio_dev->channels + bit;
|
||||
ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel),
|
||||
DFSDM_CHCFGR1_CHEN_MASK,
|
||||
DFSDM_CHCFGR1_CHEN(1));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm,
|
||||
unsigned int ch_id)
|
||||
static void stm32_dfsdm_stop_channel(struct stm32_dfsdm_adc *adc)
|
||||
{
|
||||
regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id),
|
||||
DFSDM_CHCFGR1_CHEN_MASK, DFSDM_CHCFGR1_CHEN(0));
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
struct regmap *regmap = adc->dfsdm->regmap;
|
||||
const struct iio_chan_spec *chan;
|
||||
unsigned int bit;
|
||||
|
||||
for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) {
|
||||
chan = indio_dev->channels + bit;
|
||||
regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel),
|
||||
DFSDM_CHCFGR1_CHEN_MASK,
|
||||
DFSDM_CHCFGR1_CHEN(0));
|
||||
}
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm,
|
||||
|
@ -237,9 +324,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm,
|
|||
DFSDM_CHCFGR1_CHINSEL(ch->alt_si));
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm,
|
||||
unsigned int fl_id)
|
||||
static int stm32_dfsdm_start_filter(struct stm32_dfsdm_adc *adc,
|
||||
unsigned int fl_id,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct stm32_dfsdm *dfsdm = adc->dfsdm;
|
||||
int ret;
|
||||
|
||||
/* Enable filter */
|
||||
|
@ -248,7 +337,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Start conversion */
|
||||
/* Nothing more to do for injected (scan mode/triggered) conversions */
|
||||
if (adc->nconv > 1 || trig)
|
||||
return 0;
|
||||
|
||||
/* Software start (single or continuous) regular conversion */
|
||||
return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id),
|
||||
DFSDM_CR1_RSWSTART_MASK,
|
||||
DFSDM_CR1_RSWSTART(1));
|
||||
|
@ -262,11 +355,45 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm,
|
|||
DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0));
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm,
|
||||
unsigned int fl_id, unsigned int ch_id)
|
||||
static int stm32_dfsdm_filter_set_trig(struct stm32_dfsdm_adc *adc,
|
||||
unsigned int fl_id,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct regmap *regmap = dfsdm->regmap;
|
||||
struct stm32_dfsdm_filter *fl = &dfsdm->fl_list[fl_id];
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
struct regmap *regmap = adc->dfsdm->regmap;
|
||||
u32 jextsel = 0, jexten = STM32_DFSDM_JEXTEN_DISABLED;
|
||||
int ret;
|
||||
|
||||
if (trig) {
|
||||
ret = stm32_dfsdm_get_jextsel(indio_dev, trig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set trigger source and polarity (default to rising edge) */
|
||||
jextsel = ret;
|
||||
jexten = STM32_DFSDM_JEXTEN_RISING_EDGE;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id),
|
||||
DFSDM_CR1_JEXTSEL_MASK | DFSDM_CR1_JEXTEN_MASK,
|
||||
DFSDM_CR1_JEXTSEL(jextsel) |
|
||||
DFSDM_CR1_JEXTEN(jexten));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
|
||||
unsigned int fl_id,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
struct regmap *regmap = adc->dfsdm->regmap;
|
||||
struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
|
||||
u32 cr1;
|
||||
const struct iio_chan_spec *chan;
|
||||
unsigned int bit, jchg = 0;
|
||||
int ret;
|
||||
|
||||
/* Average integrator oversampling */
|
||||
|
@ -286,15 +413,68 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* No scan mode supported for the moment */
|
||||
ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RCH_MASK,
|
||||
DFSDM_CR1_RCH(ch_id));
|
||||
ret = stm32_dfsdm_filter_set_trig(adc, fl_id, trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(regmap, DFSDM_CR1(fl_id),
|
||||
DFSDM_CR1_RSYNC_MASK,
|
||||
DFSDM_CR1_RSYNC(fl->sync_mode));
|
||||
/*
|
||||
* DFSDM modes configuration W.R.T audio/iio type modes
|
||||
* ----------------------------------------------------------------
|
||||
* Modes | regular | regular | injected | injected |
|
||||
* | | continuous | | + scan |
|
||||
* --------------|---------|--------------|----------|------------|
|
||||
* single conv | x | | | |
|
||||
* (1 chan) | | | | |
|
||||
* --------------|---------|--------------|----------|------------|
|
||||
* 1 Audio chan | | sample freq | | |
|
||||
* | | or sync_mode | | |
|
||||
* --------------|---------|--------------|----------|------------|
|
||||
* 1 IIO chan | | sample freq | trigger | |
|
||||
* | | or sync_mode | | |
|
||||
* --------------|---------|--------------|----------|------------|
|
||||
* 2+ IIO chans | | | | trigger or |
|
||||
* | | | | sync_mode |
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
if (adc->nconv == 1 && !trig) {
|
||||
bit = __ffs(adc->smask);
|
||||
chan = indio_dev->channels + bit;
|
||||
|
||||
/* Use regular conversion for single channel without trigger */
|
||||
cr1 = DFSDM_CR1_RCH(chan->channel);
|
||||
|
||||
/* Continuous conversions triggered by SPI clk in buffer mode */
|
||||
if (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE)
|
||||
cr1 |= DFSDM_CR1_RCONT(1);
|
||||
|
||||
cr1 |= DFSDM_CR1_RSYNC(fl->sync_mode);
|
||||
} else {
|
||||
/* Use injected conversion for multiple channels */
|
||||
for_each_set_bit(bit, &adc->smask,
|
||||
sizeof(adc->smask) * BITS_PER_BYTE) {
|
||||
chan = indio_dev->channels + bit;
|
||||
jchg |= BIT(chan->channel);
|
||||
}
|
||||
ret = regmap_write(regmap, DFSDM_JCHGR(fl_id), jchg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Use scan mode for multiple channels */
|
||||
cr1 = DFSDM_CR1_JSCAN((adc->nconv > 1) ? 1 : 0);
|
||||
|
||||
/*
|
||||
* Continuous conversions not supported in injected mode,
|
||||
* either use:
|
||||
* - conversions in sync with filter 0
|
||||
* - triggered conversions
|
||||
*/
|
||||
if (!fl->sync_mode && !trig)
|
||||
return -EINVAL;
|
||||
cr1 |= DFSDM_CR1_JSYNC(fl->sync_mode);
|
||||
}
|
||||
|
||||
return regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_CFG_MASK,
|
||||
cr1);
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm,
|
||||
|
@ -378,13 +558,38 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq);
|
||||
}
|
||||
|
||||
static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev,
|
||||
unsigned int sample_freq,
|
||||
unsigned int spi_freq)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
|
||||
unsigned int oversamp;
|
||||
int ret;
|
||||
|
||||
oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq);
|
||||
if (spi_freq % sample_freq)
|
||||
dev_dbg(&indio_dev->dev,
|
||||
"Rate not accurate. requested (%u), actual (%u)\n",
|
||||
sample_freq, spi_freq / oversamp);
|
||||
|
||||
ret = stm32_dfsdm_set_osrs(fl, 0, oversamp);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "No filter parameters that match!\n");
|
||||
return ret;
|
||||
}
|
||||
adc->sample_freq = spi_freq / oversamp;
|
||||
adc->oversamp = oversamp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
|
||||
uintptr_t priv,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
|
||||
struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
|
||||
unsigned int sample_freq = adc->sample_freq;
|
||||
unsigned int spi_freq;
|
||||
|
@ -403,17 +608,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
|
||||
if (sample_freq) {
|
||||
if (spi_freq % sample_freq)
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Sampling rate not accurate (%d)\n",
|
||||
spi_freq / (spi_freq / sample_freq));
|
||||
|
||||
ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq));
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"No filter parameters that match!\n");
|
||||
ret = dfsdm_adc_set_samp_freq(indio_dev, sample_freq, spi_freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
adc->spi_freq = spi_freq;
|
||||
|
||||
|
@ -421,72 +618,44 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc,
|
||||
const struct iio_chan_spec *chan,
|
||||
bool dma)
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct regmap *regmap = adc->dfsdm->regmap;
|
||||
int ret;
|
||||
unsigned int dma_en = 0, cont_en = 0;
|
||||
|
||||
ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel);
|
||||
ret = stm32_dfsdm_start_channel(adc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id,
|
||||
chan->channel);
|
||||
ret = stm32_dfsdm_filter_configure(adc, adc->fl_id, trig);
|
||||
if (ret < 0)
|
||||
goto stop_channels;
|
||||
|
||||
if (dma) {
|
||||
/* Enable DMA transfer*/
|
||||
dma_en = DFSDM_CR1_RDMAEN(1);
|
||||
/* Enable conversion triggered by SPI clock*/
|
||||
cont_en = DFSDM_CR1_RCONT(1);
|
||||
}
|
||||
/* Enable DMA transfer*/
|
||||
ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RDMAEN_MASK, dma_en);
|
||||
ret = stm32_dfsdm_start_filter(adc, adc->fl_id, trig);
|
||||
if (ret < 0)
|
||||
goto stop_channels;
|
||||
|
||||
/* Enable conversion triggered by SPI clock*/
|
||||
ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RCONT_MASK, cont_en);
|
||||
if (ret < 0)
|
||||
goto stop_channels;
|
||||
|
||||
ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id);
|
||||
if (ret < 0)
|
||||
goto stop_channels;
|
||||
goto filter_unconfigure;
|
||||
|
||||
return 0;
|
||||
|
||||
filter_unconfigure:
|
||||
regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_CFG_MASK, 0);
|
||||
stop_channels:
|
||||
regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RDMAEN_MASK, 0);
|
||||
|
||||
regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RCONT_MASK, 0);
|
||||
stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel);
|
||||
stm32_dfsdm_stop_channel(adc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc,
|
||||
const struct iio_chan_spec *chan)
|
||||
static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc)
|
||||
{
|
||||
struct regmap *regmap = adc->dfsdm->regmap;
|
||||
|
||||
stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id);
|
||||
|
||||
/* Clean conversion options */
|
||||
regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RDMAEN_MASK, 0);
|
||||
DFSDM_CR1_CFG_MASK, 0);
|
||||
|
||||
regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RCONT_MASK, 0);
|
||||
|
||||
stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel);
|
||||
stm32_dfsdm_stop_channel(adc);
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev,
|
||||
|
@ -494,6 +663,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev,
|
|||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2;
|
||||
unsigned int rx_buf_sz = DFSDM_DMA_BUFFER_SIZE;
|
||||
|
||||
/*
|
||||
* DMA cyclic transfers are used, buffer is split into two periods.
|
||||
|
@ -502,7 +672,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev,
|
|||
* - one buffer (period) driver pushed to ASoC side.
|
||||
*/
|
||||
watermark = min(watermark, val * (unsigned int)(sizeof(u32)));
|
||||
adc->buf_sz = watermark * 2;
|
||||
adc->buf_sz = min(rx_buf_sz, watermark * 2 * adc->nconv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -532,13 +702,41 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void stm32_dfsdm_audio_dma_buffer_done(void *data)
|
||||
static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
int available = stm32_dfsdm_adc_dma_residue(adc);
|
||||
|
||||
while (available >= indio_dev->scan_bytes) {
|
||||
u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi];
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
pf->timestamp);
|
||||
available -= indio_dev->scan_bytes;
|
||||
adc->bufi += indio_dev->scan_bytes;
|
||||
if (adc->bufi >= adc->buf_sz)
|
||||
adc->bufi = 0;
|
||||
}
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void stm32_dfsdm_dma_buffer_done(void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
int available = stm32_dfsdm_adc_dma_residue(adc);
|
||||
size_t old_pos;
|
||||
|
||||
if (indio_dev->currentmode & INDIO_BUFFER_TRIGGERED) {
|
||||
iio_trigger_poll_chained(indio_dev->trig);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: In Kernel interface does not support cyclic DMA buffer,and
|
||||
* offers only an interface to push data samples per samples.
|
||||
|
@ -566,6 +764,9 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data)
|
|||
adc->bufi = 0;
|
||||
old_pos = 0;
|
||||
}
|
||||
/* regular iio buffer without trigger */
|
||||
if (adc->dev_data->type == DFSDM_IIO)
|
||||
iio_push_to_buffers(indio_dev, buffer);
|
||||
}
|
||||
if (adc->cb)
|
||||
adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos,
|
||||
|
@ -575,6 +776,10 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data)
|
|||
static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
struct dma_slave_config config = {
|
||||
.src_addr = (dma_addr_t)adc->dfsdm->phys_base,
|
||||
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
};
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
dma_cookie_t cookie;
|
||||
int ret;
|
||||
|
@ -585,6 +790,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
|
|||
dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__,
|
||||
adc->buf_sz, adc->buf_sz / 2);
|
||||
|
||||
if (adc->nconv == 1 && !indio_dev->trig)
|
||||
config.src_addr += DFSDM_RDATAR(adc->fl_id);
|
||||
else
|
||||
config.src_addr += DFSDM_JDATAR(adc->fl_id);
|
||||
ret = dmaengine_slave_config(adc->dma_chan, &config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Prepare a DMA cyclic transaction */
|
||||
desc = dmaengine_prep_dma_cyclic(adc->dma_chan,
|
||||
adc->dma_buf,
|
||||
|
@ -594,71 +807,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
|
|||
if (!desc)
|
||||
return -EBUSY;
|
||||
|
||||
desc->callback = stm32_dfsdm_audio_dma_buffer_done;
|
||||
desc->callback = stm32_dfsdm_dma_buffer_done;
|
||||
desc->callback_param = indio_dev;
|
||||
|
||||
cookie = dmaengine_submit(desc);
|
||||
ret = dma_submit_error(cookie);
|
||||
if (ret) {
|
||||
dmaengine_terminate_all(adc->dma_chan);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err_stop_dma;
|
||||
|
||||
/* Issue pending DMA requests */
|
||||
dma_async_issue_pending(adc->dma_chan);
|
||||
|
||||
if (adc->nconv == 1 && !indio_dev->trig) {
|
||||
/* Enable regular DMA transfer*/
|
||||
ret = regmap_update_bits(adc->dfsdm->regmap,
|
||||
DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RDMAEN_MASK,
|
||||
DFSDM_CR1_RDMAEN_MASK);
|
||||
} else {
|
||||
/* Enable injected DMA transfer*/
|
||||
ret = regmap_update_bits(adc->dfsdm->regmap,
|
||||
DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_JDMAEN_MASK,
|
||||
DFSDM_CR1_JDMAEN_MASK);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto err_stop_dma;
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_dma:
|
||||
dmaengine_terminate_all(adc->dma_chan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
if (!adc->dma_chan)
|
||||
return;
|
||||
|
||||
regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
|
||||
DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0);
|
||||
dmaengine_terminate_all(adc->dma_chan);
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
adc->nconv = bitmap_weight(scan_mask, indio_dev->masklength);
|
||||
adc->smask = *scan_mask;
|
||||
|
||||
dev_dbg(&indio_dev->dev, "nconv=%d mask=%lx\n", adc->nconv, *scan_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
|
||||
static int __stm32_dfsdm_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
const struct iio_chan_spec *chan = &indio_dev->channels[0];
|
||||
int ret;
|
||||
|
||||
/* Reset adc buffer index */
|
||||
adc->bufi = 0;
|
||||
|
||||
if (adc->hwc) {
|
||||
ret = iio_hw_consumer_enable(adc->hwc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = stm32_dfsdm_start_dfsdm(adc->dfsdm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_stop_hwc;
|
||||
|
||||
ret = stm32_dfsdm_start_conv(adc, chan, true);
|
||||
ret = stm32_dfsdm_adc_dma_start(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Can't start conversion\n");
|
||||
dev_err(&indio_dev->dev, "Can't start DMA\n");
|
||||
goto stop_dfsdm;
|
||||
}
|
||||
|
||||
if (adc->dma_chan) {
|
||||
ret = stm32_dfsdm_adc_dma_start(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Can't start DMA\n");
|
||||
goto err_stop_conv;
|
||||
}
|
||||
ret = stm32_dfsdm_start_conv(adc, indio_dev->trig);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Can't start conversion\n");
|
||||
goto err_stop_dma;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_conv:
|
||||
stm32_dfsdm_stop_conv(adc, chan);
|
||||
err_stop_dma:
|
||||
stm32_dfsdm_adc_dma_stop(indio_dev);
|
||||
stop_dfsdm:
|
||||
stm32_dfsdm_stop_dfsdm(adc->dfsdm);
|
||||
err_stop_hwc:
|
||||
if (adc->hwc)
|
||||
iio_hw_consumer_disable(adc->hwc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
|
||||
static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
|
||||
ret = iio_triggered_buffer_postenable(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = __stm32_dfsdm_postenable(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_predisable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_predisable:
|
||||
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED)
|
||||
iio_triggered_buffer_predisable(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __stm32_dfsdm_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
const struct iio_chan_spec *chan = &indio_dev->channels[0];
|
||||
|
||||
if (adc->dma_chan)
|
||||
dmaengine_terminate_all(adc->dma_chan);
|
||||
stm32_dfsdm_stop_conv(adc);
|
||||
|
||||
stm32_dfsdm_stop_conv(adc, chan);
|
||||
stm32_dfsdm_adc_dma_stop(indio_dev);
|
||||
|
||||
stm32_dfsdm_stop_dfsdm(adc->dfsdm);
|
||||
|
||||
if (adc->hwc)
|
||||
iio_hw_consumer_disable(adc->hwc);
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
__stm32_dfsdm_predisable(indio_dev);
|
||||
|
||||
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED)
|
||||
iio_triggered_buffer_predisable(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -736,7 +1032,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
|
|||
if (ret < 0)
|
||||
goto stop_dfsdm;
|
||||
|
||||
ret = stm32_dfsdm_start_conv(adc, chan, false);
|
||||
adc->nconv = 1;
|
||||
adc->smask = BIT(chan->scan_index);
|
||||
ret = stm32_dfsdm_start_conv(adc, NULL);
|
||||
if (ret < 0) {
|
||||
regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id),
|
||||
DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0));
|
||||
|
@ -757,7 +1055,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
|
|||
else
|
||||
ret = IIO_VAL_INT;
|
||||
|
||||
stm32_dfsdm_stop_conv(adc, chan);
|
||||
stm32_dfsdm_stop_conv(adc);
|
||||
|
||||
stop_dfsdm:
|
||||
stm32_dfsdm_stop_dfsdm(adc->dfsdm);
|
||||
|
@ -777,16 +1075,23 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
|
|||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = stm32_dfsdm_set_osrs(fl, 0, val);
|
||||
if (!ret)
|
||||
adc->oversamp = val;
|
||||
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (ch->src) {
|
||||
case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL:
|
||||
spi_freq = adc->dfsdm->spi_master_freq;
|
||||
|
@ -799,20 +1104,9 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
|
|||
spi_freq = adc->spi_freq;
|
||||
}
|
||||
|
||||
if (spi_freq % val)
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Sampling rate not accurate (%d)\n",
|
||||
spi_freq / (spi_freq / val));
|
||||
|
||||
ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val));
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"Not able to find parameter that match!\n");
|
||||
return ret;
|
||||
}
|
||||
adc->sample_freq = val;
|
||||
|
||||
return 0;
|
||||
ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -827,11 +1121,15 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = iio_hw_consumer_enable(adc->hwc);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"%s: IIO enable failed (channel %d)\n",
|
||||
__func__, chan->channel);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
ret = stm32_dfsdm_single_conv(indio_dev, chan, val);
|
||||
|
@ -840,8 +1138,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
|
|||
dev_err(&indio_dev->dev,
|
||||
"%s: Conversion failed (channel %d)\n",
|
||||
__func__, chan->channel);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
|
@ -858,15 +1158,25 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_validate_trigger(struct iio_dev *indio_dev,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
return stm32_dfsdm_get_jextsel(indio_dev, trig) < 0 ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static const struct iio_info stm32_dfsdm_info_audio = {
|
||||
.hwfifo_set_watermark = stm32_dfsdm_set_watermark,
|
||||
.read_raw = stm32_dfsdm_read_raw,
|
||||
.write_raw = stm32_dfsdm_write_raw,
|
||||
.update_scan_mode = stm32_dfsdm_update_scan_mode,
|
||||
};
|
||||
|
||||
static const struct iio_info stm32_dfsdm_info_adc = {
|
||||
.hwfifo_set_watermark = stm32_dfsdm_set_watermark,
|
||||
.read_raw = stm32_dfsdm_read_raw,
|
||||
.write_raw = stm32_dfsdm_write_raw,
|
||||
.update_scan_mode = stm32_dfsdm_update_scan_mode,
|
||||
.validate_trigger = stm32_dfsdm_validate_trigger,
|
||||
};
|
||||
|
||||
static irqreturn_t stm32_dfsdm_irq(int irq, void *arg)
|
||||
|
@ -926,12 +1236,6 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev)
|
|||
static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
struct dma_slave_config config = {
|
||||
.src_addr = (dma_addr_t)adc->dfsdm->phys_base +
|
||||
DFSDM_RDATAR(adc->fl_id),
|
||||
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
};
|
||||
int ret;
|
||||
|
||||
adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx");
|
||||
if (!adc->dma_chan)
|
||||
|
@ -941,23 +1245,14 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev)
|
|||
DFSDM_DMA_BUFFER_SIZE,
|
||||
&adc->dma_buf, GFP_KERNEL);
|
||||
if (!adc->rx_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_release;
|
||||
dma_release_channel(adc->dma_chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(adc->dma_chan, &config);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
|
||||
indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
dma_free_coherent(adc->dma_chan->device->dev, DFSDM_DMA_BUFFER_SIZE,
|
||||
adc->rx_buf, adc->dma_buf);
|
||||
err_release:
|
||||
dma_release_channel(adc->dma_chan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
|
@ -978,7 +1273,8 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
|
|||
* IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling
|
||||
*/
|
||||
ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
|
||||
ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
|
||||
if (adc->dev_data->type == DFSDM_AUDIO) {
|
||||
ch->scan_type.sign = 's';
|
||||
|
@ -1000,9 +1296,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev)
|
|||
struct stm32_dfsdm_channel *d_ch;
|
||||
int ret;
|
||||
|
||||
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
|
||||
indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops;
|
||||
|
||||
ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL);
|
||||
if (!ch)
|
||||
return -ENOMEM;
|
||||
|
@ -1070,6 +1363,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
|
|||
|
||||
init_completion(&adc->completion);
|
||||
|
||||
/* Optionally request DMA */
|
||||
if (stm32_dfsdm_dma_request(indio_dev)) {
|
||||
dev_dbg(&indio_dev->dev, "No DMA support\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
&stm32_dfsdm_adc_trigger_handler,
|
||||
&stm32_dfsdm_buffer_setup_ops);
|
||||
if (ret) {
|
||||
stm32_dfsdm_dma_release(indio_dev);
|
||||
dev_err(&indio_dev->dev, "buffer setup failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* lptimer/timer hardware triggers */
|
||||
indio_dev->modes |= INDIO_HARDWARE_TRIGGERED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1117,7 +1429,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
|
|||
|
||||
iio->dev.parent = dev;
|
||||
iio->dev.of_node = np;
|
||||
iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
||||
iio->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
platform_set_drvdata(pdev, adc);
|
||||
|
||||
|
@ -1203,10 +1515,48 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dfsdm_adc_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev);
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
__stm32_dfsdm_predisable(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dfsdm_adc_resume(struct device *dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev);
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
const struct iio_chan_spec *chan;
|
||||
struct stm32_dfsdm_channel *ch;
|
||||
int i, ret;
|
||||
|
||||
/* restore channels configuration */
|
||||
for (i = 0; i < indio_dev->num_channels; i++) {
|
||||
chan = indio_dev->channels + i;
|
||||
ch = &adc->dfsdm->ch_list[chan->channel];
|
||||
ret = stm32_dfsdm_chan_configure(adc->dfsdm, ch);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
__stm32_dfsdm_postenable(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops,
|
||||
stm32_dfsdm_adc_suspend, stm32_dfsdm_adc_resume);
|
||||
|
||||
static struct platform_driver stm32_dfsdm_adc_driver = {
|
||||
.driver = {
|
||||
.name = "stm32-dfsdm-adc",
|
||||
.of_match_table = stm32_dfsdm_adc_match,
|
||||
.pm = &stm32_dfsdm_adc_pm_ops,
|
||||
},
|
||||
.probe = stm32_dfsdm_adc_probe,
|
||||
.remove = stm32_dfsdm_adc_remove,
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -90,6 +92,36 @@ struct dfsdm_priv {
|
|||
struct clk *aclk; /* audio clock */
|
||||
};
|
||||
|
||||
static inline struct dfsdm_priv *to_stm32_dfsdm_priv(struct stm32_dfsdm *dfsdm)
|
||||
{
|
||||
return container_of(dfsdm, struct dfsdm_priv, dfsdm);
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_clk_prepare_enable(struct stm32_dfsdm *dfsdm)
|
||||
{
|
||||
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret || !priv->aclk)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->aclk);
|
||||
if (ret)
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm)
|
||||
{
|
||||
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
|
||||
|
||||
if (priv->aclk)
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_dfsdm_start_dfsdm - start global dfsdm interface.
|
||||
*
|
||||
|
@ -98,24 +130,17 @@ struct dfsdm_priv {
|
|||
*/
|
||||
int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
|
||||
{
|
||||
struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm);
|
||||
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
|
||||
struct device *dev = &priv->pdev->dev;
|
||||
unsigned int clk_div = priv->spi_clk_out_div, clk_src;
|
||||
int ret;
|
||||
|
||||
if (atomic_inc_return(&priv->n_active_ch) == 1) {
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to start clock\n");
|
||||
pm_runtime_put_noidle(dev);
|
||||
goto error_ret;
|
||||
}
|
||||
if (priv->aclk) {
|
||||
ret = clk_prepare_enable(priv->aclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to start audio clock\n");
|
||||
goto disable_clk;
|
||||
}
|
||||
}
|
||||
|
||||
/* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */
|
||||
clk_src = priv->aclk ? 1 : 0;
|
||||
|
@ -123,21 +148,21 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
|
|||
DFSDM_CHCFGR1_CKOUTSRC_MASK,
|
||||
DFSDM_CHCFGR1_CKOUTSRC(clk_src));
|
||||
if (ret < 0)
|
||||
goto disable_aclk;
|
||||
goto pm_put;
|
||||
|
||||
/* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */
|
||||
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
|
||||
DFSDM_CHCFGR1_CKOUTDIV_MASK,
|
||||
DFSDM_CHCFGR1_CKOUTDIV(clk_div));
|
||||
if (ret < 0)
|
||||
goto disable_aclk;
|
||||
goto pm_put;
|
||||
|
||||
/* Global enable of DFSDM interface */
|
||||
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
|
||||
DFSDM_CHCFGR1_DFSDMEN_MASK,
|
||||
DFSDM_CHCFGR1_DFSDMEN(1));
|
||||
if (ret < 0)
|
||||
goto disable_aclk;
|
||||
goto pm_put;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s: n_active_ch %d\n", __func__,
|
||||
|
@ -145,11 +170,8 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
|
|||
|
||||
return 0;
|
||||
|
||||
disable_aclk:
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
disable_clk:
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
pm_put:
|
||||
pm_runtime_put_sync(dev);
|
||||
error_ret:
|
||||
atomic_dec(&priv->n_active_ch);
|
||||
|
||||
|
@ -165,7 +187,7 @@ EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm);
|
|||
*/
|
||||
int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm)
|
||||
{
|
||||
struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm);
|
||||
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
|
||||
int ret;
|
||||
|
||||
if (atomic_dec_and_test(&priv->n_active_ch)) {
|
||||
|
@ -183,9 +205,7 @@ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
if (priv->aclk)
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
pm_runtime_put_sync(&priv->pdev->dev);
|
||||
}
|
||||
dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__,
|
||||
atomic_read(&priv->n_active_ch));
|
||||
|
@ -199,7 +219,7 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
|
|||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct resource *res;
|
||||
unsigned long clk_freq;
|
||||
unsigned long clk_freq, divider;
|
||||
unsigned int spi_freq, rem;
|
||||
int ret;
|
||||
|
||||
|
@ -243,13 +263,20 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1;
|
||||
if (!priv->spi_clk_out_div) {
|
||||
/* spi_clk_out_div == 0 means ckout is OFF */
|
||||
divider = div_u64_rem(clk_freq, spi_freq, &rem);
|
||||
/* Round up divider when ckout isn't precise, not to exceed spi_freq */
|
||||
if (rem)
|
||||
divider++;
|
||||
|
||||
/* programmable divider is in range of [2:256] */
|
||||
if (divider < 2 || divider > 256) {
|
||||
dev_err(&pdev->dev, "spi-max-frequency not achievable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->dfsdm.spi_master_freq = spi_freq;
|
||||
|
||||
/* SPI clock output divider is: divider = CKOUTDIV + 1 */
|
||||
priv->spi_clk_out_div = divider - 1;
|
||||
priv->dfsdm.spi_master_freq = clk_freq / (priv->spi_clk_out_div + 1);
|
||||
|
||||
if (rem) {
|
||||
dev_warn(&pdev->dev, "SPI clock not accurate\n");
|
||||
|
@ -318,14 +345,111 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, dfsdm);
|
||||
|
||||
return devm_of_platform_populate(&pdev->dev);
|
||||
ret = stm32_dfsdm_clk_prepare_enable(dfsdm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to start clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
|
||||
if (ret)
|
||||
goto pm_put;
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
pm_put:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
stm32_dfsdm_clk_disable_unprepare(dfsdm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_core_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
stm32_dfsdm_clk_disable_unprepare(dfsdm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
|
||||
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Balance devm_regmap_init_mmio_clk() clk_prepare() */
|
||||
clk_unprepare(priv->clk);
|
||||
|
||||
return pinctrl_pm_select_sleep_state(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev)
|
||||
{
|
||||
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
|
||||
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_default_state(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare(priv->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return pm_runtime_force_resume(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
|
||||
|
||||
stm32_dfsdm_clk_disable_unprepare(dfsdm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
|
||||
|
||||
return stm32_dfsdm_clk_prepare_enable(dfsdm);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend,
|
||||
stm32_dfsdm_core_resume)
|
||||
SET_RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend,
|
||||
stm32_dfsdm_core_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver stm32_dfsdm_driver = {
|
||||
.probe = stm32_dfsdm_probe,
|
||||
.remove = stm32_dfsdm_core_remove,
|
||||
.driver = {
|
||||
.name = "stm32-dfsdm",
|
||||
.of_match_table = stm32_dfsdm_of_match,
|
||||
.pm = &stm32_dfsdm_core_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -184,9 +184,6 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
|
|||
struct stmpe_adc *info = (struct stmpe_adc *)dev_id;
|
||||
u16 data;
|
||||
|
||||
if (info->channel > STMPE_TEMP_CHANNEL)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (info->channel <= STMPE_ADC_LAST_NR) {
|
||||
int int_sta;
|
||||
|
||||
|
@ -205,6 +202,8 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
|
|||
/* Read value */
|
||||
stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2,
|
||||
(u8 *) &data);
|
||||
} else {
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
info->value = (u32) be16_to_cpu(data);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -36,12 +37,15 @@
|
|||
*/
|
||||
#define TI_ADS7950_VA_MV_ACPI_DEFAULT 5000
|
||||
|
||||
#define TI_ADS7950_CR_GPIO BIT(14)
|
||||
#define TI_ADS7950_CR_MANUAL BIT(12)
|
||||
#define TI_ADS7950_CR_WRITE BIT(11)
|
||||
#define TI_ADS7950_CR_CHAN(ch) ((ch) << 7)
|
||||
#define TI_ADS7950_CR_RANGE_5V BIT(6)
|
||||
#define TI_ADS7950_CR_GPIO_DATA BIT(4)
|
||||
|
||||
#define TI_ADS7950_MAX_CHAN 16
|
||||
#define TI_ADS7950_NUM_GPIOS 4
|
||||
|
||||
#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16))
|
||||
|
||||
|
@ -49,6 +53,16 @@
|
|||
#define TI_ADS7950_EXTRACT(val, dec, bits) \
|
||||
(((val) >> (dec)) & ((1 << (bits)) - 1))
|
||||
|
||||
#define TI_ADS7950_MAN_CMD(cmd) (TI_ADS7950_CR_MANUAL | (cmd))
|
||||
#define TI_ADS7950_GPIO_CMD(cmd) (TI_ADS7950_CR_GPIO | (cmd))
|
||||
|
||||
/* Manual mode configuration */
|
||||
#define TI_ADS7950_MAN_CMD_SETTINGS(st) \
|
||||
(TI_ADS7950_MAN_CMD(TI_ADS7950_CR_WRITE | st->cmd_settings_bitmask))
|
||||
/* GPIO mode configuration */
|
||||
#define TI_ADS7950_GPIO_CMD_SETTINGS(st) \
|
||||
(TI_ADS7950_GPIO_CMD(st->gpio_cmd_settings_bitmask))
|
||||
|
||||
struct ti_ads7950_state {
|
||||
struct spi_device *spi;
|
||||
struct spi_transfer ring_xfer;
|
||||
|
@ -56,10 +70,36 @@ struct ti_ads7950_state {
|
|||
struct spi_message ring_msg;
|
||||
struct spi_message scan_single_msg;
|
||||
|
||||
/* Lock to protect the spi xfer buffers */
|
||||
struct mutex slock;
|
||||
struct gpio_chip chip;
|
||||
|
||||
struct regulator *reg;
|
||||
unsigned int vref_mv;
|
||||
|
||||
unsigned int settings;
|
||||
/*
|
||||
* Bitmask of lower 7 bits used for configuration
|
||||
* These bits only can be written when TI_ADS7950_CR_WRITE
|
||||
* is set, otherwise it retains its original state.
|
||||
* [0-3] GPIO signal
|
||||
* [4] Set following frame to return GPIO signal values
|
||||
* [5] Powers down device
|
||||
* [6] Sets Vref range1(2.5v) or range2(5v)
|
||||
*
|
||||
* Bits present on Manual/Auto1/Auto2 commands
|
||||
*/
|
||||
unsigned int cmd_settings_bitmask;
|
||||
|
||||
/*
|
||||
* Bitmask of GPIO command
|
||||
* [0-3] GPIO direction
|
||||
* [4-6] Different GPIO alarm mode configurations
|
||||
* [7] GPIO 2 as device range input
|
||||
* [8] GPIO 3 as device power down input
|
||||
* [9] Reset all registers
|
||||
* [10-11] N/A
|
||||
*/
|
||||
unsigned int gpio_cmd_settings_bitmask;
|
||||
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the
|
||||
|
@ -248,7 +288,7 @@ static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev,
|
|||
|
||||
len = 0;
|
||||
for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) {
|
||||
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings;
|
||||
cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i));
|
||||
st->tx_buf[len++] = cmd;
|
||||
}
|
||||
|
||||
|
@ -268,6 +308,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
|
|||
struct ti_ads7950_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->slock);
|
||||
ret = spi_sync(st->spi, &st->ring_msg);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -276,6 +317,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
|
|||
iio_get_time_ns(indio_dev));
|
||||
|
||||
out:
|
||||
mutex_unlock(&st->slock);
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -286,9 +328,8 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
|
|||
struct ti_ads7950_state *st = iio_priv(indio_dev);
|
||||
int ret, cmd;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings;
|
||||
mutex_lock(&st->slock);
|
||||
cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch));
|
||||
st->single_tx = cmd;
|
||||
|
||||
ret = spi_sync(st->spi, &st->scan_single_msg);
|
||||
|
@ -298,7 +339,7 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
|
|||
ret = st->single_rx;
|
||||
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->slock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -317,7 +358,7 @@ static int ti_ads7950_get_range(struct ti_ads7950_state *st)
|
|||
vref /= 1000;
|
||||
}
|
||||
|
||||
if (st->settings & TI_ADS7950_CR_RANGE_5V)
|
||||
if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V)
|
||||
vref *= 2;
|
||||
|
||||
return vref;
|
||||
|
@ -362,6 +403,132 @@ static const struct iio_info ti_ads7950_info = {
|
|||
.update_scan_mode = ti_ads7950_update_scan_mode,
|
||||
};
|
||||
|
||||
static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct ti_ads7950_state *st = gpiochip_get_data(chip);
|
||||
|
||||
mutex_lock(&st->slock);
|
||||
|
||||
if (value)
|
||||
st->cmd_settings_bitmask |= BIT(offset);
|
||||
else
|
||||
st->cmd_settings_bitmask &= ~BIT(offset);
|
||||
|
||||
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
|
||||
spi_sync(st->spi, &st->scan_single_msg);
|
||||
|
||||
mutex_unlock(&st->slock);
|
||||
}
|
||||
|
||||
static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct ti_ads7950_state *st = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->slock);
|
||||
|
||||
/* If set as output, return the output */
|
||||
if (st->gpio_cmd_settings_bitmask & BIT(offset)) {
|
||||
ret = st->cmd_settings_bitmask & BIT(offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* GPIO data bit sets SDO bits 12-15 to GPIO input */
|
||||
st->cmd_settings_bitmask |= TI_ADS7950_CR_GPIO_DATA;
|
||||
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
|
||||
ret = spi_sync(st->spi, &st->scan_single_msg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0;
|
||||
|
||||
/* Revert back to original settings */
|
||||
st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA;
|
||||
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
|
||||
ret = spi_sync(st->spi, &st->scan_single_msg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
mutex_unlock(&st->slock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_ads7950_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct ti_ads7950_state *st = gpiochip_get_data(chip);
|
||||
|
||||
/* Bitmask is inverted from GPIO framework 0=input/1=output */
|
||||
return !(st->gpio_cmd_settings_bitmask & BIT(offset));
|
||||
}
|
||||
|
||||
static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset,
|
||||
int input)
|
||||
{
|
||||
struct ti_ads7950_state *st = gpiochip_get_data(chip);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&st->slock);
|
||||
|
||||
/* Only change direction if needed */
|
||||
if (input && (st->gpio_cmd_settings_bitmask & BIT(offset)))
|
||||
st->gpio_cmd_settings_bitmask &= ~BIT(offset);
|
||||
else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset)))
|
||||
st->gpio_cmd_settings_bitmask |= BIT(offset);
|
||||
else
|
||||
goto out;
|
||||
|
||||
st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
|
||||
ret = spi_sync(st->spi, &st->scan_single_msg);
|
||||
|
||||
out:
|
||||
mutex_unlock(&st->slock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_ads7950_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
return _ti_ads7950_set_direction(chip, offset, 1);
|
||||
}
|
||||
|
||||
static int ti_ads7950_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
ti_ads7950_set(chip, offset, value);
|
||||
|
||||
return _ti_ads7950_set_direction(chip, offset, 0);
|
||||
}
|
||||
|
||||
static int ti_ads7950_init_hw(struct ti_ads7950_state *st)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&st->slock);
|
||||
|
||||
/* Settings for Manual/Auto1/Auto2 commands */
|
||||
/* Default to 5v ref */
|
||||
st->cmd_settings_bitmask = TI_ADS7950_CR_RANGE_5V;
|
||||
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
|
||||
ret = spi_sync(st->spi, &st->scan_single_msg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Settings for GPIO command */
|
||||
st->gpio_cmd_settings_bitmask = 0x0;
|
||||
st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
|
||||
ret = spi_sync(st->spi, &st->scan_single_msg);
|
||||
|
||||
out:
|
||||
mutex_unlock(&st->slock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_ads7950_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ti_ads7950_state *st;
|
||||
|
@ -386,7 +553,6 @@ static int ti_ads7950_probe(struct spi_device *spi)
|
|||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
st->spi = spi;
|
||||
st->settings = TI_ADS7950_CR_MANUAL | TI_ADS7950_CR_RANGE_5V;
|
||||
|
||||
info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
|
@ -432,16 +598,19 @@ static int ti_ads7950_probe(struct spi_device *spi)
|
|||
if (ACPI_COMPANION(&spi->dev))
|
||||
st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT;
|
||||
|
||||
mutex_init(&st->slock);
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(st->reg)) {
|
||||
dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
|
||||
return PTR_ERR(st->reg);
|
||||
ret = PTR_ERR(st->reg);
|
||||
goto error_destroy_mutex;
|
||||
}
|
||||
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
|
||||
return ret;
|
||||
goto error_destroy_mutex;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
|
@ -451,18 +620,46 @@ static int ti_ads7950_probe(struct spi_device *spi)
|
|||
goto error_disable_reg;
|
||||
}
|
||||
|
||||
ret = ti_ads7950_init_hw(st);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to init adc chip\n");
|
||||
goto error_cleanup_ring;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to register iio device\n");
|
||||
goto error_cleanup_ring;
|
||||
}
|
||||
|
||||
/* Add GPIO chip */
|
||||
st->chip.label = dev_name(&st->spi->dev);
|
||||
st->chip.parent = &st->spi->dev;
|
||||
st->chip.owner = THIS_MODULE;
|
||||
st->chip.base = -1;
|
||||
st->chip.ngpio = TI_ADS7950_NUM_GPIOS;
|
||||
st->chip.get_direction = ti_ads7950_get_direction;
|
||||
st->chip.direction_input = ti_ads7950_direction_input;
|
||||
st->chip.direction_output = ti_ads7950_direction_output;
|
||||
st->chip.get = ti_ads7950_get;
|
||||
st->chip.set = ti_ads7950_set;
|
||||
|
||||
ret = gpiochip_add_data(&st->chip, st);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to init GPIOs\n");
|
||||
goto error_iio_device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_iio_device:
|
||||
iio_device_unregister(indio_dev);
|
||||
error_cleanup_ring:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
error_disable_reg:
|
||||
regulator_disable(st->reg);
|
||||
error_destroy_mutex:
|
||||
mutex_destroy(&st->slock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -472,9 +669,11 @@ static int ti_ads7950_remove(struct spi_device *spi)
|
|||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ti_ads7950_state *st = iio_priv(indio_dev);
|
||||
|
||||
gpiochip_remove(&st->chip);
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
regulator_disable(st->reg);
|
||||
mutex_destroy(&st->slock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -523,6 +523,6 @@ static struct spi_driver ads8688_driver = {
|
|||
};
|
||||
module_spi_driver(ads8688_driver);
|
||||
|
||||
MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>");
|
||||
MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>");
|
||||
MODULE_DESCRIPTION("Texas Instruments ADS8688 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -36,7 +36,8 @@ static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data)
|
|||
static void iio_buffer_cb_release(struct iio_buffer *buffer)
|
||||
{
|
||||
struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
|
||||
kfree(cb_buff->buffer.scan_mask);
|
||||
|
||||
bitmap_free(cb_buff->buffer.scan_mask);
|
||||
kfree(cb_buff);
|
||||
}
|
||||
|
||||
|
@ -74,9 +75,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
|
|||
}
|
||||
|
||||
cb_buff->indio_dev = cb_buff->channels[0].indio_dev;
|
||||
cb_buff->buffer.scan_mask
|
||||
= kcalloc(BITS_TO_LONGS(cb_buff->indio_dev->masklength),
|
||||
sizeof(long), GFP_KERNEL);
|
||||
cb_buff->buffer.scan_mask = bitmap_zalloc(cb_buff->indio_dev->masklength,
|
||||
GFP_KERNEL);
|
||||
if (cb_buff->buffer.scan_mask == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_release_channels;
|
||||
|
@ -95,7 +95,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
|
|||
return cb_buff;
|
||||
|
||||
error_free_scan_mask:
|
||||
kfree(cb_buff->buffer.scan_mask);
|
||||
bitmap_free(cb_buff->buffer.scan_mask);
|
||||
error_release_channels:
|
||||
iio_channel_release_all(cb_buff->channels);
|
||||
error_free_cb_buff:
|
||||
|
|
|
@ -12,14 +12,14 @@ config ATLAS_PH_SENSOR
|
|||
select IIO_TRIGGERED_BUFFER
|
||||
select IRQ_WORK
|
||||
help
|
||||
Say Y here to build I2C interface support for the following
|
||||
Atlas Scientific OEM SM sensors:
|
||||
Say Y here to build I2C interface support for the following
|
||||
Atlas Scientific OEM SM sensors:
|
||||
* pH SM sensor
|
||||
* EC SM sensor
|
||||
* ORP SM sensor
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called atlas-ph-sensor.
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called atlas-ph-sensor.
|
||||
|
||||
config BME680
|
||||
tristate "Bosch Sensortec BME680 sensor driver"
|
||||
|
@ -47,8 +47,8 @@ config BME680_SPI
|
|||
config CCS811
|
||||
tristate "AMS CCS811 VOC sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here to build I2C interface support for the AMS
|
||||
CCS811 VOC (Volatile Organic Compounds) sensor
|
||||
|
|
|
@ -321,7 +321,12 @@ static int pms7003_probe(struct serdev_device *serdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id pms7003_of_match[] = {
|
||||
{ .compatible = "plantower,pms1003" },
|
||||
{ .compatible = "plantower,pms3003" },
|
||||
{ .compatible = "plantower,pms5003" },
|
||||
{ .compatible = "plantower,pms6003" },
|
||||
{ .compatible = "plantower,pms7003" },
|
||||
{ .compatible = "plantower,pmsa003" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pms7003_of_match);
|
||||
|
|
|
@ -1,22 +1,13 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors.
|
||||
*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver uses the cros-ec interface to communicate with the Chrome OS
|
||||
* EC about sensors data. Data access is presented through iio sysfs.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/common/cros_ec_sensors_core.h>
|
||||
|
@ -30,7 +21,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#define CROS_EC_SENSORS_MAX_CHANNELS 4
|
||||
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cros_ec_sensors_core - Common function for Chrome OS EC sensor driver.
|
||||
*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@ -25,7 +17,6 @@
|
|||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static char *cros_ec_loc[] = {
|
||||
|
@ -269,6 +260,17 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_read_lpc() - read acceleration data from EC shared memory.
|
||||
* @indio_dev: pointer to IIO device.
|
||||
* @scan_mask: bitmap of the sensor indices to scan.
|
||||
* @data: location to store data.
|
||||
*
|
||||
* Note: this is the safe function for reading the EC data. It guarantees
|
||||
* that the data sampled was not modified by the EC while being read.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev,
|
||||
unsigned long scan_mask, s16 *data)
|
||||
{
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
#
|
||||
|
||||
config IIO_MS_SENSORS_I2C
|
||||
tristate
|
||||
tristate
|
||||
|
|
|
@ -81,7 +81,7 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
|
|||
unsigned int len, int64_t timestamp)
|
||||
{
|
||||
__le32 time;
|
||||
int64_t calculated_time;
|
||||
int64_t calculated_time = 0;
|
||||
struct ssp_sensor_data *spd = iio_priv(indio_dev);
|
||||
|
||||
if (indio_dev->scan_bytes == 0)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/mfd/stm32-lptimer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct stm32_lptim_cnt {
|
||||
|
@ -23,6 +24,7 @@ struct stm32_lptim_cnt {
|
|||
u32 preset;
|
||||
u32 polarity;
|
||||
u32 quadrature_mode;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv)
|
||||
|
@ -50,6 +52,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
|
|||
|
||||
if (!enable) {
|
||||
clk_disable(priv->clk);
|
||||
priv->enabled = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -79,6 +82,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
|
|||
regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
|
||||
return ret;
|
||||
}
|
||||
priv->enabled = true;
|
||||
|
||||
/* Start LP timer in continuous mode */
|
||||
return regmap_update_bits(priv->regmap, STM32_LPTIM_CR,
|
||||
|
@ -361,6 +365,56 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev)
|
|||
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int stm32_lptim_cnt_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
/* Only take care of enabled counter: don't disturb other MFD child */
|
||||
if (priv->enabled) {
|
||||
ret = stm32_lptim_setup(priv, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = stm32_lptim_set_enable_state(priv, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Force enable state for later resume */
|
||||
priv->enabled = true;
|
||||
}
|
||||
|
||||
return pinctrl_pm_select_sleep_state(dev);
|
||||
}
|
||||
|
||||
static int stm32_lptim_cnt_resume(struct device *dev)
|
||||
{
|
||||
struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_default_state(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->enabled) {
|
||||
priv->enabled = false;
|
||||
ret = stm32_lptim_setup(priv, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = stm32_lptim_set_enable_state(priv, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend,
|
||||
stm32_lptim_cnt_resume);
|
||||
|
||||
static const struct of_device_id stm32_lptim_cnt_of_match[] = {
|
||||
{ .compatible = "st,stm32-lptimer-counter", },
|
||||
{},
|
||||
|
@ -372,6 +426,7 @@ static struct platform_driver stm32_lptim_cnt_driver = {
|
|||
.driver = {
|
||||
.name = "stm32-lptimer-counter",
|
||||
.of_match_table = stm32_lptim_cnt_of_match,
|
||||
.pm = &stm32_lptim_cnt_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(stm32_lptim_cnt_driver);
|
||||
|
|
|
@ -112,6 +112,8 @@ struct ad5064_state {
|
|||
bool use_internal_vref;
|
||||
|
||||
ad5064_write_func write;
|
||||
/* Lock used to maintain consistency between cached and dev state */
|
||||
struct mutex lock;
|
||||
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the
|
||||
|
@ -248,11 +250,11 @@ static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev,
|
|||
struct ad5064_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
st->pwr_down_mode[chan->channel] = mode + 1;
|
||||
|
||||
ret = ad5064_sync_powerdown_mode(st, chan);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -291,11 +293,11 @@ static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
st->pwr_down[chan->channel] = pwr_down;
|
||||
|
||||
ret = ad5064_sync_powerdown_mode(st, chan);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
|
@ -349,12 +351,12 @@ static int ad5064_write_raw(struct iio_dev *indio_dev,
|
|||
if (val >= (1 << chan->scan_type.realbits) || val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N,
|
||||
chan->address, val, chan->scan_type.shift);
|
||||
if (ret == 0)
|
||||
st->dac_cache[chan->channel] = val;
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -856,6 +858,7 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type,
|
|||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
mutex_init(&st->lock);
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
|
||||
st->chip_info = &ad5064_chip_info_tbl[type];
|
||||
|
|
|
@ -429,6 +429,6 @@ static struct i2c_driver dac5571_driver = {
|
|||
};
|
||||
module_i2c_driver(dac5571_driver);
|
||||
|
||||
MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>");
|
||||
MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>");
|
||||
MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -872,22 +872,22 @@ static int ad9523_setup(struct iio_dev *indio_dev)
|
|||
return ret;
|
||||
|
||||
ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER,
|
||||
AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_diff_m1) |
|
||||
AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_diff_m2) |
|
||||
AD_IFE(pll2_vco_diff_m1, 0,
|
||||
AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_div_m1) |
|
||||
AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_div_m2) |
|
||||
AD_IFE(pll2_vco_div_m1, 0,
|
||||
AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) |
|
||||
AD_IFE(pll2_vco_diff_m2, 0,
|
||||
AD_IFE(pll2_vco_div_m2, 0,
|
||||
AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (pdata->pll2_vco_diff_m1)
|
||||
if (pdata->pll2_vco_div_m1)
|
||||
st->vco_out_freq[AD9523_VCO1] =
|
||||
st->vco_freq / pdata->pll2_vco_diff_m1;
|
||||
st->vco_freq / pdata->pll2_vco_div_m1;
|
||||
|
||||
if (pdata->pll2_vco_diff_m2)
|
||||
if (pdata->pll2_vco_div_m2)
|
||||
st->vco_out_freq[AD9523_VCO2] =
|
||||
st->vco_freq / pdata->pll2_vco_diff_m2;
|
||||
st->vco_freq / pdata->pll2_vco_div_m2;
|
||||
|
||||
st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq;
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ struct bmg160_data {
|
|||
struct regmap *regmap;
|
||||
struct iio_trigger *dready_trig;
|
||||
struct iio_trigger *motion_trig;
|
||||
struct iio_mount_matrix orientation;
|
||||
struct mutex mutex;
|
||||
s16 buffer[8];
|
||||
u32 dps_range;
|
||||
|
@ -794,6 +795,20 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
bmg160_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct bmg160_data *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info bmg160_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmg160_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000");
|
||||
|
||||
static IIO_CONST_ATTR(in_anglvel_scale_available,
|
||||
|
@ -831,6 +846,7 @@ static const struct iio_event_spec bmg160_event = {
|
|||
.storagebits = 16, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
.ext_info = bmg160_ext_info, \
|
||||
.event_spec = &bmg160_event, \
|
||||
.num_event_specs = 1 \
|
||||
}
|
||||
|
@ -1075,6 +1091,11 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
data->irq = irq;
|
||||
data->regmap = regmap;
|
||||
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bmg160_chip_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
@ -54,10 +54,19 @@ static const struct i2c_device_id bmg160_i2c_id[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id);
|
||||
|
||||
static const struct of_device_id bmg160_of_match[] = {
|
||||
{ .compatible = "bosch,bmg160" },
|
||||
{ .compatible = "bosch,bmi055_gyro" },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, bmg160_of_match);
|
||||
|
||||
static struct i2c_driver bmg160_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "bmg160_i2c",
|
||||
.acpi_match_table = ACPI_PTR(bmg160_acpi_match),
|
||||
.of_match_table = bmg160_of_match,
|
||||
.pm = &bmg160_pm_ops,
|
||||
},
|
||||
.probe = bmg160_i2c_probe,
|
||||
|
|
|
@ -242,6 +242,20 @@ err_ret:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
itg3200_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct itg3200 *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info itg3200_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, itg3200_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
#define ITG3200_ST \
|
||||
{ .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE }
|
||||
|
||||
|
@ -255,6 +269,7 @@ err_ret:
|
|||
.address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \
|
||||
.scan_index = ITG3200_SCAN_GYRO_ ## _mod, \
|
||||
.scan_type = ITG3200_ST, \
|
||||
.ext_info = itg3200_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec itg3200_channels[] = {
|
||||
|
@ -297,6 +312,11 @@ static int itg3200_probe(struct i2c_client *client,
|
|||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
|
||||
&st->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
st->i2c = client;
|
||||
|
||||
|
|
|
@ -1149,8 +1149,7 @@ int mpu3050_common_probe(struct device *dev,
|
|||
mpu3050->divisor = 99;
|
||||
|
||||
/* Read the mounting matrix, if present */
|
||||
ret = of_iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&mpu3050->orientation);
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix", &mpu3050->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
menu "Humidity sensors"
|
||||
|
||||
config AM2315
|
||||
tristate "Aosong AM2315 relative humidity and temperature sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for the Aosong AM2315
|
||||
relative humidity and ambient temperature sensor.
|
||||
tristate "Aosong AM2315 relative humidity and temperature sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for the Aosong AM2315
|
||||
relative humidity and ambient temperature sensor.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called am2315.
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called am2315.
|
||||
|
||||
config DHT11
|
||||
tristate "DHT11 (and compatible sensors) driver"
|
||||
|
@ -78,7 +78,7 @@ config HTS221_SPI
|
|||
config HTU21
|
||||
tristate "Measurement Specialties HTU21 humidity & temperature sensor"
|
||||
depends on I2C
|
||||
select IIO_MS_SENSORS_I2C
|
||||
select IIO_MS_SENSORS_I2C
|
||||
help
|
||||
If you say yes here you get support for the Measurement Specialties
|
||||
HTU21 humidity and temperature sensor.
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
adis16400-y := adis16400_core.o
|
||||
adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o
|
||||
obj-$(CONFIG_ADIS16400) += adis16400.o
|
||||
obj-$(CONFIG_ADIS16480) += adis16480.o
|
||||
|
||||
|
|
|
@ -31,8 +31,183 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/imu/adis.h>
|
||||
|
||||
#include "adis16400.h"
|
||||
#define ADIS16400_STARTUP_DELAY 290 /* ms */
|
||||
#define ADIS16400_MTEST_DELAY 90 /* ms */
|
||||
|
||||
#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */
|
||||
#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */
|
||||
#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */
|
||||
#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */
|
||||
#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */
|
||||
#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */
|
||||
#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */
|
||||
#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */
|
||||
#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */
|
||||
#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */
|
||||
#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */
|
||||
#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */
|
||||
#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */
|
||||
|
||||
#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */
|
||||
#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */
|
||||
#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */
|
||||
|
||||
#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */
|
||||
#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */
|
||||
#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */
|
||||
|
||||
#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */
|
||||
#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */
|
||||
|
||||
/* Calibration parameters */
|
||||
#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
|
||||
#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */
|
||||
#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */
|
||||
#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */
|
||||
#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */
|
||||
#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */
|
||||
#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */
|
||||
#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */
|
||||
#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */
|
||||
#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */
|
||||
#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */
|
||||
#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */
|
||||
|
||||
#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */
|
||||
#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */
|
||||
#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */
|
||||
#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */
|
||||
#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */
|
||||
#define ADIS16400_DIAG_STAT 0x3C /* System status */
|
||||
|
||||
/* Alarm functions */
|
||||
#define ADIS16400_GLOB_CMD 0x3E /* System command */
|
||||
#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */
|
||||
#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */
|
||||
#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */
|
||||
#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */
|
||||
#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */
|
||||
#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */
|
||||
|
||||
#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */
|
||||
#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */
|
||||
#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */
|
||||
#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */
|
||||
|
||||
#define ADIS16400_ERROR_ACTIVE (1<<14)
|
||||
#define ADIS16400_NEW_DATA (1<<14)
|
||||
|
||||
/* MSC_CTRL */
|
||||
#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11)
|
||||
#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10)
|
||||
#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9)
|
||||
#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8)
|
||||
#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7)
|
||||
#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6)
|
||||
#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2)
|
||||
#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
|
||||
#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
|
||||
|
||||
/* SMPL_PRD */
|
||||
#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7)
|
||||
#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F
|
||||
|
||||
/* DIAG_STAT */
|
||||
#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15
|
||||
#define ADIS16400_DIAG_STAT_YACCL_FAIL 14
|
||||
#define ADIS16400_DIAG_STAT_XACCL_FAIL 13
|
||||
#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12
|
||||
#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11
|
||||
#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10
|
||||
#define ADIS16400_DIAG_STAT_ALARM2 9
|
||||
#define ADIS16400_DIAG_STAT_ALARM1 8
|
||||
#define ADIS16400_DIAG_STAT_FLASH_CHK 6
|
||||
#define ADIS16400_DIAG_STAT_SELF_TEST 5
|
||||
#define ADIS16400_DIAG_STAT_OVERFLOW 4
|
||||
#define ADIS16400_DIAG_STAT_SPI_FAIL 3
|
||||
#define ADIS16400_DIAG_STAT_FLASH_UPT 2
|
||||
#define ADIS16400_DIAG_STAT_POWER_HIGH 1
|
||||
#define ADIS16400_DIAG_STAT_POWER_LOW 0
|
||||
|
||||
/* GLOB_CMD */
|
||||
#define ADIS16400_GLOB_CMD_SW_RESET (1<<7)
|
||||
#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4)
|
||||
#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3)
|
||||
#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2)
|
||||
#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1)
|
||||
#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0)
|
||||
|
||||
/* SLP_CNT */
|
||||
#define ADIS16400_SLP_CNT_POWER_OFF (1<<8)
|
||||
|
||||
#define ADIS16334_RATE_DIV_SHIFT 8
|
||||
#define ADIS16334_RATE_INT_CLK BIT(0)
|
||||
|
||||
#define ADIS16400_SPI_SLOW (u32)(300 * 1000)
|
||||
#define ADIS16400_SPI_BURST (u32)(1000 * 1000)
|
||||
#define ADIS16400_SPI_FAST (u32)(2000 * 1000)
|
||||
|
||||
#define ADIS16400_HAS_PROD_ID BIT(0)
|
||||
#define ADIS16400_NO_BURST BIT(1)
|
||||
#define ADIS16400_HAS_SLOW_MODE BIT(2)
|
||||
#define ADIS16400_HAS_SERIAL_NUMBER BIT(3)
|
||||
#define ADIS16400_BURST_DIAG_STAT BIT(4)
|
||||
|
||||
struct adis16400_state;
|
||||
|
||||
struct adis16400_chip_info {
|
||||
const struct iio_chan_spec *channels;
|
||||
const int num_channels;
|
||||
const long flags;
|
||||
unsigned int gyro_scale_micro;
|
||||
unsigned int accel_scale_micro;
|
||||
int temp_scale_nano;
|
||||
int temp_offset;
|
||||
int (*set_freq)(struct adis16400_state *st, unsigned int freq);
|
||||
int (*get_freq)(struct adis16400_state *st);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adis16400_state - device instance specific data
|
||||
* @variant: chip variant info
|
||||
* @filt_int: integer part of requested filter frequency
|
||||
* @adis: adis device
|
||||
**/
|
||||
struct adis16400_state {
|
||||
struct adis16400_chip_info *variant;
|
||||
int filt_int;
|
||||
|
||||
struct adis adis;
|
||||
unsigned long avail_scan_mask[2];
|
||||
};
|
||||
|
||||
/* At the moment triggers are only used for ring buffer
|
||||
* filling. This may change!
|
||||
*/
|
||||
|
||||
enum {
|
||||
ADIS16400_SCAN_SUPPLY,
|
||||
ADIS16400_SCAN_GYRO_X,
|
||||
ADIS16400_SCAN_GYRO_Y,
|
||||
ADIS16400_SCAN_GYRO_Z,
|
||||
ADIS16400_SCAN_ACC_X,
|
||||
ADIS16400_SCAN_ACC_Y,
|
||||
ADIS16400_SCAN_ACC_Z,
|
||||
ADIS16400_SCAN_MAGN_X,
|
||||
ADIS16400_SCAN_MAGN_Y,
|
||||
ADIS16400_SCAN_MAGN_Z,
|
||||
ADIS16400_SCAN_BARO,
|
||||
ADIS16350_SCAN_TEMP_X,
|
||||
ADIS16350_SCAN_TEMP_Y,
|
||||
ADIS16350_SCAN_TEMP_Z,
|
||||
ADIS16300_SCAN_INCLI_X,
|
||||
ADIS16300_SCAN_INCLI_Y,
|
||||
ADIS16400_SCAN_ADC,
|
||||
ADIS16400_SCAN_TIMESTAMP,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
|
@ -145,6 +320,11 @@ enum adis16400_chip_variant {
|
|||
ADIS16448,
|
||||
};
|
||||
|
||||
static struct adis_burst adis16400_burst = {
|
||||
.en = true,
|
||||
.reg_cmd = ADIS16400_GLOB_CMD,
|
||||
};
|
||||
|
||||
static int adis16334_get_freq(struct adis16400_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
@ -465,6 +645,51 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IIO_BUFFER)
|
||||
static irqreturn_t adis16400_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct adis16400_state *st = iio_priv(indio_dev);
|
||||
struct adis *adis = &st->adis;
|
||||
u32 old_speed_hz = st->adis.spi->max_speed_hz;
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
if (!adis->buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!(st->variant->flags & ADIS16400_NO_BURST) &&
|
||||
st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
|
||||
st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
|
||||
spi_setup(st->adis.spi);
|
||||
}
|
||||
|
||||
ret = spi_sync(adis->spi, &adis->msg);
|
||||
if (ret)
|
||||
dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
|
||||
|
||||
if (!(st->variant->flags & ADIS16400_NO_BURST)) {
|
||||
st->adis.spi->max_speed_hz = old_speed_hz;
|
||||
spi_setup(st->adis.spi);
|
||||
}
|
||||
|
||||
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
|
||||
buffer = adis->buffer + sizeof(u16);
|
||||
else
|
||||
buffer = adis->buffer;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
pf->timestamp);
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
#else
|
||||
#define adis16400_trigger_handler NULL
|
||||
#endif /* IS_ENABLED(CONFIG_IIO_BUFFER) */
|
||||
|
||||
#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
|
@ -835,7 +1060,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
|
|||
static const struct iio_info adis16400_info = {
|
||||
.read_raw = &adis16400_read_raw,
|
||||
.write_raw = &adis16400_write_raw,
|
||||
.update_scan_mode = adis16400_update_scan_mode,
|
||||
.update_scan_mode = adis_update_scan_mode,
|
||||
.debugfs_reg_access = adis_debugfs_reg_access,
|
||||
};
|
||||
|
||||
|
@ -926,6 +1151,9 @@ static int adis16400_probe(struct spi_device *spi)
|
|||
if (!(st->variant->flags & ADIS16400_NO_BURST)) {
|
||||
adis16400_setup_chan_mask(st);
|
||||
indio_dev->available_scan_masks = st->avail_scan_mask;
|
||||
st->adis.burst = &adis16400_burst;
|
||||
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
|
||||
st->adis.burst->extra_len = sizeof(u16);
|
||||
}
|
||||
|
||||
ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
|
|
@ -1,215 +0,0 @@
|
|||
/*
|
||||
* adis16400.h support Analog Devices ADIS16400
|
||||
* 3d 18g accelerometers,
|
||||
* 3d gyroscopes,
|
||||
* 3d 2.5gauss magnetometers via SPI
|
||||
*
|
||||
* Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
|
||||
* Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
|
||||
*
|
||||
* Loosely based upon lis3l02dq.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef SPI_ADIS16400_H_
|
||||
#define SPI_ADIS16400_H_
|
||||
|
||||
#include <linux/iio/imu/adis.h>
|
||||
|
||||
#define ADIS16400_STARTUP_DELAY 290 /* ms */
|
||||
#define ADIS16400_MTEST_DELAY 90 /* ms */
|
||||
|
||||
#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */
|
||||
#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */
|
||||
#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */
|
||||
#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */
|
||||
#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */
|
||||
#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */
|
||||
#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */
|
||||
#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */
|
||||
#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */
|
||||
#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */
|
||||
#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */
|
||||
#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */
|
||||
#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */
|
||||
|
||||
#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */
|
||||
#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */
|
||||
#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */
|
||||
|
||||
#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */
|
||||
#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */
|
||||
#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */
|
||||
|
||||
#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */
|
||||
#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */
|
||||
|
||||
/* Calibration parameters */
|
||||
#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
|
||||
#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */
|
||||
#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */
|
||||
#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */
|
||||
#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */
|
||||
#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */
|
||||
#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */
|
||||
#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */
|
||||
#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */
|
||||
#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */
|
||||
#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */
|
||||
#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */
|
||||
|
||||
#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */
|
||||
#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */
|
||||
#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */
|
||||
#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */
|
||||
#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */
|
||||
#define ADIS16400_DIAG_STAT 0x3C /* System status */
|
||||
|
||||
/* Alarm functions */
|
||||
#define ADIS16400_GLOB_CMD 0x3E /* System command */
|
||||
#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */
|
||||
#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */
|
||||
#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */
|
||||
#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */
|
||||
#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */
|
||||
#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */
|
||||
|
||||
#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */
|
||||
#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */
|
||||
#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */
|
||||
#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */
|
||||
|
||||
#define ADIS16400_ERROR_ACTIVE (1<<14)
|
||||
#define ADIS16400_NEW_DATA (1<<14)
|
||||
|
||||
/* MSC_CTRL */
|
||||
#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11)
|
||||
#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10)
|
||||
#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9)
|
||||
#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8)
|
||||
#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7)
|
||||
#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6)
|
||||
#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2)
|
||||
#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
|
||||
#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
|
||||
|
||||
/* SMPL_PRD */
|
||||
#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7)
|
||||
#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F
|
||||
|
||||
/* DIAG_STAT */
|
||||
#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15
|
||||
#define ADIS16400_DIAG_STAT_YACCL_FAIL 14
|
||||
#define ADIS16400_DIAG_STAT_XACCL_FAIL 13
|
||||
#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12
|
||||
#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11
|
||||
#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10
|
||||
#define ADIS16400_DIAG_STAT_ALARM2 9
|
||||
#define ADIS16400_DIAG_STAT_ALARM1 8
|
||||
#define ADIS16400_DIAG_STAT_FLASH_CHK 6
|
||||
#define ADIS16400_DIAG_STAT_SELF_TEST 5
|
||||
#define ADIS16400_DIAG_STAT_OVERFLOW 4
|
||||
#define ADIS16400_DIAG_STAT_SPI_FAIL 3
|
||||
#define ADIS16400_DIAG_STAT_FLASH_UPT 2
|
||||
#define ADIS16400_DIAG_STAT_POWER_HIGH 1
|
||||
#define ADIS16400_DIAG_STAT_POWER_LOW 0
|
||||
|
||||
/* GLOB_CMD */
|
||||
#define ADIS16400_GLOB_CMD_SW_RESET (1<<7)
|
||||
#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4)
|
||||
#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3)
|
||||
#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2)
|
||||
#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1)
|
||||
#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0)
|
||||
|
||||
/* SLP_CNT */
|
||||
#define ADIS16400_SLP_CNT_POWER_OFF (1<<8)
|
||||
|
||||
#define ADIS16334_RATE_DIV_SHIFT 8
|
||||
#define ADIS16334_RATE_INT_CLK BIT(0)
|
||||
|
||||
#define ADIS16400_SPI_SLOW (u32)(300 * 1000)
|
||||
#define ADIS16400_SPI_BURST (u32)(1000 * 1000)
|
||||
#define ADIS16400_SPI_FAST (u32)(2000 * 1000)
|
||||
|
||||
#define ADIS16400_HAS_PROD_ID BIT(0)
|
||||
#define ADIS16400_NO_BURST BIT(1)
|
||||
#define ADIS16400_HAS_SLOW_MODE BIT(2)
|
||||
#define ADIS16400_HAS_SERIAL_NUMBER BIT(3)
|
||||
#define ADIS16400_BURST_DIAG_STAT BIT(4)
|
||||
|
||||
struct adis16400_state;
|
||||
|
||||
struct adis16400_chip_info {
|
||||
const struct iio_chan_spec *channels;
|
||||
const int num_channels;
|
||||
const long flags;
|
||||
unsigned int gyro_scale_micro;
|
||||
unsigned int accel_scale_micro;
|
||||
int temp_scale_nano;
|
||||
int temp_offset;
|
||||
int (*set_freq)(struct adis16400_state *st, unsigned int freq);
|
||||
int (*get_freq)(struct adis16400_state *st);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adis16400_state - device instance specific data
|
||||
* @variant: chip variant info
|
||||
* @filt_int: integer part of requested filter frequency
|
||||
* @adis: adis device
|
||||
**/
|
||||
struct adis16400_state {
|
||||
struct adis16400_chip_info *variant;
|
||||
int filt_int;
|
||||
|
||||
struct adis adis;
|
||||
unsigned long avail_scan_mask[2];
|
||||
};
|
||||
|
||||
/* At the moment triggers are only used for ring buffer
|
||||
* filling. This may change!
|
||||
*/
|
||||
|
||||
enum {
|
||||
ADIS16400_SCAN_SUPPLY,
|
||||
ADIS16400_SCAN_GYRO_X,
|
||||
ADIS16400_SCAN_GYRO_Y,
|
||||
ADIS16400_SCAN_GYRO_Z,
|
||||
ADIS16400_SCAN_ACC_X,
|
||||
ADIS16400_SCAN_ACC_Y,
|
||||
ADIS16400_SCAN_ACC_Z,
|
||||
ADIS16400_SCAN_MAGN_X,
|
||||
ADIS16400_SCAN_MAGN_Y,
|
||||
ADIS16400_SCAN_MAGN_Z,
|
||||
ADIS16400_SCAN_BARO,
|
||||
ADIS16350_SCAN_TEMP_X,
|
||||
ADIS16350_SCAN_TEMP_Y,
|
||||
ADIS16350_SCAN_TEMP_Z,
|
||||
ADIS16300_SCAN_INCLI_X,
|
||||
ADIS16300_SCAN_INCLI_Y,
|
||||
ADIS16400_SCAN_ADC,
|
||||
ADIS16400_SCAN_TIMESTAMP,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IIO_BUFFER
|
||||
|
||||
ssize_t adis16400_read_data_from_ring(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf);
|
||||
|
||||
|
||||
int adis16400_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask);
|
||||
irqreturn_t adis16400_trigger_handler(int irq, void *p);
|
||||
|
||||
#else /* CONFIG_IIO_BUFFER */
|
||||
|
||||
#define adis16400_update_scan_mode NULL
|
||||
#define adis16400_trigger_handler NULL
|
||||
|
||||
#endif /* CONFIG_IIO_BUFFER */
|
||||
|
||||
#endif /* SPI_ADIS16400_H_ */
|
|
@ -1,101 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#include "adis16400.h"
|
||||
|
||||
int adis16400_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct adis16400_state *st = iio_priv(indio_dev);
|
||||
struct adis *adis = &st->adis;
|
||||
unsigned int burst_length;
|
||||
u8 *tx;
|
||||
|
||||
if (st->variant->flags & ADIS16400_NO_BURST)
|
||||
return adis_update_scan_mode(indio_dev, scan_mask);
|
||||
|
||||
kfree(adis->xfer);
|
||||
kfree(adis->buffer);
|
||||
|
||||
/* All but the timestamp channel */
|
||||
burst_length = (indio_dev->num_channels - 1) * sizeof(u16);
|
||||
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
|
||||
burst_length += sizeof(u16);
|
||||
|
||||
adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
|
||||
if (!adis->xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL);
|
||||
if (!adis->buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
tx = adis->buffer + burst_length;
|
||||
tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
|
||||
tx[1] = 0;
|
||||
|
||||
adis->xfer[0].tx_buf = tx;
|
||||
adis->xfer[0].bits_per_word = 8;
|
||||
adis->xfer[0].len = 2;
|
||||
adis->xfer[1].rx_buf = adis->buffer;
|
||||
adis->xfer[1].bits_per_word = 8;
|
||||
adis->xfer[1].len = burst_length;
|
||||
|
||||
spi_message_init(&adis->msg);
|
||||
spi_message_add_tail(&adis->xfer[0], &adis->msg);
|
||||
spi_message_add_tail(&adis->xfer[1], &adis->msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
irqreturn_t adis16400_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct adis16400_state *st = iio_priv(indio_dev);
|
||||
struct adis *adis = &st->adis;
|
||||
u32 old_speed_hz = st->adis.spi->max_speed_hz;
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
if (!adis->buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!(st->variant->flags & ADIS16400_NO_BURST) &&
|
||||
st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
|
||||
st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
|
||||
spi_setup(st->adis.spi);
|
||||
}
|
||||
|
||||
ret = spi_sync(adis->spi, &adis->msg);
|
||||
if (ret)
|
||||
dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
|
||||
|
||||
if (!(st->variant->flags & ADIS16400_NO_BURST)) {
|
||||
st->adis.spi->max_speed_hz = old_speed_hz;
|
||||
spi_setup(st->adis.spi);
|
||||
}
|
||||
|
||||
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
|
||||
buffer = adis->buffer + sizeof(u16);
|
||||
else
|
||||
buffer = adis->buffer;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
pf->timestamp);
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
|
@ -9,6 +9,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -97,6 +100,12 @@
|
|||
#define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A)
|
||||
#define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C)
|
||||
|
||||
/*
|
||||
* External clock scaling in PPS mode.
|
||||
* Available only for ADIS1649x devices
|
||||
*/
|
||||
#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10)
|
||||
|
||||
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
|
||||
|
||||
/* Each filter coefficent bank spans two pages */
|
||||
|
@ -107,6 +116,20 @@
|
|||
#define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x))
|
||||
#define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x))
|
||||
|
||||
/* ADIS16480_REG_FNCTIO_CTRL */
|
||||
#define ADIS16480_DRDY_SEL_MSK GENMASK(1, 0)
|
||||
#define ADIS16480_DRDY_SEL(x) FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x)
|
||||
#define ADIS16480_DRDY_POL_MSK BIT(2)
|
||||
#define ADIS16480_DRDY_POL(x) FIELD_PREP(ADIS16480_DRDY_POL_MSK, x)
|
||||
#define ADIS16480_DRDY_EN_MSK BIT(3)
|
||||
#define ADIS16480_DRDY_EN(x) FIELD_PREP(ADIS16480_DRDY_EN_MSK, x)
|
||||
#define ADIS16480_SYNC_SEL_MSK GENMASK(5, 4)
|
||||
#define ADIS16480_SYNC_SEL(x) FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x)
|
||||
#define ADIS16480_SYNC_EN_MSK BIT(7)
|
||||
#define ADIS16480_SYNC_EN(x) FIELD_PREP(ADIS16480_SYNC_EN_MSK, x)
|
||||
#define ADIS16480_SYNC_MODE_MSK BIT(8)
|
||||
#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x)
|
||||
|
||||
struct adis16480_chip_info {
|
||||
unsigned int num_channels;
|
||||
const struct iio_chan_spec *channels;
|
||||
|
@ -114,12 +137,40 @@ struct adis16480_chip_info {
|
|||
unsigned int gyro_max_scale;
|
||||
unsigned int accel_max_val;
|
||||
unsigned int accel_max_scale;
|
||||
unsigned int temp_scale;
|
||||
unsigned int int_clk;
|
||||
unsigned int max_dec_rate;
|
||||
const unsigned int *filter_freqs;
|
||||
bool has_pps_clk_mode;
|
||||
};
|
||||
|
||||
enum adis16480_int_pin {
|
||||
ADIS16480_PIN_DIO1,
|
||||
ADIS16480_PIN_DIO2,
|
||||
ADIS16480_PIN_DIO3,
|
||||
ADIS16480_PIN_DIO4
|
||||
};
|
||||
|
||||
enum adis16480_clock_mode {
|
||||
ADIS16480_CLK_SYNC,
|
||||
ADIS16480_CLK_PPS,
|
||||
ADIS16480_CLK_INT
|
||||
};
|
||||
|
||||
struct adis16480 {
|
||||
const struct adis16480_chip_info *chip_info;
|
||||
|
||||
struct adis adis;
|
||||
struct clk *ext_clk;
|
||||
enum adis16480_clock_mode clk_mode;
|
||||
unsigned int clk_freq;
|
||||
};
|
||||
|
||||
static const char * const adis16480_int_pin_names[4] = {
|
||||
[ADIS16480_PIN_DIO1] = "DIO1",
|
||||
[ADIS16480_PIN_DIO2] = "DIO2",
|
||||
[ADIS16480_PIN_DIO3] = "DIO3",
|
||||
[ADIS16480_PIN_DIO4] = "DIO4",
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -268,20 +319,34 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev)
|
|||
static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
|
||||
{
|
||||
struct adis16480 *st = iio_priv(indio_dev);
|
||||
unsigned int t;
|
||||
unsigned int t, reg;
|
||||
|
||||
t = val * 1000 + val2 / 1000;
|
||||
if (t <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
t = 2460000 / t;
|
||||
if (t > 2048)
|
||||
t = 2048;
|
||||
/*
|
||||
* When using PPS mode, the rate of data collection is equal to the
|
||||
* product of the external clock frequency and the scale factor in the
|
||||
* SYNC_SCALE register.
|
||||
* When using sync mode, or internal clock, the output data rate is
|
||||
* equal with the clock frequency divided by DEC_RATE + 1.
|
||||
*/
|
||||
if (st->clk_mode == ADIS16480_CLK_PPS) {
|
||||
t = t / st->clk_freq;
|
||||
reg = ADIS16495_REG_SYNC_SCALE;
|
||||
} else {
|
||||
t = st->clk_freq / t;
|
||||
reg = ADIS16480_REG_DEC_RATE;
|
||||
}
|
||||
|
||||
if (t != 0)
|
||||
if (t > st->chip_info->max_dec_rate)
|
||||
t = st->chip_info->max_dec_rate;
|
||||
|
||||
if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS))
|
||||
t--;
|
||||
|
||||
return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
|
||||
return adis_write_reg_16(&st->adis, reg, t);
|
||||
}
|
||||
|
||||
static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
|
||||
|
@ -290,12 +355,29 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
|
|||
uint16_t t;
|
||||
int ret;
|
||||
unsigned freq;
|
||||
unsigned int reg;
|
||||
|
||||
ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
|
||||
if (st->clk_mode == ADIS16480_CLK_PPS)
|
||||
reg = ADIS16495_REG_SYNC_SCALE;
|
||||
else
|
||||
reg = ADIS16480_REG_DEC_RATE;
|
||||
|
||||
ret = adis_read_reg_16(&st->adis, reg, &t);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
freq = 2460000 / (t + 1);
|
||||
/*
|
||||
* When using PPS mode, the rate of data collection is equal to the
|
||||
* product of the external clock frequency and the scale factor in the
|
||||
* SYNC_SCALE register.
|
||||
* When using sync mode, or internal clock, the output data rate is
|
||||
* equal with the clock frequency divided by DEC_RATE + 1.
|
||||
*/
|
||||
if (st->clk_mode == ADIS16480_CLK_PPS)
|
||||
freq = st->clk_freq * t;
|
||||
else
|
||||
freq = st->clk_freq / (t + 1);
|
||||
|
||||
*val = freq / 1000;
|
||||
*val2 = (freq % 1000) * 1000;
|
||||
|
||||
|
@ -425,6 +507,13 @@ static const unsigned int adis16480_def_filter_freqs[] = {
|
|||
63,
|
||||
};
|
||||
|
||||
static const unsigned int adis16495_def_filter_freqs[] = {
|
||||
300,
|
||||
100,
|
||||
300,
|
||||
100,
|
||||
};
|
||||
|
||||
static const unsigned int ad16480_filter_data[][2] = {
|
||||
[ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 },
|
||||
[ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 },
|
||||
|
@ -456,7 +545,7 @@ static int adis16480_get_filter_freq(struct iio_dev *indio_dev,
|
|||
if (!(val & enable_mask))
|
||||
*freq = 0;
|
||||
else
|
||||
*freq = adis16480_def_filter_freqs[(val >> offset) & 0x3];
|
||||
*freq = st->chip_info->filter_freqs[(val >> offset) & 0x3];
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
@ -483,10 +572,10 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
|
|||
val &= ~enable_mask;
|
||||
} else {
|
||||
best_freq = 0;
|
||||
best_diff = 310;
|
||||
best_diff = st->chip_info->filter_freqs[0];
|
||||
for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) {
|
||||
if (adis16480_def_filter_freqs[i] >= freq) {
|
||||
diff = adis16480_def_filter_freqs[i] - freq;
|
||||
if (st->chip_info->filter_freqs[i] >= freq) {
|
||||
diff = st->chip_info->filter_freqs[i] - freq;
|
||||
if (diff < best_diff) {
|
||||
best_diff = diff;
|
||||
best_freq = i;
|
||||
|
@ -506,6 +595,7 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
|
|||
const struct iio_chan_spec *chan, int *val, int *val2, long info)
|
||||
{
|
||||
struct adis16480 *st = iio_priv(indio_dev);
|
||||
unsigned int temp;
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
|
@ -525,8 +615,13 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
|
|||
*val2 = 100; /* 0.0001 gauss */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_TEMP:
|
||||
*val = 5;
|
||||
*val2 = 650000; /* 5.65 milli degree Celsius */
|
||||
/*
|
||||
* +85 degrees Celsius = temp_max_scale
|
||||
* +25 degrees Celsius = 0
|
||||
* LSB, 25 degrees Celsius = 60 / temp_max_scale
|
||||
*/
|
||||
*val = st->chip_info->temp_scale / 1000;
|
||||
*val2 = (st->chip_info->temp_scale % 1000) * 1000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_PRESSURE:
|
||||
*val = 0;
|
||||
|
@ -537,7 +632,8 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
/* Only the temperature channel has a offset */
|
||||
*val = 4425; /* 25 degree Celsius = 0x0000 */
|
||||
temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */
|
||||
*val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
return adis16480_get_calibbias(indio_dev, chan, val);
|
||||
|
@ -678,6 +774,12 @@ enum adis16480_variant {
|
|||
ADIS16480,
|
||||
ADIS16485,
|
||||
ADIS16488,
|
||||
ADIS16495_1,
|
||||
ADIS16495_2,
|
||||
ADIS16495_3,
|
||||
ADIS16497_1,
|
||||
ADIS16497_2,
|
||||
ADIS16497_3,
|
||||
};
|
||||
|
||||
static const struct adis16480_chip_info adis16480_chip_info[] = {
|
||||
|
@ -693,6 +795,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
|
|||
.gyro_max_scale = 300,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(21973),
|
||||
.accel_max_scale = 18,
|
||||
.temp_scale = 5650, /* 5.65 milli degree Celsius */
|
||||
.int_clk = 2460000,
|
||||
.max_dec_rate = 2048,
|
||||
.filter_freqs = adis16480_def_filter_freqs,
|
||||
},
|
||||
[ADIS16480] = {
|
||||
.channels = adis16480_channels,
|
||||
|
@ -701,6 +807,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
|
|||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(12500),
|
||||
.accel_max_scale = 10,
|
||||
.temp_scale = 5650, /* 5.65 milli degree Celsius */
|
||||
.int_clk = 2460000,
|
||||
.max_dec_rate = 2048,
|
||||
.filter_freqs = adis16480_def_filter_freqs,
|
||||
},
|
||||
[ADIS16485] = {
|
||||
.channels = adis16485_channels,
|
||||
|
@ -709,6 +819,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
|
|||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(20000),
|
||||
.accel_max_scale = 5,
|
||||
.temp_scale = 5650, /* 5.65 milli degree Celsius */
|
||||
.int_clk = 2460000,
|
||||
.max_dec_rate = 2048,
|
||||
.filter_freqs = adis16480_def_filter_freqs,
|
||||
},
|
||||
[ADIS16488] = {
|
||||
.channels = adis16480_channels,
|
||||
|
@ -717,6 +831,88 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
|
|||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(22500),
|
||||
.accel_max_scale = 18,
|
||||
.temp_scale = 5650, /* 5.65 milli degree Celsius */
|
||||
.int_clk = 2460000,
|
||||
.max_dec_rate = 2048,
|
||||
.filter_freqs = adis16480_def_filter_freqs,
|
||||
},
|
||||
[ADIS16495_1] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
|
||||
.gyro_max_scale = 125,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(32000),
|
||||
.accel_max_scale = 8,
|
||||
.temp_scale = 12500, /* 12.5 milli degree Celsius */
|
||||
.int_clk = 4250000,
|
||||
.max_dec_rate = 4250,
|
||||
.filter_freqs = adis16495_def_filter_freqs,
|
||||
.has_pps_clk_mode = true,
|
||||
},
|
||||
[ADIS16495_2] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(18000),
|
||||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(32000),
|
||||
.accel_max_scale = 8,
|
||||
.temp_scale = 12500, /* 12.5 milli degree Celsius */
|
||||
.int_clk = 4250000,
|
||||
.max_dec_rate = 4250,
|
||||
.filter_freqs = adis16495_def_filter_freqs,
|
||||
.has_pps_clk_mode = true,
|
||||
},
|
||||
[ADIS16495_3] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
|
||||
.gyro_max_scale = 2000,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(32000),
|
||||
.accel_max_scale = 8,
|
||||
.temp_scale = 12500, /* 12.5 milli degree Celsius */
|
||||
.int_clk = 4250000,
|
||||
.max_dec_rate = 4250,
|
||||
.filter_freqs = adis16495_def_filter_freqs,
|
||||
.has_pps_clk_mode = true,
|
||||
},
|
||||
[ADIS16497_1] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
|
||||
.gyro_max_scale = 125,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(32000),
|
||||
.accel_max_scale = 40,
|
||||
.temp_scale = 12500, /* 12.5 milli degree Celsius */
|
||||
.int_clk = 4250000,
|
||||
.max_dec_rate = 4250,
|
||||
.filter_freqs = adis16495_def_filter_freqs,
|
||||
.has_pps_clk_mode = true,
|
||||
},
|
||||
[ADIS16497_2] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(18000),
|
||||
.gyro_max_scale = 450,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(32000),
|
||||
.accel_max_scale = 40,
|
||||
.temp_scale = 12500, /* 12.5 milli degree Celsius */
|
||||
.int_clk = 4250000,
|
||||
.max_dec_rate = 4250,
|
||||
.filter_freqs = adis16495_def_filter_freqs,
|
||||
.has_pps_clk_mode = true,
|
||||
},
|
||||
[ADIS16497_3] = {
|
||||
.channels = adis16485_channels,
|
||||
.num_channels = ARRAY_SIZE(adis16485_channels),
|
||||
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
|
||||
.gyro_max_scale = 2000,
|
||||
.accel_max_val = IIO_M_S_2_TO_G(32000),
|
||||
.accel_max_scale = 40,
|
||||
.temp_scale = 12500, /* 12.5 milli degree Celsius */
|
||||
.int_clk = 4250000,
|
||||
.max_dec_rate = 4250,
|
||||
.filter_freqs = adis16495_def_filter_freqs,
|
||||
.has_pps_clk_mode = true,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -741,8 +937,17 @@ static int adis16480_stop_device(struct iio_dev *indio_dev)
|
|||
|
||||
static int adis16480_enable_irq(struct adis *adis, bool enable)
|
||||
{
|
||||
return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL,
|
||||
enable ? BIT(3) : 0);
|
||||
uint16_t val;
|
||||
int ret;
|
||||
|
||||
ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val &= ~ADIS16480_DRDY_EN_MSK;
|
||||
val |= ADIS16480_DRDY_EN(enable);
|
||||
|
||||
return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
|
||||
}
|
||||
|
||||
static int adis16480_initial_setup(struct iio_dev *indio_dev)
|
||||
|
@ -826,6 +1031,156 @@ static const struct adis_data adis16480_data = {
|
|||
.enable_irq = adis16480_enable_irq,
|
||||
};
|
||||
|
||||
static int adis16480_config_irq_pin(struct device_node *of_node,
|
||||
struct adis16480 *st)
|
||||
{
|
||||
struct irq_data *desc;
|
||||
enum adis16480_int_pin pin;
|
||||
unsigned int irq_type;
|
||||
uint16_t val;
|
||||
int i, irq = 0;
|
||||
|
||||
desc = irq_get_irq_data(st->adis.spi->irq);
|
||||
if (!desc) {
|
||||
dev_err(&st->adis.spi->dev, "Could not find IRQ %d\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Disable data ready since the default after reset is on */
|
||||
val = ADIS16480_DRDY_EN(0);
|
||||
|
||||
/*
|
||||
* Get the interrupt from the devicetre by reading the interrupt-names
|
||||
* property. If it is not specified, use DIO1 pin as default.
|
||||
* According to the datasheet, the factory default assigns DIO2 as data
|
||||
* ready signal. However, in the previous versions of the driver, DIO1
|
||||
* pin was used. So, we should leave it as is since some devices might
|
||||
* be expecting the interrupt on the wrong physical pin.
|
||||
*/
|
||||
pin = ADIS16480_PIN_DIO1;
|
||||
for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) {
|
||||
irq = of_irq_get_byname(of_node, adis16480_int_pin_names[i]);
|
||||
if (irq > 0) {
|
||||
pin = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
val |= ADIS16480_DRDY_SEL(pin);
|
||||
|
||||
/*
|
||||
* Get the interrupt line behaviour. The data ready polarity can be
|
||||
* configured as positive or negative, corresponding to
|
||||
* IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING respectively.
|
||||
*/
|
||||
irq_type = irqd_get_trigger_type(desc);
|
||||
if (irq_type == IRQF_TRIGGER_RISING) { /* Default */
|
||||
val |= ADIS16480_DRDY_POL(1);
|
||||
} else if (irq_type == IRQF_TRIGGER_FALLING) {
|
||||
val |= ADIS16480_DRDY_POL(0);
|
||||
} else {
|
||||
dev_err(&st->adis.spi->dev,
|
||||
"Invalid interrupt type 0x%x specified\n", irq_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Write the data ready configuration to the FNCTIO_CTRL register */
|
||||
return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val);
|
||||
}
|
||||
|
||||
static int adis16480_of_get_ext_clk_pin(struct adis16480 *st,
|
||||
struct device_node *of_node)
|
||||
{
|
||||
const char *ext_clk_pin;
|
||||
enum adis16480_int_pin pin;
|
||||
int i;
|
||||
|
||||
pin = ADIS16480_PIN_DIO2;
|
||||
if (of_property_read_string(of_node, "adi,ext-clk-pin", &ext_clk_pin))
|
||||
goto clk_input_not_found;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) {
|
||||
if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
clk_input_not_found:
|
||||
dev_info(&st->adis.spi->dev,
|
||||
"clk input line not specified, using DIO2\n");
|
||||
return pin;
|
||||
}
|
||||
|
||||
static int adis16480_ext_clk_config(struct adis16480 *st,
|
||||
struct device_node *of_node,
|
||||
bool enable)
|
||||
{
|
||||
unsigned int mode, mask;
|
||||
enum adis16480_int_pin pin;
|
||||
uint16_t val;
|
||||
int ret;
|
||||
|
||||
ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pin = adis16480_of_get_ext_clk_pin(st, of_node);
|
||||
/*
|
||||
* Each DIOx pin supports only one function at a time. When a single pin
|
||||
* has two assignments, the enable bit for a lower priority function
|
||||
* automatically resets to zero (disabling the lower priority function).
|
||||
*/
|
||||
if (pin == ADIS16480_DRDY_SEL(val))
|
||||
dev_warn(&st->adis.spi->dev,
|
||||
"DIO%x pin supports only one function at a time\n",
|
||||
pin + 1);
|
||||
|
||||
mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin);
|
||||
mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK;
|
||||
/* Only ADIS1649x devices support pps ext clock mode */
|
||||
if (st->chip_info->has_pps_clk_mode) {
|
||||
mode |= ADIS16480_SYNC_MODE(st->clk_mode);
|
||||
mask |= ADIS16480_SYNC_MODE_MSK;
|
||||
}
|
||||
|
||||
val &= ~mask;
|
||||
val |= mode;
|
||||
|
||||
ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return clk_prepare_enable(st->ext_clk);
|
||||
}
|
||||
|
||||
static int adis16480_get_ext_clocks(struct adis16480 *st)
|
||||
{
|
||||
st->clk_mode = ADIS16480_CLK_INT;
|
||||
st->ext_clk = devm_clk_get(&st->adis.spi->dev, "sync");
|
||||
if (!IS_ERR_OR_NULL(st->ext_clk)) {
|
||||
st->clk_mode = ADIS16480_CLK_SYNC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PTR_ERR(st->ext_clk) != -ENOENT) {
|
||||
dev_err(&st->adis.spi->dev, "failed to get ext clk\n");
|
||||
return PTR_ERR(st->ext_clk);
|
||||
}
|
||||
|
||||
if (st->chip_info->has_pps_clk_mode) {
|
||||
st->ext_clk = devm_clk_get(&st->adis.spi->dev, "pps");
|
||||
if (!IS_ERR_OR_NULL(st->ext_clk)) {
|
||||
st->clk_mode = ADIS16480_CLK_PPS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PTR_ERR(st->ext_clk) != -ENOENT) {
|
||||
dev_err(&st->adis.spi->dev, "failed to get ext clk\n");
|
||||
return PTR_ERR(st->ext_clk);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adis16480_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
@ -853,10 +1208,29 @@ static int adis16480_probe(struct spi_device *spi)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
|
||||
ret = adis16480_config_irq_pin(spi->dev.of_node, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adis16480_get_ext_clocks(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!IS_ERR_OR_NULL(st->ext_clk)) {
|
||||
ret = adis16480_ext_clk_config(st, spi->dev.of_node, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->clk_freq = clk_get_rate(st->ext_clk);
|
||||
st->clk_freq *= 1000; /* micro */
|
||||
} else {
|
||||
st->clk_freq = st->chip_info->int_clk;
|
||||
}
|
||||
|
||||
ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
|
||||
if (ret)
|
||||
goto error_clk_disable_unprepare;
|
||||
|
||||
ret = adis16480_initial_setup(indio_dev);
|
||||
if (ret)
|
||||
goto error_cleanup_buffer;
|
||||
|
@ -873,6 +1247,8 @@ error_stop_device:
|
|||
adis16480_stop_device(indio_dev);
|
||||
error_cleanup_buffer:
|
||||
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
|
||||
error_clk_disable_unprepare:
|
||||
clk_disable_unprepare(st->ext_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -885,6 +1261,7 @@ static int adis16480_remove(struct spi_device *spi)
|
|||
adis16480_stop_device(indio_dev);
|
||||
|
||||
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
|
||||
clk_disable_unprepare(st->ext_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -894,13 +1271,35 @@ static const struct spi_device_id adis16480_ids[] = {
|
|||
{ "adis16480", ADIS16480 },
|
||||
{ "adis16485", ADIS16485 },
|
||||
{ "adis16488", ADIS16488 },
|
||||
{ "adis16495-1", ADIS16495_1 },
|
||||
{ "adis16495-2", ADIS16495_2 },
|
||||
{ "adis16495-3", ADIS16495_3 },
|
||||
{ "adis16497-1", ADIS16497_1 },
|
||||
{ "adis16497-2", ADIS16497_2 },
|
||||
{ "adis16497-3", ADIS16497_3 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adis16480_ids);
|
||||
|
||||
static const struct of_device_id adis16480_of_match[] = {
|
||||
{ .compatible = "adi,adis16375" },
|
||||
{ .compatible = "adi,adis16480" },
|
||||
{ .compatible = "adi,adis16485" },
|
||||
{ .compatible = "adi,adis16488" },
|
||||
{ .compatible = "adi,adis16495-1" },
|
||||
{ .compatible = "adi,adis16495-2" },
|
||||
{ .compatible = "adi,adis16495-3" },
|
||||
{ .compatible = "adi,adis16497-1" },
|
||||
{ .compatible = "adi,adis16497-2" },
|
||||
{ .compatible = "adi,adis16497-3" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adis16480_of_match);
|
||||
|
||||
static struct spi_driver adis16480_driver = {
|
||||
.driver = {
|
||||
.name = "adis16480",
|
||||
.of_match_table = adis16480_of_match,
|
||||
},
|
||||
.id_table = adis16480_ids,
|
||||
.probe = adis16480_probe,
|
||||
|
|
|
@ -20,6 +20,43 @@
|
|||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/imu/adis.h>
|
||||
|
||||
static int adis_update_scan_mode_burst(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct adis *adis = iio_device_get_drvdata(indio_dev);
|
||||
unsigned int burst_length;
|
||||
u8 *tx;
|
||||
|
||||
/* All but the timestamp channel */
|
||||
burst_length = (indio_dev->num_channels - 1) * sizeof(u16);
|
||||
burst_length += adis->burst->extra_len;
|
||||
|
||||
adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
|
||||
if (!adis->xfer)
|
||||
return -ENOMEM;
|
||||
|
||||
adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL);
|
||||
if (!adis->buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
tx = adis->buffer + burst_length;
|
||||
tx[0] = ADIS_READ_REG(adis->burst->reg_cmd);
|
||||
tx[1] = 0;
|
||||
|
||||
adis->xfer[0].tx_buf = tx;
|
||||
adis->xfer[0].bits_per_word = 8;
|
||||
adis->xfer[0].len = 2;
|
||||
adis->xfer[1].rx_buf = adis->buffer;
|
||||
adis->xfer[1].bits_per_word = 8;
|
||||
adis->xfer[1].len = burst_length;
|
||||
|
||||
spi_message_init(&adis->msg);
|
||||
spi_message_add_tail(&adis->xfer[0], &adis->msg);
|
||||
spi_message_add_tail(&adis->xfer[1], &adis->msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int adis_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
|
@ -32,6 +69,9 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
|
|||
kfree(adis->xfer);
|
||||
kfree(adis->buffer);
|
||||
|
||||
if (adis->burst && adis->burst->en)
|
||||
return adis_update_scan_mode_burst(indio_dev, scan_mask);
|
||||
|
||||
scan_count = indio_dev->scan_bytes / 2;
|
||||
|
||||
adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL);
|
||||
|
|
|
@ -796,12 +796,14 @@ static const struct iio_mount_matrix *
|
|||
inv_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation;
|
||||
struct inv_mpu6050_state *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info inv_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix),
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
|
||||
#define INV_MPU6050_CHAN(_type, _channel2, _index) \
|
||||
|
@ -1021,8 +1023,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
|||
|
||||
pdata = dev_get_platdata(dev);
|
||||
if (!pdata) {
|
||||
result = of_iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&st->orientation);
|
||||
result = iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&st->orientation);
|
||||
if (result) {
|
||||
dev_err(dev, "Failed to retrieve mounting matrix %d\n",
|
||||
result);
|
||||
|
|
|
@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX
|
|||
help
|
||||
Say yes here to build support for STMicroelectronics LSM6DSx imu
|
||||
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
|
||||
ism330dlc, lsm6dso
|
||||
ism330dlc, lsm6dso, lsm6dsox, asm330lhh
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called st_lsm6dsx.
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#define ST_LSM6DSM_DEV_NAME "lsm6dsm"
|
||||
#define ST_ISM330DLC_DEV_NAME "ism330dlc"
|
||||
#define ST_LSM6DSO_DEV_NAME "lsm6dso"
|
||||
#define ST_ASM330LHH_DEV_NAME "asm330lhh"
|
||||
#define ST_LSM6DSOX_DEV_NAME "lsm6dsox"
|
||||
|
||||
enum st_lsm6dsx_hw_id {
|
||||
ST_LSM6DS3_ID,
|
||||
|
@ -28,6 +30,8 @@ enum st_lsm6dsx_hw_id {
|
|||
ST_LSM6DSM_ID,
|
||||
ST_ISM330DLC_ID,
|
||||
ST_LSM6DSO_ID,
|
||||
ST_ASM330LHH_ID,
|
||||
ST_LSM6DSOX_ID,
|
||||
ST_LSM6DSX_MAX_ID,
|
||||
};
|
||||
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
* (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
|
||||
* value of the decimation factor and ODR set for each FIFO data set.
|
||||
*
|
||||
* LSM6DSO: The FIFO buffer can be configured to store data from gyroscope and
|
||||
* accelerometer. Each sample is queued with a tag (1B) indicating data source
|
||||
* (gyroscope, accelerometer, hw timer).
|
||||
* LSM6DSO/LSM6DSOX/ASM330LHH: The FIFO buffer can be configured to store data
|
||||
* from gyroscope and accelerometer. Each sample is queued with a tag (1B)
|
||||
* indicating data source (gyroscope, accelerometer, hw timer).
|
||||
*
|
||||
* FIFO supported modes:
|
||||
* - BYPASS: FIFO disabled
|
||||
|
@ -506,7 +506,7 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
|
|||
}
|
||||
|
||||
/**
|
||||
* st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine
|
||||
* st_lsm6dsx_read_tagged_fifo() - LSM6DSO/LSM6DSOX/ASM330LHH read FIFO routine
|
||||
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
|
||||
*
|
||||
* Read samples from the hw FIFO and push them to IIO buffers.
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
|
||||
* - FIFO size: 4KB
|
||||
*
|
||||
* - LSM6DSO
|
||||
* - LSM6DSO/LSM6DSOX/ASM330LHH
|
||||
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
|
||||
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
|
||||
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
|
||||
|
@ -287,6 +287,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
|||
.max_fifo_size = 512,
|
||||
.id = {
|
||||
[0] = ST_LSM6DSO_ID,
|
||||
[1] = ST_LSM6DSOX_ID,
|
||||
},
|
||||
.batch = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
|
@ -347,6 +348,45 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
|||
.batch_en = BIT(3),
|
||||
}
|
||||
},
|
||||
{
|
||||
.wai = 0x6b,
|
||||
.max_fifo_size = 512,
|
||||
.id = {
|
||||
[0] = ST_ASM330LHH_ID,
|
||||
},
|
||||
.batch = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.addr = 0x09,
|
||||
.mask = GENMASK(3, 0),
|
||||
},
|
||||
[ST_LSM6DSX_ID_GYRO] = {
|
||||
.addr = 0x09,
|
||||
.mask = GENMASK(7, 4),
|
||||
},
|
||||
},
|
||||
.fifo_ops = {
|
||||
.read_fifo = st_lsm6dsx_read_tagged_fifo,
|
||||
.fifo_th = {
|
||||
.addr = 0x07,
|
||||
.mask = GENMASK(8, 0),
|
||||
},
|
||||
.fifo_diff = {
|
||||
.addr = 0x3a,
|
||||
.mask = GENMASK(8, 0),
|
||||
},
|
||||
.th_wl = 1,
|
||||
},
|
||||
.ts_settings = {
|
||||
.timer_en = {
|
||||
.addr = 0x19,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.decimator = {
|
||||
.addr = 0x0a,
|
||||
.mask = GENMASK(7, 6),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
|
||||
|
|
|
@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
|
|||
.compatible = "st,lsm6dso",
|
||||
.data = (void *)ST_LSM6DSO_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,asm330lhh",
|
||||
.data = (void *)ST_ASM330LHH_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm6dsox",
|
||||
.data = (void *)ST_LSM6DSOX_ID,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
|
||||
|
@ -76,6 +84,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
|
|||
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
|
||||
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
|
||||
{ ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
|
||||
{ ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
|
||||
{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
|
||||
|
|
|
@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
|
|||
.compatible = "st,lsm6dso",
|
||||
.data = (void *)ST_LSM6DSO_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,asm330lhh",
|
||||
.data = (void *)ST_ASM330LHH_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm6dsox",
|
||||
.data = (void *)ST_LSM6DSOX_ID,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
|
||||
|
@ -76,6 +84,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
|
|||
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
|
||||
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
|
||||
{ ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
|
||||
{ ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
|
||||
{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
|
||||
|
|
|
@ -320,9 +320,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
|
|||
const unsigned long *mask;
|
||||
unsigned long *trialmask;
|
||||
|
||||
trialmask = kmalloc_array(BITS_TO_LONGS(indio_dev->masklength),
|
||||
sizeof(*trialmask),
|
||||
GFP_KERNEL);
|
||||
trialmask = bitmap_alloc(indio_dev->masklength, GFP_KERNEL);
|
||||
if (trialmask == NULL)
|
||||
return -ENOMEM;
|
||||
if (!indio_dev->masklength) {
|
||||
|
@ -344,12 +342,12 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
|
|||
}
|
||||
bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
|
||||
|
||||
kfree(trialmask);
|
||||
bitmap_free(trialmask);
|
||||
|
||||
return 0;
|
||||
|
||||
err_invalid_mask:
|
||||
kfree(trialmask);
|
||||
bitmap_free(trialmask);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -666,7 +664,7 @@ static void iio_free_scan_mask(struct iio_dev *indio_dev,
|
|||
{
|
||||
/* If the mask is dynamically allocated free it, otherwise do nothing */
|
||||
if (!indio_dev->available_scan_masks)
|
||||
kfree(mask);
|
||||
bitmap_free(mask);
|
||||
}
|
||||
|
||||
struct iio_device_config {
|
||||
|
@ -736,8 +734,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
/* What scan mask do we actually have? */
|
||||
compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
|
||||
sizeof(long), GFP_KERNEL);
|
||||
compound_mask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL);
|
||||
if (compound_mask == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -762,7 +759,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
|
|||
indio_dev->masklength,
|
||||
compound_mask,
|
||||
strict_scanmask);
|
||||
kfree(compound_mask);
|
||||
bitmap_free(compound_mask);
|
||||
if (scan_mask == NULL)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
|
@ -1303,9 +1300,8 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
|
|||
channels[i].scan_index;
|
||||
}
|
||||
if (indio_dev->masklength && buffer->scan_mask == NULL) {
|
||||
buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
|
||||
sizeof(*buffer->scan_mask),
|
||||
GFP_KERNEL);
|
||||
buffer->scan_mask = bitmap_zalloc(indio_dev->masklength,
|
||||
GFP_KERNEL);
|
||||
if (buffer->scan_mask == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_cleanup_dynamic;
|
||||
|
@ -1334,7 +1330,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
|
|||
return 0;
|
||||
|
||||
error_free_scan_mask:
|
||||
kfree(buffer->scan_mask);
|
||||
bitmap_free(buffer->scan_mask);
|
||||
error_cleanup_dynamic:
|
||||
iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
|
||||
kfree(indio_dev->buffer->buffer_group.attrs);
|
||||
|
@ -1347,7 +1343,7 @@ void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
|
|||
if (!indio_dev->buffer)
|
||||
return;
|
||||
|
||||
kfree(indio_dev->buffer->scan_mask);
|
||||
bitmap_free(indio_dev->buffer->scan_mask);
|
||||
kfree(indio_dev->buffer->buffer_group.attrs);
|
||||
kfree(indio_dev->buffer->scan_el_group.attrs);
|
||||
iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/cdev.h>
|
||||
|
@ -530,8 +531,8 @@ ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv,
|
|||
EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
|
||||
|
||||
/**
|
||||
* of_iio_read_mount_matrix() - retrieve iio device mounting matrix from
|
||||
* device-tree "mount-matrix" property
|
||||
* iio_read_mount_matrix() - retrieve iio device mounting matrix from
|
||||
* device "mount-matrix" property
|
||||
* @dev: device the mounting matrix property is assigned to
|
||||
* @propname: device specific mounting matrix property name
|
||||
* @matrix: where to store retrieved matrix
|
||||
|
@ -541,40 +542,29 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
|
|||
*
|
||||
* Return: 0 if success, or a negative error code on failure.
|
||||
*/
|
||||
#ifdef CONFIG_OF
|
||||
int of_iio_read_mount_matrix(const struct device *dev,
|
||||
const char *propname,
|
||||
struct iio_mount_matrix *matrix)
|
||||
int iio_read_mount_matrix(struct device *dev, const char *propname,
|
||||
struct iio_mount_matrix *matrix)
|
||||
{
|
||||
if (dev->of_node) {
|
||||
int err = of_property_read_string_array(dev->of_node,
|
||||
propname, matrix->rotation,
|
||||
ARRAY_SIZE(iio_mount_idmatrix.rotation));
|
||||
size_t len = ARRAY_SIZE(iio_mount_idmatrix.rotation);
|
||||
int err;
|
||||
|
||||
if (err == ARRAY_SIZE(iio_mount_idmatrix.rotation))
|
||||
return 0;
|
||||
err = device_property_read_string_array(dev, propname,
|
||||
matrix->rotation, len);
|
||||
if (err == len)
|
||||
return 0;
|
||||
|
||||
if (err >= 0)
|
||||
/* Invalid number of matrix entries. */
|
||||
return -EINVAL;
|
||||
if (err >= 0)
|
||||
/* Invalid number of matrix entries. */
|
||||
return -EINVAL;
|
||||
|
||||
if (err != -EINVAL)
|
||||
/* Invalid matrix declaration format. */
|
||||
return err;
|
||||
}
|
||||
if (err != -EINVAL)
|
||||
/* Invalid matrix declaration format. */
|
||||
return err;
|
||||
|
||||
/* Matrix was not declared at all: fallback to identity. */
|
||||
return iio_setup_mount_idmatrix(dev, matrix);
|
||||
}
|
||||
#else
|
||||
int of_iio_read_mount_matrix(const struct device *dev,
|
||||
const char *propname,
|
||||
struct iio_mount_matrix *matrix)
|
||||
{
|
||||
return iio_setup_mount_idmatrix(dev, matrix);
|
||||
}
|
||||
#endif
|
||||
EXPORT_SYMBOL(of_iio_read_mount_matrix);
|
||||
EXPORT_SYMBOL(iio_read_mount_matrix);
|
||||
|
||||
static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
|
||||
int size, const int *vals)
|
||||
|
|
|
@ -254,8 +254,11 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
|
|||
|
||||
/* Get irq number */
|
||||
pf->irq = iio_trigger_get_irq(trig);
|
||||
if (pf->irq < 0)
|
||||
if (pf->irq < 0) {
|
||||
pr_err("Could not find an available irq for trigger %s, CONFIG_IIO_CONSUMERS_PER_TRIGGER=%d limit might be exceeded\n",
|
||||
trig->name, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
|
||||
goto out_put_module;
|
||||
}
|
||||
|
||||
/* Request irq */
|
||||
ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
|
||||
|
|
|
@ -13,11 +13,11 @@ config ACPI_ALS
|
|||
select IIO_TRIGGERED_BUFFER
|
||||
select IIO_KFIFO_BUF
|
||||
help
|
||||
Say Y here if you want to build a driver for the ACPI0008
|
||||
Ambient Light Sensor.
|
||||
Say Y here if you want to build a driver for the ACPI0008
|
||||
Ambient Light Sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called acpi-als.
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called acpi-als.
|
||||
|
||||
config ADJD_S311
|
||||
tristate "ADJD-S311-CR999 digital color sensor"
|
||||
|
@ -25,31 +25,31 @@ config ADJD_S311
|
|||
select IIO_TRIGGERED_BUFFER
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Avago ADJD-S311-CR999
|
||||
digital color light sensor.
|
||||
If you say yes here you get support for the Avago ADJD-S311-CR999
|
||||
digital color light sensor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adjd_s311.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adjd_s311.
|
||||
|
||||
config AL3320A
|
||||
tristate "AL3320A ambient light sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the Dyna Image AL3320A
|
||||
ambient light sensor.
|
||||
Say Y here if you want to build a driver for the Dyna Image AL3320A
|
||||
ambient light sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called al3320a.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called al3320a.
|
||||
|
||||
config APDS9300
|
||||
tristate "APDS9300 ambient light sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the Avago APDS9300
|
||||
ambient light sensor.
|
||||
Say Y here if you want to build a driver for the Avago APDS9300
|
||||
ambient light sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called apds9300.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called apds9300.
|
||||
|
||||
config APDS9960
|
||||
tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor"
|
||||
|
@ -68,74 +68,74 @@ config BH1750
|
|||
tristate "ROHM BH1750 ambient light sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to build support for the ROHM BH1710, BH1715, BH1721,
|
||||
BH1750, BH1751 ambient light sensors.
|
||||
Say Y here to build support for the ROHM BH1710, BH1715, BH1721,
|
||||
BH1750, BH1751 ambient light sensors.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called bh1750.
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called bh1750.
|
||||
|
||||
config BH1780
|
||||
tristate "ROHM BH1780 ambient light sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to build support for the ROHM BH1780GLI ambient
|
||||
light sensor.
|
||||
Say Y here to build support for the ROHM BH1780GLI ambient
|
||||
light sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called bh1780.
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called bh1780.
|
||||
|
||||
config CM32181
|
||||
depends on I2C
|
||||
tristate "CM32181 driver"
|
||||
help
|
||||
Say Y here if you use cm32181.
|
||||
This option enables ambient light sensor using
|
||||
Capella cm32181 device driver.
|
||||
Say Y here if you use cm32181.
|
||||
This option enables ambient light sensor using
|
||||
Capella cm32181 device driver.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called cm32181.
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called cm32181.
|
||||
|
||||
config CM3232
|
||||
depends on I2C
|
||||
tristate "CM3232 ambient light sensor"
|
||||
help
|
||||
Say Y here if you use cm3232.
|
||||
This option enables ambient light sensor using
|
||||
Capella Microsystems cm3232 device driver.
|
||||
Say Y here if you use cm3232.
|
||||
This option enables ambient light sensor using
|
||||
Capella Microsystems cm3232 device driver.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called cm3232.
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called cm3232.
|
||||
|
||||
config CM3323
|
||||
depends on I2C
|
||||
tristate "Capella CM3323 color light sensor"
|
||||
help
|
||||
Say Y here if you want to build a driver for Capella CM3323
|
||||
color sensor.
|
||||
Say Y here if you want to build a driver for Capella CM3323
|
||||
color sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called cm3323.
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called cm3323.
|
||||
|
||||
config CM3605
|
||||
tristate "Capella CM3605 ambient light and proximity sensor"
|
||||
depends on OF
|
||||
help
|
||||
Say Y here if you want to build a driver for Capella CM3605
|
||||
ambient light and short range proximity sensor.
|
||||
Say Y here if you want to build a driver for Capella CM3605
|
||||
ambient light and short range proximity sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called cm3605.
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called cm3605.
|
||||
|
||||
config CM36651
|
||||
depends on I2C
|
||||
tristate "CM36651 driver"
|
||||
help
|
||||
Say Y here if you use cm36651.
|
||||
This option enables proximity & RGB sensor using
|
||||
Capella cm36651 device driver.
|
||||
Say Y here if you use cm36651.
|
||||
This option enables proximity & RGB sensor using
|
||||
Capella cm36651 device driver.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called cm36651.
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called cm36651.
|
||||
|
||||
config IIO_CROS_EC_LIGHT_PROX
|
||||
tristate "ChromeOS EC Light and Proximity Sensors"
|
||||
|
@ -167,21 +167,21 @@ config SENSORS_ISL29018
|
|||
select REGMAP_I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for ambient light sensing and
|
||||
proximity infrared sensing from Intersil ISL29018.
|
||||
This driver will provide the measurements of ambient light intensity
|
||||
in lux, proximity infrared sensing and normal infrared sensing.
|
||||
Data from sensor is accessible via sysfs.
|
||||
If you say yes here you get support for ambient light sensing and
|
||||
proximity infrared sensing from Intersil ISL29018.
|
||||
This driver will provide the measurements of ambient light intensity
|
||||
in lux, proximity infrared sensing and normal infrared sensing.
|
||||
Data from sensor is accessible via sysfs.
|
||||
|
||||
config SENSORS_ISL29028
|
||||
tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Provides driver for the Intersil's ISL29028 device.
|
||||
This driver supports the sysfs interface to get the ALS, IR intensity,
|
||||
Proximity value via iio. The ISL29028 provides the concurrent sensing
|
||||
of ambient light and proximity.
|
||||
Provides driver for the Intersil's ISL29028 device.
|
||||
This driver supports the sysfs interface to get the ALS, IR intensity,
|
||||
Proximity value via iio. The ISL29028 provides the concurrent sensing
|
||||
of ambient light and proximity.
|
||||
|
||||
config ISL29125
|
||||
tristate "Intersil ISL29125 digital color light sensor"
|
||||
|
@ -228,22 +228,22 @@ config JSA1212
|
|||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here if you want to build a IIO driver for JSA1212
|
||||
proximity & ALS sensor device.
|
||||
Say Y here if you want to build a IIO driver for JSA1212
|
||||
proximity & ALS sensor device.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called jsa1212.
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called jsa1212.
|
||||
|
||||
config RPR0521
|
||||
tristate "ROHM RPR0521 ALS and proximity sensor driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here if you want to build support for ROHM's RPR0521
|
||||
ambient light and proximity sensor device.
|
||||
Say Y here if you want to build support for ROHM's RPR0521
|
||||
ambient light and proximity sensor device.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called rpr0521.
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called rpr0521.
|
||||
|
||||
config SENSORS_LM3533
|
||||
tristate "LM3533 ambient light sensor"
|
||||
|
@ -269,22 +269,22 @@ config LTR501
|
|||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for the Lite-On LTR-501ALS-01
|
||||
ambient light and proximity sensor. This driver also supports LTR-559
|
||||
ALS/PS or LTR-301 ALS sensors.
|
||||
If you say yes here you get support for the Lite-On LTR-501ALS-01
|
||||
ambient light and proximity sensor. This driver also supports LTR-559
|
||||
ALS/PS or LTR-301 ALS sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ltr501.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ltr501.
|
||||
|
||||
config LV0104CS
|
||||
tristate "LV0104CS Ambient Light Sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build support for the On Semiconductor
|
||||
LV0104CS ambient light sensor.
|
||||
Say Y here if you want to build support for the On Semiconductor
|
||||
LV0104CS ambient light sensor.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called lv0104cs.
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called lv0104cs.
|
||||
|
||||
config MAX44000
|
||||
tristate "MAX44000 Ambient and Infrared Proximity Sensor"
|
||||
|
@ -293,11 +293,11 @@ config MAX44000
|
|||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here if you want to build support for Maxim Integrated's
|
||||
MAX44000 ambient and infrared proximity sensor device.
|
||||
Say Y here if you want to build support for Maxim Integrated's
|
||||
MAX44000 ambient and infrared proximity sensor device.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called max44000.
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called max44000.
|
||||
|
||||
config MAX44009
|
||||
tristate "MAX44009 Ambient Light Sensor"
|
||||
|
@ -320,15 +320,15 @@ config OPT3001
|
|||
opt3001.
|
||||
|
||||
config PA12203001
|
||||
tristate "TXC PA12203001 light and proximity sensor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the TXC PA12203001
|
||||
ambient light and proximity sensor.
|
||||
tristate "TXC PA12203001 light and proximity sensor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the TXC PA12203001
|
||||
ambient light and proximity sensor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pa12203001.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pa12203001.
|
||||
|
||||
config SI1133
|
||||
tristate "SI1133 UV Index Sensor and Ambient Light Sensor"
|
||||
|
@ -359,12 +359,12 @@ config STK3310
|
|||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to get support for the Sensortek STK3310 ambient light
|
||||
and proximity sensor. The STK3311 model is also supported by this
|
||||
driver.
|
||||
Say yes here to get support for the Sensortek STK3310 ambient light
|
||||
and proximity sensor. The STK3311 model is also supported by this
|
||||
driver.
|
||||
|
||||
Choosing M will build the driver as a module. If so, the module
|
||||
will be called stk3310.
|
||||
Choosing M will build the driver as a module. If so, the module
|
||||
will be called stk3310.
|
||||
|
||||
config ST_UVIS25
|
||||
tristate "STMicroelectronics UVIS25 sensor driver"
|
||||
|
@ -396,11 +396,11 @@ config TCS3414
|
|||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for the TAOS TCS3414
|
||||
family of digital color sensors.
|
||||
If you say yes here you get support for the TAOS TCS3414
|
||||
family of digital color sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tcs3414.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tcs3414.
|
||||
|
||||
config TCS3472
|
||||
tristate "TAOS TCS3472 color light-to-digital converter"
|
||||
|
@ -408,67 +408,67 @@ config TCS3472
|
|||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for the TAOS TCS3472
|
||||
family of color light-to-digital converters with IR filter.
|
||||
If you say yes here you get support for the TAOS TCS3472
|
||||
family of color light-to-digital converters with IR filter.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tcs3472.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tcs3472.
|
||||
|
||||
config SENSORS_TSL2563
|
||||
tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Taos TSL2560,
|
||||
TSL2561, TSL2562 and TSL2563 ambient light sensors.
|
||||
If you say yes here you get support for the Taos TSL2560,
|
||||
TSL2561, TSL2562 and TSL2563 ambient light sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tsl2563.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tsl2563.
|
||||
|
||||
config TSL2583
|
||||
tristate "TAOS TSL2580, TSL2581 and TSL2583 light-to-digital converters"
|
||||
depends on I2C
|
||||
help
|
||||
Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
|
||||
Access ALS data via iio, sysfs.
|
||||
Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
|
||||
Access ALS data via iio, sysfs.
|
||||
|
||||
config TSL2772
|
||||
tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
|
||||
depends on I2C
|
||||
help
|
||||
Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
|
||||
tmd2672, tsl2772, tmd2772 devices.
|
||||
Provides iio_events and direct access via sysfs.
|
||||
Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
|
||||
tmd2672, tsl2772, tmd2772 devices.
|
||||
Provides iio_events and direct access via sysfs.
|
||||
|
||||
config TSL4531
|
||||
tristate "TAOS TSL4531 ambient light sensors"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the TAOS TSL4531 family
|
||||
of ambient light sensors with direct lux output.
|
||||
Say Y here if you want to build a driver for the TAOS TSL4531 family
|
||||
of ambient light sensors with direct lux output.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tsl4531.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tsl4531.
|
||||
|
||||
config US5182D
|
||||
tristate "UPISEMI light and proximity sensor"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the UPISEMI US5182D
|
||||
ambient light and proximity sensor.
|
||||
If you say yes here you get support for the UPISEMI US5182D
|
||||
ambient light and proximity sensor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called us5182d.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called us5182d.
|
||||
|
||||
config VCNL4000
|
||||
tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the Vishay VCNL4000,
|
||||
VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity
|
||||
sensor.
|
||||
Say Y here if you want to build a driver for the Vishay VCNL4000,
|
||||
VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity
|
||||
sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vcnl4000.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vcnl4000.
|
||||
|
||||
config VCNL4035
|
||||
tristate "VCNL4035 combined ALS and proximity sensor"
|
||||
|
@ -476,41 +476,41 @@ config VCNL4035
|
|||
select REGMAP_I2C
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the Vishay VCNL4035,
|
||||
combined ambient light (ALS) and proximity sensor. Currently only ALS
|
||||
function is available.
|
||||
Say Y here if you want to build a driver for the Vishay VCNL4035,
|
||||
combined ambient light (ALS) and proximity sensor. Currently only ALS
|
||||
function is available.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vcnl4035.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vcnl4035.
|
||||
|
||||
config VEML6070
|
||||
tristate "VEML6070 UV A light sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the Vishay VEML6070 UV A
|
||||
light sensor.
|
||||
Say Y here if you want to build a driver for the Vishay VEML6070 UV A
|
||||
light sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called veml6070.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called veml6070.
|
||||
|
||||
config VL6180
|
||||
tristate "VL6180 ALS, range and proximity sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the STMicroelectronics
|
||||
VL6180 combined ambient light, range and proximity sensor.
|
||||
Say Y here if you want to build a driver for the STMicroelectronics
|
||||
VL6180 combined ambient light, range and proximity sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vl6180.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vl6180.
|
||||
|
||||
config ZOPT2201
|
||||
tristate "ZOPT2201 ALS and UV B sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the IDT
|
||||
ZOPT2201 ambient light and UV B sensor.
|
||||
Say Y here if you want to build a driver for the IDT
|
||||
ZOPT2201 ambient light and UV B sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called zopt2201.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called zopt2201.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,19 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cros_ec_light_prox - Driver for light and prox sensors behing CrosEC.
|
||||
*
|
||||
* Copyright (C) 2017 Google, Inc
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/common/cros_ec_sensors_core.h>
|
||||
|
@ -28,7 +19,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/*
|
||||
* We only represent one entry for light or proximity. EC is merging different
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4200 combined ambient
|
||||
* vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient
|
||||
* light and proximity sensor
|
||||
*
|
||||
* Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
|
||||
* Copyright 2019 Pursim SPC
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
|
@ -10,13 +11,14 @@
|
|||
*
|
||||
* IIO driver for:
|
||||
* VCNL4000/10/20 (7-bit I2C slave address 0x13)
|
||||
* VCNL4040 (7-bit I2C slave address 0x60)
|
||||
* VCNL4200 (7-bit I2C slave address 0x51)
|
||||
*
|
||||
* TODO:
|
||||
* allow to adjust IR current
|
||||
* proximity threshold and event handling
|
||||
* periodic ALS/proximity measurement (VCNL4010/20)
|
||||
* interrupts (VCNL4010/20, VCNL4200)
|
||||
* interrupts (VCNL4010/20/40, VCNL4200)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -30,6 +32,7 @@
|
|||
#define VCNL4000_DRV_NAME "vcnl4000"
|
||||
#define VCNL4000_PROD_ID 0x01
|
||||
#define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
|
||||
#define VCNL4040_PROD_ID 0x86
|
||||
#define VCNL4200_PROD_ID 0x58
|
||||
|
||||
#define VCNL4000_COMMAND 0x80 /* Command register */
|
||||
|
@ -49,6 +52,8 @@
|
|||
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
|
||||
#define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
|
||||
|
||||
#define VCNL4040_DEV_ID 0x0c /* Device ID and version */
|
||||
|
||||
/* Bit masks for COMMAND register */
|
||||
#define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */
|
||||
#define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
|
||||
|
@ -58,6 +63,7 @@
|
|||
enum vcnl4000_device_ids {
|
||||
VCNL4000,
|
||||
VCNL4010,
|
||||
VCNL4040,
|
||||
VCNL4200,
|
||||
};
|
||||
|
||||
|
@ -90,6 +96,7 @@ static const struct i2c_device_id vcnl4000_id[] = {
|
|||
{ "vcnl4000", VCNL4000 },
|
||||
{ "vcnl4010", VCNL4010 },
|
||||
{ "vcnl4020", VCNL4010 },
|
||||
{ "vcnl4040", VCNL4040 },
|
||||
{ "vcnl4200", VCNL4200 },
|
||||
{ }
|
||||
};
|
||||
|
@ -128,31 +135,53 @@ static int vcnl4000_init(struct vcnl4000_data *data)
|
|||
|
||||
static int vcnl4200_init(struct vcnl4000_data *data)
|
||||
{
|
||||
int ret;
|
||||
int ret, id;
|
||||
|
||||
ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret & 0xff) != VCNL4200_PROD_ID)
|
||||
return -ENODEV;
|
||||
id = ret & 0xff;
|
||||
|
||||
if (id != VCNL4200_PROD_ID) {
|
||||
ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
id = ret & 0xff;
|
||||
|
||||
if (id != VCNL4040_PROD_ID)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_dbg(&data->client->dev, "device id 0x%x", id);
|
||||
|
||||
data->rev = (ret >> 8) & 0xf;
|
||||
|
||||
/* Set defaults and enable both channels */
|
||||
ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00);
|
||||
ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00);
|
||||
ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->al_scale = 24000;
|
||||
data->vcnl4200_al.reg = VCNL4200_AL_DATA;
|
||||
data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
|
||||
/* Integration time is 50ms, but the experiments show 54ms in total. */
|
||||
data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
|
||||
data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
|
||||
switch (id) {
|
||||
case VCNL4200_PROD_ID:
|
||||
/* Integration time is 50ms, but the experiments */
|
||||
/* show 54ms in total. */
|
||||
data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
|
||||
data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
|
||||
break;
|
||||
case VCNL4040_PROD_ID:
|
||||
/* Integration time is 80ms, add 10ms. */
|
||||
data->vcnl4200_al.sampling_rate = ktime_set(0, 100000 * 1000);
|
||||
data->vcnl4200_ps.sampling_rate = ktime_set(0, 100000 * 1000);
|
||||
break;
|
||||
}
|
||||
data->vcnl4200_al.last_measurement = ktime_set(0, 0);
|
||||
data->vcnl4200_ps.last_measurement = ktime_set(0, 0);
|
||||
mutex_init(&data->vcnl4200_al.lock);
|
||||
|
@ -271,6 +300,12 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
|
|||
.measure_light = vcnl4000_measure_light,
|
||||
.measure_proximity = vcnl4000_measure_proximity,
|
||||
},
|
||||
[VCNL4040] = {
|
||||
.prod = "VCNL4040",
|
||||
.init = vcnl4200_init,
|
||||
.measure_light = vcnl4200_measure_light,
|
||||
.measure_proximity = vcnl4200_measure_proximity,
|
||||
},
|
||||
[VCNL4200] = {
|
||||
.prod = "VCNL4200",
|
||||
.init = vcnl4200_init,
|
||||
|
@ -363,9 +398,31 @@ static int vcnl4000_probe(struct i2c_client *client,
|
|||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id vcnl_4000_of_match[] = {
|
||||
{
|
||||
.compatible = "vishay,vcnl4000",
|
||||
.data = "VCNL4000",
|
||||
},
|
||||
{
|
||||
.compatible = "vishay,vcnl4010",
|
||||
.data = "VCNL4010",
|
||||
},
|
||||
{
|
||||
.compatible = "vishay,vcnl4010",
|
||||
.data = "VCNL4020",
|
||||
},
|
||||
{
|
||||
.compatible = "vishay,vcnl4200",
|
||||
.data = "VCNL4200",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
|
||||
|
||||
static struct i2c_driver vcnl4000_driver = {
|
||||
.driver = {
|
||||
.name = VCNL4000_DRV_NAME,
|
||||
.of_match_table = vcnl_4000_of_match,
|
||||
},
|
||||
.probe = vcnl4000_probe,
|
||||
.id_table = vcnl4000_id,
|
||||
|
|
|
@ -733,9 +733,8 @@ static int ak8974_probe(struct i2c_client *i2c,
|
|||
ak8974->i2c = i2c;
|
||||
mutex_init(&ak8974->lock);
|
||||
|
||||
ret = of_iio_read_mount_matrix(&i2c->dev,
|
||||
"mount-matrix",
|
||||
&ak8974->orientation);
|
||||
ret = iio_read_mount_matrix(&i2c->dev, "mount-matrix",
|
||||
&ak8974->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -746,12 +746,14 @@ static const struct iio_mount_matrix *
|
|||
ak8975_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
return &((struct ak8975_data *)iio_priv(indio_dev))->orientation;
|
||||
struct ak8975_data *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info ak8975_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8975_get_mount_matrix),
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
|
||||
#define AK8975_CHANNEL(axis, index) \
|
||||
|
@ -792,7 +794,7 @@ static const struct acpi_device_id ak_acpi_match[] = {
|
|||
{"AK09911", AK09911},
|
||||
{"AKM9911", AK09911},
|
||||
{"AK09912", AK09912},
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
|
||||
#endif
|
||||
|
@ -911,9 +913,8 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
data->eoc_irq = 0;
|
||||
|
||||
if (!pdata) {
|
||||
err = of_iio_read_mount_matrix(&client->dev,
|
||||
"mount-matrix",
|
||||
&data->orientation);
|
||||
err = iio_read_mount_matrix(&client->dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
if (err)
|
||||
return err;
|
||||
} else
|
||||
|
|
|
@ -143,6 +143,7 @@ struct bmc150_magn_data {
|
|||
*/
|
||||
struct mutex mutex;
|
||||
struct regmap *regmap;
|
||||
struct iio_mount_matrix orientation;
|
||||
/* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */
|
||||
s32 buffer[6];
|
||||
struct iio_trigger *dready_trig;
|
||||
|
@ -612,6 +613,20 @@ static ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev,
|
|||
return len;
|
||||
}
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
bmc150_magn_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct bmc150_magn_data *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info bmc150_magn_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_magn_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(bmc150_magn_show_samp_freq_avail);
|
||||
|
||||
static struct attribute *bmc150_magn_attributes[] = {
|
||||
|
@ -638,6 +653,7 @@ static const struct attribute_group bmc150_magn_attrs_group = {
|
|||
.storagebits = 32, \
|
||||
.endianness = IIO_LE \
|
||||
}, \
|
||||
.ext_info = bmc150_magn_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec bmc150_magn_channels[] = {
|
||||
|
@ -861,6 +877,11 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
|
|||
data->irq = irq;
|
||||
data->dev = dev;
|
||||
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!name && ACPI_HANDLE(dev))
|
||||
name = bmc150_magn_match_acpi_device(dev);
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ struct hmc5843_data {
|
|||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
const struct hmc5843_chip_info *variant;
|
||||
struct iio_mount_matrix orientation;
|
||||
__be16 buffer[8];
|
||||
};
|
||||
|
||||
|
|
|
@ -237,6 +237,15 @@ int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev,
|
|||
return hmc5843_set_meas_conf(data, meas_conf);
|
||||
}
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
hmc5843_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_enum hmc5843_meas_conf_enum = {
|
||||
.items = hmc5843_meas_conf_modes,
|
||||
.num_items = ARRAY_SIZE(hmc5843_meas_conf_modes),
|
||||
|
@ -247,7 +256,8 @@ static const struct iio_enum hmc5843_meas_conf_enum = {
|
|||
static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = {
|
||||
IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum),
|
||||
IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum),
|
||||
{ },
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct iio_enum hmc5983_meas_conf_enum = {
|
||||
|
@ -260,7 +270,8 @@ static const struct iio_enum hmc5983_meas_conf_enum = {
|
|||
static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = {
|
||||
IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum),
|
||||
IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum),
|
||||
{ },
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
static
|
||||
|
@ -635,6 +646,11 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
|
|||
data->variant = &hmc5843_chip_info_tbl[id];
|
||||
mutex_init(&data->lock);
|
||||
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->name = name;
|
||||
indio_dev->info = &hmc5843_info;
|
||||
|
|
|
@ -58,8 +58,13 @@ static const struct regmap_config hmc5843_i2c_regmap_config = {
|
|||
static int hmc5843_i2c_probe(struct i2c_client *cli,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *regmap = devm_regmap_init_i2c(cli,
|
||||
&hmc5843_i2c_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return hmc5843_common_probe(&cli->dev,
|
||||
devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config),
|
||||
regmap,
|
||||
id->driver_data, id->name);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ static const struct regmap_config hmc5843_spi_regmap_config = {
|
|||
static int hmc5843_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
struct regmap *regmap;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
spi->mode = SPI_MODE_3;
|
||||
|
@ -67,8 +68,12 @@ static int hmc5843_spi_probe(struct spi_device *spi)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return hmc5843_common_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config),
|
||||
regmap,
|
||||
id->driver_data, id->name);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,26 +26,26 @@ config DS1803
|
|||
module will be called ds1803.
|
||||
|
||||
config MAX5481
|
||||
tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for the Maxim
|
||||
MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer
|
||||
chips.
|
||||
tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for the Maxim
|
||||
MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer
|
||||
chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called max5481.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called max5481.
|
||||
|
||||
config MAX5487
|
||||
tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for the Maxim
|
||||
MAX5487, MAX5488, MAX5489 digital potentiometer
|
||||
chips.
|
||||
tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for the Maxim
|
||||
MAX5487, MAX5488, MAX5489 digital potentiometer
|
||||
chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called max5487.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called max5487.
|
||||
|
||||
config MCP4018
|
||||
tristate "Microchip MCP4017/18/19 Digital Potentiometer driver"
|
||||
|
|
|
@ -113,7 +113,7 @@ static int lmp91000_read(struct lmp91000_data *data, int channel, int *val)
|
|||
return -EINVAL;
|
||||
|
||||
/* delay till first temperature reading is complete */
|
||||
if ((state != channel) && (channel == LMP91000_REG_MODECN_TEMP))
|
||||
if (state != channel && channel == LMP91000_REG_MODECN_TEMP)
|
||||
usleep_range(3000, 4000);
|
||||
|
||||
data->chan_select = channel != LMP91000_REG_MODECN_3LEAD;
|
||||
|
@ -211,12 +211,11 @@ static int lmp91000_read_config(struct lmp91000_data *data)
|
|||
|
||||
ret = of_property_read_u32(np, "ti,tia-gain-ohm", &val);
|
||||
if (ret) {
|
||||
if (of_property_read_bool(np, "ti,external-tia-resistor"))
|
||||
val = 0;
|
||||
else {
|
||||
dev_err(dev, "no ti,tia-gain-ohm defined");
|
||||
if (!of_property_read_bool(np, "ti,external-tia-resistor")) {
|
||||
dev_err(dev, "no ti,tia-gain-ohm defined and external resistor not specified\n");
|
||||
return ret;
|
||||
}
|
||||
val = 0;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
@ -255,8 +254,8 @@ static int lmp91000_read_config(struct lmp91000_data *data)
|
|||
|
||||
regmap_write(data->regmap, LMP91000_REG_LOCK, 0);
|
||||
regmap_write(data->regmap, LMP91000_REG_TIACN, reg);
|
||||
regmap_write(data->regmap, LMP91000_REG_REFCN, LMP91000_REG_REFCN_EXT_REF
|
||||
| LMP91000_REG_REFCN_50_ZERO);
|
||||
regmap_write(data->regmap, LMP91000_REG_REFCN,
|
||||
LMP91000_REG_REFCN_EXT_REF | LMP91000_REG_REFCN_50_ZERO);
|
||||
regmap_write(data->regmap, LMP91000_REG_LOCK, 1);
|
||||
|
||||
return 0;
|
||||
|
@ -276,7 +275,6 @@ static int lmp91000_buffer_cb(const void *val, void *private)
|
|||
static const struct iio_trigger_ops lmp91000_trigger_ops = {
|
||||
};
|
||||
|
||||
|
||||
static int lmp91000_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct lmp91000_data *data = iio_priv(indio_dev);
|
||||
|
|
|
@ -164,6 +164,9 @@ static int bmp280_read_calib(struct bmp280_data *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Toss the temperature calibration data into the entropy pool */
|
||||
add_device_randomness(t_buf, sizeof(t_buf));
|
||||
|
||||
calib->T1 = le16_to_cpu(t_buf[T1]);
|
||||
calib->T2 = le16_to_cpu(t_buf[T2]);
|
||||
calib->T3 = le16_to_cpu(t_buf[T3]);
|
||||
|
@ -177,6 +180,9 @@ static int bmp280_read_calib(struct bmp280_data *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Toss the pressure calibration data into the entropy pool */
|
||||
add_device_randomness(p_buf, sizeof(p_buf));
|
||||
|
||||
calib->P1 = le16_to_cpu(p_buf[P1]);
|
||||
calib->P2 = le16_to_cpu(p_buf[P2]);
|
||||
calib->P3 = le16_to_cpu(p_buf[P3]);
|
||||
|
|
|
@ -1,19 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cros_ec_baro - Driver for barometer sensor behind CrosEC.
|
||||
*
|
||||
* Copyright (C) 2017 Google, Inc
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/common/cros_ec_sensors_core.h>
|
||||
|
|
|
@ -45,6 +45,18 @@ config LIDAR_LITE_V2
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called pulsedlight-lite-v2
|
||||
|
||||
config MB1232
|
||||
tristate "MaxSonar I2CXL family ultrasonic sensors"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y to build a driver for the ultrasonic sensors I2CXL of
|
||||
MaxBotix which have an i2c interface. It can be used to measure
|
||||
the distance of objects. Supported types are mb1202, mb1212,
|
||||
mb1222, mb1232, mb1242, mb7040, mb7137
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mb1232.
|
||||
|
||||
config RFD77402
|
||||
tristate "RFD77402 ToF sensor"
|
||||
depends on I2C
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
obj-$(CONFIG_AS3935) += as3935.o
|
||||
obj-$(CONFIG_ISL29501) += isl29501.o
|
||||
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
|
||||
obj-$(CONFIG_MB1232) += mb1232.o
|
||||
obj-$(CONFIG_RFD77402) += rfd77402.o
|
||||
obj-$(CONFIG_SRF04) += srf04.o
|
||||
obj-$(CONFIG_SRF08) += srf08.o
|
||||
|
|
|
@ -345,6 +345,14 @@ static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);
|
|||
#define AS3935_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static void as3935_stop_work(void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
|
||||
cancel_delayed_work_sync(&st->work);
|
||||
}
|
||||
|
||||
static int as3935_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
|
@ -368,7 +376,6 @@ static int as3935_probe(struct spi_device *spi)
|
|||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
mutex_init(&st->lock);
|
||||
INIT_DELAYED_WORK(&st->work, as3935_event_work);
|
||||
|
||||
ret = of_property_read_u32(np,
|
||||
"ams,tuning-capacitor-pf", &st->tune_cap);
|
||||
|
@ -414,22 +421,28 @@ static int as3935_probe(struct spi_device *spi)
|
|||
iio_trigger_set_drvdata(trig, indio_dev);
|
||||
trig->ops = &iio_interrupt_trigger_ops;
|
||||
|
||||
ret = iio_trigger_register(trig);
|
||||
ret = devm_iio_trigger_register(&spi->dev, trig);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to register trigger\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
|
||||
&as3935_trigger_handler, NULL);
|
||||
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
as3935_trigger_handler, NULL);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "cannot setup iio trigger\n");
|
||||
goto unregister_trigger;
|
||||
return ret;
|
||||
}
|
||||
|
||||
calibrate_as3935(st);
|
||||
|
||||
INIT_DELAYED_WORK(&st->work, as3935_event_work);
|
||||
ret = devm_add_action(&spi->dev, as3935_stop_work, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(&spi->dev, spi->irq,
|
||||
&as3935_interrupt_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
|
@ -438,35 +451,15 @@ static int as3935_probe(struct spi_device *spi)
|
|||
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "unable to request irq\n");
|
||||
goto unregister_buffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
ret = devm_iio_device_register(&spi->dev, indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "unable to register device\n");
|
||||
goto unregister_buffer;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
unregister_buffer:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
unregister_trigger:
|
||||
iio_trigger_unregister(st->trig);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as3935_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
iio_trigger_unregister(st->trig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id as3935_of_match[] = {
|
||||
|
@ -488,7 +481,6 @@ static struct spi_driver as3935_driver = {
|
|||
.pm = AS3935_PM_OPS,
|
||||
},
|
||||
.probe = as3935_probe,
|
||||
.remove = as3935_remove,
|
||||
.id_table = as3935_id,
|
||||
};
|
||||
module_spi_driver(as3935_driver);
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* mb1232.c - Support for MaxBotix I2CXL-MaxSonar-EZ series ultrasonic
|
||||
* ranger with i2c interface
|
||||
* actually tested with mb1232 type
|
||||
*
|
||||
* Copyright (c) 2019 Andreas Klinger <ak@it-klinger.de>
|
||||
*
|
||||
* For details about the device see:
|
||||
* https://www.maxbotix.com/documents/I2CXL-MaxSonar-EZ_Datasheet.pdf
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
/* registers of MaxSonar device */
|
||||
#define MB1232_RANGE_COMMAND 0x51 /* Command for reading range */
|
||||
#define MB1232_ADDR_UNLOCK_1 0xAA /* Command 1 for changing address */
|
||||
#define MB1232_ADDR_UNLOCK_2 0xA5 /* Command 2 for changing address */
|
||||
|
||||
struct mb1232_data {
|
||||
struct i2c_client *client;
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
/*
|
||||
* optionally a gpio can be used to announce when ranging has
|
||||
* finished
|
||||
* since we are just using the falling trigger of it we request
|
||||
* only the interrupt for announcing when data is ready to be read
|
||||
*/
|
||||
struct completion ranging;
|
||||
int irqnr;
|
||||
};
|
||||
|
||||
static irqreturn_t mb1232_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_id;
|
||||
struct mb1232_data *data = iio_priv(indio_dev);
|
||||
|
||||
complete(&data->ranging);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static s16 mb1232_read_distance(struct mb1232_data *data)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
s16 distance;
|
||||
__be16 buf;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
reinit_completion(&data->ranging);
|
||||
|
||||
ret = i2c_smbus_write_byte(client, MB1232_RANGE_COMMAND);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "write command - err: %d\n", ret);
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
if (data->irqnr >= 0) {
|
||||
/* it cannot take more than 100 ms */
|
||||
ret = wait_for_completion_killable_timeout(&data->ranging,
|
||||
HZ/10);
|
||||
if (ret < 0)
|
||||
goto error_unlock;
|
||||
else if (ret == 0) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto error_unlock;
|
||||
}
|
||||
} else {
|
||||
/* use simple sleep if announce irq is not connected */
|
||||
msleep(15);
|
||||
}
|
||||
|
||||
ret = i2c_master_recv(client, (char *)&buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "i2c_master_recv: ret=%d\n", ret);
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
distance = __be16_to_cpu(buf);
|
||||
/* check for not returning misleading error codes */
|
||||
if (distance < 0) {
|
||||
dev_err(&client->dev, "distance=%d\n", distance);
|
||||
ret = -EINVAL;
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return distance;
|
||||
|
||||
error_unlock:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t mb1232_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct mb1232_data *data = iio_priv(indio_dev);
|
||||
/*
|
||||
* triggered buffer
|
||||
* 16-bit channel + 48-bit padding + 64-bit timestamp
|
||||
*/
|
||||
s16 buffer[8] = { 0 };
|
||||
|
||||
buffer[0] = mb1232_read_distance(data);
|
||||
if (buffer[0] < 0)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
|
||||
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mb1232_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *channel, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct mb1232_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (channel->type != IIO_DISTANCE)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = mb1232_read_distance(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
/* 1 LSB is 1 cm */
|
||||
*val = 0;
|
||||
*val2 = 10000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mb1232_channels[] = {
|
||||
{
|
||||
.type = IIO_DISTANCE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
};
|
||||
|
||||
static const struct iio_info mb1232_info = {
|
||||
.read_raw = mb1232_read_raw,
|
||||
};
|
||||
|
||||
static int mb1232_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct mb1232_data *data;
|
||||
int ret;
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_BYTE |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
indio_dev->info = &mb1232_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = mb1232_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mb1232_channels);
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
init_completion(&data->ranging);
|
||||
|
||||
data->irqnr = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (data->irqnr <= 0) {
|
||||
/* usage of interrupt is optional */
|
||||
data->irqnr = -1;
|
||||
} else {
|
||||
ret = devm_request_irq(dev, data->irqnr, mb1232_handle_irq,
|
||||
IRQF_TRIGGER_FALLING, id->name, indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "request_irq: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time, mb1232_trigger_handler, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "setup of iio triggered buffer failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id of_mb1232_match[] = {
|
||||
{ .compatible = "maxbotix,mb1202", },
|
||||
{ .compatible = "maxbotix,mb1212", },
|
||||
{ .compatible = "maxbotix,mb1222", },
|
||||
{ .compatible = "maxbotix,mb1232", },
|
||||
{ .compatible = "maxbotix,mb1242", },
|
||||
{ .compatible = "maxbotix,mb7040", },
|
||||
{ .compatible = "maxbotix,mb7137", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, of_mb1232_match);
|
||||
|
||||
static const struct i2c_device_id mb1232_id[] = {
|
||||
{ "maxbotix-mb1202", },
|
||||
{ "maxbotix-mb1212", },
|
||||
{ "maxbotix-mb1222", },
|
||||
{ "maxbotix-mb1232", },
|
||||
{ "maxbotix-mb1242", },
|
||||
{ "maxbotix-mb7040", },
|
||||
{ "maxbotix-mb7137", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mb1232_id);
|
||||
|
||||
static struct i2c_driver mb1232_driver = {
|
||||
.driver = {
|
||||
.name = "maxbotix-mb1232",
|
||||
.of_match_table = of_mb1232_match,
|
||||
},
|
||||
.probe = mb1232_probe,
|
||||
.id_table = mb1232_id,
|
||||
};
|
||||
module_i2c_driver(mb1232_driver);
|
||||
|
||||
MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
|
||||
MODULE_DESCRIPTION("Maxbotix I2CXL-MaxSonar i2c ultrasonic ranger driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -66,14 +66,14 @@ config TMP006
|
|||
be called tmp006.
|
||||
|
||||
config TMP007
|
||||
tristate "TMP007 infrared thermopile sensor with Integrated Math Engine"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Texas Instruments
|
||||
TMP007 infrared thermopile sensor with Integrated Math Engine.
|
||||
tristate "TMP007 infrared thermopile sensor with Integrated Math Engine"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Texas Instruments
|
||||
TMP007 infrared thermopile sensor with Integrated Math Engine.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called tmp007.
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called tmp007.
|
||||
|
||||
config TSYS01
|
||||
tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
|
||||
|
@ -97,4 +97,14 @@ config TSYS02D
|
|||
This driver can also be built as a module. If so, the module will
|
||||
be called tsys02d.
|
||||
|
||||
config MAX31856
|
||||
tristate "MAX31856 thermocouple sensor"
|
||||
depends on SPI
|
||||
help
|
||||
If you say yes here you get support for MAX31856
|
||||
thermocouple sensor chip connected via SPI.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max31856.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
|
||||
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
|
||||
obj-$(CONFIG_MAX31856) += max31856.o
|
||||
obj-$(CONFIG_MLX90614) += mlx90614.o
|
||||
obj-$(CONFIG_MLX90632) += mlx90632.o
|
||||
obj-$(CONFIG_TMP006) += tmp006.o
|
||||
|
|
|
@ -0,0 +1,353 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* max31856.c
|
||||
*
|
||||
* Maxim MAX31856 thermocouple sensor driver
|
||||
*
|
||||
* Copyright (C) 2018-2019 Rockwell Collins
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <dt-bindings/iio/temperature/thermocouple.h>
|
||||
/*
|
||||
* The MSB of the register value determines whether the following byte will
|
||||
* be written or read. If it is 0, one or more byte reads will follow.
|
||||
*/
|
||||
#define MAX31856_RD_WR_BIT BIT(7)
|
||||
|
||||
#define MAX31856_CR0_AUTOCONVERT BIT(7)
|
||||
#define MAX31856_CR0_1SHOT BIT(6)
|
||||
#define MAX31856_CR0_OCFAULT BIT(4)
|
||||
#define MAX31856_CR0_OCFAULT_MASK GENMASK(5, 4)
|
||||
#define MAX31856_TC_TYPE_MASK GENMASK(3, 0)
|
||||
#define MAX31856_FAULT_OVUV BIT(1)
|
||||
#define MAX31856_FAULT_OPEN BIT(0)
|
||||
|
||||
/* The MAX31856 registers */
|
||||
#define MAX31856_CR0_REG 0x00
|
||||
#define MAX31856_CR1_REG 0x01
|
||||
#define MAX31856_MASK_REG 0x02
|
||||
#define MAX31856_CJHF_REG 0x03
|
||||
#define MAX31856_CJLF_REG 0x04
|
||||
#define MAX31856_LTHFTH_REG 0x05
|
||||
#define MAX31856_LTHFTL_REG 0x06
|
||||
#define MAX31856_LTLFTH_REG 0x07
|
||||
#define MAX31856_LTLFTL_REG 0x08
|
||||
#define MAX31856_CJTO_REG 0x09
|
||||
#define MAX31856_CJTH_REG 0x0A
|
||||
#define MAX31856_CJTL_REG 0x0B
|
||||
#define MAX31856_LTCBH_REG 0x0C
|
||||
#define MAX31856_LTCBM_REG 0x0D
|
||||
#define MAX31856_LTCBL_REG 0x0E
|
||||
#define MAX31856_SR_REG 0x0F
|
||||
|
||||
static const struct iio_chan_spec max31856_channels[] = {
|
||||
{ /* Thermocouple Temperature */
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{ /* Cold Junction Temperature */
|
||||
.type = IIO_TEMP,
|
||||
.channel2 = IIO_MOD_TEMP_AMBIENT,
|
||||
.modified = 1,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
};
|
||||
|
||||
struct max31856_data {
|
||||
struct spi_device *spi;
|
||||
u32 thermocouple_type;
|
||||
};
|
||||
|
||||
static int max31856_read(struct max31856_data *data, u8 reg,
|
||||
u8 val[], unsigned int read_size)
|
||||
{
|
||||
return spi_write_then_read(data->spi, ®, 1, val, read_size);
|
||||
}
|
||||
|
||||
static int max31856_write(struct max31856_data *data, u8 reg,
|
||||
unsigned int val)
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
buf[0] = reg | (MAX31856_RD_WR_BIT);
|
||||
buf[1] = val;
|
||||
|
||||
return spi_write(data->spi, buf, 2);
|
||||
}
|
||||
|
||||
static int max31856_init(struct max31856_data *data)
|
||||
{
|
||||
int ret;
|
||||
u8 reg_cr0_val, reg_cr1_val;
|
||||
|
||||
/* Start by changing to Off mode before making changes as
|
||||
* some settings are recommended to be set only when the device
|
||||
* is off
|
||||
*/
|
||||
ret = max31856_read(data, MAX31856_CR0_REG, ®_cr0_val, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg_cr0_val &= ~MAX31856_CR0_AUTOCONVERT;
|
||||
ret = max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set thermocouple type based on dts property */
|
||||
ret = max31856_read(data, MAX31856_CR1_REG, ®_cr1_val, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg_cr1_val &= ~MAX31856_TC_TYPE_MASK;
|
||||
reg_cr1_val |= data->thermocouple_type;
|
||||
ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Enable Open circuit fault detection
|
||||
* Read datasheet for more information: Table 4.
|
||||
* Value 01 means : Enabled (Once every 16 conversions)
|
||||
*/
|
||||
reg_cr0_val &= ~MAX31856_CR0_OCFAULT_MASK;
|
||||
reg_cr0_val |= MAX31856_CR0_OCFAULT;
|
||||
|
||||
/* Set Auto Conversion Mode */
|
||||
reg_cr0_val &= ~MAX31856_CR0_1SHOT;
|
||||
reg_cr0_val |= MAX31856_CR0_AUTOCONVERT;
|
||||
|
||||
return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
|
||||
}
|
||||
|
||||
static int max31856_thermocouple_read(struct max31856_data *data,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val)
|
||||
{
|
||||
int ret, offset_cjto;
|
||||
u8 reg_val[3];
|
||||
|
||||
switch (chan->channel2) {
|
||||
case IIO_NO_MOD:
|
||||
/*
|
||||
* Multibyte Read
|
||||
* MAX31856_LTCBH_REG, MAX31856_LTCBM_REG, MAX31856_LTCBL_REG
|
||||
*/
|
||||
ret = max31856_read(data, MAX31856_LTCBH_REG, reg_val, 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Skip last 5 dead bits of LTCBL */
|
||||
*val = (reg_val[0] << 16 | reg_val[1] << 8 | reg_val[2]) >> 5;
|
||||
/* Check 7th bit of LTCBH reg. value for sign*/
|
||||
if (reg_val[0] & 0x80)
|
||||
*val -= 0x80000;
|
||||
break;
|
||||
|
||||
case IIO_MOD_TEMP_AMBIENT:
|
||||
/*
|
||||
* Multibyte Read
|
||||
* MAX31856_CJTO_REG, MAX31856_CJTH_REG, MAX31856_CJTL_REG
|
||||
*/
|
||||
ret = max31856_read(data, MAX31856_CJTO_REG, reg_val, 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Get Cold Junction Temp. offset register value */
|
||||
offset_cjto = reg_val[0];
|
||||
/* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */
|
||||
*val = (reg_val[1] << 8 | reg_val[2]) >> 2;
|
||||
/* As per datasheet add offset into CJTH and CJTL */
|
||||
*val += offset_cjto;
|
||||
/* Check 7th bit of CJTH reg. value for sign */
|
||||
if (reg_val[1] & 0x80)
|
||||
*val -= 0x4000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = max31856_read(data, MAX31856_SR_REG, reg_val, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Check for over/under voltage or open circuit fault */
|
||||
if (reg_val[0] & (MAX31856_FAULT_OVUV | MAX31856_FAULT_OPEN))
|
||||
return -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max31856_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct max31856_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = max31856_thermocouple_read(data, chan, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_TEMP_AMBIENT:
|
||||
/* Cold junction Temp. Data resolution is 0.015625 */
|
||||
*val = 15;
|
||||
*val2 = 625000; /* 1000 * 0.015625 */
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
default:
|
||||
/* Thermocouple Temp. Data resolution is 0.0078125 */
|
||||
*val = 7;
|
||||
*val2 = 812500; /* 1000 * 0.0078125) */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct max31856_data *data = iio_priv(indio_dev);
|
||||
u8 reg_val;
|
||||
int ret;
|
||||
bool fault;
|
||||
|
||||
ret = max31856_read(data, MAX31856_SR_REG, ®_val, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fault = reg_val & faultbit;
|
||||
|
||||
return sprintf(buf, "%d\n", fault);
|
||||
}
|
||||
|
||||
static ssize_t show_fault_ovuv(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return show_fault(dev, MAX31856_FAULT_OVUV, buf);
|
||||
}
|
||||
|
||||
static ssize_t show_fault_oc(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return show_fault(dev, MAX31856_FAULT_OPEN, buf);
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
|
||||
static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
|
||||
|
||||
static struct attribute *max31856_attributes[] = {
|
||||
&iio_dev_attr_fault_ovuv.dev_attr.attr,
|
||||
&iio_dev_attr_fault_oc.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group max31856_group = {
|
||||
.attrs = max31856_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info max31856_info = {
|
||||
.read_raw = max31856_read_raw,
|
||||
.attrs = &max31856_group,
|
||||
};
|
||||
|
||||
static int max31856_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct iio_dev *indio_dev;
|
||||
struct max31856_data *data;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->spi = spi;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->info = &max31856_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = max31856_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(max31856_channels);
|
||||
|
||||
ret = of_property_read_u32(spi->dev.of_node, "thermocouple-type",
|
||||
&data->thermocouple_type);
|
||||
|
||||
if (ret) {
|
||||
dev_info(&spi->dev,
|
||||
"Could not read thermocouple type DT property, configuring as a K-Type\n");
|
||||
data->thermocouple_type = THERMOCOUPLE_TYPE_K;
|
||||
}
|
||||
|
||||
/*
|
||||
* no need to translate values as the supported types
|
||||
* have the same value as the #defines
|
||||
*/
|
||||
switch (data->thermocouple_type) {
|
||||
case THERMOCOUPLE_TYPE_B:
|
||||
case THERMOCOUPLE_TYPE_E:
|
||||
case THERMOCOUPLE_TYPE_J:
|
||||
case THERMOCOUPLE_TYPE_K:
|
||||
case THERMOCOUPLE_TYPE_N:
|
||||
case THERMOCOUPLE_TYPE_R:
|
||||
case THERMOCOUPLE_TYPE_S:
|
||||
case THERMOCOUPLE_TYPE_T:
|
||||
break;
|
||||
default:
|
||||
dev_err(&spi->dev,
|
||||
"error: thermocouple-type %u not supported by max31856\n"
|
||||
, data->thermocouple_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = max31856_init(data);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "error: Failed to configure max31856\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id max31856_id[] = {
|
||||
{ "max31856", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max31856_id);
|
||||
|
||||
static const struct of_device_id max31856_of_match[] = {
|
||||
{ .compatible = "maxim,max31856" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max31856_of_match);
|
||||
|
||||
static struct spi_driver max31856_driver = {
|
||||
.driver = {
|
||||
.name = "max31856",
|
||||
.of_match_table = max31856_of_match,
|
||||
},
|
||||
.probe = max31856_probe,
|
||||
.id_table = max31856_id,
|
||||
};
|
||||
module_spi_driver(max31856_driver);
|
||||
|
||||
MODULE_AUTHOR("Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>");
|
||||
MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>");
|
||||
MODULE_DESCRIPTION("Maxim MAX31856 thermocouple sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -60,7 +60,7 @@ static int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state)
|
|||
if (state) {
|
||||
loop_trig->task = kthread_run(iio_loop_thread,
|
||||
trig, trig->name);
|
||||
if (unlikely(IS_ERR(loop_trig->task))) {
|
||||
if (IS_ERR(loop_trig->task)) {
|
||||
dev_err(&trig->dev,
|
||||
"failed to create trigger loop thread\n");
|
||||
return PTR_ERR(loop_trig->task);
|
||||
|
|
|
@ -4,19 +4,6 @@
|
|||
#
|
||||
menu "Analog to digital converters"
|
||||
|
||||
config AD7780
|
||||
tristate "Analog Devices AD7780 and similar ADCs driver"
|
||||
depends on SPI
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
select AD_SIGMA_DELTA
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7170, AD7171,
|
||||
AD7780 and AD7781 SPI analog to digital converters (ADC).
|
||||
If unsure, say N (but it's safe to say "Y").
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7780.
|
||||
|
||||
config AD7816
|
||||
tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver"
|
||||
depends on SPI
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue