mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
Second set of IIO + counter new device support, features etc for the 5.5 cycle.
Note two merge commits in here, both for immutable branches based of 5.4-rc1. 1. Ti eqep driver because of some file moves in precursor patches. I suspect no one else will pull this one. 2. ab8500 refactor as changes in power supply, hwmon and mfd trees. This may come via numerous trees as well as IIO. Counter subsystem related * ti eqep - New device support with bindings. - Includes prior file move to reflect more general use of ti-pwmss. * Counter core - simplify count_read and count_write callbacks + document change. - fix a typo in docs. Various subsystems related * AB8500 - ab8500_btemp driver converted to be an IIO consumer driver. - ab8500_charger driver converted to be an IIO consumer driver. - ab8500_fg fuel gauge driver converted to be an IIO consumer driver. - ab8500 hwmon driver converted to be an IIO consumer driver. - mfd bindings augmented with the adc channels to make the above work. - drop original mfd driver. New device support * ab8500 - new ADC driver used by the above other subystems via the IIO consumer interface. * adux1020 photometric sensor - new driver and dt bindings. * fxos877cq - new driver for this simple(ish) IMU with DT bindings. * intel_mrfld_adc - new driver for the ADC found on Intel Merrifield platforms. * ltc2983 - new driver for this multi-sensor type temperature interface. Includes complex DT bindings. * max1027 - support for 12 bit devices, max1227, max1229 and max1231 + add to trivial bindings. * st_lsm6dsx - support for the LSM6DS0 6 axis MEMs sensor. Note different from the LSM6DSO which the driver already supports *sigh* - support for the LSM6DSRX 6 axis MEMs sensor. Features and cleanups * ad7303 - replace use of core mlock with a local lock with cleanly defined scope. * ad9834 - add a check for devm_clk_get failing. * at91-sama5d2 - tidy up a 0 as NULL warning. * bmp280 - endian type tidy ups. - use bulk regulator ops for a small reduction in code. - use devm_add_action... to simplify error path handling. * exynos - drop stray semicolon. - use devm_platform_ioremap_resource to reduce boilerplate. * hx711 - various tricks to improve the frequency of read out possible. * max1027 - debugfs support. - make interrupts optional. - reset at probe to get clean state. - refactors to allow addition of new device support. * maxim thermocouple - drop an unneeded semicolon. * mb1232 - yaml binding conversion. * mcp320x - tidy up an endian types in cast warning. * meson_saradc - use devm_platform_ioremap_resource to reduce boilerplate. * mpu3050 - make a poison value explicity big endian to supress a warning. * pulsedlight v2 - endian type tidy ups. * sgp30 - drop an excess semicolon. * sps30 - make truncation explicit with masking to clean up a warning. * st sensors - drop gpio include as none of these support gpios. * st_lsm6dsx - tidy up some alignment issues. - refactors to allow addition of new device support. * allow varients of irq related reg definitions. * avoid accessing active-low, open-drain regs if not provided. * allow varients of bdu/boot and reset regs. * allow for enabling or disabling wakeup sources through platform data (seems someone still uses this). - enable wake-up events for LSM6DS0 - use the drdy mask to avoid some invalid samples during initial start of sensor. - Add support to trim the timestamp. * stm32_adc - kernel-doc fixes. * stm32_dac - power management support. * stmpe-adc - Fix endian type of local variable. * twl4030 - use false / true instead of 0 / 1 for booleans. * xilinx-xadc - use devm_platform_ioremap_resouce to reduce boilerplate. * zpa2326 - reorganise buffer handling setup to be more consistent. Fixes (mostly recent additions) * cpcap-adc - Fix mising IRQF_ONESHOT that would cause warnings to be printed. * st_lsm6dsx - Sanity check the read_fifo pointer is set. - use locked read and update functions to prevent some races. - avoid accessing enable_reg if not provided. - take a lock to prevent a race in updating the config. - kernel-doc fixes. - document wakeup-source property in dt binding. - fix lsm9ds1 gyro gain definitions. -----BEGIN PGP SIGNATURE----- iQJEBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAl27PN8RHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FojRzA/4svFkyp9+08sZxYN3Z6enw6VwS+OxgVXx ikM+j6Wny/kv71yhALoU0SY/GzWnqpudz9SUKVUgXGhOZbG7mJLYx9Ahk1/g2zrI wHVwO+PZIxBHUtpewKmcB+uVpaCfXGH6Bu9XYtefnhB1LeGbgS1UQ8q0RbveIyZ6 sI1cOY7rMr0Sfzf+MgPuZ5sceLDXUuLRgTCro0hHSo8IVG1+raE37UMbmlQ8EYVl 8gEHoeBrjM4ky8SX+DRyDjxfdgK/am6jqJhOrgmq72+/ltaytz8RaTs/X17GTi6J Jii2ODxdfUoxyN0/C57/2iTuL/yXmsEm7nKNdc3VFyjDiUlBs/kSgXpXTX2g3q8m SVG0OYHPfJlkwWkSKF463hD5hZ29yBwUNKKyQPwGD4x8+hs8xcw7Zx+KUu/PRkjW iZmiQksbJUgU1n8IMINz0NeHCbtI1psfMv+ZnNKwxlPWczYducLNfYPJbhdjuUpT Mi5r1An4xpSrlKgwr3JLsXetJLNxvCxbqQQq9kMZW2CF+tBuLhUJMd/7KDrfUQ/P wyWJ5TxlVA05ZwsuIWW+gCsQuXTDb6w2y0s9YxjiAUpRP3VAUZhZVWG5VWyxxfr/ zCx+GT7NSPh70ActiUWrHOyB6zzGeIo8SVX43e7sxdmNkyPK2/d+24u/GOVBP7hg hGQ9Ra8JoA== =zfsO -----END PGP SIGNATURE----- Merge tag 'iio-for-5.5b' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Second set of IIO + counter new device support, features etc for the 5.5 cycle. Note two merge commits in here, both for immutable branches based of 5.4-rc1. 1. Ti eqep driver because of some file moves in precursor patches. I suspect no one else will pull this one. 2. ab8500 refactor as changes in power supply, hwmon and mfd trees. This may come via numerous trees as well as IIO. Counter subsystem related * ti eqep - New device support with bindings. - Includes prior file move to reflect more general use of ti-pwmss. * Counter core - simplify count_read and count_write callbacks + document change. - fix a typo in docs. Various subsystems related * AB8500 - ab8500_btemp driver converted to be an IIO consumer driver. - ab8500_charger driver converted to be an IIO consumer driver. - ab8500_fg fuel gauge driver converted to be an IIO consumer driver. - ab8500 hwmon driver converted to be an IIO consumer driver. - mfd bindings augmented with the adc channels to make the above work. - drop original mfd driver. New device support * ab8500 - new ADC driver used by the above other subystems via the IIO consumer interface. * adux1020 photometric sensor - new driver and dt bindings. * fxos877cq - new driver for this simple(ish) IMU with DT bindings. * intel_mrfld_adc - new driver for the ADC found on Intel Merrifield platforms. * ltc2983 - new driver for this multi-sensor type temperature interface. Includes complex DT bindings. * max1027 - support for 12 bit devices, max1227, max1229 and max1231 + add to trivial bindings. * st_lsm6dsx - support for the LSM6DS0 6 axis MEMs sensor. Note different from the LSM6DSO which the driver already supports *sigh* - support for the LSM6DSRX 6 axis MEMs sensor. Features and cleanups * ad7303 - replace use of core mlock with a local lock with cleanly defined scope. * ad9834 - add a check for devm_clk_get failing. * at91-sama5d2 - tidy up a 0 as NULL warning. * bmp280 - endian type tidy ups. - use bulk regulator ops for a small reduction in code. - use devm_add_action... to simplify error path handling. * exynos - drop stray semicolon. - use devm_platform_ioremap_resource to reduce boilerplate. * hx711 - various tricks to improve the frequency of read out possible. * max1027 - debugfs support. - make interrupts optional. - reset at probe to get clean state. - refactors to allow addition of new device support. * maxim thermocouple - drop an unneeded semicolon. * mb1232 - yaml binding conversion. * mcp320x - tidy up an endian types in cast warning. * meson_saradc - use devm_platform_ioremap_resource to reduce boilerplate. * mpu3050 - make a poison value explicity big endian to supress a warning. * pulsedlight v2 - endian type tidy ups. * sgp30 - drop an excess semicolon. * sps30 - make truncation explicit with masking to clean up a warning. * st sensors - drop gpio include as none of these support gpios. * st_lsm6dsx - tidy up some alignment issues. - refactors to allow addition of new device support. * allow varients of irq related reg definitions. * avoid accessing active-low, open-drain regs if not provided. * allow varients of bdu/boot and reset regs. * allow for enabling or disabling wakeup sources through platform data (seems someone still uses this). - enable wake-up events for LSM6DS0 - use the drdy mask to avoid some invalid samples during initial start of sensor. - Add support to trim the timestamp. * stm32_adc - kernel-doc fixes. * stm32_dac - power management support. * stmpe-adc - Fix endian type of local variable. * twl4030 - use false / true instead of 0 / 1 for booleans. * xilinx-xadc - use devm_platform_ioremap_resouce to reduce boilerplate. * zpa2326 - reorganise buffer handling setup to be more consistent. Fixes (mostly recent additions) * cpcap-adc - Fix mising IRQF_ONESHOT that would cause warnings to be printed. * st_lsm6dsx - Sanity check the read_fifo pointer is set. - use locked read and update functions to prevent some races. - avoid accessing enable_reg if not provided. - take a lock to prevent a race in updating the config. - kernel-doc fixes. - document wakeup-source property in dt binding. - fix lsm9ds1 gyro gain definitions. * tag 'iio-for-5.5b' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (73 commits) dt-bindings: iio: imu: st_lsm6dsx: add lsm6dsrx device bindings iio: imu: st_lsm6dsx: add support to LSM6DSRX iio: st: Drop GPIO include iio: adc: hx711: optimize performance in read cycle iio: adc: stm32-adc: fix kernel-doc warnings iio: pressure: zpa2326: fix iio_triggered_buffer_postenable position iio: chemical: sgp30: drop excess semicolon iio: adc: twl4030: Use false / true instead of 0 / 1 with booleans dt-bindings: iio: Add ltc2983 documentation iio: temperature: Add support for LTC2983 iio: pressure: bmp280: use devm action and remove labels from probe iio: pressure: bmp280: use bulk regulator ops iio: imu: Add support for the FXOS8700 IMU dt-bindings: iio: imu: add fxos8700 imu binding staging: iio: ad9834: add a check for devm_clk_get iio: adc: xilinx-xadc: use devm_platform_ioremap_resource iio: temp: maxim thermocouple: Drop unneeded semi colon. iio: adc: cpcap-adc: Fix missing IRQF_ONESHOT as only threaded handler. iio: adc: meson_saradc: use devm_platform_ioremap_resource iio: adc: exynos: use devm_platform_ioremap_resource ...
This commit is contained in:
commit
ebc8f4f603
50
Documentation/devicetree/bindings/counter/ti-eqep.yaml
Normal file
50
Documentation/devicetree/bindings/counter/ti-eqep.yaml
Normal file
@ -0,0 +1,50 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/counter/ti-eqep.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP) Module
|
||||
|
||||
maintainers:
|
||||
- David Lechner <david@lechnology.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ti,am3352-eqep
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: The eQEP event interrupt
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: The clock that determines the SYSCLKOUT rate for the eQEP
|
||||
peripheral.
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: sysclkout
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
eqep0: counter@180 {
|
||||
compatible = "ti,am3352-eqep";
|
||||
reg = <0x180 0x80>;
|
||||
clocks = <&l4ls_gclk>;
|
||||
clock-names = "sysclkout";
|
||||
interrupts = <79>;
|
||||
};
|
||||
|
||||
...
|
@ -1,20 +0,0 @@
|
||||
* Maxim 1027/1029/1031 Analog to Digital Converter (ADC)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "maxim,max1027" or "maxim,max1029" or "maxim,max1031"
|
||||
- reg: SPI chip select number for the device
|
||||
- interrupts: IRQ line for the ADC
|
||||
see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "maxim,max1027";
|
||||
reg = <0>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <15 IRQ_TYPE_EDGE_RISING>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
76
Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml
Normal file
76
Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml
Normal file
@ -0,0 +1,76 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/imu/nxp,fxos8700.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale FXOS8700 Inertial Measurement Unit
|
||||
|
||||
maintainers:
|
||||
- Robert Jones <rjones@gateworks.com>
|
||||
|
||||
description: |
|
||||
Accelerometer and magnetometer combo device with an i2c and SPI interface.
|
||||
https://www.nxp.com/products/sensors/motion-sensors/6-axis/digital-motion-sensor-3d-accelerometer-2g-4g-8g-plus-3d-magnetometer:FXOS8700CQ
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nxp,fxos8700
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
enum:
|
||||
- INT1
|
||||
- INT2
|
||||
|
||||
drive-open-drain:
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fxos8700@1e {
|
||||
compatible = "nxp,fxos8700";
|
||||
reg = <0x1e>;
|
||||
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "INT1";
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fxos8700@0 {
|
||||
compatible = "nxp,fxos8700";
|
||||
reg = <0>;
|
||||
|
||||
spi-max-frequency = <1000000>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "INT2";
|
||||
};
|
||||
};
|
@ -14,6 +14,8 @@ Required properties:
|
||||
"st,lsm6ds3tr-c"
|
||||
"st,ism330dhcx"
|
||||
"st,lsm9ds1-imu"
|
||||
"st,lsm6ds0"
|
||||
"st,lsm6dsrx"
|
||||
- reg: i2c address of the sensor / spi cs line
|
||||
|
||||
Optional properties:
|
||||
@ -31,6 +33,7 @@ Optional properties:
|
||||
- interrupts: interrupt mapping for IRQ. It should be configured with
|
||||
flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
|
||||
IRQ_TYPE_EDGE_FALLING.
|
||||
- wakeup-source: Enables wake up of host system on event.
|
||||
|
||||
Refer to interrupt-controller/interrupts.txt for generic interrupt
|
||||
client node bindings.
|
||||
|
47
Documentation/devicetree/bindings/iio/light/adux1020.yaml
Normal file
47
Documentation/devicetree/bindings/iio/light/adux1020.yaml
Normal file
@ -0,0 +1,47 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/adux1020.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices ADUX1020 Photometric sensor
|
||||
|
||||
maintainers:
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
description: |
|
||||
Photometric sensor over an i2c interface.
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ADUX1020.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adux1020
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adux1020@64 {
|
||||
compatible = "adi,adux1020";
|
||||
reg = <0x64>;
|
||||
interrupt-parent = <&msmgpio>;
|
||||
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,29 +0,0 @@
|
||||
* 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,60 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/proximity/maxbotix,mb1232.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MaxBotix I2CXL-MaxSonar ultrasonic distance sensor
|
||||
|
||||
maintainers:
|
||||
- Andreas Klinger <ak@it-klinger.de>
|
||||
|
||||
description: |
|
||||
MaxBotix I2CXL-MaxSonar ultrasonic distance sensor of type mb1202,
|
||||
mb1212, mb1222, mb1232, mb1242, mb7040 or mb7137 using the i2c interface
|
||||
for ranging
|
||||
|
||||
Specifications about the devices can be found at:
|
||||
https://www.maxbotix.com/documents/I2CXL-MaxSonar-EZ_Datasheet.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxbotix,mb1202
|
||||
- maxbotix,mb1212
|
||||
- maxbotix,mb1222
|
||||
- maxbotix,mb1232
|
||||
- maxbotix,mb1242
|
||||
- maxbotix,mb7040
|
||||
- maxbotix,mb7137
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
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.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
proximity@70 {
|
||||
compatible = "maxbotix,mb1232";
|
||||
reg = <0x70>;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
@ -0,0 +1,480 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/temperature/adi,ltc2983.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices LTC2983 Multi-sensor Temperature system
|
||||
|
||||
maintainers:
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices LTC2983 Multi-Sensor Digital Temperature Measurement System
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/2983fc.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ltc2983
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
adi,mux-delay-config-us:
|
||||
description:
|
||||
The LTC2983 performs 2 or 3 internal conversion cycles per temperature
|
||||
result. Each conversion cycle is performed with different excitation and
|
||||
input multiplexer configurations. Prior to each conversion, these
|
||||
excitation circuits and input switch configurations are changed and an
|
||||
internal 1ms delay ensures settling prior to the conversion cycle in most
|
||||
cases. An extra delay can be configured using this property. The value is
|
||||
rounded to nearest 100us.
|
||||
maximum: 255
|
||||
|
||||
adi,filter-notch-freq:
|
||||
description:
|
||||
Set's the default setting of the digital filter. The default is
|
||||
simultaneous 50/60Hz rejection.
|
||||
0 - 50/60Hz rejection
|
||||
1 - 60Hz rejection
|
||||
2 - 50Hz rejection
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- minimum: 0
|
||||
maximum: 2
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"@([1-9]|1[0-9]|20)$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
The channel number. It can be connected to one of the 20 channels of
|
||||
the device.
|
||||
minimum: 1
|
||||
maximum: 20
|
||||
|
||||
adi,sensor-type:
|
||||
description: Identifies the type of sensor connected to the device.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
required:
|
||||
- reg
|
||||
- adi,sensor-type
|
||||
|
||||
"^thermocouple@":
|
||||
type: object
|
||||
description:
|
||||
Represents a thermocouple sensor which is connected to one of the device
|
||||
channels.
|
||||
|
||||
properties:
|
||||
adi,sensor-type:
|
||||
description: |
|
||||
1 - Type J Thermocouple
|
||||
2 - Type K Thermocouple
|
||||
3 - Type E Thermocouple
|
||||
4 - Type N Thermocouple
|
||||
5 - Type R Thermocouple
|
||||
6 - Type S Thermocouple
|
||||
7 - Type T Thermocouple
|
||||
8 - Type B Thermocouple
|
||||
9 - Custom Thermocouple
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 9
|
||||
|
||||
adi,single-ended:
|
||||
description:
|
||||
Boolean property which set's the thermocouple as single-ended.
|
||||
type: boolean
|
||||
|
||||
adi,sensor-oc-current-microamp:
|
||||
description:
|
||||
This property set's the pulsed current value applied during
|
||||
open-circuit detect.
|
||||
enum: [10, 100, 500, 1000]
|
||||
|
||||
adi,cold-junction-handle:
|
||||
description:
|
||||
Phandle which points to a sensor object responsible for measuring
|
||||
the thermocouple cold junction temperature.
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
|
||||
adi,custom-thermocouple:
|
||||
description:
|
||||
This is a table, where each entry should be a pair of
|
||||
voltage(mv)-temperature(K). The entries must be given in nv and uK
|
||||
so that, the original values must be multiplied by 1000000. For
|
||||
more details look at table 69 and 70.
|
||||
Note should be signed, but dtc doesn't currently maintain the
|
||||
sign.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint64-matrix
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 64
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
"^diode@":
|
||||
type: object
|
||||
description:
|
||||
Represents a diode sensor which is connected to one of the device
|
||||
channels.
|
||||
|
||||
properties:
|
||||
adi,sensor-type:
|
||||
description: Identifies the sensor as a diode.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
const: 28
|
||||
|
||||
adi,single-ended:
|
||||
description: Boolean property which set's the diode as single-ended.
|
||||
type: boolean
|
||||
|
||||
adi,three-conversion-cycles:
|
||||
description:
|
||||
Boolean property which set's three conversion cycles removing
|
||||
parasitic resistance effects between the LTC2983 and the diode.
|
||||
type: boolean
|
||||
|
||||
adi,average-on:
|
||||
description:
|
||||
Boolean property which enables a running average of the diode
|
||||
temperature reading. This reduces the noise when the diode is used
|
||||
as a cold junction temperature element on an isothermal block
|
||||
where temperatures change slowly.
|
||||
type: boolean
|
||||
|
||||
adi,excitation-current-microamp:
|
||||
description:
|
||||
This property controls the magnitude of the excitation current
|
||||
applied to the diode. Depending on the number of conversions
|
||||
cycles, this property will assume different predefined values on
|
||||
each cycle. Just set the value of the first cycle (1l).
|
||||
enum: [10, 20, 40, 80]
|
||||
|
||||
adi,ideal-factor-value:
|
||||
description:
|
||||
This property sets the diode ideality factor. The real value must
|
||||
be multiplied by 1000000 to remove the fractional part. For more
|
||||
information look at table 20 of the datasheet.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
"^rtd@":
|
||||
type: object
|
||||
description:
|
||||
Represents a rtd sensor which is connected to one of the device channels.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 2
|
||||
maximum: 20
|
||||
|
||||
adi,sensor-type:
|
||||
description: |
|
||||
10 - RTD PT-10
|
||||
11 - RTD PT-50
|
||||
12 - RTD PT-100
|
||||
13 - RTD PT-200
|
||||
14 - RTD PT-500
|
||||
15 - RTD PT-1000
|
||||
16 - RTD PT-1000 (0.00375)
|
||||
17 - RTD NI-120
|
||||
18 - RTD Custom
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 10
|
||||
maximum: 18
|
||||
|
||||
adi,rsense-handle:
|
||||
description:
|
||||
Phandle pointing to a rsense object associated with this RTD.
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
|
||||
adi,number-of-wires:
|
||||
description:
|
||||
Identifies the number of wires used by the RTD. Setting this
|
||||
property to 5 means 4 wires with Kelvin Rsense.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [2, 3, 4, 5]
|
||||
|
||||
adi,rsense-share:
|
||||
description:
|
||||
Boolean property which enables Rsense sharing, where one sense
|
||||
resistor is used for multiple 2-, 3-, and/or 4-wire RTDs.
|
||||
type: boolean
|
||||
|
||||
adi,current-rotate:
|
||||
description:
|
||||
Boolean property which enables excitation current rotation to
|
||||
automatically remove parasitic thermocouple effects. Note that
|
||||
this property is not allowed for 2- and 3-wire RTDs.
|
||||
type: boolean
|
||||
|
||||
adi,excitation-current-microamp:
|
||||
description:
|
||||
This property controls the magnitude of the excitation current
|
||||
applied to the RTD.
|
||||
enum: [5, 10, 25, 50, 100, 250, 500, 1000]
|
||||
|
||||
adi,rtd-curve:
|
||||
description:
|
||||
This property set the RTD curve used and the corresponding
|
||||
Callendar-VanDusen constants. Look at table 30 of the datasheet.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- minimum: 0
|
||||
maximum: 3
|
||||
|
||||
adi,custom-rtd:
|
||||
description:
|
||||
This is a table, where each entry should be a pair of
|
||||
resistance(ohm)-temperature(K). The entries added here are in uohm
|
||||
and uK. For more details values look at table 74 and 75.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint64-matrix
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 64
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
required:
|
||||
- adi,rsense-handle
|
||||
|
||||
dependencies:
|
||||
adi,current-rotate: [ adi,rsense-share ]
|
||||
|
||||
"^thermistor@":
|
||||
type: object
|
||||
description:
|
||||
Represents a thermistor sensor which is connected to one of the device
|
||||
channels.
|
||||
|
||||
properties:
|
||||
adi,sensor-type:
|
||||
description:
|
||||
19 - Thermistor 44004/44033 2.252kohm at 25°C
|
||||
20 - Thermistor 44005/44030 3kohm at 25°C
|
||||
21 - Thermistor 44007/44034 5kohm at 25°C
|
||||
22 - Thermistor 44006/44031 10kohm at 25°C
|
||||
23 - Thermistor 44008/44032 30kohm at 25°C
|
||||
24 - Thermistor YSI 400 2.252kohm at 25°C
|
||||
25 - Thermistor Spectrum 1003k 1kohm
|
||||
26 - Thermistor Custom Steinhart-Hart
|
||||
27 - Custom Thermistor
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 19
|
||||
maximum: 27
|
||||
|
||||
adi,rsense-handle:
|
||||
description:
|
||||
Phandle pointing to a rsense object associated with this
|
||||
thermistor.
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
|
||||
adi,single-ended:
|
||||
description:
|
||||
Boolean property which set's the thermistor as single-ended.
|
||||
type: boolean
|
||||
|
||||
adi,rsense-share:
|
||||
description:
|
||||
Boolean property which enables Rsense sharing, where one sense
|
||||
resistor is used for multiple thermistors. Note that this property
|
||||
is ignored if adi,single-ended is set.
|
||||
type: boolean
|
||||
|
||||
adi,current-rotate:
|
||||
description:
|
||||
Boolean property which enables excitation current rotation to
|
||||
automatically remove parasitic thermocouple effects.
|
||||
type: boolean
|
||||
|
||||
adi,excitation-current-nanoamp:
|
||||
description:
|
||||
This property controls the magnitude of the excitation current
|
||||
applied to the thermistor. Value 0 set's the sensor in auto-range
|
||||
mode.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [0, 250, 500, 1000, 5000, 10000, 25000, 50000, 100000,
|
||||
250000, 500000, 1000000]
|
||||
|
||||
adi,custom-thermistor:
|
||||
description:
|
||||
This is a table, where each entry should be a pair of
|
||||
resistance(ohm)-temperature(K). The entries added here are in uohm
|
||||
and uK only for custom thermistors. For more details look at table
|
||||
78 and 79.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint64-matrix
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 64
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
adi,custom-steinhart:
|
||||
description:
|
||||
Steinhart-Hart coefficients are also supported and can
|
||||
be programmed into the device memory using this property. For
|
||||
Steinhart sensors the coefficients are given in the raw
|
||||
format. Look at table 82 for more information.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
items:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
|
||||
required:
|
||||
- adi,rsense-handle
|
||||
|
||||
dependencies:
|
||||
adi,current-rotate: [ adi,rsense-share ]
|
||||
|
||||
"^adc@":
|
||||
type: object
|
||||
description: Represents a channel which is being used as a direct adc.
|
||||
|
||||
properties:
|
||||
adi,sensor-type:
|
||||
description: Identifies the sensor as a direct adc.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
const: 30
|
||||
|
||||
adi,single-ended:
|
||||
description: Boolean property which set's the adc as single-ended.
|
||||
type: boolean
|
||||
|
||||
"^rsense@":
|
||||
type: object
|
||||
description:
|
||||
Represents a rsense which is connected to one of the device channels.
|
||||
Rsense are used by thermistors and RTD's.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 2
|
||||
maximum: 20
|
||||
|
||||
adi,sensor-type:
|
||||
description: Identifies the sensor as a rsense.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
const: 29
|
||||
|
||||
adi,rsense-val-milli-ohms:
|
||||
description:
|
||||
Sets the value of the sense resistor. Look at table 20 of the
|
||||
datasheet for information.
|
||||
|
||||
required:
|
||||
- adi,rsense-val-milli-ohms
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor_ltc2983: ltc2983@0 {
|
||||
compatible = "adi,ltc2983";
|
||||
reg = <0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-parent = <&gpio>;
|
||||
|
||||
thermocouple@18 {
|
||||
reg = <18>;
|
||||
adi,sensor-type = <8>; //Type B
|
||||
adi,sensor-oc-current-microamp = <10>;
|
||||
adi,cold-junction-handle = <&diode5>;
|
||||
};
|
||||
|
||||
diode5: diode@5 {
|
||||
reg = <5>;
|
||||
adi,sensor-type = <28>;
|
||||
};
|
||||
|
||||
rsense2: rsense@2 {
|
||||
reg = <2>;
|
||||
adi,sensor-type = <29>;
|
||||
adi,rsense-val-milli-ohms = <1200000>; //1.2Kohms
|
||||
};
|
||||
|
||||
rtd@14 {
|
||||
reg = <14>;
|
||||
adi,sensor-type = <15>; //PT1000
|
||||
/*2-wire, internal gnd, no current rotation*/
|
||||
adi,number-of-wires = <2>;
|
||||
adi,rsense-share;
|
||||
adi,excitation-current-microamp = <500>;
|
||||
adi,rsense-handle = <&rsense2>;
|
||||
};
|
||||
|
||||
adc@10 {
|
||||
reg = <10>;
|
||||
adi,sensor-type = <30>;
|
||||
adi,single-ended;
|
||||
};
|
||||
|
||||
thermistor@12 {
|
||||
reg = <12>;
|
||||
adi,sensor-type = <26>; //Steinhart
|
||||
adi,rsense-handle = <&rsense2>;
|
||||
adi,custom-steinhart = <0x00F371EC 0x12345678
|
||||
0x2C0F8733 0x10018C66 0xA0FEACCD
|
||||
0x90021D99>; //6 entries
|
||||
};
|
||||
|
||||
thermocouple@20 {
|
||||
reg = <20>;
|
||||
adi,sensor-type = <9>; //custom thermocouple
|
||||
adi,single-ended;
|
||||
adi,custom-thermocouple = /bits/ 64
|
||||
<(-50220000) 0
|
||||
(-30200000) 99100000
|
||||
(-5300000) 135400000
|
||||
0 273150000
|
||||
40200000 361200000
|
||||
55300000 522100000
|
||||
88300000 720300000
|
||||
132200000 811200000
|
||||
188700000 922500000
|
||||
460400000 1000000000>; //10 pairs
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
...
|
@ -69,6 +69,18 @@ Required child device properties:
|
||||
- compatible : "stericsson,ab8500-[bm|btemp|charger|fg|gpadc|gpio|ponkey|
|
||||
pwm|regulator|rtc|sysctrl|usb]";
|
||||
|
||||
A few child devices require ADC channels from the GPADC node. Those follow the
|
||||
standard bindings from iio/iio-bindings.txt and iio/adc/adc.txt
|
||||
|
||||
abx500-temp : io-channels "aux1" and "aux2" for measuring external
|
||||
temperatures.
|
||||
ab8500-fg : io-channel "main_bat_v" for measuring main battery voltage,
|
||||
ab8500-btemp : io-channels "btemp_ball" and "bat_ctrl" for measuring the
|
||||
battery voltage.
|
||||
ab8500-charger : io-channels "main_charger_v", "main_charger_c", "vbus_v",
|
||||
"usb_charger_c" for measuring voltage and current of the
|
||||
different charging supplies.
|
||||
|
||||
Optional child device properties:
|
||||
- interrupts : contains the device IRQ(s) using the 2-cell format (see above)
|
||||
- interrupt-names : contains names of IRQ resource in the order in which they were
|
||||
@ -102,8 +114,115 @@ ab8500 {
|
||||
39 0x4>;
|
||||
interrupt-names = "HW_CONV_END", "SW_CONV_END";
|
||||
vddadc-supply = <&ab8500_ldo_tvout_reg>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#io-channel-cells = <1>;
|
||||
|
||||
/* GPADC channels */
|
||||
bat_ctrl: channel@1 {
|
||||
reg = <0x01>;
|
||||
};
|
||||
btemp_ball: channel@2 {
|
||||
reg = <0x02>;
|
||||
};
|
||||
main_charger_v: channel@3 {
|
||||
reg = <0x03>;
|
||||
};
|
||||
acc_detect1: channel@4 {
|
||||
reg = <0x04>;
|
||||
};
|
||||
acc_detect2: channel@5 {
|
||||
reg = <0x05>;
|
||||
};
|
||||
adc_aux1: channel@6 {
|
||||
reg = <0x06>;
|
||||
};
|
||||
adc_aux2: channel@7 {
|
||||
reg = <0x07>;
|
||||
};
|
||||
main_batt_v: channel@8 {
|
||||
reg = <0x08>;
|
||||
};
|
||||
vbus_v: channel@9 {
|
||||
reg = <0x09>;
|
||||
};
|
||||
main_charger_c: channel@a {
|
||||
reg = <0x0a>;
|
||||
};
|
||||
usb_charger_c: channel@b {
|
||||
reg = <0x0b>;
|
||||
};
|
||||
bk_bat_v: channel@c {
|
||||
reg = <0x0c>;
|
||||
};
|
||||
die_temp: channel@d {
|
||||
reg = <0x0d>;
|
||||
};
|
||||
usb_id: channel@e {
|
||||
reg = <0x0e>;
|
||||
};
|
||||
xtal_temp: channel@12 {
|
||||
reg = <0x12>;
|
||||
};
|
||||
vbat_true_meas: channel@13 {
|
||||
reg = <0x13>;
|
||||
};
|
||||
bat_ctrl_and_ibat: channel@1c {
|
||||
reg = <0x1c>;
|
||||
};
|
||||
vbat_meas_and_ibat: channel@1d {
|
||||
reg = <0x1d>;
|
||||
};
|
||||
vbat_true_meas_and_ibat: channel@1e {
|
||||
reg = <0x1e>;
|
||||
};
|
||||
bat_temp_and_ibat: channel@1f {
|
||||
reg = <0x1f>;
|
||||
};
|
||||
};
|
||||
|
||||
ab8500_temp {
|
||||
compatible = "stericsson,abx500-temp";
|
||||
io-channels = <&gpadc 0x06>,
|
||||
<&gpadc 0x07>;
|
||||
io-channel-name = "aux1", "aux2";
|
||||
};
|
||||
|
||||
ab8500_battery: ab8500_battery {
|
||||
stericsson,battery-type = "LIPO";
|
||||
thermistor-on-batctrl;
|
||||
};
|
||||
|
||||
ab8500_fg {
|
||||
compatible = "stericsson,ab8500-fg";
|
||||
battery = <&ab8500_battery>;
|
||||
io-channels = <&gpadc 0x08>;
|
||||
io-channel-name = "main_bat_v";
|
||||
};
|
||||
|
||||
ab8500_btemp {
|
||||
compatible = "stericsson,ab8500-btemp";
|
||||
battery = <&ab8500_battery>;
|
||||
io-channels = <&gpadc 0x02>,
|
||||
<&gpadc 0x01>;
|
||||
io-channel-name = "btemp_ball",
|
||||
"bat_ctrl";
|
||||
};
|
||||
|
||||
ab8500_charger {
|
||||
compatible = "stericsson,ab8500-charger";
|
||||
battery = <&ab8500_battery>;
|
||||
vddadc-supply = <&ab8500_ldo_tvout_reg>;
|
||||
io-channels = <&gpadc 0x03>,
|
||||
<&gpadc 0x0a>,
|
||||
<&gpadc 0x09>,
|
||||
<&gpadc 0x0b>;
|
||||
io-channel-name = "main_charger_v",
|
||||
"main_charger_c",
|
||||
"vbus_v",
|
||||
"usb_charger_c";
|
||||
};
|
||||
|
||||
ab8500-usb {
|
||||
compatible = "stericsson,ab8500-usb";
|
||||
interrupts = < 90 0x4
|
||||
|
@ -114,6 +114,18 @@ properties:
|
||||
- isil,isl68137
|
||||
# 5 Bit Programmable, Pulse-Width Modulator
|
||||
- maxim,ds1050
|
||||
# 10-bit 8 channels 300ks/s SPI ADC with temperature sensor
|
||||
- maxim,max1027
|
||||
# 10-bit 12 channels 300ks/s SPI ADC with temperature sensor
|
||||
- maxim,max1029
|
||||
# 10-bit 16 channels 300ks/s SPI ADC with temperature sensor
|
||||
- maxim,max1031
|
||||
# 12-bit 8 channels 300ks/s SPI ADC with temperature sensor
|
||||
- maxim,max1227
|
||||
# 12-bit 12 channels 300ks/s SPI ADC with temperature sensor
|
||||
- maxim,max1229
|
||||
# 12-bit 16 channels 300ks/s SPI ADC with temperature sensor
|
||||
- maxim,max1231
|
||||
# Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
|
||||
- maxim,max1237
|
||||
# PECI-to-I2C translator for PECI-to-SMBus/I2C protocol conversion
|
||||
|
@ -7,7 +7,7 @@ Generic Counter Interface
|
||||
Introduction
|
||||
============
|
||||
|
||||
Counter devices are prevalent within a diverse spectrum of industries.
|
||||
Counter devices are prevalent among a diverse spectrum of industries.
|
||||
The ubiquitous presence of these devices necessitates a common interface
|
||||
and standard of interaction and exposure. This driver API attempts to
|
||||
resolve the issue of duplicate code found among existing counter device
|
||||
@ -26,23 +26,72 @@ the Generic Counter interface.
|
||||
|
||||
There are three core components to a counter:
|
||||
|
||||
* Count:
|
||||
Count data for a set of Signals.
|
||||
|
||||
* Signal:
|
||||
Input data that is evaluated by the counter to determine the count
|
||||
data.
|
||||
Stream of data to be evaluated by the counter.
|
||||
|
||||
* Synapse:
|
||||
The association of a Signal with a respective Count.
|
||||
Association of a Signal, and evaluation trigger, with a Count.
|
||||
|
||||
* Count:
|
||||
Accumulation of the effects of connected Synapses.
|
||||
|
||||
SIGNAL
|
||||
------
|
||||
A Signal represents a stream of data. This is the input data that is
|
||||
evaluated by the counter to determine the count data; e.g. a quadrature
|
||||
signal output line of a rotary encoder. Not all counter devices provide
|
||||
user access to the Signal data, so exposure is optional for drivers.
|
||||
|
||||
When the Signal data is available for user access, the Generic Counter
|
||||
interface provides the following available signal values:
|
||||
|
||||
* SIGNAL_LOW:
|
||||
Signal line is in a low state.
|
||||
|
||||
* SIGNAL_HIGH:
|
||||
Signal line is in a high state.
|
||||
|
||||
A Signal may be associated with one or more Counts.
|
||||
|
||||
SYNAPSE
|
||||
-------
|
||||
A Synapse represents the association of a Signal with a Count. Signal
|
||||
data affects respective Count data, and the Synapse represents this
|
||||
relationship.
|
||||
|
||||
The Synapse action mode specifies the Signal data condition that
|
||||
triggers the respective Count's count function evaluation to update the
|
||||
count data. The Generic Counter interface provides the following
|
||||
available action modes:
|
||||
|
||||
* None:
|
||||
Signal does not trigger the count function. In Pulse-Direction count
|
||||
function mode, this Signal is evaluated as Direction.
|
||||
|
||||
* Rising Edge:
|
||||
Low state transitions to high state.
|
||||
|
||||
* Falling Edge:
|
||||
High state transitions to low state.
|
||||
|
||||
* Both Edges:
|
||||
Any state transition.
|
||||
|
||||
A counter is defined as a set of input signals associated with count
|
||||
data that are generated by the evaluation of the state of the associated
|
||||
input signals as defined by the respective count functions. Within the
|
||||
context of the Generic Counter interface, a counter consists of Counts
|
||||
each associated with a set of Signals, whose respective Synapse
|
||||
instances represent the count function update conditions for the
|
||||
associated Counts.
|
||||
|
||||
A Synapse associates one Signal with one Count.
|
||||
|
||||
COUNT
|
||||
-----
|
||||
A Count represents the count data for a set of Signals. The Generic
|
||||
Counter interface provides the following available count data types:
|
||||
|
||||
* COUNT_POSITION:
|
||||
Unsigned integer value representing position.
|
||||
A Count represents the accumulation of the effects of connected
|
||||
Synapses; i.e. the count data for a set of Signals. The Generic
|
||||
Counter interface represents the count data as a natural number.
|
||||
|
||||
A Count has a count function mode which represents the update behavior
|
||||
for the count data. The Generic Counter interface provides the following
|
||||
@ -86,60 +135,7 @@ available count function modes:
|
||||
Any state transition on either quadrature pair signals updates the
|
||||
respective count. Quadrature encoding determines the direction.
|
||||
|
||||
A Count has a set of one or more associated Signals.
|
||||
|
||||
SIGNAL
|
||||
------
|
||||
A Signal represents a counter input data; this is the input data that is
|
||||
evaluated by the counter to determine the count data; e.g. a quadrature
|
||||
signal output line of a rotary encoder. Not all counter devices provide
|
||||
user access to the Signal data.
|
||||
|
||||
The Generic Counter interface provides the following available signal
|
||||
data types for when the Signal data is available for user access:
|
||||
|
||||
* SIGNAL_LEVEL:
|
||||
Signal line state level. The following states are possible:
|
||||
|
||||
- SIGNAL_LEVEL_LOW:
|
||||
Signal line is in a low state.
|
||||
|
||||
- SIGNAL_LEVEL_HIGH:
|
||||
Signal line is in a high state.
|
||||
|
||||
A Signal may be associated with one or more Counts.
|
||||
|
||||
SYNAPSE
|
||||
-------
|
||||
A Synapse represents the association of a Signal with a respective
|
||||
Count. Signal data affects respective Count data, and the Synapse
|
||||
represents this relationship.
|
||||
|
||||
The Synapse action mode specifies the Signal data condition which
|
||||
triggers the respective Count's count function evaluation to update the
|
||||
count data. The Generic Counter interface provides the following
|
||||
available action modes:
|
||||
|
||||
* None:
|
||||
Signal does not trigger the count function. In Pulse-Direction count
|
||||
function mode, this Signal is evaluated as Direction.
|
||||
|
||||
* Rising Edge:
|
||||
Low state transitions to high state.
|
||||
|
||||
* Falling Edge:
|
||||
High state transitions to low state.
|
||||
|
||||
* Both Edges:
|
||||
Any state transition.
|
||||
|
||||
A counter is defined as a set of input signals associated with count
|
||||
data that are generated by the evaluation of the state of the associated
|
||||
input signals as defined by the respective count functions. Within the
|
||||
context of the Generic Counter interface, a counter consists of Counts
|
||||
each associated with a set of Signals, whose respective Synapse
|
||||
instances represent the count function update conditions for the
|
||||
associated Counts.
|
||||
A Count has a set of one or more associated Synapses.
|
||||
|
||||
Paradigm
|
||||
========
|
||||
@ -286,10 +282,36 @@ if device memory-managed registration is desired.
|
||||
Extension sysfs attributes can be created for auxiliary functionality
|
||||
and data by passing in defined counter_device_ext, counter_count_ext,
|
||||
and counter_signal_ext structures. In these cases, the
|
||||
counter_device_ext structure is used for global configuration of the
|
||||
respective Counter device, while the counter_count_ext and
|
||||
counter_signal_ext structures allow for auxiliary exposure and
|
||||
configuration of a specific Count or Signal respectively.
|
||||
counter_device_ext structure is used for global/miscellaneous exposure
|
||||
and configuration of the respective Counter device, while the
|
||||
counter_count_ext and counter_signal_ext structures allow for auxiliary
|
||||
exposure and configuration of a specific Count or Signal respectively.
|
||||
|
||||
Determining the type of extension to create is a matter of scope.
|
||||
|
||||
* Signal extensions are attributes that expose information/control
|
||||
specific to a Signal. These types of attributes will exist under a
|
||||
Signal's directory in sysfs.
|
||||
|
||||
For example, if you have an invert feature for a Signal, you can have
|
||||
a Signal extension called "invert" that toggles that feature:
|
||||
/sys/bus/counter/devices/counterX/signalY/invert
|
||||
|
||||
* Count extensions are attributes that expose information/control
|
||||
specific to a Count. These type of attributes will exist under a
|
||||
Count's directory in sysfs.
|
||||
|
||||
For example, if you want to pause/unpause a Count from updating, you
|
||||
can have a Count extension called "enable" that toggles such:
|
||||
/sys/bus/counter/devices/counterX/countY/enable
|
||||
|
||||
* Device extensions are attributes that expose information/control
|
||||
non-specific to a particular Count or Signal. This is where you would
|
||||
put your global features or other miscellanous functionality.
|
||||
|
||||
For example, if your device has an overtemp sensor, you can report the
|
||||
chip overheated via a device extension called "error_overtemp":
|
||||
/sys/bus/counter/devices/counterX/error_overtemp
|
||||
|
||||
Architecture
|
||||
============
|
||||
|
15
MAINTAINERS
15
MAINTAINERS
@ -2005,6 +2005,7 @@ F: drivers/dma/ste_dma40*
|
||||
F: drivers/hwspinlock/u8500_hsem.c
|
||||
F: drivers/i2c/busses/i2c-nomadik.c
|
||||
F: drivers/i2c/busses/i2c-stu300.c
|
||||
F: drivers/iio/adc/ab8500-gpadc.c
|
||||
F: drivers/mfd/ab3100*
|
||||
F: drivers/mfd/ab8500*
|
||||
F: drivers/mfd/abx500*
|
||||
@ -9624,6 +9625,14 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/dac/ltc1660.txt
|
||||
F: drivers/iio/dac/ltc1660.c
|
||||
|
||||
LTC2983 IIO TEMPERATURE DRIVER
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iio/temperature/ltc2983.c
|
||||
F: Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
|
||||
|
||||
LTC4261 HARDWARE MONITOR DRIVER
|
||||
M: Guenter Roeck <linux@roeck-us.net>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
@ -16228,6 +16237,12 @@ S: Maintained
|
||||
F: drivers/media/platform/davinci/
|
||||
F: include/media/davinci/
|
||||
|
||||
TI ENHANCED QUADRATURE ENCODER PULSE (eQEP) DRIVER
|
||||
R: David Lechner <david@lechnology.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
F: Documentation/devicetree/bindings/counter/ti-eqep.yaml
|
||||
F: drivers/counter/ti-eqep.c
|
||||
|
||||
TI ETHERNET SWITCH DRIVER (CPSW)
|
||||
R: Grygorii Strashko <grygorii.strashko@ti.com>
|
||||
L: linux-omap@vger.kernel.org
|
||||
|
@ -150,6 +150,15 @@ config TEGRA_GMI
|
||||
Driver for the Tegra Generic Memory Interface bus which can be used
|
||||
to attach devices such as NOR, UART, FPGA and more.
|
||||
|
||||
config TI_PWMSS
|
||||
bool
|
||||
default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM || TI_EQEP)
|
||||
help
|
||||
PWM Subsystem driver support for AM33xx SOC.
|
||||
|
||||
PWM submodules require PWM config space access from submodule
|
||||
drivers and require common parent driver support.
|
||||
|
||||
config TI_SYSC
|
||||
bool "TI sysc interconnect target module driver"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
|
@ -27,6 +27,7 @@ obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
|
||||
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
|
||||
obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
|
||||
obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o
|
||||
obj-$(CONFIG_TI_PWMSS) += ti-pwmss.o
|
||||
obj-$(CONFIG_TI_SYSC) += ti-sysc.o
|
||||
obj-$(CONFIG_TS_NBUS) += ts-nbus.o
|
||||
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
|
||||
|
@ -562,11 +562,10 @@ static const struct iio_chan_spec quad8_channels[] = {
|
||||
};
|
||||
|
||||
static int quad8_signal_read(struct counter_device *counter,
|
||||
struct counter_signal *signal, struct counter_signal_read_value *val)
|
||||
struct counter_signal *signal, enum counter_signal_value *val)
|
||||
{
|
||||
const struct quad8_iio *const priv = counter->priv;
|
||||
unsigned int state;
|
||||
enum counter_signal_level level;
|
||||
|
||||
/* Only Index signal levels can be read */
|
||||
if (signal->id < 16)
|
||||
@ -575,22 +574,19 @@ static int quad8_signal_read(struct counter_device *counter,
|
||||
state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
|
||||
& BIT(signal->id - 16);
|
||||
|
||||
level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
|
||||
|
||||
counter_signal_read_value_set(val, COUNTER_SIGNAL_LEVEL, &level);
|
||||
*val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int quad8_count_read(struct counter_device *counter,
|
||||
struct counter_count *count, struct counter_count_read_value *val)
|
||||
struct counter_count *count, unsigned long *val)
|
||||
{
|
||||
const struct quad8_iio *const priv = counter->priv;
|
||||
const int base_offset = priv->base + 2 * count->id;
|
||||
unsigned int flags;
|
||||
unsigned int borrow;
|
||||
unsigned int carry;
|
||||
unsigned long position;
|
||||
int i;
|
||||
|
||||
flags = inb(base_offset + 1);
|
||||
@ -598,36 +594,27 @@ static int quad8_count_read(struct counter_device *counter,
|
||||
carry = !!(flags & QUAD8_FLAG_CT);
|
||||
|
||||
/* Borrow XOR Carry effectively doubles count range */
|
||||
position = (unsigned long)(borrow ^ carry) << 24;
|
||||
*val = (unsigned long)(borrow ^ carry) << 24;
|
||||
|
||||
/* Reset Byte Pointer; transfer Counter to Output Latch */
|
||||
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
|
||||
base_offset + 1);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
position |= (unsigned long)inb(base_offset) << (8 * i);
|
||||
|
||||
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &position);
|
||||
*val |= (unsigned long)inb(base_offset) << (8 * i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int quad8_count_write(struct counter_device *counter,
|
||||
struct counter_count *count, struct counter_count_write_value *val)
|
||||
struct counter_count *count, unsigned long val)
|
||||
{
|
||||
const struct quad8_iio *const priv = counter->priv;
|
||||
const int base_offset = priv->base + 2 * count->id;
|
||||
int err;
|
||||
unsigned long position;
|
||||
int i;
|
||||
|
||||
err = counter_count_write_value_get(&position, COUNTER_COUNT_POSITION,
|
||||
val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Only 24-bit values are supported */
|
||||
if (position > 0xFFFFFF)
|
||||
if (val > 0xFFFFFF)
|
||||
return -EINVAL;
|
||||
|
||||
/* Reset Byte Pointer */
|
||||
@ -635,7 +622,7 @@ static int quad8_count_write(struct counter_device *counter,
|
||||
|
||||
/* Counter can only be set via Preset Register */
|
||||
for (i = 0; i < 3; i++)
|
||||
outb(position >> (8 * i), base_offset);
|
||||
outb(val >> (8 * i), base_offset);
|
||||
|
||||
/* Transfer Preset Register to Counter */
|
||||
outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
|
||||
@ -644,9 +631,9 @@ static int quad8_count_write(struct counter_device *counter,
|
||||
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
|
||||
|
||||
/* Set Preset Register back to original value */
|
||||
position = priv->preset[count->id];
|
||||
val = priv->preset[count->id];
|
||||
for (i = 0; i < 3; i++)
|
||||
outb(position >> (8 * i), base_offset);
|
||||
outb(val >> (8 * i), base_offset);
|
||||
|
||||
/* Reset Borrow, Carry, Compare, and Sign flags */
|
||||
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
|
||||
|
@ -49,6 +49,17 @@ config STM32_LPTIMER_CNT
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called stm32-lptimer-cnt.
|
||||
|
||||
config TI_EQEP
|
||||
tristate "TI eQEP counter driver"
|
||||
depends on (SOC_AM33XX || COMPILE_TEST)
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Select this option to enable the Texas Instruments Enhanced Quadrature
|
||||
Encoder Pulse (eQEP) counter driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ti-eqep.
|
||||
|
||||
config FTM_QUADDEC
|
||||
tristate "Flex Timer Module Quadrature decoder driver"
|
||||
depends on HAS_IOMEM && OF
|
||||
|
@ -8,4 +8,5 @@ obj-$(CONFIG_COUNTER) += counter.o
|
||||
obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o
|
||||
obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o
|
||||
obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o
|
||||
obj-$(CONFIG_TI_EQEP) += ti-eqep.o
|
||||
obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o
|
||||
|
@ -220,86 +220,6 @@ ssize_t counter_device_enum_available_read(struct counter_device *counter,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
|
||||
|
||||
static const char *const counter_signal_level_str[] = {
|
||||
[COUNTER_SIGNAL_LEVEL_LOW] = "low",
|
||||
[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
|
||||
};
|
||||
|
||||
/**
|
||||
* counter_signal_read_value_set - set counter_signal_read_value data
|
||||
* @val: counter_signal_read_value structure to set
|
||||
* @type: property Signal data represents
|
||||
* @data: Signal data
|
||||
*
|
||||
* This function sets an opaque counter_signal_read_value structure with the
|
||||
* provided Signal data.
|
||||
*/
|
||||
void counter_signal_read_value_set(struct counter_signal_read_value *const val,
|
||||
const enum counter_signal_value_type type,
|
||||
void *const data)
|
||||
{
|
||||
if (type == COUNTER_SIGNAL_LEVEL)
|
||||
val->len = sprintf(val->buf, "%s\n",
|
||||
counter_signal_level_str[*(enum counter_signal_level *)data]);
|
||||
else
|
||||
val->len = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(counter_signal_read_value_set);
|
||||
|
||||
/**
|
||||
* counter_count_read_value_set - set counter_count_read_value data
|
||||
* @val: counter_count_read_value structure to set
|
||||
* @type: property Count data represents
|
||||
* @data: Count data
|
||||
*
|
||||
* This function sets an opaque counter_count_read_value structure with the
|
||||
* provided Count data.
|
||||
*/
|
||||
void counter_count_read_value_set(struct counter_count_read_value *const val,
|
||||
const enum counter_count_value_type type,
|
||||
void *const data)
|
||||
{
|
||||
switch (type) {
|
||||
case COUNTER_COUNT_POSITION:
|
||||
val->len = sprintf(val->buf, "%lu\n", *(unsigned long *)data);
|
||||
break;
|
||||
default:
|
||||
val->len = 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(counter_count_read_value_set);
|
||||
|
||||
/**
|
||||
* counter_count_write_value_get - get counter_count_write_value data
|
||||
* @data: Count data
|
||||
* @type: property Count data represents
|
||||
* @val: counter_count_write_value structure containing data
|
||||
*
|
||||
* This function extracts Count data from the provided opaque
|
||||
* counter_count_write_value structure and stores it at the address provided by
|
||||
* @data.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, negative error number on failure.
|
||||
*/
|
||||
int counter_count_write_value_get(void *const data,
|
||||
const enum counter_count_value_type type,
|
||||
const struct counter_count_write_value *const val)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (type) {
|
||||
case COUNTER_COUNT_POSITION:
|
||||
err = kstrtoul(val->buf, 0, data);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(counter_count_write_value_get);
|
||||
|
||||
struct counter_attr_parm {
|
||||
struct counter_device_attr_group *group;
|
||||
const char *prefix;
|
||||
@ -369,6 +289,11 @@ struct counter_signal_unit {
|
||||
struct counter_signal *signal;
|
||||
};
|
||||
|
||||
static const char *const counter_signal_value_str[] = {
|
||||
[COUNTER_SIGNAL_LOW] = "low",
|
||||
[COUNTER_SIGNAL_HIGH] = "high"
|
||||
};
|
||||
|
||||
static ssize_t counter_signal_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -377,13 +302,13 @@ static ssize_t counter_signal_show(struct device *dev,
|
||||
const struct counter_signal_unit *const component = devattr->component;
|
||||
struct counter_signal *const signal = component->signal;
|
||||
int err;
|
||||
struct counter_signal_read_value val = { .buf = buf };
|
||||
enum counter_signal_value val;
|
||||
|
||||
err = counter->ops->signal_read(counter, signal, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return val.len;
|
||||
return sprintf(buf, "%s\n", counter_signal_value_str[val]);
|
||||
}
|
||||
|
||||
struct counter_name_unit {
|
||||
@ -788,13 +713,13 @@ static ssize_t counter_count_show(struct device *dev,
|
||||
const struct counter_count_unit *const component = devattr->component;
|
||||
struct counter_count *const count = component->count;
|
||||
int err;
|
||||
struct counter_count_read_value val = { .buf = buf };
|
||||
unsigned long val;
|
||||
|
||||
err = counter->ops->count_read(counter, count, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return val.len;
|
||||
return sprintf(buf, "%lu\n", val);
|
||||
}
|
||||
|
||||
static ssize_t counter_count_store(struct device *dev,
|
||||
@ -806,9 +731,13 @@ static ssize_t counter_count_store(struct device *dev,
|
||||
const struct counter_count_unit *const component = devattr->component;
|
||||
struct counter_count *const count = component->count;
|
||||
int err;
|
||||
struct counter_count_write_value val = { .buf = buf };
|
||||
unsigned long val;
|
||||
|
||||
err = counter->ops->count_write(counter, count, &val);
|
||||
err = kstrtoul(buf, 0, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = counter->ops->count_write(counter, count, val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -178,31 +178,25 @@ static const enum counter_count_function ftm_quaddec_count_functions[] = {
|
||||
|
||||
static int ftm_quaddec_count_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_count_read_value *val)
|
||||
unsigned long *val)
|
||||
{
|
||||
struct ftm_quaddec *const ftm = counter->priv;
|
||||
uint32_t cntval;
|
||||
|
||||
ftm_read(ftm, FTM_CNT, &cntval);
|
||||
|
||||
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cntval);
|
||||
*val = cntval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftm_quaddec_count_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_count_write_value *val)
|
||||
const unsigned long val)
|
||||
{
|
||||
struct ftm_quaddec *const ftm = counter->priv;
|
||||
u32 cnt;
|
||||
int err;
|
||||
|
||||
err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cnt != 0) {
|
||||
if (val != 0) {
|
||||
dev_warn(&ftm->pdev->dev, "Can only accept '0' as new counter value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -377,8 +377,7 @@ static enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
|
||||
};
|
||||
|
||||
static int stm32_lptim_cnt_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_count_read_value *val)
|
||||
struct counter_count *count, unsigned long *val)
|
||||
{
|
||||
struct stm32_lptim_cnt *const priv = counter->priv;
|
||||
u32 cnt;
|
||||
@ -388,7 +387,7 @@ static int stm32_lptim_cnt_read(struct counter_device *counter,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt);
|
||||
*val = cnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -48,34 +48,27 @@ static enum counter_count_function stm32_count_functions[] = {
|
||||
};
|
||||
|
||||
static int stm32_count_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_count_read_value *val)
|
||||
struct counter_count *count, unsigned long *val)
|
||||
{
|
||||
struct stm32_timer_cnt *const priv = counter->priv;
|
||||
u32 cnt;
|
||||
|
||||
regmap_read(priv->regmap, TIM_CNT, &cnt);
|
||||
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt);
|
||||
*val = cnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_count_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_count_write_value *val)
|
||||
const unsigned long val)
|
||||
{
|
||||
struct stm32_timer_cnt *const priv = counter->priv;
|
||||
u32 cnt;
|
||||
int err;
|
||||
|
||||
err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cnt > priv->ceiling)
|
||||
if (val > priv->ceiling)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_write(priv->regmap, TIM_CNT, cnt);
|
||||
return regmap_write(priv->regmap, TIM_CNT, val);
|
||||
}
|
||||
|
||||
static int stm32_count_function_get(struct counter_device *counter,
|
||||
|
466
drivers/counter/ti-eqep.c
Normal file
466
drivers/counter/ti-eqep.c
Normal file
@ -0,0 +1,466 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2019 David Lechner <david@lechnology.com>
|
||||
*
|
||||
* Counter driver for Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP)
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/counter.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* 32-bit registers */
|
||||
#define QPOSCNT 0x0
|
||||
#define QPOSINIT 0x4
|
||||
#define QPOSMAX 0x8
|
||||
#define QPOSCMP 0xc
|
||||
#define QPOSILAT 0x10
|
||||
#define QPOSSLAT 0x14
|
||||
#define QPOSLAT 0x18
|
||||
#define QUTMR 0x1c
|
||||
#define QUPRD 0x20
|
||||
|
||||
/* 16-bit registers */
|
||||
#define QWDTMR 0x0 /* 0x24 */
|
||||
#define QWDPRD 0x2 /* 0x26 */
|
||||
#define QDECCTL 0x4 /* 0x28 */
|
||||
#define QEPCTL 0x6 /* 0x2a */
|
||||
#define QCAPCTL 0x8 /* 0x2c */
|
||||
#define QPOSCTL 0xa /* 0x2e */
|
||||
#define QEINT 0xc /* 0x30 */
|
||||
#define QFLG 0xe /* 0x32 */
|
||||
#define QCLR 0x10 /* 0x34 */
|
||||
#define QFRC 0x12 /* 0x36 */
|
||||
#define QEPSTS 0x14 /* 0x38 */
|
||||
#define QCTMR 0x16 /* 0x3a */
|
||||
#define QCPRD 0x18 /* 0x3c */
|
||||
#define QCTMRLAT 0x1a /* 0x3e */
|
||||
#define QCPRDLAT 0x1c /* 0x40 */
|
||||
|
||||
#define QDECCTL_QSRC_SHIFT 14
|
||||
#define QDECCTL_QSRC GENMASK(15, 14)
|
||||
#define QDECCTL_SOEN BIT(13)
|
||||
#define QDECCTL_SPSEL BIT(12)
|
||||
#define QDECCTL_XCR BIT(11)
|
||||
#define QDECCTL_SWAP BIT(10)
|
||||
#define QDECCTL_IGATE BIT(9)
|
||||
#define QDECCTL_QAP BIT(8)
|
||||
#define QDECCTL_QBP BIT(7)
|
||||
#define QDECCTL_QIP BIT(6)
|
||||
#define QDECCTL_QSP BIT(5)
|
||||
|
||||
#define QEPCTL_FREE_SOFT GENMASK(15, 14)
|
||||
#define QEPCTL_PCRM GENMASK(13, 12)
|
||||
#define QEPCTL_SEI GENMASK(11, 10)
|
||||
#define QEPCTL_IEI GENMASK(9, 8)
|
||||
#define QEPCTL_SWI BIT(7)
|
||||
#define QEPCTL_SEL BIT(6)
|
||||
#define QEPCTL_IEL GENMASK(5, 4)
|
||||
#define QEPCTL_PHEN BIT(3)
|
||||
#define QEPCTL_QCLM BIT(2)
|
||||
#define QEPCTL_UTE BIT(1)
|
||||
#define QEPCTL_WDE BIT(0)
|
||||
|
||||
/* EQEP Inputs */
|
||||
enum {
|
||||
TI_EQEP_SIGNAL_QEPA, /* QEPA/XCLK */
|
||||
TI_EQEP_SIGNAL_QEPB, /* QEPB/XDIR */
|
||||
};
|
||||
|
||||
/* Position Counter Input Modes */
|
||||
enum {
|
||||
TI_EQEP_COUNT_FUNC_QUAD_COUNT,
|
||||
TI_EQEP_COUNT_FUNC_DIR_COUNT,
|
||||
TI_EQEP_COUNT_FUNC_UP_COUNT,
|
||||
TI_EQEP_COUNT_FUNC_DOWN_COUNT,
|
||||
};
|
||||
|
||||
enum {
|
||||
TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES,
|
||||
TI_EQEP_SYNAPSE_ACTION_RISING_EDGE,
|
||||
TI_EQEP_SYNAPSE_ACTION_NONE,
|
||||
};
|
||||
|
||||
struct ti_eqep_cnt {
|
||||
struct counter_device counter;
|
||||
struct regmap *regmap32;
|
||||
struct regmap *regmap16;
|
||||
};
|
||||
|
||||
static int ti_eqep_count_read(struct counter_device *counter,
|
||||
struct counter_count *count, unsigned long *val)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
u32 cnt;
|
||||
|
||||
regmap_read(priv->regmap32, QPOSCNT, &cnt);
|
||||
*val = cnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_eqep_count_write(struct counter_device *counter,
|
||||
struct counter_count *count, unsigned long val)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
u32 max;
|
||||
|
||||
regmap_read(priv->regmap32, QPOSMAX, &max);
|
||||
if (val > max)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_write(priv->regmap32, QPOSCNT, val);
|
||||
}
|
||||
|
||||
static int ti_eqep_function_get(struct counter_device *counter,
|
||||
struct counter_count *count, size_t *function)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
u32 qdecctl;
|
||||
|
||||
regmap_read(priv->regmap16, QDECCTL, &qdecctl);
|
||||
*function = (qdecctl & QDECCTL_QSRC) >> QDECCTL_QSRC_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_eqep_function_set(struct counter_device *counter,
|
||||
struct counter_count *count, size_t function)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
|
||||
return regmap_write_bits(priv->regmap16, QDECCTL, QDECCTL_QSRC,
|
||||
function << QDECCTL_QSRC_SHIFT);
|
||||
}
|
||||
|
||||
static int ti_eqep_action_get(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_synapse *synapse, size_t *action)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
size_t function;
|
||||
u32 qdecctl;
|
||||
int err;
|
||||
|
||||
err = ti_eqep_function_get(counter, count, &function);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (function) {
|
||||
case TI_EQEP_COUNT_FUNC_QUAD_COUNT:
|
||||
/* In quadrature mode, the rising and falling edge of both
|
||||
* QEPA and QEPB trigger QCLK.
|
||||
*/
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
|
||||
break;
|
||||
case TI_EQEP_COUNT_FUNC_DIR_COUNT:
|
||||
/* In direction-count mode only rising edge of QEPA is counted
|
||||
* and QEPB gives direction.
|
||||
*/
|
||||
switch (synapse->signal->id) {
|
||||
case TI_EQEP_SIGNAL_QEPA:
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
|
||||
break;
|
||||
default:
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TI_EQEP_COUNT_FUNC_UP_COUNT:
|
||||
case TI_EQEP_COUNT_FUNC_DOWN_COUNT:
|
||||
/* In up/down-count modes only QEPA is counted and QEPB is not
|
||||
* used.
|
||||
*/
|
||||
switch (synapse->signal->id) {
|
||||
case TI_EQEP_SIGNAL_QEPA:
|
||||
err = regmap_read(priv->regmap16, QDECCTL, &qdecctl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (qdecctl & QDECCTL_XCR)
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
|
||||
else
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
|
||||
break;
|
||||
default:
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct counter_ops ti_eqep_counter_ops = {
|
||||
.count_read = ti_eqep_count_read,
|
||||
.count_write = ti_eqep_count_write,
|
||||
.function_get = ti_eqep_function_get,
|
||||
.function_set = ti_eqep_function_set,
|
||||
.action_get = ti_eqep_action_get,
|
||||
};
|
||||
|
||||
static ssize_t ti_eqep_position_ceiling_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *ext_priv, char *buf)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
u32 qposmax;
|
||||
|
||||
regmap_read(priv->regmap32, QPOSMAX, &qposmax);
|
||||
|
||||
return sprintf(buf, "%u\n", qposmax);
|
||||
}
|
||||
|
||||
static ssize_t ti_eqep_position_ceiling_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *ext_priv, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
int err;
|
||||
u32 res;
|
||||
|
||||
err = kstrtouint(buf, 0, &res);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
regmap_write(priv->regmap32, QPOSMAX, res);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t ti_eqep_position_floor_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *ext_priv, char *buf)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
u32 qposinit;
|
||||
|
||||
regmap_read(priv->regmap32, QPOSINIT, &qposinit);
|
||||
|
||||
return sprintf(buf, "%u\n", qposinit);
|
||||
}
|
||||
|
||||
static ssize_t ti_eqep_position_floor_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *ext_priv, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
int err;
|
||||
u32 res;
|
||||
|
||||
err = kstrtouint(buf, 0, &res);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
regmap_write(priv->regmap32, QPOSINIT, res);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t ti_eqep_position_enable_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *ext_priv, char *buf)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
u32 qepctl;
|
||||
|
||||
regmap_read(priv->regmap16, QEPCTL, &qepctl);
|
||||
|
||||
return sprintf(buf, "%u\n", !!(qepctl & QEPCTL_PHEN));
|
||||
}
|
||||
|
||||
static ssize_t ti_eqep_position_enable_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *ext_priv, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = counter->priv;
|
||||
int err;
|
||||
bool res;
|
||||
|
||||
err = kstrtobool(buf, &res);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, res ? -1 : 0);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct counter_count_ext ti_eqep_position_ext[] = {
|
||||
{
|
||||
.name = "ceiling",
|
||||
.read = ti_eqep_position_ceiling_read,
|
||||
.write = ti_eqep_position_ceiling_write,
|
||||
},
|
||||
{
|
||||
.name = "floor",
|
||||
.read = ti_eqep_position_floor_read,
|
||||
.write = ti_eqep_position_floor_write,
|
||||
},
|
||||
{
|
||||
.name = "enable",
|
||||
.read = ti_eqep_position_enable_read,
|
||||
.write = ti_eqep_position_enable_write,
|
||||
},
|
||||
};
|
||||
|
||||
static struct counter_signal ti_eqep_signals[] = {
|
||||
[TI_EQEP_SIGNAL_QEPA] = {
|
||||
.id = TI_EQEP_SIGNAL_QEPA,
|
||||
.name = "QEPA"
|
||||
},
|
||||
[TI_EQEP_SIGNAL_QEPB] = {
|
||||
.id = TI_EQEP_SIGNAL_QEPB,
|
||||
.name = "QEPB"
|
||||
},
|
||||
};
|
||||
|
||||
static const enum counter_count_function ti_eqep_position_functions[] = {
|
||||
[TI_EQEP_COUNT_FUNC_QUAD_COUNT] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
[TI_EQEP_COUNT_FUNC_DIR_COUNT] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
|
||||
[TI_EQEP_COUNT_FUNC_UP_COUNT] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[TI_EQEP_COUNT_FUNC_DOWN_COUNT] = COUNTER_COUNT_FUNCTION_DECREASE,
|
||||
};
|
||||
|
||||
static const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {
|
||||
[TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
|
||||
[TI_EQEP_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
|
||||
[TI_EQEP_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
|
||||
};
|
||||
|
||||
static struct counter_synapse ti_eqep_position_synapses[] = {
|
||||
{
|
||||
.actions_list = ti_eqep_position_synapse_actions,
|
||||
.num_actions = ARRAY_SIZE(ti_eqep_position_synapse_actions),
|
||||
.signal = &ti_eqep_signals[TI_EQEP_SIGNAL_QEPA],
|
||||
},
|
||||
{
|
||||
.actions_list = ti_eqep_position_synapse_actions,
|
||||
.num_actions = ARRAY_SIZE(ti_eqep_position_synapse_actions),
|
||||
.signal = &ti_eqep_signals[TI_EQEP_SIGNAL_QEPB],
|
||||
},
|
||||
};
|
||||
|
||||
static struct counter_count ti_eqep_counts[] = {
|
||||
{
|
||||
.id = 0,
|
||||
.name = "QPOSCNT",
|
||||
.functions_list = ti_eqep_position_functions,
|
||||
.num_functions = ARRAY_SIZE(ti_eqep_position_functions),
|
||||
.synapses = ti_eqep_position_synapses,
|
||||
.num_synapses = ARRAY_SIZE(ti_eqep_position_synapses),
|
||||
.ext = ti_eqep_position_ext,
|
||||
.num_ext = ARRAY_SIZE(ti_eqep_position_ext),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config ti_eqep_regmap32_config = {
|
||||
.name = "32-bit",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = 0x24,
|
||||
};
|
||||
|
||||
static const struct regmap_config ti_eqep_regmap16_config = {
|
||||
.name = "16-bit",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
.reg_stride = 2,
|
||||
.max_register = 0x1e,
|
||||
};
|
||||
|
||||
static int ti_eqep_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ti_eqep_cnt *priv;
|
||||
void __iomem *base;
|
||||
int err;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
priv->regmap32 = devm_regmap_init_mmio(dev, base,
|
||||
&ti_eqep_regmap32_config);
|
||||
if (IS_ERR(priv->regmap32))
|
||||
return PTR_ERR(priv->regmap32);
|
||||
|
||||
priv->regmap16 = devm_regmap_init_mmio(dev, base + 0x24,
|
||||
&ti_eqep_regmap16_config);
|
||||
if (IS_ERR(priv->regmap16))
|
||||
return PTR_ERR(priv->regmap16);
|
||||
|
||||
priv->counter.name = dev_name(dev);
|
||||
priv->counter.parent = dev;
|
||||
priv->counter.ops = &ti_eqep_counter_ops;
|
||||
priv->counter.counts = ti_eqep_counts;
|
||||
priv->counter.num_counts = ARRAY_SIZE(ti_eqep_counts);
|
||||
priv->counter.signals = ti_eqep_signals;
|
||||
priv->counter.num_signals = ARRAY_SIZE(ti_eqep_signals);
|
||||
priv->counter.priv = priv;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
/*
|
||||
* Need to make sure power is turned on. On AM33xx, this comes from the
|
||||
* parent PWMSS bus driver. On AM17xx, this comes from the PSC power
|
||||
* domain.
|
||||
*/
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
err = counter_register(&priv->counter);
|
||||
if (err < 0) {
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_eqep_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ti_eqep_cnt *priv = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
counter_unregister(&priv->counter);
|
||||
pm_runtime_put_sync(dev),
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ti_eqep_of_match[] = {
|
||||
{ .compatible = "ti,am3352-eqep", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ti_eqep_of_match);
|
||||
|
||||
static struct platform_driver ti_eqep_driver = {
|
||||
.probe = ti_eqep_probe,
|
||||
.remove = ti_eqep_remove,
|
||||
.driver = {
|
||||
.name = "ti-eqep-cnt",
|
||||
.of_match_table = ti_eqep_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ti_eqep_driver);
|
||||
|
||||
MODULE_AUTHOR("David Lechner <david@lechnology.com>");
|
||||
MODULE_DESCRIPTION("TI eQEP counter driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -40,7 +40,8 @@ comment "Native drivers"
|
||||
|
||||
config SENSORS_AB8500
|
||||
tristate "AB8500 thermal monitoring"
|
||||
depends on AB8500_GPADC && AB8500_BM
|
||||
depends on AB8500_GPADC && AB8500_BM && (IIO = y)
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for the thermal sensor part
|
||||
of the AB8500 chip. The driver includes thermal management for
|
||||
|
@ -17,20 +17,24 @@
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power/ab8500.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
#include "abx500.h"
|
||||
|
||||
#define DEFAULT_POWER_OFF_DELAY (HZ * 10)
|
||||
#define THERMAL_VCC 1800
|
||||
#define PULL_UP_RESISTOR 47000
|
||||
/* Number of monitored sensors should not greater than NUM_SENSORS */
|
||||
#define NUM_MONITORED_SENSORS 4
|
||||
|
||||
#define AB8500_SENSOR_AUX1 0
|
||||
#define AB8500_SENSOR_AUX2 1
|
||||
#define AB8500_SENSOR_BTEMP_BALL 2
|
||||
#define AB8500_SENSOR_BAT_CTRL 3
|
||||
#define NUM_MONITORED_SENSORS 4
|
||||
|
||||
struct ab8500_gpadc_cfg {
|
||||
const struct abx500_res_to_temp *temp_tbl;
|
||||
@ -40,7 +44,8 @@ struct ab8500_gpadc_cfg {
|
||||
};
|
||||
|
||||
struct ab8500_temp {
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct iio_channel *aux1;
|
||||
struct iio_channel *aux2;
|
||||
struct ab8500_btemp *btemp;
|
||||
struct delayed_work power_off_work;
|
||||
struct ab8500_gpadc_cfg cfg;
|
||||
@ -82,15 +87,21 @@ static int ab8500_read_sensor(struct abx500_temp *data, u8 sensor, int *temp)
|
||||
int voltage, ret;
|
||||
struct ab8500_temp *ab8500_data = data->plat_data;
|
||||
|
||||
if (sensor == BAT_CTRL) {
|
||||
*temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp);
|
||||
} else if (sensor == BTEMP_BALL) {
|
||||
if (sensor == AB8500_SENSOR_BTEMP_BALL) {
|
||||
*temp = ab8500_btemp_get_temp(ab8500_data->btemp);
|
||||
} else {
|
||||
voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor);
|
||||
if (voltage < 0)
|
||||
return voltage;
|
||||
|
||||
} else if (sensor == AB8500_SENSOR_BAT_CTRL) {
|
||||
*temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp);
|
||||
} else if (sensor == AB8500_SENSOR_AUX1) {
|
||||
ret = iio_read_channel_processed(ab8500_data->aux1, &voltage);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (sensor == AB8500_SENSOR_AUX2) {
|
||||
ret = iio_read_channel_processed(ab8500_data->aux2, &voltage);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -164,10 +175,6 @@ int abx500_hwmon_init(struct abx500_temp *data)
|
||||
if (!ab8500_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ab8500_data->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
if (IS_ERR(ab8500_data->gpadc))
|
||||
return PTR_ERR(ab8500_data->gpadc);
|
||||
|
||||
ab8500_data->btemp = ab8500_btemp_get();
|
||||
if (IS_ERR(ab8500_data->btemp))
|
||||
return PTR_ERR(ab8500_data->btemp);
|
||||
@ -181,15 +188,25 @@ int abx500_hwmon_init(struct abx500_temp *data)
|
||||
ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size;
|
||||
|
||||
data->plat_data = ab8500_data;
|
||||
ab8500_data->aux1 = devm_iio_channel_get(&data->pdev->dev, "aux1");
|
||||
if (IS_ERR(ab8500_data->aux1)) {
|
||||
if (PTR_ERR(ab8500_data->aux1) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&data->pdev->dev, "failed to get AUX1 ADC channel\n");
|
||||
return PTR_ERR(ab8500_data->aux1);
|
||||
}
|
||||
ab8500_data->aux2 = devm_iio_channel_get(&data->pdev->dev, "aux2");
|
||||
if (IS_ERR(ab8500_data->aux2)) {
|
||||
if (PTR_ERR(ab8500_data->aux2) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&data->pdev->dev, "failed to get AUX2 ADC channel\n");
|
||||
return PTR_ERR(ab8500_data->aux2);
|
||||
}
|
||||
|
||||
/*
|
||||
* ADC_AUX1 and ADC_AUX2, connected to external NTC
|
||||
* BTEMP_BALL and BAT_CTRL, fixed usage
|
||||
*/
|
||||
data->gpadc_addr[0] = ADC_AUX1;
|
||||
data->gpadc_addr[1] = ADC_AUX2;
|
||||
data->gpadc_addr[2] = BTEMP_BALL;
|
||||
data->gpadc_addr[3] = BAT_CTRL;
|
||||
data->gpadc_addr[0] = AB8500_SENSOR_AUX1;
|
||||
data->gpadc_addr[1] = AB8500_SENSOR_AUX2;
|
||||
data->gpadc_addr[2] = AB8500_SENSOR_BTEMP_BALL;
|
||||
data->gpadc_addr[3] = AB8500_SENSOR_BAT_CTRL;
|
||||
data->monitored_sensors = NUM_MONITORED_SENSORS;
|
||||
|
||||
data->ops.read_sensor = ab8500_read_sensor;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
@ -6,6 +6,16 @@
|
||||
|
||||
menu "Analog to digital converters"
|
||||
|
||||
config AB8500_GPADC
|
||||
bool "ST-Ericsson AB8500 GPADC driver"
|
||||
depends on AB8500_CORE && REGULATOR_AB8500
|
||||
default y
|
||||
help
|
||||
AB8500 Analog Baseband, mixed signal integrated circuit GPADC
|
||||
(General Purpose Analog to Digital Converter) driver used to monitor
|
||||
internal voltages, convert accessory and battery, AC (charger, mains)
|
||||
and USB voltages integral to the U8500 platform.
|
||||
|
||||
config AD_SIGMA_DELTA
|
||||
tristate
|
||||
select IIO_BUFFER
|
||||
@ -432,6 +442,17 @@ config INGENIC_ADC
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called ingenic_adc.
|
||||
|
||||
config INTEL_MRFLD_ADC
|
||||
tristate "Intel Merrifield Basin Cove ADC driver"
|
||||
depends on INTEL_SOC_PMIC_MRFLD
|
||||
help
|
||||
Say yes here to have support for Basin Cove power management IC (PMIC) ADC
|
||||
device. Depending on platform configuration, this general purpose ADC can
|
||||
be used for sampling sensors such as thermal resistors.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called intel_mrfld_adc.
|
||||
|
||||
config IMX7D_ADC
|
||||
tristate "Freescale IMX7D ADC driver"
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
@ -508,8 +529,8 @@ config MAX1027
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Maxim SPI ADC models
|
||||
max1027, max1029 and max1031.
|
||||
Say yes here to build support for Maxim SPI {10,12}-bit ADC models:
|
||||
max1027, max1029, max1031, max1227, max1229 and max1231.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max1027.
|
||||
|
@ -4,6 +4,7 @@
|
||||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
|
||||
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
|
||||
obj-$(CONFIG_AD7124) += ad7124.o
|
||||
obj-$(CONFIG_AD7266) += ad7266.o
|
||||
@ -42,6 +43,7 @@ obj-$(CONFIG_HX711) += hx711.o
|
||||
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
|
||||
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
|
||||
obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
|
||||
obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
|
||||
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
|
||||
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
|
||||
|
1218
drivers/iio/adc/ab8500-gpadc.c
Normal file
1218
drivers/iio/adc/ab8500-gpadc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1483,7 +1483,7 @@ dma_free_area:
|
||||
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
|
||||
dma_chan_disable:
|
||||
dma_release_channel(st->dma_st.dma_chan);
|
||||
st->dma_st.dma_chan = 0;
|
||||
st->dma_st.dma_chan = NULL;
|
||||
dma_exit:
|
||||
dev_info(&pdev->dev, "continuing without DMA support\n");
|
||||
}
|
||||
@ -1506,7 +1506,7 @@ static void at91_adc_dma_disable(struct platform_device *pdev)
|
||||
dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE,
|
||||
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
|
||||
dma_release_channel(st->dma_st.dma_chan);
|
||||
st->dma_st.dma_chan = 0;
|
||||
st->dma_st.dma_chan = NULL;
|
||||
|
||||
dev_info(&pdev->dev, "continuing without DMA support\n");
|
||||
}
|
||||
|
@ -1008,7 +1008,7 @@ static int cpcap_adc_probe(struct platform_device *pdev)
|
||||
|
||||
error = devm_request_threaded_irq(&pdev->dev, ddata->irq, NULL,
|
||||
cpcap_adc_irq_thread,
|
||||
IRQF_TRIGGER_NONE,
|
||||
IRQF_TRIGGER_NONE | IRQF_ONESHOT,
|
||||
"cpcap-adc", indio_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "could not get irq: %i\n",
|
||||
|
@ -651,7 +651,7 @@ static irqreturn_t exynos_ts_isr(int irq, void *dev_id)
|
||||
input_sync(info->input);
|
||||
|
||||
usleep_range(1000, 1100);
|
||||
};
|
||||
}
|
||||
|
||||
writel(0, ADC_V1_CLRINTPNDNUP(info->regs));
|
||||
|
||||
@ -769,7 +769,6 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct iio_dev *indio_dev = NULL;
|
||||
struct resource *mem;
|
||||
bool has_ts = false;
|
||||
int ret = -ENODEV;
|
||||
int irq;
|
||||
@ -788,8 +787,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
info->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
info->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(info->regs))
|
||||
return PTR_ERR(info->regs);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
/* gain to pulse and scale conversion */
|
||||
#define HX711_GAIN_MAX 3
|
||||
#define HX711_RESET_GAIN 128
|
||||
|
||||
struct hx711_gain_to_scale {
|
||||
int gain;
|
||||
@ -185,8 +186,7 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data)
|
||||
|
||||
static int hx711_reset(struct hx711_data *hx711_data)
|
||||
{
|
||||
int ret;
|
||||
int val = gpiod_get_value(hx711_data->gpiod_dout);
|
||||
int val = hx711_wait_for_ready(hx711_data);
|
||||
|
||||
if (val) {
|
||||
/*
|
||||
@ -202,22 +202,10 @@ static int hx711_reset(struct hx711_data *hx711_data)
|
||||
msleep(10);
|
||||
gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
|
||||
|
||||
ret = hx711_wait_for_ready(hx711_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* after a reset the gain is 128 so we do a dummy read
|
||||
* to set the gain for the next read
|
||||
*/
|
||||
ret = hx711_read(hx711_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* after a dummy read we need to wait vor readiness
|
||||
* for not mixing gain pulses with the clock
|
||||
*/
|
||||
val = hx711_wait_for_ready(hx711_data);
|
||||
|
||||
/* after a reset the gain is 128 */
|
||||
hx711_data->gain_set = HX711_RESET_GAIN;
|
||||
}
|
||||
|
||||
return val;
|
||||
|
262
drivers/iio/adc/intel_mrfld_adc.c
Normal file
262
drivers/iio/adc/intel_mrfld_adc.c
Normal file
@ -0,0 +1,262 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ADC driver for Basin Cove PMIC
|
||||
*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
* Author: Bin Yang <bin.yang@intel.com>
|
||||
*
|
||||
* Rewritten for upstream by:
|
||||
* Vincent Pelletier <plr.vincent@gmail.com>
|
||||
* Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/intel_soc_pmic.h>
|
||||
#include <linux/mfd/intel_soc_pmic_mrfld.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/machine.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define BCOVE_GPADCREQ 0xDC
|
||||
#define BCOVE_GPADCREQ_BUSY BIT(0)
|
||||
#define BCOVE_GPADCREQ_IRQEN BIT(1)
|
||||
|
||||
#define BCOVE_ADCIRQ_ALL ( \
|
||||
BCOVE_ADCIRQ_BATTEMP | \
|
||||
BCOVE_ADCIRQ_SYSTEMP | \
|
||||
BCOVE_ADCIRQ_BATTID | \
|
||||
BCOVE_ADCIRQ_VIBATT | \
|
||||
BCOVE_ADCIRQ_CCTICK)
|
||||
|
||||
#define BCOVE_ADC_TIMEOUT msecs_to_jiffies(1000)
|
||||
|
||||
static const u8 mrfld_adc_requests[] = {
|
||||
BCOVE_ADCIRQ_VIBATT,
|
||||
BCOVE_ADCIRQ_BATTID,
|
||||
BCOVE_ADCIRQ_VIBATT,
|
||||
BCOVE_ADCIRQ_SYSTEMP,
|
||||
BCOVE_ADCIRQ_BATTEMP,
|
||||
BCOVE_ADCIRQ_BATTEMP,
|
||||
BCOVE_ADCIRQ_SYSTEMP,
|
||||
BCOVE_ADCIRQ_SYSTEMP,
|
||||
BCOVE_ADCIRQ_SYSTEMP,
|
||||
};
|
||||
|
||||
struct mrfld_adc {
|
||||
struct regmap *regmap;
|
||||
struct completion completion;
|
||||
/* Lock to protect the IPC transfers */
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static irqreturn_t mrfld_adc_thread_isr(int irq, void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct mrfld_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
complete(&adc->completion);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mrfld_adc_single_conv(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *result)
|
||||
{
|
||||
struct mrfld_adc *adc = iio_priv(indio_dev);
|
||||
struct regmap *regmap = adc->regmap;
|
||||
unsigned int req;
|
||||
long timeout;
|
||||
u8 buf[2];
|
||||
int ret;
|
||||
|
||||
reinit_completion(&adc->completion);
|
||||
|
||||
regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0);
|
||||
regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0);
|
||||
|
||||
ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req,
|
||||
!(req & BCOVE_GPADCREQ_BUSY),
|
||||
2000, 1000000);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
req = mrfld_adc_requests[chan->channel];
|
||||
ret = regmap_write(regmap, BCOVE_GPADCREQ, BCOVE_GPADCREQ_IRQEN | req);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
timeout = wait_for_completion_interruptible_timeout(&adc->completion,
|
||||
BCOVE_ADC_TIMEOUT);
|
||||
if (timeout < 0) {
|
||||
ret = timeout;
|
||||
goto done;
|
||||
}
|
||||
if (timeout == 0) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(regmap, chan->address, buf, 2);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
*result = get_unaligned_be16(buf);
|
||||
ret = IIO_VAL_INT;
|
||||
|
||||
done:
|
||||
regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0xff);
|
||||
regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0xff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mrfld_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct mrfld_adc *adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&adc->lock);
|
||||
ret = mrfld_adc_single_conv(indio_dev, chan, val);
|
||||
mutex_unlock(&adc->lock);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info mrfld_adc_iio_info = {
|
||||
.read_raw = &mrfld_adc_read_raw,
|
||||
};
|
||||
|
||||
#define BCOVE_ADC_CHANNEL(_type, _channel, _datasheet_name, _address) \
|
||||
{ \
|
||||
.indexed = 1, \
|
||||
.type = _type, \
|
||||
.channel = _channel, \
|
||||
.address = _address, \
|
||||
.datasheet_name = _datasheet_name, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mrfld_adc_channels[] = {
|
||||
BCOVE_ADC_CHANNEL(IIO_VOLTAGE, 0, "CH0", 0xE9),
|
||||
BCOVE_ADC_CHANNEL(IIO_RESISTANCE, 1, "CH1", 0xEB),
|
||||
BCOVE_ADC_CHANNEL(IIO_CURRENT, 2, "CH2", 0xED),
|
||||
BCOVE_ADC_CHANNEL(IIO_TEMP, 3, "CH3", 0xCC),
|
||||
BCOVE_ADC_CHANNEL(IIO_TEMP, 4, "CH4", 0xC8),
|
||||
BCOVE_ADC_CHANNEL(IIO_TEMP, 5, "CH5", 0xCA),
|
||||
BCOVE_ADC_CHANNEL(IIO_TEMP, 6, "CH6", 0xC2),
|
||||
BCOVE_ADC_CHANNEL(IIO_TEMP, 7, "CH7", 0xC4),
|
||||
BCOVE_ADC_CHANNEL(IIO_TEMP, 8, "CH8", 0xC6),
|
||||
};
|
||||
|
||||
static struct iio_map iio_maps[] = {
|
||||
IIO_MAP("CH0", "bcove-battery", "VBATRSLT"),
|
||||
IIO_MAP("CH1", "bcove-battery", "BATTID"),
|
||||
IIO_MAP("CH2", "bcove-battery", "IBATRSLT"),
|
||||
IIO_MAP("CH3", "bcove-temp", "PMICTEMP"),
|
||||
IIO_MAP("CH4", "bcove-temp", "BATTEMP0"),
|
||||
IIO_MAP("CH5", "bcove-temp", "BATTEMP1"),
|
||||
IIO_MAP("CH6", "bcove-temp", "SYSTEMP0"),
|
||||
IIO_MAP("CH7", "bcove-temp", "SYSTEMP1"),
|
||||
IIO_MAP("CH8", "bcove-temp", "SYSTEMP2"),
|
||||
{}
|
||||
};
|
||||
|
||||
static int mrfld_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
|
||||
struct iio_dev *indio_dev;
|
||||
struct mrfld_adc *adc;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*indio_dev));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
adc = iio_priv(indio_dev);
|
||||
|
||||
mutex_init(&adc->lock);
|
||||
init_completion(&adc->completion);
|
||||
adc->regmap = pmic->regmap;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_adc_thread_isr,
|
||||
IRQF_ONESHOT | IRQF_SHARED, pdev->name,
|
||||
indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->name = pdev->name;
|
||||
|
||||
indio_dev->channels = mrfld_adc_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mrfld_adc_channels);
|
||||
indio_dev->info = &mrfld_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = iio_map_array_register(indio_dev, iio_maps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_device_register(dev, indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_array_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
err_array_unregister:
|
||||
iio_map_array_unregister(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mrfld_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
|
||||
iio_map_array_unregister(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id mrfld_adc_id_table[] = {
|
||||
{ .name = "mrfld_bcove_adc" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mrfld_adc_id_table);
|
||||
|
||||
static struct platform_driver mrfld_adc_driver = {
|
||||
.driver = {
|
||||
.name = "mrfld_bcove_adc",
|
||||
},
|
||||
.probe = mrfld_adc_probe,
|
||||
.remove = mrfld_adc_remove,
|
||||
.id_table = mrfld_adc_id_table,
|
||||
};
|
||||
module_platform_driver(mrfld_adc_driver);
|
||||
|
||||
MODULE_AUTHOR("Bin Yang <bin.yang@intel.com>");
|
||||
MODULE_AUTHOR("Vincent Pelletier <plr.vincent@gmail.com>");
|
||||
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("ADC driver for Basin Cove PMIC");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -63,12 +63,18 @@ enum max1027_id {
|
||||
max1027,
|
||||
max1029,
|
||||
max1031,
|
||||
max1227,
|
||||
max1229,
|
||||
max1231,
|
||||
};
|
||||
|
||||
static const struct spi_device_id max1027_id[] = {
|
||||
{"max1027", max1027},
|
||||
{"max1029", max1029},
|
||||
{"max1031", max1031},
|
||||
{"max1227", max1227},
|
||||
{"max1229", max1229},
|
||||
{"max1231", max1231},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max1027_id);
|
||||
@ -78,12 +84,15 @@ static const struct of_device_id max1027_adc_dt_ids[] = {
|
||||
{ .compatible = "maxim,max1027" },
|
||||
{ .compatible = "maxim,max1029" },
|
||||
{ .compatible = "maxim,max1031" },
|
||||
{ .compatible = "maxim,max1227" },
|
||||
{ .compatible = "maxim,max1229" },
|
||||
{ .compatible = "maxim,max1231" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
|
||||
#endif
|
||||
|
||||
#define MAX1027_V_CHAN(index) \
|
||||
#define MAX1027_V_CHAN(index, depth) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
@ -93,7 +102,7 @@ MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
|
||||
.scan_index = index + 1, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 10, \
|
||||
.realbits = depth, \
|
||||
.storagebits = 16, \
|
||||
.shift = 2, \
|
||||
.endianness = IIO_BE, \
|
||||
@ -115,52 +124,54 @@ MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
|
||||
}, \
|
||||
}
|
||||
|
||||
#define MAX1X27_CHANNELS(depth) \
|
||||
MAX1027_T_CHAN, \
|
||||
MAX1027_V_CHAN(0, depth), \
|
||||
MAX1027_V_CHAN(1, depth), \
|
||||
MAX1027_V_CHAN(2, depth), \
|
||||
MAX1027_V_CHAN(3, depth), \
|
||||
MAX1027_V_CHAN(4, depth), \
|
||||
MAX1027_V_CHAN(5, depth), \
|
||||
MAX1027_V_CHAN(6, depth), \
|
||||
MAX1027_V_CHAN(7, depth)
|
||||
|
||||
#define MAX1X29_CHANNELS(depth) \
|
||||
MAX1X27_CHANNELS(depth), \
|
||||
MAX1027_V_CHAN(8, depth), \
|
||||
MAX1027_V_CHAN(9, depth), \
|
||||
MAX1027_V_CHAN(10, depth), \
|
||||
MAX1027_V_CHAN(11, depth)
|
||||
|
||||
#define MAX1X31_CHANNELS(depth) \
|
||||
MAX1X27_CHANNELS(depth), \
|
||||
MAX1X29_CHANNELS(depth), \
|
||||
MAX1027_V_CHAN(12, depth), \
|
||||
MAX1027_V_CHAN(13, depth), \
|
||||
MAX1027_V_CHAN(14, depth), \
|
||||
MAX1027_V_CHAN(15, depth)
|
||||
|
||||
static const struct iio_chan_spec max1027_channels[] = {
|
||||
MAX1027_T_CHAN,
|
||||
MAX1027_V_CHAN(0),
|
||||
MAX1027_V_CHAN(1),
|
||||
MAX1027_V_CHAN(2),
|
||||
MAX1027_V_CHAN(3),
|
||||
MAX1027_V_CHAN(4),
|
||||
MAX1027_V_CHAN(5),
|
||||
MAX1027_V_CHAN(6),
|
||||
MAX1027_V_CHAN(7)
|
||||
MAX1X27_CHANNELS(10),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max1029_channels[] = {
|
||||
MAX1027_T_CHAN,
|
||||
MAX1027_V_CHAN(0),
|
||||
MAX1027_V_CHAN(1),
|
||||
MAX1027_V_CHAN(2),
|
||||
MAX1027_V_CHAN(3),
|
||||
MAX1027_V_CHAN(4),
|
||||
MAX1027_V_CHAN(5),
|
||||
MAX1027_V_CHAN(6),
|
||||
MAX1027_V_CHAN(7),
|
||||
MAX1027_V_CHAN(8),
|
||||
MAX1027_V_CHAN(9),
|
||||
MAX1027_V_CHAN(10),
|
||||
MAX1027_V_CHAN(11)
|
||||
MAX1X29_CHANNELS(10),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max1031_channels[] = {
|
||||
MAX1027_T_CHAN,
|
||||
MAX1027_V_CHAN(0),
|
||||
MAX1027_V_CHAN(1),
|
||||
MAX1027_V_CHAN(2),
|
||||
MAX1027_V_CHAN(3),
|
||||
MAX1027_V_CHAN(4),
|
||||
MAX1027_V_CHAN(5),
|
||||
MAX1027_V_CHAN(6),
|
||||
MAX1027_V_CHAN(7),
|
||||
MAX1027_V_CHAN(8),
|
||||
MAX1027_V_CHAN(9),
|
||||
MAX1027_V_CHAN(10),
|
||||
MAX1027_V_CHAN(11),
|
||||
MAX1027_V_CHAN(12),
|
||||
MAX1027_V_CHAN(13),
|
||||
MAX1027_V_CHAN(14),
|
||||
MAX1027_V_CHAN(15)
|
||||
MAX1X31_CHANNELS(10),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max1227_channels[] = {
|
||||
MAX1X27_CHANNELS(12),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max1229_channels[] = {
|
||||
MAX1X29_CHANNELS(12),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max1231_channels[] = {
|
||||
MAX1X31_CHANNELS(12),
|
||||
};
|
||||
|
||||
static const unsigned long max1027_available_scan_masks[] = {
|
||||
@ -200,6 +211,21 @@ static const struct max1027_chip_info max1027_chip_info_tbl[] = {
|
||||
.num_channels = ARRAY_SIZE(max1031_channels),
|
||||
.available_scan_masks = max1031_available_scan_masks,
|
||||
},
|
||||
[max1227] = {
|
||||
.channels = max1227_channels,
|
||||
.num_channels = ARRAY_SIZE(max1227_channels),
|
||||
.available_scan_masks = max1027_available_scan_masks,
|
||||
},
|
||||
[max1229] = {
|
||||
.channels = max1229_channels,
|
||||
.num_channels = ARRAY_SIZE(max1229_channels),
|
||||
.available_scan_masks = max1029_available_scan_masks,
|
||||
},
|
||||
[max1231] = {
|
||||
.channels = max1231_channels,
|
||||
.num_channels = ARRAY_SIZE(max1231_channels),
|
||||
.available_scan_masks = max1031_available_scan_masks,
|
||||
},
|
||||
};
|
||||
|
||||
struct max1027_state {
|
||||
@ -284,7 +310,7 @@ static int max1027_read_raw(struct iio_dev *indio_dev,
|
||||
break;
|
||||
case IIO_VOLTAGE:
|
||||
*val = 2500;
|
||||
*val2 = 10;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
ret = IIO_VAL_FRACTIONAL_LOG2;
|
||||
break;
|
||||
default:
|
||||
@ -309,8 +335,11 @@ static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
u8 *val = (u8 *)st->buffer;
|
||||
|
||||
if (readval != NULL)
|
||||
return -EINVAL;
|
||||
if (readval) {
|
||||
int ret = spi_read(st->spi, val, 2);
|
||||
*readval = be16_to_cpu(st->buffer[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = (u8)writeval;
|
||||
return spi_write(st->spi, val, 1);
|
||||
@ -427,34 +456,47 @@ static int max1027_probe(struct spi_device *spi)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
&max1027_trigger_handler, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
|
||||
return ret;
|
||||
if (spi->irq) {
|
||||
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
&max1027_trigger_handler,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
|
||||
indio_dev->name);
|
||||
if (st->trig == NULL) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(&indio_dev->dev,
|
||||
"Failed to allocate iio trigger\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->trig->ops = &max1027_trigger_ops;
|
||||
st->trig->dev.parent = &spi->dev;
|
||||
iio_trigger_set_drvdata(st->trig, indio_dev);
|
||||
iio_trigger_register(st->trig);
|
||||
|
||||
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
NULL,
|
||||
IRQF_TRIGGER_FALLING,
|
||||
spi->dev.driver->name,
|
||||
st->trig);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
|
||||
indio_dev->name);
|
||||
if (st->trig == NULL) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->trig->ops = &max1027_trigger_ops;
|
||||
st->trig->dev.parent = &spi->dev;
|
||||
iio_trigger_set_drvdata(st->trig, indio_dev);
|
||||
iio_trigger_register(st->trig);
|
||||
|
||||
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
NULL,
|
||||
IRQF_TRIGGER_FALLING,
|
||||
spi->dev.driver->name, st->trig);
|
||||
/* Internal reset */
|
||||
st->reg = MAX1027_RST_REG;
|
||||
ret = spi_write(st->spi, &st->reg, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
|
||||
dev_err(&indio_dev->dev, "Failed to reset the ADC\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -480,5 +522,5 @@ static struct spi_driver max1027_driver = {
|
||||
module_spi_driver(max1027_driver);
|
||||
|
||||
MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>");
|
||||
MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC");
|
||||
MODULE_DESCRIPTION("MAX1X27/MAX1X29/MAX1X31 ADC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -164,7 +164,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
|
||||
case mcp3550_60:
|
||||
case mcp3551:
|
||||
case mcp3553: {
|
||||
u32 raw = be32_to_cpup((u32 *)adc->rx_buf);
|
||||
u32 raw = be32_to_cpup((__be32 *)adc->rx_buf);
|
||||
|
||||
if (!(adc->spi->mode & SPI_CPOL))
|
||||
raw <<= 1; /* strip Data Ready bit in SPI mode 0,0 */
|
||||
|
@ -1187,7 +1187,6 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
|
||||
const struct meson_sar_adc_data *match_data;
|
||||
struct meson_sar_adc_priv *priv;
|
||||
struct iio_dev *indio_dev;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int irq, ret;
|
||||
|
||||
@ -1214,8 +1213,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &meson_sar_adc_iio_info;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -38,12 +38,12 @@
|
||||
#define HAS_ANASWVDD BIT(1)
|
||||
|
||||
/**
|
||||
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
|
||||
* struct stm32_adc_common_regs - stm32 common registers
|
||||
* @csr: common status register offset
|
||||
* @ccr: common control register offset
|
||||
* @eoc1: adc1 end of conversion flag in @csr
|
||||
* @eoc2: adc2 end of conversion flag in @csr
|
||||
* @eoc3: adc3 end of conversion flag in @csr
|
||||
* @eoc1_msk: adc1 end of conversion flag in @csr
|
||||
* @eoc2_msk: adc2 end of conversion flag in @csr
|
||||
* @eoc3_msk: adc3 end of conversion flag in @csr
|
||||
* @ier: interrupt enable register offset for each adc
|
||||
* @eocie_msk: end of conversion interrupt enable mask in @ier
|
||||
*/
|
||||
@ -60,7 +60,7 @@ struct stm32_adc_common_regs {
|
||||
struct stm32_adc_priv;
|
||||
|
||||
/**
|
||||
* stm32_adc_priv_cfg - stm32 core compatible configuration data
|
||||
* struct stm32_adc_priv_cfg - stm32 core compatible configuration data
|
||||
* @regs: common registers for all instances
|
||||
* @clk_sel: clock selection routine
|
||||
* @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
|
||||
@ -117,6 +117,7 @@ static int stm32f4_pclk_div[] = {2, 4, 6, 8};
|
||||
|
||||
/**
|
||||
* stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler
|
||||
* @pdev: platform device
|
||||
* @priv: stm32 ADC core private data
|
||||
* Select clock prescaler used for analog conversions, before using ADC.
|
||||
*/
|
||||
|
@ -102,7 +102,7 @@ struct stm32_adc_calib {
|
||||
};
|
||||
|
||||
/**
|
||||
* stm32_adc_regs - stm32 ADC misc registers & bitfield desc
|
||||
* struct stm32_adc_regs - stm32 ADC misc registers & bitfield desc
|
||||
* @reg: register offset
|
||||
* @mask: bitfield mask
|
||||
* @shift: left shift
|
||||
@ -114,7 +114,7 @@ struct stm32_adc_regs {
|
||||
};
|
||||
|
||||
/**
|
||||
* stm32_adc_regspec - stm32 registers definition, compatible dependent data
|
||||
* struct stm32_adc_regspec - stm32 registers definition
|
||||
* @dr: data register offset
|
||||
* @ier_eoc: interrupt enable register & eocie bitfield
|
||||
* @isr_eoc: interrupt status register & eoc bitfield
|
||||
@ -140,7 +140,7 @@ struct stm32_adc_regspec {
|
||||
struct stm32_adc;
|
||||
|
||||
/**
|
||||
* stm32_adc_cfg - stm32 compatible configuration data
|
||||
* struct stm32_adc_cfg - stm32 compatible configuration data
|
||||
* @regs: registers descriptions
|
||||
* @adc_info: per instance input channels definitions
|
||||
* @trigs: external trigger sources
|
||||
@ -183,8 +183,8 @@ struct stm32_adc_cfg {
|
||||
* @rx_buf: dma rx buffer cpu address
|
||||
* @rx_dma_buf: dma rx buffer bus address
|
||||
* @rx_buf_sz: dma rx buffer size
|
||||
* @difsel bitmask to set single-ended/differential channel
|
||||
* @pcsel bitmask to preselect channels on some devices
|
||||
* @difsel: bitmask to set single-ended/differential channel
|
||||
* @pcsel: bitmask to preselect channels on some devices
|
||||
* @smpr_val: sampling time settings (e.g. smpr1 / smpr2)
|
||||
* @cal: optional calibration data on some devices
|
||||
* @chan_name: channel name array
|
||||
@ -254,7 +254,7 @@ static const struct stm32_adc_info stm32h7_adc_info = {
|
||||
.num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* stm32f4_sq - describe regular sequence registers
|
||||
* - L: sequence len (register & bit field)
|
||||
* - SQ1..SQ16: sequence entries (register & bit field)
|
||||
@ -301,7 +301,7 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
|
||||
{}, /* sentinel */
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* stm32f4_smp_bits[] - describe sampling time register index & bit fields
|
||||
* Sorted so it can be indexed by channel number.
|
||||
*/
|
||||
@ -392,7 +392,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* stm32h7_smp_bits - describe sampling time register index & bit fields
|
||||
* Sorted so it can be indexed by channel number.
|
||||
*/
|
||||
@ -994,6 +994,7 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
|
||||
|
||||
/**
|
||||
* stm32_adc_get_trig_extsel() - Get external trigger selection
|
||||
* @indio_dev: IIO device structure
|
||||
* @trig: trigger
|
||||
*
|
||||
* Returns trigger extsel value, if trig matches, -EINVAL otherwise.
|
||||
@ -1297,6 +1298,10 @@ static int stm32_adc_of_xlate(struct iio_dev *indio_dev,
|
||||
|
||||
/**
|
||||
* stm32_adc_debugfs_reg_access - read or write register value
|
||||
* @indio_dev: IIO device structure
|
||||
* @reg: register offset
|
||||
* @writeval: value to write
|
||||
* @readval: value to read
|
||||
*
|
||||
* To read a value from an ADC register:
|
||||
* echo [ADC reg offset] > direct_reg_access
|
||||
|
@ -175,7 +175,7 @@ static int stmpe_read_raw(struct iio_dev *indio_dev,
|
||||
static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct stmpe_adc *info = (struct stmpe_adc *)dev_id;
|
||||
u16 data;
|
||||
__be16 data;
|
||||
|
||||
if (info->channel <= STMPE_ADC_LAST_NR) {
|
||||
int int_sta;
|
||||
|
@ -495,7 +495,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
|
||||
ret = twl4030_madc_disable_irq(madc, i);
|
||||
if (ret < 0)
|
||||
dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
|
||||
madc->requests[i].result_pending = 1;
|
||||
madc->requests[i].result_pending = true;
|
||||
}
|
||||
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
|
||||
r = &madc->requests[i];
|
||||
@ -507,8 +507,8 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
|
||||
len = twl4030_madc_read_channels(madc, method->rbase,
|
||||
r->channels, r->rbuf, r->raw);
|
||||
/* Free request */
|
||||
r->result_pending = 0;
|
||||
r->active = 0;
|
||||
r->result_pending = false;
|
||||
r->active = false;
|
||||
}
|
||||
mutex_unlock(&madc->lock);
|
||||
|
||||
@ -521,15 +521,15 @@ err_i2c:
|
||||
*/
|
||||
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
|
||||
r = &madc->requests[i];
|
||||
if (r->active == 0)
|
||||
if (!r->active)
|
||||
continue;
|
||||
method = &twl4030_conversion_methods[r->method];
|
||||
/* Read results */
|
||||
len = twl4030_madc_read_channels(madc, method->rbase,
|
||||
r->channels, r->rbuf, r->raw);
|
||||
/* Free request */
|
||||
r->result_pending = 0;
|
||||
r->active = 0;
|
||||
r->result_pending = false;
|
||||
r->active = false;
|
||||
}
|
||||
mutex_unlock(&madc->lock);
|
||||
|
||||
@ -652,16 +652,16 @@ static int twl4030_madc_conversion(struct twl4030_madc_request *req)
|
||||
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
twl4030_madc->requests[req->method].active = 1;
|
||||
twl4030_madc->requests[req->method].active = true;
|
||||
/* Wait until conversion is ready (ctrl register returns EOC) */
|
||||
ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
|
||||
if (ret) {
|
||||
twl4030_madc->requests[req->method].active = 0;
|
||||
twl4030_madc->requests[req->method].active = false;
|
||||
goto out;
|
||||
}
|
||||
ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
|
||||
req->channels, req->rbuf, req->raw);
|
||||
twl4030_madc->requests[req->method].active = 0;
|
||||
twl4030_madc->requests[req->method].active = false;
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl4030_madc->lock);
|
||||
|
@ -1150,7 +1150,6 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
const struct of_device_id *id;
|
||||
struct iio_dev *indio_dev;
|
||||
unsigned int bipolar_mask;
|
||||
struct resource *mem;
|
||||
unsigned int conf0;
|
||||
struct xadc *xadc;
|
||||
int ret;
|
||||
@ -1180,8 +1179,7 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&xadc->lock);
|
||||
INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
xadc->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
xadc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(xadc->base))
|
||||
return PTR_ERR(xadc->base);
|
||||
|
||||
|
@ -483,7 +483,7 @@ static void sgp_init(struct sgp_data *data)
|
||||
data->iaq_defval_skip_jiffies =
|
||||
43 * data->measure_interval_jiffies;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info sgp_info = {
|
||||
|
@ -117,7 +117,7 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
|
||||
break;
|
||||
case SPS30_READ_AUTO_CLEANING_PERIOD:
|
||||
buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8;
|
||||
buf[1] = (u8)SPS30_AUTO_CLEANING_PERIOD;
|
||||
buf[1] = (u8)(SPS30_AUTO_CLEANING_PERIOD & 0xff);
|
||||
/* fall through */
|
||||
case SPS30_READ_DATA_READY_FLAG:
|
||||
case SPS30_READ_DATA:
|
||||
|
@ -41,6 +41,7 @@ struct ad7303_state {
|
||||
struct regulator *vdd_reg;
|
||||
struct regulator *vref_reg;
|
||||
|
||||
struct mutex lock;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
@ -79,7 +80,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
if (pwr_down)
|
||||
st->config |= AD7303_CFG_POWER_DOWN(chan->channel);
|
||||
@ -90,7 +91,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
|
||||
* mode, so just write one of the DAC channels again */
|
||||
ad7303_write(st, chan->channel, st->dac_cache[chan->channel]);
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -116,7 +117,9 @@ static int ad7303_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&st->lock);
|
||||
*val = st->dac_cache[chan->channel];
|
||||
mutex_unlock(&st->lock);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
vref_uv = ad7303_get_vref(st, chan);
|
||||
@ -144,11 +147,11 @@ static int ad7303_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 = ad7303_write(st, chan->address, val);
|
||||
if (ret == 0)
|
||||
st->dac_cache[chan->channel] = val;
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@ -211,6 +214,8 @@ static int ad7303_probe(struct spi_device *spi)
|
||||
|
||||
st->spi = spi;
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd");
|
||||
if (IS_ERR(st->vdd_reg))
|
||||
return PTR_ERR(st->vdd_reg);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
@ -50,6 +51,41 @@ static const struct regmap_config stm32_dac_regmap_cfg = {
|
||||
.max_register = 0x3fc,
|
||||
};
|
||||
|
||||
static int stm32_dac_core_hw_start(struct device *dev)
|
||||
{
|
||||
struct stm32_dac_common *common = dev_get_drvdata(dev);
|
||||
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "vref enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->pclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "pclk enable failed: %d\n", ret);
|
||||
goto err_regulator_disable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_regulator_disable:
|
||||
regulator_disable(priv->vref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stm32_dac_core_hw_stop(struct device *dev)
|
||||
{
|
||||
struct stm32_dac_common *common = dev_get_drvdata(dev);
|
||||
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
|
||||
|
||||
clk_disable_unprepare(priv->pclk);
|
||||
regulator_disable(priv->vref);
|
||||
}
|
||||
|
||||
static int stm32_dac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -66,6 +102,8 @@ static int stm32_dac_probe(struct platform_device *pdev)
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, &priv->common);
|
||||
|
||||
cfg = (const struct stm32_dac_cfg *)
|
||||
of_match_device(dev->driver->of_match_table, dev)->data;
|
||||
|
||||
@ -74,11 +112,19 @@ static int stm32_dac_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(mmio))
|
||||
return PTR_ERR(mmio);
|
||||
|
||||
regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg);
|
||||
regmap = devm_regmap_init_mmio_clk(dev, "pclk", mmio,
|
||||
&stm32_dac_regmap_cfg);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
priv->common.regmap = regmap;
|
||||
|
||||
priv->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(priv->pclk)) {
|
||||
ret = PTR_ERR(priv->pclk);
|
||||
dev_err(dev, "pclk get failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->vref = devm_regulator_get(dev, "vref");
|
||||
if (IS_ERR(priv->vref)) {
|
||||
ret = PTR_ERR(priv->vref);
|
||||
@ -86,33 +132,22 @@ static int stm32_dac_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_enable(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "vref enable failed\n");
|
||||
return ret;
|
||||
}
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = stm32_dac_core_hw_start(dev);
|
||||
if (ret)
|
||||
goto err_pm_stop;
|
||||
|
||||
ret = regulator_get_voltage(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "vref get voltage failed, %d\n", ret);
|
||||
goto err_vref;
|
||||
goto err_hw_stop;
|
||||
}
|
||||
priv->common.vref_mv = ret / 1000;
|
||||
dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
|
||||
|
||||
priv->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(priv->pclk)) {
|
||||
ret = PTR_ERR(priv->pclk);
|
||||
dev_err(dev, "pclk get failed\n");
|
||||
goto err_vref;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->pclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "pclk enable failed\n");
|
||||
goto err_vref;
|
||||
}
|
||||
|
||||
priv->rst = devm_reset_control_get_exclusive(dev, NULL);
|
||||
if (!IS_ERR(priv->rst)) {
|
||||
reset_control_assert(priv->rst);
|
||||
@ -128,39 +163,79 @@ static int stm32_dac_probe(struct platform_device *pdev)
|
||||
priv->common.hfsel ?
|
||||
STM32H7_DAC_CR_HFSEL : 0);
|
||||
if (ret)
|
||||
goto err_pclk;
|
||||
goto err_hw_stop;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, &priv->common);
|
||||
|
||||
ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to populate DT children\n");
|
||||
goto err_pclk;
|
||||
goto err_hw_stop;
|
||||
}
|
||||
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pclk:
|
||||
clk_disable_unprepare(priv->pclk);
|
||||
err_vref:
|
||||
regulator_disable(priv->vref);
|
||||
err_hw_stop:
|
||||
stm32_dac_core_hw_stop(dev);
|
||||
err_pm_stop:
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_dac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_dac_common *common = platform_get_drvdata(pdev);
|
||||
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
clk_disable_unprepare(priv->pclk);
|
||||
regulator_disable(priv->vref);
|
||||
stm32_dac_core_hw_stop(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dac_core_resume(struct device *dev)
|
||||
{
|
||||
struct stm32_dac_common *common = dev_get_drvdata(dev);
|
||||
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
|
||||
int ret;
|
||||
|
||||
if (priv->common.hfsel) {
|
||||
/* restore hfsel (maybe lost under low power state) */
|
||||
ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR,
|
||||
STM32H7_DAC_CR_HFSEL,
|
||||
STM32H7_DAC_CR_HFSEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return pm_runtime_force_resume(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dac_core_runtime_suspend(struct device *dev)
|
||||
{
|
||||
stm32_dac_core_hw_stop(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dac_core_runtime_resume(struct device *dev)
|
||||
{
|
||||
return stm32_dac_core_hw_start(dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops stm32_dac_core_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume)
|
||||
SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend,
|
||||
stm32_dac_core_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct stm32_dac_cfg stm32h7_dac_cfg = {
|
||||
.has_hfsel = true,
|
||||
};
|
||||
@ -182,6 +257,7 @@ static struct platform_driver stm32_dac_driver = {
|
||||
.driver = {
|
||||
.name = "stm32-dac-core",
|
||||
.of_match_table = stm32_dac_of_match,
|
||||
.pm = &stm32_dac_core_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(stm32_dac_driver);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "stm32-dac-core.h"
|
||||
|
||||
@ -20,6 +21,8 @@
|
||||
#define STM32_DAC_CHANNEL_2 2
|
||||
#define STM32_DAC_IS_CHAN_1(ch) ((ch) & STM32_DAC_CHANNEL_1)
|
||||
|
||||
#define STM32_DAC_AUTO_SUSPEND_DELAY_MS 2000
|
||||
|
||||
/**
|
||||
* struct stm32_dac - private data of DAC driver
|
||||
* @common: reference to DAC common data
|
||||
@ -49,15 +52,34 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
|
||||
bool enable)
|
||||
{
|
||||
struct stm32_dac *dac = iio_priv(indio_dev);
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
|
||||
u32 en = enable ? msk : 0;
|
||||
int ret;
|
||||
|
||||
/* already enabled / disabled ? */
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = stm32_dac_is_enabled(indio_dev, ch);
|
||||
if (ret < 0 || enable == !!ret) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "%s failed\n", en ?
|
||||
"Enable" : "Disable");
|
||||
return ret;
|
||||
goto err_put_pm;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -68,7 +90,20 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
|
||||
if (en && dac->common->hfsel)
|
||||
udelay(1);
|
||||
|
||||
if (!enable) {
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_pm:
|
||||
if (enable) {
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val)
|
||||
@ -272,6 +307,7 @@ static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
|
||||
static int stm32_dac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct stm32_dac *dac;
|
||||
int ret;
|
||||
@ -296,9 +332,61 @@ static int stm32_dac_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
/* Get stm32-dac-core PM online */
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, STM32_DAC_AUTO_SUSPEND_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto err_pm_put;
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pm_put:
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_dac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
iio_device_unregister(indio_dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_dac_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
int channel = indio_dev->channels[0].channel;
|
||||
int ret;
|
||||
|
||||
/* Ensure DAC is disabled before suspend */
|
||||
ret = stm32_dac_is_enabled(indio_dev, channel);
|
||||
if (ret)
|
||||
return ret < 0 ? ret : -EBUSY;
|
||||
|
||||
return pm_runtime_force_suspend(dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops stm32_dac_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_dac_of_match[] = {
|
||||
{ .compatible = "st,stm32-dac", },
|
||||
{},
|
||||
@ -307,9 +395,11 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
|
||||
|
||||
static struct platform_driver stm32_dac_driver = {
|
||||
.probe = stm32_dac_probe,
|
||||
.remove = stm32_dac_remove,
|
||||
.driver = {
|
||||
.name = "stm32-dac",
|
||||
.of_match_table = stm32_dac_of_match,
|
||||
.pm = &stm32_dac_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(stm32_dac_driver);
|
||||
|
@ -543,7 +543,7 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p)
|
||||
toread = bytes_per_datum;
|
||||
offset = 1;
|
||||
/* Put in some dummy value */
|
||||
fifo_values[0] = 0xAAAA;
|
||||
fifo_values[0] = cpu_to_be16(0xAAAA);
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(mpu3050->map,
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -40,6 +40,33 @@ config ADIS16480
|
||||
|
||||
source "drivers/iio/imu/bmi160/Kconfig"
|
||||
|
||||
config FXOS8700
|
||||
tristate
|
||||
|
||||
config FXOS8700_I2C
|
||||
tristate "NXP FXOS8700 I2C driver"
|
||||
depends on I2C
|
||||
select FXOS8700
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to build support for the NXP FXOS8700 m+g combo
|
||||
sensor on I2C.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called fxos8700_i2c.
|
||||
|
||||
config FXOS8700_SPI
|
||||
tristate "NXP FXOS8700 SPI driver"
|
||||
depends on SPI
|
||||
select FXOS8700
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to build support for the NXP FXOS8700 m+g combo
|
||||
sensor on SPI.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called fxos8700_spi.
|
||||
|
||||
config KMX61
|
||||
tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
|
||||
depends on I2C
|
||||
|
@ -14,6 +14,11 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
|
||||
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
|
||||
|
||||
obj-y += bmi160/
|
||||
|
||||
obj-$(CONFIG_FXOS8700) += fxos8700_core.o
|
||||
obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
|
||||
obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
|
||||
|
||||
obj-y += inv_mpu6050/
|
||||
|
||||
obj-$(CONFIG_KMX61) += kmx61.o
|
||||
|
10
drivers/iio/imu/fxos8700.h
Normal file
10
drivers/iio/imu/fxos8700.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef FXOS8700_H_
|
||||
#define FXOS8700_H_
|
||||
|
||||
extern const struct regmap_config fxos8700_regmap_config;
|
||||
|
||||
int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name, bool use_spi);
|
||||
|
||||
#endif /* FXOS8700_H_ */
|
649
drivers/iio/imu/fxos8700_core.c
Normal file
649
drivers/iio/imu/fxos8700_core.c
Normal file
@ -0,0 +1,649 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* FXOS8700 - NXP IMU (accelerometer plus magnetometer)
|
||||
*
|
||||
* IIO core driver for FXOS8700, with support for I2C/SPI busses
|
||||
*
|
||||
* TODO: Buffer, trigger, and IRQ support
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#include "fxos8700.h"
|
||||
|
||||
/* Register Definitions */
|
||||
#define FXOS8700_STATUS 0x00
|
||||
#define FXOS8700_OUT_X_MSB 0x01
|
||||
#define FXOS8700_OUT_X_LSB 0x02
|
||||
#define FXOS8700_OUT_Y_MSB 0x03
|
||||
#define FXOS8700_OUT_Y_LSB 0x04
|
||||
#define FXOS8700_OUT_Z_MSB 0x05
|
||||
#define FXOS8700_OUT_Z_LSB 0x06
|
||||
#define FXOS8700_F_SETUP 0x09
|
||||
#define FXOS8700_TRIG_CFG 0x0a
|
||||
#define FXOS8700_SYSMOD 0x0b
|
||||
#define FXOS8700_INT_SOURCE 0x0c
|
||||
#define FXOS8700_WHO_AM_I 0x0d
|
||||
#define FXOS8700_XYZ_DATA_CFG 0x0e
|
||||
#define FXOS8700_HP_FILTER_CUTOFF 0x0f
|
||||
#define FXOS8700_PL_STATUS 0x10
|
||||
#define FXOS8700_PL_CFG 0x11
|
||||
#define FXOS8700_PL_COUNT 0x12
|
||||
#define FXOS8700_PL_BF_ZCOMP 0x13
|
||||
#define FXOS8700_PL_THS_REG 0x14
|
||||
#define FXOS8700_A_FFMT_CFG 0x15
|
||||
#define FXOS8700_A_FFMT_SRC 0x16
|
||||
#define FXOS8700_A_FFMT_THS 0x17
|
||||
#define FXOS8700_A_FFMT_COUNT 0x18
|
||||
#define FXOS8700_TRANSIENT_CFG 0x1d
|
||||
#define FXOS8700_TRANSIENT_SRC 0x1e
|
||||
#define FXOS8700_TRANSIENT_THS 0x1f
|
||||
#define FXOS8700_TRANSIENT_COUNT 0x20
|
||||
#define FXOS8700_PULSE_CFG 0x21
|
||||
#define FXOS8700_PULSE_SRC 0x22
|
||||
#define FXOS8700_PULSE_THSX 0x23
|
||||
#define FXOS8700_PULSE_THSY 0x24
|
||||
#define FXOS8700_PULSE_THSZ 0x25
|
||||
#define FXOS8700_PULSE_TMLT 0x26
|
||||
#define FXOS8700_PULSE_LTCY 0x27
|
||||
#define FXOS8700_PULSE_WIND 0x28
|
||||
#define FXOS8700_ASLP_COUNT 0x29
|
||||
#define FXOS8700_CTRL_REG1 0x2a
|
||||
#define FXOS8700_CTRL_REG2 0x2b
|
||||
#define FXOS8700_CTRL_REG3 0x2c
|
||||
#define FXOS8700_CTRL_REG4 0x2d
|
||||
#define FXOS8700_CTRL_REG5 0x2e
|
||||
#define FXOS8700_OFF_X 0x2f
|
||||
#define FXOS8700_OFF_Y 0x30
|
||||
#define FXOS8700_OFF_Z 0x31
|
||||
#define FXOS8700_M_DR_STATUS 0x32
|
||||
#define FXOS8700_M_OUT_X_MSB 0x33
|
||||
#define FXOS8700_M_OUT_X_LSB 0x34
|
||||
#define FXOS8700_M_OUT_Y_MSB 0x35
|
||||
#define FXOS8700_M_OUT_Y_LSB 0x36
|
||||
#define FXOS8700_M_OUT_Z_MSB 0x37
|
||||
#define FXOS8700_M_OUT_Z_LSB 0x38
|
||||
#define FXOS8700_CMP_X_MSB 0x39
|
||||
#define FXOS8700_CMP_X_LSB 0x3a
|
||||
#define FXOS8700_CMP_Y_MSB 0x3b
|
||||
#define FXOS8700_CMP_Y_LSB 0x3c
|
||||
#define FXOS8700_CMP_Z_MSB 0x3d
|
||||
#define FXOS8700_CMP_Z_LSB 0x3e
|
||||
#define FXOS8700_M_OFF_X_MSB 0x3f
|
||||
#define FXOS8700_M_OFF_X_LSB 0x40
|
||||
#define FXOS8700_M_OFF_Y_MSB 0x41
|
||||
#define FXOS8700_M_OFF_Y_LSB 0x42
|
||||
#define FXOS8700_M_OFF_Z_MSB 0x43
|
||||
#define FXOS8700_M_OFF_Z_LSB 0x44
|
||||
#define FXOS8700_MAX_X_MSB 0x45
|
||||
#define FXOS8700_MAX_X_LSB 0x46
|
||||
#define FXOS8700_MAX_Y_MSB 0x47
|
||||
#define FXOS8700_MAX_Y_LSB 0x48
|
||||
#define FXOS8700_MAX_Z_MSB 0x49
|
||||
#define FXOS8700_MAX_Z_LSB 0x4a
|
||||
#define FXOS8700_MIN_X_MSB 0x4b
|
||||
#define FXOS8700_MIN_X_LSB 0x4c
|
||||
#define FXOS8700_MIN_Y_MSB 0x4d
|
||||
#define FXOS8700_MIN_Y_LSB 0x4e
|
||||
#define FXOS8700_MIN_Z_MSB 0x4f
|
||||
#define FXOS8700_MIN_Z_LSB 0x50
|
||||
#define FXOS8700_TEMP 0x51
|
||||
#define FXOS8700_M_THS_CFG 0x52
|
||||
#define FXOS8700_M_THS_SRC 0x53
|
||||
#define FXOS8700_M_THS_X_MSB 0x54
|
||||
#define FXOS8700_M_THS_X_LSB 0x55
|
||||
#define FXOS8700_M_THS_Y_MSB 0x56
|
||||
#define FXOS8700_M_THS_Y_LSB 0x57
|
||||
#define FXOS8700_M_THS_Z_MSB 0x58
|
||||
#define FXOS8700_M_THS_Z_LSB 0x59
|
||||
#define FXOS8700_M_THS_COUNT 0x5a
|
||||
#define FXOS8700_M_CTRL_REG1 0x5b
|
||||
#define FXOS8700_M_CTRL_REG2 0x5c
|
||||
#define FXOS8700_M_CTRL_REG3 0x5d
|
||||
#define FXOS8700_M_INT_SRC 0x5e
|
||||
#define FXOS8700_A_VECM_CFG 0x5f
|
||||
#define FXOS8700_A_VECM_THS_MSB 0x60
|
||||
#define FXOS8700_A_VECM_THS_LSB 0x61
|
||||
#define FXOS8700_A_VECM_CNT 0x62
|
||||
#define FXOS8700_A_VECM_INITX_MSB 0x63
|
||||
#define FXOS8700_A_VECM_INITX_LSB 0x64
|
||||
#define FXOS8700_A_VECM_INITY_MSB 0x65
|
||||
#define FXOS8700_A_VECM_INITY_LSB 0x66
|
||||
#define FXOS8700_A_VECM_INITZ_MSB 0x67
|
||||
#define FXOS8700_A_VECM_INITZ_LSB 0x68
|
||||
#define FXOS8700_M_VECM_CFG 0x69
|
||||
#define FXOS8700_M_VECM_THS_MSB 0x6a
|
||||
#define FXOS8700_M_VECM_THS_LSB 0x6b
|
||||
#define FXOS8700_M_VECM_CNT 0x6c
|
||||
#define FXOS8700_M_VECM_INITX_MSB 0x6d
|
||||
#define FXOS8700_M_VECM_INITX_LSB 0x6e
|
||||
#define FXOS8700_M_VECM_INITY_MSB 0x6f
|
||||
#define FXOS8700_M_VECM_INITY_LSB 0x70
|
||||
#define FXOS8700_M_VECM_INITZ_MSB 0x71
|
||||
#define FXOS8700_M_VECM_INITZ_LSB 0x72
|
||||
#define FXOS8700_A_FFMT_THS_X_MSB 0x73
|
||||
#define FXOS8700_A_FFMT_THS_X_LSB 0x74
|
||||
#define FXOS8700_A_FFMT_THS_Y_MSB 0x75
|
||||
#define FXOS8700_A_FFMT_THS_Y_LSB 0x76
|
||||
#define FXOS8700_A_FFMT_THS_Z_MSB 0x77
|
||||
#define FXOS8700_A_FFMT_THS_Z_LSB 0x78
|
||||
#define FXOS8700_A_TRAN_INIT_MSB 0x79
|
||||
#define FXOS8700_A_TRAN_INIT_LSB_X 0x7a
|
||||
#define FXOS8700_A_TRAN_INIT_LSB_Y 0x7b
|
||||
#define FXOS8700_A_TRAN_INIT_LSB_Z 0x7d
|
||||
#define FXOS8700_TM_NVM_LOCK 0x7e
|
||||
#define FXOS8700_NVM_DATA0_35 0x80
|
||||
#define FXOS8700_NVM_DATA_BNK3 0xa4
|
||||
#define FXOS8700_NVM_DATA_BNK2 0xa5
|
||||
#define FXOS8700_NVM_DATA_BNK1 0xa6
|
||||
#define FXOS8700_NVM_DATA_BNK0 0xa7
|
||||
|
||||
/* Bit definitions for FXOS8700_CTRL_REG1 */
|
||||
#define FXOS8700_CTRL_ODR_MSK 0x38
|
||||
#define FXOS8700_CTRL_ODR_MAX 0x00
|
||||
#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3)
|
||||
|
||||
/* Bit definitions for FXOS8700_M_CTRL_REG1 */
|
||||
#define FXOS8700_HMS_MASK GENMASK(1, 0)
|
||||
#define FXOS8700_OS_MASK GENMASK(4, 2)
|
||||
|
||||
/* Bit definitions for FXOS8700_M_CTRL_REG2 */
|
||||
#define FXOS8700_MAXMIN_RST BIT(2)
|
||||
#define FXOS8700_MAXMIN_DIS_THS BIT(3)
|
||||
#define FXOS8700_MAXMIN_DIS BIT(4)
|
||||
|
||||
#define FXOS8700_ACTIVE 0x01
|
||||
#define FXOS8700_ACTIVE_MIN_USLEEP 4000 /* from table 6 in datasheet */
|
||||
|
||||
#define FXOS8700_DEVICE_ID 0xC7
|
||||
#define FXOS8700_PRE_DEVICE_ID 0xC4
|
||||
#define FXOS8700_DATA_BUF_SIZE 3
|
||||
|
||||
struct fxos8700_data {
|
||||
struct regmap *regmap;
|
||||
struct iio_trigger *trig;
|
||||
__be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
/* Regmap info */
|
||||
static const struct regmap_range read_range[] = {
|
||||
{
|
||||
.range_min = FXOS8700_STATUS,
|
||||
.range_max = FXOS8700_A_FFMT_COUNT,
|
||||
}, {
|
||||
.range_min = FXOS8700_TRANSIENT_CFG,
|
||||
.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range write_range[] = {
|
||||
{
|
||||
.range_min = FXOS8700_F_SETUP,
|
||||
.range_max = FXOS8700_TRIG_CFG,
|
||||
}, {
|
||||
.range_min = FXOS8700_XYZ_DATA_CFG,
|
||||
.range_max = FXOS8700_HP_FILTER_CUTOFF,
|
||||
}, {
|
||||
.range_min = FXOS8700_PL_CFG,
|
||||
.range_max = FXOS8700_A_FFMT_CFG,
|
||||
}, {
|
||||
.range_min = FXOS8700_A_FFMT_THS,
|
||||
.range_max = FXOS8700_TRANSIENT_CFG,
|
||||
}, {
|
||||
.range_min = FXOS8700_TRANSIENT_THS,
|
||||
.range_max = FXOS8700_PULSE_CFG,
|
||||
}, {
|
||||
.range_min = FXOS8700_PULSE_THSX,
|
||||
.range_max = FXOS8700_OFF_Z,
|
||||
}, {
|
||||
.range_min = FXOS8700_M_OFF_X_MSB,
|
||||
.range_max = FXOS8700_M_OFF_Z_LSB,
|
||||
}, {
|
||||
.range_min = FXOS8700_M_THS_CFG,
|
||||
.range_max = FXOS8700_M_THS_CFG,
|
||||
}, {
|
||||
.range_min = FXOS8700_M_THS_X_MSB,
|
||||
.range_max = FXOS8700_M_CTRL_REG3,
|
||||
}, {
|
||||
.range_min = FXOS8700_A_VECM_CFG,
|
||||
.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_access_table driver_read_table = {
|
||||
.yes_ranges = read_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(read_range),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table driver_write_table = {
|
||||
.yes_ranges = write_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(write_range),
|
||||
};
|
||||
|
||||
const struct regmap_config fxos8700_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = FXOS8700_NVM_DATA_BNK0,
|
||||
.rd_table = &driver_read_table,
|
||||
.wr_table = &driver_write_table,
|
||||
};
|
||||
EXPORT_SYMBOL(fxos8700_regmap_config);
|
||||
|
||||
#define FXOS8700_CHANNEL(_type, _axis) { \
|
||||
.type = _type, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##_axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
}
|
||||
|
||||
enum fxos8700_accel_scale_bits {
|
||||
MODE_2G = 0,
|
||||
MODE_4G,
|
||||
MODE_8G,
|
||||
};
|
||||
|
||||
/* scan indexes follow DATA register order */
|
||||
enum fxos8700_scan_axis {
|
||||
FXOS8700_SCAN_ACCEL_X = 0,
|
||||
FXOS8700_SCAN_ACCEL_Y,
|
||||
FXOS8700_SCAN_ACCEL_Z,
|
||||
FXOS8700_SCAN_MAGN_X,
|
||||
FXOS8700_SCAN_MAGN_Y,
|
||||
FXOS8700_SCAN_MAGN_Z,
|
||||
FXOS8700_SCAN_RHALL,
|
||||
FXOS8700_SCAN_TIMESTAMP,
|
||||
};
|
||||
|
||||
enum fxos8700_sensor {
|
||||
FXOS8700_ACCEL = 0,
|
||||
FXOS8700_MAGN,
|
||||
FXOS8700_NUM_SENSORS /* must be last */
|
||||
};
|
||||
|
||||
enum fxos8700_int_pin {
|
||||
FXOS8700_PIN_INT1,
|
||||
FXOS8700_PIN_INT2
|
||||
};
|
||||
|
||||
struct fxos8700_scale {
|
||||
u8 bits;
|
||||
int uscale;
|
||||
};
|
||||
|
||||
struct fxos8700_odr {
|
||||
u8 bits;
|
||||
int odr;
|
||||
int uodr;
|
||||
};
|
||||
|
||||
static const struct fxos8700_scale fxos8700_accel_scale[] = {
|
||||
{ MODE_2G, 244},
|
||||
{ MODE_4G, 488},
|
||||
{ MODE_8G, 976},
|
||||
};
|
||||
|
||||
/*
|
||||
* Accellerometer and magnetometer have the same ODR options, set in the
|
||||
* CTRL_REG1 register. ODR is halved when using both sensors at once in
|
||||
* hybrid mode.
|
||||
*/
|
||||
static const struct fxos8700_odr fxos8700_odr[] = {
|
||||
{0x00, 800, 0},
|
||||
{0x01, 400, 0},
|
||||
{0x02, 200, 0},
|
||||
{0x03, 100, 0},
|
||||
{0x04, 50, 0},
|
||||
{0x05, 12, 500000},
|
||||
{0x06, 6, 250000},
|
||||
{0x07, 1, 562500},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec fxos8700_channels[] = {
|
||||
FXOS8700_CHANNEL(IIO_ACCEL, X),
|
||||
FXOS8700_CHANNEL(IIO_ACCEL, Y),
|
||||
FXOS8700_CHANNEL(IIO_ACCEL, Z),
|
||||
FXOS8700_CHANNEL(IIO_MAGN, X),
|
||||
FXOS8700_CHANNEL(IIO_MAGN, Y),
|
||||
FXOS8700_CHANNEL(IIO_MAGN, Z),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP),
|
||||
};
|
||||
|
||||
static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type)
|
||||
{
|
||||
switch (iio_type) {
|
||||
case IIO_ACCEL:
|
||||
return FXOS8700_ACCEL;
|
||||
case IIO_ANGL_VEL:
|
||||
return FXOS8700_MAGN;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int fxos8700_set_active_mode(struct fxos8700_data *data,
|
||||
enum fxos8700_sensor t, bool mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usleep_range(FXOS8700_ACTIVE_MIN_USLEEP,
|
||||
FXOS8700_ACTIVE_MIN_USLEEP + 1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fxos8700_set_scale(struct fxos8700_data *data,
|
||||
enum fxos8700_sensor t, int uscale)
|
||||
{
|
||||
int i;
|
||||
static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
|
||||
if (t == FXOS8700_MAGN) {
|
||||
dev_err(dev, "Magnetometer scale is locked at 1200uT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < scale_num; i++)
|
||||
if (fxos8700_accel_scale[i].uscale == uscale)
|
||||
break;
|
||||
|
||||
if (i == scale_num)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
|
||||
fxos8700_accel_scale[i].bits);
|
||||
}
|
||||
|
||||
static int fxos8700_get_scale(struct fxos8700_data *data,
|
||||
enum fxos8700_sensor t, int *uscale)
|
||||
{
|
||||
int i, ret, val;
|
||||
static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
|
||||
|
||||
if (t == FXOS8700_MAGN) {
|
||||
*uscale = 1200; /* Magnetometer is locked at 1200uT */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < scale_num; i++) {
|
||||
if (fxos8700_accel_scale[i].bits == (val & 0x3)) {
|
||||
*uscale = fxos8700_accel_scale[i].uscale;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,
|
||||
int axis, int *val)
|
||||
{
|
||||
u8 base, reg;
|
||||
int ret;
|
||||
enum fxos8700_sensor type = fxos8700_to_sensor(chan_type);
|
||||
|
||||
base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB;
|
||||
|
||||
/* Block read 6 bytes of device output registers to avoid data loss */
|
||||
ret = regmap_bulk_read(data->regmap, base, data->buf,
|
||||
FXOS8700_DATA_BUF_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Convert axis to buffer index */
|
||||
reg = axis - IIO_MOD_X;
|
||||
|
||||
/* Convert to native endianness */
|
||||
*val = sign_extend32(be16_to_cpu(data->buf[reg]), 15);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
|
||||
int odr, int uodr)
|
||||
{
|
||||
int i, ret, val;
|
||||
bool active_mode;
|
||||
static const int odr_num = ARRAY_SIZE(fxos8700_odr);
|
||||
|
||||
ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
active_mode = val & FXOS8700_ACTIVE;
|
||||
|
||||
if (active_mode) {
|
||||
/*
|
||||
* The device must be in standby mode to change any of the
|
||||
* other fields within CTRL_REG1
|
||||
*/
|
||||
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
|
||||
val & ~FXOS8700_ACTIVE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < odr_num; i++)
|
||||
if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr)
|
||||
break;
|
||||
|
||||
if (i >= odr_num)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(data->regmap,
|
||||
FXOS8700_CTRL_REG1,
|
||||
FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE,
|
||||
fxos8700_odr[i].bits << 3 | active_mode);
|
||||
}
|
||||
|
||||
static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
|
||||
int *odr, int *uodr)
|
||||
{
|
||||
int i, val, ret;
|
||||
static const int odr_num = ARRAY_SIZE(fxos8700_odr);
|
||||
|
||||
ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= FXOS8700_CTRL_ODR_MSK;
|
||||
|
||||
for (i = 0; i < odr_num; i++)
|
||||
if (val == fxos8700_odr[i].bits)
|
||||
break;
|
||||
|
||||
if (i >= odr_num)
|
||||
return -EINVAL;
|
||||
|
||||
*odr = fxos8700_odr[i].odr;
|
||||
*uodr = fxos8700_odr[i].uodr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fxos8700_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
int ret;
|
||||
struct fxos8700_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = fxos8700_get_data(data, chan->type, chan->channel2, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),
|
||||
val2);
|
||||
return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),
|
||||
val, val2);
|
||||
return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int fxos8700_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct fxos8700_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type),
|
||||
val2);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type),
|
||||
val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR(in_accel_sampling_frequency_available,
|
||||
"1.5625 6.25 12.5 50 100 200 400 800");
|
||||
static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
|
||||
"1.5625 6.25 12.5 50 100 200 400 800");
|
||||
static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
|
||||
static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200");
|
||||
|
||||
static struct attribute *fxos8700_attrs[] = {
|
||||
&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_in_magn_scale_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group fxos8700_attrs_group = {
|
||||
.attrs = fxos8700_attrs,
|
||||
};
|
||||
|
||||
static const struct iio_info fxos8700_info = {
|
||||
.read_raw = fxos8700_read_raw,
|
||||
.write_raw = fxos8700_write_raw,
|
||||
.attrs = &fxos8700_attrs_group,
|
||||
};
|
||||
|
||||
static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val;
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
|
||||
ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error reading chip id\n");
|
||||
return ret;
|
||||
}
|
||||
if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {
|
||||
dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",
|
||||
val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The device must be in standby mode to change any of the other fields
|
||||
* within CTRL_REG1
|
||||
*/
|
||||
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set max oversample ratio (OSR) and both devices active */
|
||||
ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,
|
||||
FXOS8700_HMS_MASK | FXOS8700_OS_MASK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable and rst min/max measurements & threshold */
|
||||
ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,
|
||||
FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |
|
||||
FXOS8700_MAXMIN_DIS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Max ODR (800Hz individual or 400Hz hybrid), active mode */
|
||||
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
|
||||
FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set for max full-scale range (+/-8G) */
|
||||
return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
|
||||
}
|
||||
|
||||
static void fxos8700_chip_uninit(void *data)
|
||||
{
|
||||
struct fxos8700_data *fxos8700_data = data;
|
||||
|
||||
fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false);
|
||||
fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false);
|
||||
}
|
||||
|
||||
int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name, bool use_spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct fxos8700_data *data;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
data->regmap = regmap;
|
||||
|
||||
ret = fxos8700_chip_init(data, use_spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->channels = fxos8700_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels);
|
||||
indio_dev->name = name ? name : "fxos8700";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &fxos8700_info;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fxos8700_core_probe);
|
||||
|
||||
MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
|
||||
MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
71
drivers/iio/imu/fxos8700_i2c.c
Normal file
71
drivers/iio/imu/fxos8700_i2c.c
Normal file
@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* FXOS8700 - NXP IMU, I2C bits
|
||||
*
|
||||
* 7-bit I2C slave address determined by SA1 and SA0 logic level
|
||||
* inputs represented in the following table:
|
||||
* SA1 | SA0 | Slave Address
|
||||
* 0 | 0 | 0x1E
|
||||
* 0 | 1 | 0x1D
|
||||
* 1 | 0 | 0x1C
|
||||
* 1 | 1 | 0x1F
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "fxos8700.h"
|
||||
|
||||
static int fxos8700_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
const char *name = NULL;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
|
||||
(int)PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
if (id)
|
||||
name = id->name;
|
||||
|
||||
return fxos8700_core_probe(&client->dev, regmap, name, false);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id fxos8700_i2c_id[] = {
|
||||
{"fxos8700", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id);
|
||||
|
||||
static const struct acpi_device_id fxos8700_acpi_match[] = {
|
||||
{"FXOS8700", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
|
||||
|
||||
static const struct of_device_id fxos8700_of_match[] = {
|
||||
{ .compatible = "nxp,fxos8700" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fxos8700_of_match);
|
||||
|
||||
static struct i2c_driver fxos8700_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "fxos8700_i2c",
|
||||
.acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
|
||||
.of_match_table = fxos8700_of_match,
|
||||
},
|
||||
.probe = fxos8700_i2c_probe,
|
||||
.id_table = fxos8700_i2c_id,
|
||||
};
|
||||
module_i2c_driver(fxos8700_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
|
||||
MODULE_DESCRIPTION("FXOS8700 I2C driver");
|
||||
MODULE_LICENSE("GPL v2");
|
59
drivers/iio/imu/fxos8700_spi.c
Normal file
59
drivers/iio/imu/fxos8700_spi.c
Normal file
@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* FXOS8700 - NXP IMU, SPI bits
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "fxos8700.h"
|
||||
|
||||
static int fxos8700_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
|
||||
(int)PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return fxos8700_core_probe(&spi->dev, regmap, id->name, true);
|
||||
}
|
||||
|
||||
static const struct spi_device_id fxos8700_spi_id[] = {
|
||||
{"fxos8700", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, fxos8700_spi_id);
|
||||
|
||||
static const struct acpi_device_id fxos8700_acpi_match[] = {
|
||||
{"FXOS8700", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
|
||||
|
||||
static const struct of_device_id fxos8700_of_match[] = {
|
||||
{ .compatible = "nxp,fxos8700" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fxos8700_of_match);
|
||||
|
||||
static struct spi_driver fxos8700_spi_driver = {
|
||||
.probe = fxos8700_spi_probe,
|
||||
.id_table = fxos8700_spi_id,
|
||||
.driver = {
|
||||
.acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
|
||||
.of_match_table = fxos8700_of_match,
|
||||
.name = "fxos8700_spi",
|
||||
},
|
||||
};
|
||||
module_spi_driver(fxos8700_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
|
||||
MODULE_DESCRIPTION("FXOS8700 SPI driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -12,7 +12,8 @@ config IIO_ST_LSM6DSX
|
||||
Say yes here to build support for STMicroelectronics LSM6DSx imu
|
||||
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
|
||||
ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c,
|
||||
ism330dhcx and the accelerometer/gyroscope of lsm9ds1.
|
||||
ism330dhcx, lsm6dsrx, lsm6ds0 and the accelerometer/gyroscope
|
||||
of lsm9ds1.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called st_lsm6dsx.
|
||||
|
@ -26,6 +26,8 @@
|
||||
#define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c"
|
||||
#define ST_ISM330DHCX_DEV_NAME "ism330dhcx"
|
||||
#define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu"
|
||||
#define ST_LSM6DS0_DEV_NAME "lsm6ds0"
|
||||
#define ST_LSM6DSRX_DEV_NAME "lsm6dsrx"
|
||||
|
||||
enum st_lsm6dsx_hw_id {
|
||||
ST_LSM6DS3_ID,
|
||||
@ -40,6 +42,8 @@ enum st_lsm6dsx_hw_id {
|
||||
ST_LSM6DS3TRC_ID,
|
||||
ST_ISM330DHCX_ID,
|
||||
ST_LSM9DS1_ID,
|
||||
ST_LSM6DS0_ID,
|
||||
ST_LSM6DSRX_ID,
|
||||
ST_LSM6DSX_MAX_ID,
|
||||
};
|
||||
|
||||
@ -153,12 +157,14 @@ struct st_lsm6dsx_fifo_ops {
|
||||
* @hr_timer: Hw timer resolution register info (addr + mask).
|
||||
* @fifo_en: Hw timer FIFO enable register info (addr + mask).
|
||||
* @decimator: Hw timer FIFO decimator register info (addr + mask).
|
||||
* @freq_fine: Difference in % of ODR with respect to the typical.
|
||||
*/
|
||||
struct st_lsm6dsx_hw_ts_settings {
|
||||
struct st_lsm6dsx_reg timer_en;
|
||||
struct st_lsm6dsx_reg hr_timer;
|
||||
struct st_lsm6dsx_reg fifo_en;
|
||||
struct st_lsm6dsx_reg decimator;
|
||||
u8 freq_fine;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -238,30 +244,27 @@ struct st_lsm6dsx_ext_dev_settings {
|
||||
/**
|
||||
* struct st_lsm6dsx_settings - ST IMU sensor settings
|
||||
* @wai: Sensor WhoAmI default value.
|
||||
* @int1_addr: Control Register address for INT1
|
||||
* @int2_addr: Control Register address for INT2
|
||||
* @reset_addr: register address for reset/reboot
|
||||
* @reset: register address for reset.
|
||||
* @boot: register address for boot.
|
||||
* @bdu: register address for Block Data Update.
|
||||
* @max_fifo_size: Sensor max fifo length in FIFO words.
|
||||
* @id: List of hw id/device name supported by the driver configuration.
|
||||
* @channels: IIO channels supported by the device.
|
||||
* @irq_config: interrupts related registers.
|
||||
* @drdy_mask: register info for data-ready mask (addr + mask).
|
||||
* @odr_table: Hw sensors odr table (Hz + val).
|
||||
* @fs_table: Hw sensors gain table (gain + val).
|
||||
* @decimator: List of decimator register info (addr + mask).
|
||||
* @batch: List of FIFO batching register info (addr + mask).
|
||||
* @lir: Latched interrupt register info (addr + mask).
|
||||
* @clear_on_read: Clear on read register info (addr + mask).
|
||||
* @fifo_ops: Sensor hw FIFO parameters.
|
||||
* @ts_settings: Hw timer related settings.
|
||||
* @shub_settings: i2c controller related settings.
|
||||
*/
|
||||
struct st_lsm6dsx_settings {
|
||||
u8 wai;
|
||||
u8 int1_addr;
|
||||
u8 int2_addr;
|
||||
u8 int1_func_addr;
|
||||
u8 int2_func_addr;
|
||||
u8 int_func_mask;
|
||||
u8 reset_addr;
|
||||
struct st_lsm6dsx_reg reset;
|
||||
struct st_lsm6dsx_reg boot;
|
||||
struct st_lsm6dsx_reg bdu;
|
||||
u16 max_fifo_size;
|
||||
struct {
|
||||
enum st_lsm6dsx_hw_id hw_id;
|
||||
@ -271,12 +274,21 @@ struct st_lsm6dsx_settings {
|
||||
const struct iio_chan_spec *chan;
|
||||
int len;
|
||||
} channels[2];
|
||||
struct {
|
||||
struct st_lsm6dsx_reg irq1;
|
||||
struct st_lsm6dsx_reg irq2;
|
||||
struct st_lsm6dsx_reg irq1_func;
|
||||
struct st_lsm6dsx_reg irq2_func;
|
||||
struct st_lsm6dsx_reg lir;
|
||||
struct st_lsm6dsx_reg clear_on_read;
|
||||
struct st_lsm6dsx_reg hla;
|
||||
struct st_lsm6dsx_reg od;
|
||||
} irq_config;
|
||||
struct st_lsm6dsx_reg drdy_mask;
|
||||
struct st_lsm6dsx_odr_table_entry odr_table[2];
|
||||
struct st_lsm6dsx_fs_table_entry fs_table[2];
|
||||
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
|
||||
struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
|
||||
struct st_lsm6dsx_reg lir;
|
||||
struct st_lsm6dsx_reg clear_on_read;
|
||||
struct st_lsm6dsx_fifo_ops fifo_ops;
|
||||
struct st_lsm6dsx_hw_ts_settings ts_settings;
|
||||
struct st_lsm6dsx_shub_settings shub_settings;
|
||||
@ -340,9 +352,13 @@ struct st_lsm6dsx_sensor {
|
||||
* @fifo_mode: FIFO operating mode supported by the device.
|
||||
* @suspend_mask: Suspended sensor bitmask.
|
||||
* @enable_mask: Enabled sensor bitmask.
|
||||
* @ts_gain: Hw timestamp rate after internal calibration.
|
||||
* @ts_sip: Total number of timestamp samples in a given pattern.
|
||||
* @sip: Total number of samples (acc/gyro/ts) in a given pattern.
|
||||
* @buff: Device read buffer.
|
||||
* @irq_routing: pointer to interrupt routing configuration.
|
||||
* @event_threshold: wakeup event threshold.
|
||||
* @enable_event: enabled event bitmask.
|
||||
* @iio_devs: Pointers to acc/gyro iio_dev instances.
|
||||
* @settings: Pointer to the specific sensor settings in use.
|
||||
*/
|
||||
@ -358,12 +374,13 @@ struct st_lsm6dsx_hw {
|
||||
enum st_lsm6dsx_fifo_mode fifo_mode;
|
||||
u8 suspend_mask;
|
||||
u8 enable_mask;
|
||||
s64 ts_gain;
|
||||
u8 ts_sip;
|
||||
u8 sip;
|
||||
|
||||
const struct st_lsm6dsx_reg *irq_routing;
|
||||
u8 event_threshold;
|
||||
u8 enable_event;
|
||||
struct st_lsm6dsx_reg irq_routing;
|
||||
|
||||
u8 *buff;
|
||||
|
||||
|
@ -14,10 +14,10 @@
|
||||
* (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/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: 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/LSM6DSR/LSM6DSRX/ISM330DHCX:
|
||||
* 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
|
||||
@ -50,7 +50,6 @@
|
||||
|
||||
#define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08
|
||||
|
||||
#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */
|
||||
#define ST_LSM6DSX_TS_RESET_VAL 0xaa
|
||||
|
||||
struct st_lsm6dsx_decimator_entry {
|
||||
@ -423,7 +422,7 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
||||
*/
|
||||
if (!reset_ts && ts >= 0xff0000)
|
||||
reset_ts = true;
|
||||
ts *= ST_LSM6DSX_TS_SENSITIVITY;
|
||||
ts *= hw->ts_gain;
|
||||
|
||||
offset += ST_LSM6DSX_SAMPLE_SIZE;
|
||||
}
|
||||
@ -450,13 +449,19 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
||||
return read_len;
|
||||
}
|
||||
|
||||
#define ST_LSM6DSX_INVALID_SAMPLE 0x7ffd
|
||||
static int
|
||||
st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
|
||||
u8 *data, s64 ts)
|
||||
{
|
||||
s16 val = le16_to_cpu(*(__le16 *)data);
|
||||
struct st_lsm6dsx_sensor *sensor;
|
||||
struct iio_dev *iio_dev;
|
||||
|
||||
/* invalid sample during bootstrap phase */
|
||||
if (val >= ST_LSM6DSX_INVALID_SAMPLE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* EXT_TAG are managed in FIFO fashion so ST_LSM6DSX_EXT0_TAG
|
||||
* corresponds to the first enabled channel, ST_LSM6DSX_EXT1_TAG
|
||||
@ -566,7 +571,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
|
||||
*/
|
||||
if (!reset_ts && ts >= 0xffff0000)
|
||||
reset_ts = true;
|
||||
ts *= ST_LSM6DSX_TS_SENSITIVITY;
|
||||
ts *= hw->ts_gain;
|
||||
} else {
|
||||
st_lsm6dsx_push_tagged_data(hw, tag, iio_buff,
|
||||
ts);
|
||||
@ -586,6 +591,9 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!hw->settings->fifo_ops.read_fifo)
|
||||
return -ENOTSUPP;
|
||||
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
|
||||
hw->settings->fifo_ops.read_fifo(hw);
|
||||
|
@ -32,7 +32,7 @@
|
||||
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
|
||||
* - FIFO size: 3KB
|
||||
*
|
||||
* - LSM9DS1:
|
||||
* - LSM9DS1/LSM6DS0:
|
||||
* - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952
|
||||
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
|
||||
* - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952
|
||||
@ -61,17 +61,9 @@
|
||||
|
||||
#include "st_lsm6dsx.h"
|
||||
|
||||
#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3)
|
||||
#define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f
|
||||
#define ST_LSM6DSX_REG_RESET_MASK BIT(0)
|
||||
#define ST_LSM6DSX_REG_BOOT_MASK BIT(7)
|
||||
#define ST_LSM6DSX_REG_BDU_ADDR 0x12
|
||||
#define ST_LSM6DSX_REG_BDU_MASK BIT(6)
|
||||
|
||||
#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12
|
||||
#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5)
|
||||
#define ST_LSM6DSX_REG_PP_OD_ADDR 0x12
|
||||
#define ST_LSM6DSX_REG_PP_OD_MASK BIT(4)
|
||||
#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */
|
||||
|
||||
static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
|
||||
ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x28, IIO_MOD_X, 0),
|
||||
@ -97,14 +89,26 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = {
|
||||
static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
{
|
||||
.wai = 0x68,
|
||||
.int1_addr = 0x0c,
|
||||
.int2_addr = 0x0d,
|
||||
.reset_addr = 0x22,
|
||||
.reset = {
|
||||
.addr = 0x22,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.boot = {
|
||||
.addr = 0x22,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x22,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.max_fifo_size = 32,
|
||||
.id = {
|
||||
{
|
||||
.hw_id = ST_LSM9DS1_ID,
|
||||
.name = ST_LSM9DS1_DEV_NAME,
|
||||
}, {
|
||||
.hw_id = ST_LSM6DS0_ID,
|
||||
.name = ST_LSM6DS0_DEV_NAME,
|
||||
},
|
||||
},
|
||||
.channels = {
|
||||
@ -160,21 +164,46 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.addr = 0x10,
|
||||
.mask = GENMASK(4, 3),
|
||||
},
|
||||
.fs_avl[0] = { IIO_DEGREE_TO_RAD(245), 0x0 },
|
||||
.fs_avl[1] = { IIO_DEGREE_TO_RAD(500), 0x1 },
|
||||
.fs_avl[2] = { IIO_DEGREE_TO_RAD(2000), 0x3 },
|
||||
|
||||
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
|
||||
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
|
||||
.fs_avl[2] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
|
||||
.fs_len = 3,
|
||||
},
|
||||
},
|
||||
.irq_config = {
|
||||
.irq1 = {
|
||||
.addr = 0x0c,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.irq2 = {
|
||||
.addr = 0x0d,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.hla = {
|
||||
.addr = 0x22,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.od = {
|
||||
.addr = 0x22,
|
||||
.mask = BIT(4),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.wai = 0x69,
|
||||
.int1_addr = 0x0d,
|
||||
.int2_addr = 0x0e,
|
||||
.int1_func_addr = 0x5e,
|
||||
.int2_func_addr = 0x5f,
|
||||
.int_func_mask = BIT(5),
|
||||
.reset_addr = 0x12,
|
||||
.reset = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.boot = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.max_fifo_size = 1365,
|
||||
.id = {
|
||||
{
|
||||
@ -242,6 +271,36 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.fs_len = 4,
|
||||
},
|
||||
},
|
||||
.irq_config = {
|
||||
.irq1 = {
|
||||
.addr = 0x0d,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.irq2 = {
|
||||
.addr = 0x0e,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x58,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.irq1_func = {
|
||||
.addr = 0x5e,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.irq2_func = {
|
||||
.addr = 0x5f,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.hla = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.od = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(4),
|
||||
},
|
||||
},
|
||||
.decimator = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.addr = 0x08,
|
||||
@ -252,10 +311,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.mask = GENMASK(5, 3),
|
||||
},
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x58,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.fifo_ops = {
|
||||
.update_fifo = st_lsm6dsx_update_fifo,
|
||||
.read_fifo = st_lsm6dsx_read_fifo,
|
||||
@ -301,12 +356,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
},
|
||||
{
|
||||
.wai = 0x69,
|
||||
.int1_addr = 0x0d,
|
||||
.int2_addr = 0x0e,
|
||||
.int1_func_addr = 0x5e,
|
||||
.int2_func_addr = 0x5f,
|
||||
.int_func_mask = BIT(5),
|
||||
.reset_addr = 0x12,
|
||||
.reset = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.boot = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.max_fifo_size = 682,
|
||||
.id = {
|
||||
{
|
||||
@ -374,6 +435,36 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.fs_len = 4,
|
||||
},
|
||||
},
|
||||
.irq_config = {
|
||||
.irq1 = {
|
||||
.addr = 0x0d,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.irq2 = {
|
||||
.addr = 0x0e,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x58,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.irq1_func = {
|
||||
.addr = 0x5e,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.irq2_func = {
|
||||
.addr = 0x5f,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.hla = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.od = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(4),
|
||||
},
|
||||
},
|
||||
.decimator = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.addr = 0x08,
|
||||
@ -384,10 +475,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.mask = GENMASK(5, 3),
|
||||
},
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x58,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.fifo_ops = {
|
||||
.update_fifo = st_lsm6dsx_update_fifo,
|
||||
.read_fifo = st_lsm6dsx_read_fifo,
|
||||
@ -433,12 +520,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
},
|
||||
{
|
||||
.wai = 0x6a,
|
||||
.int1_addr = 0x0d,
|
||||
.int2_addr = 0x0e,
|
||||
.int1_func_addr = 0x5e,
|
||||
.int2_func_addr = 0x5f,
|
||||
.int_func_mask = BIT(5),
|
||||
.reset_addr = 0x12,
|
||||
.reset = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.boot = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.max_fifo_size = 682,
|
||||
.id = {
|
||||
{
|
||||
@ -515,6 +608,36 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.fs_len = 4,
|
||||
},
|
||||
},
|
||||
.irq_config = {
|
||||
.irq1 = {
|
||||
.addr = 0x0d,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.irq2 = {
|
||||
.addr = 0x0e,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x58,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.irq1_func = {
|
||||
.addr = 0x5e,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.irq2_func = {
|
||||
.addr = 0x5f,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.hla = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.od = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(4),
|
||||
},
|
||||
},
|
||||
.decimator = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.addr = 0x08,
|
||||
@ -525,10 +648,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.mask = GENMASK(5, 3),
|
||||
},
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x58,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.fifo_ops = {
|
||||
.update_fifo = st_lsm6dsx_update_fifo,
|
||||
.read_fifo = st_lsm6dsx_read_fifo,
|
||||
@ -578,9 +697,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
},
|
||||
{
|
||||
.wai = 0x6c,
|
||||
.int1_addr = 0x0d,
|
||||
.int2_addr = 0x0e,
|
||||
.reset_addr = 0x12,
|
||||
.reset = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.boot = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.max_fifo_size = 512,
|
||||
.id = {
|
||||
{
|
||||
@ -601,6 +729,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
|
||||
},
|
||||
},
|
||||
.drdy_mask = {
|
||||
.addr = 0x13,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.odr_table = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.reg = {
|
||||
@ -651,6 +783,40 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.fs_len = 4,
|
||||
},
|
||||
},
|
||||
.irq_config = {
|
||||
.irq1 = {
|
||||
.addr = 0x0d,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.irq2 = {
|
||||
.addr = 0x0e,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.clear_on_read = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.irq1_func = {
|
||||
.addr = 0x5e,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.irq2_func = {
|
||||
.addr = 0x5f,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.hla = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.od = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(4),
|
||||
},
|
||||
},
|
||||
.batch = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.addr = 0x09,
|
||||
@ -661,14 +827,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.mask = GENMASK(7, 4),
|
||||
},
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.clear_on_read = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.fifo_ops = {
|
||||
.update_fifo = st_lsm6dsx_update_fifo,
|
||||
.read_fifo = st_lsm6dsx_read_tagged_fifo,
|
||||
@ -691,6 +849,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.addr = 0x0a,
|
||||
.mask = GENMASK(7, 6),
|
||||
},
|
||||
.freq_fine = 0x63,
|
||||
},
|
||||
.shub_settings = {
|
||||
.page_mux = {
|
||||
@ -717,16 +876,37 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.slv0_addr = 0x15,
|
||||
.dw_slv0_addr = 0x21,
|
||||
.batch_en = BIT(3),
|
||||
}
|
||||
},
|
||||
.event_settings = {
|
||||
.enable_reg = {
|
||||
.addr = 0x58,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.wakeup_reg = {
|
||||
.addr = 0x5b,
|
||||
.mask = GENMASK(5, 0),
|
||||
},
|
||||
.wakeup_src_reg = 0x1b,
|
||||
.wakeup_src_status_mask = BIT(3),
|
||||
.wakeup_src_z_mask = BIT(0),
|
||||
.wakeup_src_y_mask = BIT(1),
|
||||
.wakeup_src_x_mask = BIT(2),
|
||||
},
|
||||
},
|
||||
{
|
||||
.wai = 0x6b,
|
||||
.int1_addr = 0x0d,
|
||||
.int2_addr = 0x0e,
|
||||
.int1_func_addr = 0x5e,
|
||||
.int2_func_addr = 0x5f,
|
||||
.int_func_mask = BIT(5),
|
||||
.reset_addr = 0x12,
|
||||
.reset = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.boot = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.max_fifo_size = 512,
|
||||
.id = {
|
||||
{
|
||||
@ -744,6 +924,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
|
||||
},
|
||||
},
|
||||
.drdy_mask = {
|
||||
.addr = 0x13,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.odr_table = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.reg = {
|
||||
@ -794,6 +978,40 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.fs_len = 4,
|
||||
},
|
||||
},
|
||||
.irq_config = {
|
||||
.irq1 = {
|
||||
.addr = 0x0d,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.irq2 = {
|
||||
.addr = 0x0e,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.clear_on_read = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.irq1_func = {
|
||||
.addr = 0x5e,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.irq2_func = {
|
||||
.addr = 0x5f,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.hla = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.od = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(4),
|
||||
},
|
||||
},
|
||||
.batch = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.addr = 0x09,
|
||||
@ -804,14 +1022,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.mask = GENMASK(7, 4),
|
||||
},
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.clear_on_read = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.fifo_ops = {
|
||||
.update_fifo = st_lsm6dsx_update_fifo,
|
||||
.read_fifo = st_lsm6dsx_read_tagged_fifo,
|
||||
@ -834,6 +1044,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.addr = 0x0a,
|
||||
.mask = GENMASK(7, 6),
|
||||
},
|
||||
.freq_fine = 0x63,
|
||||
},
|
||||
.event_settings = {
|
||||
.enable_reg = {
|
||||
@ -853,12 +1064,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
},
|
||||
{
|
||||
.wai = 0x6b,
|
||||
.int1_addr = 0x0d,
|
||||
.int2_addr = 0x0e,
|
||||
.int1_func_addr = 0x5e,
|
||||
.int2_func_addr = 0x5f,
|
||||
.int_func_mask = BIT(5),
|
||||
.reset_addr = 0x12,
|
||||
.reset = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.boot = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.max_fifo_size = 512,
|
||||
.id = {
|
||||
{
|
||||
@ -867,6 +1084,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
}, {
|
||||
.hw_id = ST_ISM330DHCX_ID,
|
||||
.name = ST_ISM330DHCX_DEV_NAME,
|
||||
}, {
|
||||
.hw_id = ST_LSM6DSRX_ID,
|
||||
.name = ST_LSM6DSRX_DEV_NAME,
|
||||
},
|
||||
},
|
||||
.channels = {
|
||||
@ -879,6 +1099,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
|
||||
},
|
||||
},
|
||||
.drdy_mask = {
|
||||
.addr = 0x13,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.odr_table = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.reg = {
|
||||
@ -929,6 +1153,40 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.fs_len = 4,
|
||||
},
|
||||
},
|
||||
.irq_config = {
|
||||
.irq1 = {
|
||||
.addr = 0x0d,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.irq2 = {
|
||||
.addr = 0x0e,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.clear_on_read = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.irq1_func = {
|
||||
.addr = 0x5e,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.irq2_func = {
|
||||
.addr = 0x5f,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.hla = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.od = {
|
||||
.addr = 0x12,
|
||||
.mask = BIT(4),
|
||||
},
|
||||
},
|
||||
.batch = {
|
||||
[ST_LSM6DSX_ID_ACC] = {
|
||||
.addr = 0x09,
|
||||
@ -939,14 +1197,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.mask = GENMASK(7, 4),
|
||||
},
|
||||
},
|
||||
.lir = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.clear_on_read = {
|
||||
.addr = 0x56,
|
||||
.mask = BIT(6),
|
||||
},
|
||||
.fifo_ops = {
|
||||
.update_fifo = st_lsm6dsx_update_fifo,
|
||||
.read_fifo = st_lsm6dsx_read_tagged_fifo,
|
||||
@ -969,6 +1219,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.addr = 0x0a,
|
||||
.mask = GENMASK(7, 6),
|
||||
},
|
||||
.freq_fine = 0x63,
|
||||
},
|
||||
.shub_settings = {
|
||||
.page_mux = {
|
||||
@ -1293,27 +1544,26 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
|
||||
|
||||
static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state)
|
||||
{
|
||||
const struct st_lsm6dsx_reg *reg;
|
||||
unsigned int data;
|
||||
int err;
|
||||
u8 enable = 0;
|
||||
|
||||
if (!hw->settings->int1_func_addr)
|
||||
if (!hw->settings->irq_config.irq1_func.addr)
|
||||
return -ENOTSUPP;
|
||||
|
||||
enable = state ? hw->settings->event_settings.enable_reg.mask : 0;
|
||||
|
||||
err = regmap_update_bits(hw->regmap,
|
||||
hw->settings->event_settings.enable_reg.addr,
|
||||
hw->settings->event_settings.enable_reg.mask,
|
||||
enable);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
enable = state ? hw->irq_routing.mask : 0;
|
||||
reg = &hw->settings->event_settings.enable_reg;
|
||||
if (reg->addr) {
|
||||
data = ST_LSM6DSX_SHIFT_VAL(state, reg->mask);
|
||||
err = st_lsm6dsx_update_bits_locked(hw, reg->addr,
|
||||
reg->mask, data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Enable wakeup interrupt */
|
||||
return regmap_update_bits(hw->regmap, hw->irq_routing.addr,
|
||||
hw->irq_routing.mask,
|
||||
enable);
|
||||
data = ST_LSM6DSX_SHIFT_VAL(state, hw->irq_routing->mask);
|
||||
return st_lsm6dsx_update_bits_locked(hw, hw->irq_routing->addr,
|
||||
hw->irq_routing->mask, data);
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_read_event(struct iio_dev *iio_dev,
|
||||
@ -1335,15 +1585,18 @@ static int st_lsm6dsx_read_event(struct iio_dev *iio_dev,
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_write_event(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info,
|
||||
int val, int val2)
|
||||
static int
|
||||
st_lsm6dsx_write_event(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info,
|
||||
int val, int val2)
|
||||
{
|
||||
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
|
||||
struct st_lsm6dsx_hw *hw = sensor->hw;
|
||||
const struct st_lsm6dsx_reg *reg;
|
||||
unsigned int data;
|
||||
int err;
|
||||
|
||||
if (type != IIO_EV_TYPE_THRESH)
|
||||
@ -1352,11 +1605,11 @@ static int st_lsm6dsx_write_event(struct iio_dev *iio_dev,
|
||||
if (val < 0 || val > 31)
|
||||
return -EINVAL;
|
||||
|
||||
err = regmap_update_bits(hw->regmap,
|
||||
hw->settings->event_settings.wakeup_reg.addr,
|
||||
hw->settings->event_settings.wakeup_reg.mask,
|
||||
val);
|
||||
if (err)
|
||||
reg = &hw->settings->event_settings.wakeup_reg;
|
||||
data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
|
||||
err = st_lsm6dsx_update_bits_locked(hw, reg->addr,
|
||||
reg->mask, data);
|
||||
if (err < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hw->event_threshold = val;
|
||||
@ -1364,10 +1617,11 @@ static int st_lsm6dsx_write_event(struct iio_dev *iio_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
static int
|
||||
st_lsm6dsx_read_event_config(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
|
||||
struct st_lsm6dsx_hw *hw = sensor->hw;
|
||||
@ -1378,11 +1632,11 @@ static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev,
|
||||
return !!(hw->enable_event & BIT(chan->channel2));
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state)
|
||||
static int
|
||||
st_lsm6dsx_write_event_config(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
|
||||
struct st_lsm6dsx_hw *hw = sensor->hw;
|
||||
@ -1414,7 +1668,9 @@ static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mutex_lock(&hw->conf_lock);
|
||||
err = st_lsm6dsx_sensor_set_enable(sensor, state);
|
||||
mutex_unlock(&hw->conf_lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -1537,7 +1793,9 @@ static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
|
||||
return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
|
||||
static int
|
||||
st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw,
|
||||
const struct st_lsm6dsx_reg **drdy_reg)
|
||||
{
|
||||
int err = 0, drdy_pin;
|
||||
|
||||
@ -1551,14 +1809,12 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
|
||||
|
||||
switch (drdy_pin) {
|
||||
case 1:
|
||||
*drdy_reg = hw->settings->int1_addr;
|
||||
hw->irq_routing.addr = hw->settings->int1_func_addr;
|
||||
hw->irq_routing.mask = hw->settings->int_func_mask;
|
||||
hw->irq_routing = &hw->settings->irq_config.irq1_func;
|
||||
*drdy_reg = &hw->settings->irq_config.irq1;
|
||||
break;
|
||||
case 2:
|
||||
*drdy_reg = hw->settings->int2_addr;
|
||||
hw->irq_routing.addr = hw->settings->int2_func_addr;
|
||||
hw->irq_routing.mask = hw->settings->int_func_mask;
|
||||
hw->irq_routing = &hw->settings->irq_config.irq2_func;
|
||||
*drdy_reg = &hw->settings->irq_config.irq2;
|
||||
break;
|
||||
default:
|
||||
dev_err(hw->dev, "unsupported data ready pin\n");
|
||||
@ -1649,74 +1905,95 @@ static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw)
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* calibrate timestamp sensitivity */
|
||||
hw->ts_gain = ST_LSM6DSX_TS_SENSITIVITY;
|
||||
if (ts_settings->freq_fine) {
|
||||
err = regmap_read(hw->regmap, ts_settings->freq_fine, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* linearize the AN5192 formula:
|
||||
* 1 / (1 + x) ~= 1 - x (Taylor’s Series)
|
||||
* ttrim[s] = 1 / (40000 * (1 + 0.0015 * val))
|
||||
* ttrim[ns] ~= 25000 - 37.5 * val
|
||||
* ttrim[ns] ~= 25000 - (37500 * val) / 1000
|
||||
*/
|
||||
hw->ts_gain -= ((s8)val * 37500) / 1000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
|
||||
{
|
||||
u8 drdy_int_reg;
|
||||
const struct st_lsm6dsx_reg *reg;
|
||||
int err;
|
||||
|
||||
/* device sw reset */
|
||||
err = regmap_update_bits(hw->regmap, hw->settings->reset_addr,
|
||||
ST_LSM6DSX_REG_RESET_MASK,
|
||||
FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1));
|
||||
reg = &hw->settings->reset;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
msleep(50);
|
||||
|
||||
/* reload trimming parameter */
|
||||
err = regmap_update_bits(hw->regmap, hw->settings->reset_addr,
|
||||
ST_LSM6DSX_REG_BOOT_MASK,
|
||||
FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1));
|
||||
reg = &hw->settings->boot;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
msleep(50);
|
||||
|
||||
/* enable Block Data Update */
|
||||
err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR,
|
||||
ST_LSM6DSX_REG_BDU_MASK,
|
||||
FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1));
|
||||
reg = &hw->settings->bdu;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* enable FIFO watermak interrupt */
|
||||
err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg);
|
||||
err = st_lsm6dsx_get_drdy_reg(hw, ®);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(hw->regmap, drdy_int_reg,
|
||||
ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
|
||||
FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
|
||||
1));
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* enable Latched interrupts for device events */
|
||||
if (hw->settings->lir.addr) {
|
||||
unsigned int data;
|
||||
|
||||
data = ST_LSM6DSX_SHIFT_VAL(1, hw->settings->lir.mask);
|
||||
err = regmap_update_bits(hw->regmap, hw->settings->lir.addr,
|
||||
hw->settings->lir.mask, data);
|
||||
if (hw->settings->irq_config.lir.addr) {
|
||||
reg = &hw->settings->irq_config.lir;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* enable clear on read for latched interrupts */
|
||||
if (hw->settings->clear_on_read.addr) {
|
||||
data = ST_LSM6DSX_SHIFT_VAL(1,
|
||||
hw->settings->clear_on_read.mask);
|
||||
if (hw->settings->irq_config.clear_on_read.addr) {
|
||||
reg = &hw->settings->irq_config.clear_on_read;
|
||||
err = regmap_update_bits(hw->regmap,
|
||||
hw->settings->clear_on_read.addr,
|
||||
hw->settings->clear_on_read.mask,
|
||||
data);
|
||||
reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable drdy-mas if available */
|
||||
if (hw->settings->drdy_mask.addr) {
|
||||
reg = &hw->settings->drdy_mask;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = st_lsm6dsx_init_shub(hw);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -1767,10 +2044,23 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
|
||||
return iio_dev;
|
||||
}
|
||||
|
||||
static void st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw, int data)
|
||||
static bool
|
||||
st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw)
|
||||
{
|
||||
s64 timestamp = iio_get_time_ns(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
|
||||
const struct st_lsm6dsx_event_settings *event_settings;
|
||||
int err, data;
|
||||
s64 timestamp;
|
||||
|
||||
if (!hw->enable_event)
|
||||
return false;
|
||||
|
||||
event_settings = &hw->settings->event_settings;
|
||||
err = st_lsm6dsx_read_locked(hw, event_settings->wakeup_src_reg,
|
||||
&data, sizeof(data));
|
||||
if (err < 0)
|
||||
return false;
|
||||
|
||||
timestamp = iio_get_time_ns(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
|
||||
if ((data & hw->settings->event_settings.wakeup_src_z_mask) &&
|
||||
(hw->enable_event & BIT(IIO_MOD_Z)))
|
||||
iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC],
|
||||
@ -1800,36 +2090,33 @@ static void st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw, int data)
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
timestamp);
|
||||
|
||||
return data & event_settings->wakeup_src_status_mask;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
|
||||
{
|
||||
struct st_lsm6dsx_hw *hw = private;
|
||||
bool event;
|
||||
int count;
|
||||
int data, err;
|
||||
|
||||
if (hw->enable_event) {
|
||||
err = regmap_read(hw->regmap,
|
||||
hw->settings->event_settings.wakeup_src_reg,
|
||||
&data);
|
||||
if (err < 0)
|
||||
return IRQ_NONE;
|
||||
event = st_lsm6dsx_report_motion_event(hw);
|
||||
|
||||
if (data & hw->settings->event_settings.wakeup_src_status_mask)
|
||||
st_lsm6dsx_report_motion_event(hw, data);
|
||||
}
|
||||
if (!hw->settings->fifo_ops.read_fifo)
|
||||
return event ? IRQ_HANDLED : IRQ_NONE;
|
||||
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
count = hw->settings->fifo_ops.read_fifo(hw);
|
||||
mutex_unlock(&hw->fifo_lock);
|
||||
|
||||
return count ? IRQ_HANDLED : IRQ_NONE;
|
||||
return count || event ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
|
||||
{
|
||||
struct st_sensors_platform_data *pdata;
|
||||
struct device_node *np = hw->dev->of_node;
|
||||
struct st_sensors_platform_data *pdata;
|
||||
const struct st_lsm6dsx_reg *reg;
|
||||
unsigned long irq_type;
|
||||
bool irq_active_low;
|
||||
int err;
|
||||
@ -1850,20 +2137,19 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_HLACTIVE_ADDR,
|
||||
ST_LSM6DSX_REG_HLACTIVE_MASK,
|
||||
FIELD_PREP(ST_LSM6DSX_REG_HLACTIVE_MASK,
|
||||
irq_active_low));
|
||||
reg = &hw->settings->irq_config.hla;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(irq_active_low,
|
||||
reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
|
||||
if ((np && of_property_read_bool(np, "drive-open-drain")) ||
|
||||
(pdata && pdata->open_drain)) {
|
||||
err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_PP_OD_ADDR,
|
||||
ST_LSM6DSX_REG_PP_OD_MASK,
|
||||
FIELD_PREP(ST_LSM6DSX_REG_PP_OD_MASK,
|
||||
1));
|
||||
reg = &hw->settings->irq_config.od;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
ST_LSM6DSX_SHIFT_VAL(1, reg->mask));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -1887,7 +2173,9 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
|
||||
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct st_sensors_platform_data *pdata = dev->platform_data;
|
||||
const struct st_lsm6dsx_shub_settings *hub_settings;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct st_lsm6dsx_hw *hw;
|
||||
const char *name = NULL;
|
||||
int i, err;
|
||||
@ -1950,7 +2238,8 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (dev->of_node && of_property_read_bool(dev->of_node, "wakeup-source"))
|
||||
if ((np && of_property_read_bool(np, "wakeup-source")) ||
|
||||
(pdata && pdata->wakeup_source))
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
return 0;
|
||||
|
@ -87,6 +87,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
|
||||
.compatible = "st,lsm9ds1-imu",
|
||||
.data = (void *)ST_LSM9DS1_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm6ds0",
|
||||
.data = (void *)ST_LSM6DS0_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm6dsrx",
|
||||
.data = (void *)ST_LSM6DSRX_ID,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
|
||||
@ -104,6 +112,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
|
||||
{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
|
||||
{ ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
|
||||
{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
|
||||
{ ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID },
|
||||
{ ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
|
||||
|
@ -87,6 +87,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
|
||||
.compatible = "st,lsm9ds1-imu",
|
||||
.data = (void *)ST_LSM9DS1_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm6ds0",
|
||||
.data = (void *)ST_LSM6DS0_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm6dsrx",
|
||||
.data = (void *)ST_LSM6DSRX_ID,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
|
||||
@ -104,6 +112,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
|
||||
{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
|
||||
{ ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
|
||||
{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
|
||||
{ ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID },
|
||||
{ ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
|
||||
|
@ -32,6 +32,17 @@ config ADJD_S311
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adjd_s311.
|
||||
|
||||
config ADUX1020
|
||||
tristate "ADUX1020 photometric sensor"
|
||||
select REGMAP_I2C
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the Analog Devices
|
||||
ADUX1020 photometric sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adux1020.
|
||||
|
||||
config AL3320A
|
||||
tristate "AL3320A ambient light sensor"
|
||||
depends on I2C
|
||||
|
@ -6,6 +6,7 @@
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_ACPI_ALS) += acpi-als.o
|
||||
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
|
||||
obj-$(CONFIG_ADUX1020) += adux1020.o
|
||||
obj-$(CONFIG_AL3320A) += al3320a.o
|
||||
obj-$(CONFIG_APDS9300) += apds9300.o
|
||||
obj-$(CONFIG_APDS9960) += apds9960.o
|
||||
|
849
drivers/iio/light/adux1020.c
Normal file
849
drivers/iio/light/adux1020.c
Normal file
@ -0,0 +1,849 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* adux1020.c - Support for Analog Devices ADUX1020 photometric sensor
|
||||
*
|
||||
* Copyright (C) 2019 Linaro Ltd.
|
||||
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
*
|
||||
* TODO: Triggered buffer support
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
|
||||
#define ADUX1020_REGMAP_NAME "adux1020_regmap"
|
||||
#define ADUX1020_DRV_NAME "adux1020"
|
||||
|
||||
/* System registers */
|
||||
#define ADUX1020_REG_CHIP_ID 0x08
|
||||
#define ADUX1020_REG_SLAVE_ADDRESS 0x09
|
||||
|
||||
#define ADUX1020_REG_SW_RESET 0x0f
|
||||
#define ADUX1020_REG_INT_ENABLE 0x1c
|
||||
#define ADUX1020_REG_INT_POLARITY 0x1d
|
||||
#define ADUX1020_REG_PROX_TH_ON1 0x2a
|
||||
#define ADUX1020_REG_PROX_TH_OFF1 0x2b
|
||||
#define ADUX1020_REG_PROX_TYPE 0x2f
|
||||
#define ADUX1020_REG_TEST_MODES_3 0x32
|
||||
#define ADUX1020_REG_FORCE_MODE 0x33
|
||||
#define ADUX1020_REG_FREQUENCY 0x40
|
||||
#define ADUX1020_REG_LED_CURRENT 0x41
|
||||
#define ADUX1020_REG_OP_MODE 0x45
|
||||
#define ADUX1020_REG_INT_MASK 0x48
|
||||
#define ADUX1020_REG_INT_STATUS 0x49
|
||||
#define ADUX1020_REG_DATA_BUFFER 0x60
|
||||
|
||||
/* Chip ID bits */
|
||||
#define ADUX1020_CHIP_ID_MASK GENMASK(11, 0)
|
||||
#define ADUX1020_CHIP_ID 0x03fc
|
||||
|
||||
#define ADUX1020_SW_RESET BIT(1)
|
||||
#define ADUX1020_FIFO_FLUSH BIT(15)
|
||||
#define ADUX1020_OP_MODE_MASK GENMASK(3, 0)
|
||||
#define ADUX1020_DATA_OUT_MODE_MASK GENMASK(7, 4)
|
||||
#define ADUX1020_DATA_OUT_PROX_I FIELD_PREP(ADUX1020_DATA_OUT_MODE_MASK, 1)
|
||||
|
||||
#define ADUX1020_MODE_INT_MASK GENMASK(7, 0)
|
||||
#define ADUX1020_INT_ENABLE 0x2094
|
||||
#define ADUX1020_INT_DISABLE 0x2090
|
||||
#define ADUX1020_PROX_INT_ENABLE 0x00f0
|
||||
#define ADUX1020_PROX_ON1_INT BIT(0)
|
||||
#define ADUX1020_PROX_OFF1_INT BIT(1)
|
||||
#define ADUX1020_FIFO_INT_ENABLE 0x7f
|
||||
#define ADUX1020_MODE_INT_DISABLE 0xff
|
||||
#define ADUX1020_MODE_INT_STATUS_MASK GENMASK(7, 0)
|
||||
#define ADUX1020_FIFO_STATUS_MASK GENMASK(15, 8)
|
||||
#define ADUX1020_INT_CLEAR 0xff
|
||||
#define ADUX1020_PROX_TYPE BIT(15)
|
||||
|
||||
#define ADUX1020_INT_PROX_ON1 BIT(0)
|
||||
#define ADUX1020_INT_PROX_OFF1 BIT(1)
|
||||
|
||||
#define ADUX1020_FORCE_CLOCK_ON 0x0f4f
|
||||
#define ADUX1020_FORCE_CLOCK_RESET 0x0040
|
||||
#define ADUX1020_ACTIVE_4_STATE 0x0008
|
||||
|
||||
#define ADUX1020_PROX_FREQ_MASK GENMASK(7, 4)
|
||||
#define ADUX1020_PROX_FREQ(x) FIELD_PREP(ADUX1020_PROX_FREQ_MASK, x)
|
||||
|
||||
#define ADUX1020_LED_CURRENT_MASK GENMASK(3, 0)
|
||||
#define ADUX1020_LED_PIREF_EN BIT(12)
|
||||
|
||||
/* Operating modes */
|
||||
enum adux1020_op_modes {
|
||||
ADUX1020_MODE_STANDBY,
|
||||
ADUX1020_MODE_PROX_I,
|
||||
ADUX1020_MODE_PROX_XY,
|
||||
ADUX1020_MODE_GEST,
|
||||
ADUX1020_MODE_SAMPLE,
|
||||
ADUX1020_MODE_FORCE = 0x0e,
|
||||
ADUX1020_MODE_IDLE = 0x0f,
|
||||
};
|
||||
|
||||
struct adux1020_data {
|
||||
struct i2c_client *client;
|
||||
struct iio_dev *indio_dev;
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
struct adux1020_mode_data {
|
||||
u8 bytes;
|
||||
u8 buf_len;
|
||||
u16 int_en;
|
||||
};
|
||||
|
||||
static const struct adux1020_mode_data adux1020_modes[] = {
|
||||
[ADUX1020_MODE_PROX_I] = {
|
||||
.bytes = 2,
|
||||
.buf_len = 1,
|
||||
.int_en = ADUX1020_PROX_INT_ENABLE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config adux1020_regmap_config = {
|
||||
.name = ADUX1020_REGMAP_NAME,
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.max_register = 0x6F,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static const struct reg_sequence adux1020_def_conf[] = {
|
||||
{ 0x000c, 0x000f },
|
||||
{ 0x0010, 0x1010 },
|
||||
{ 0x0011, 0x004c },
|
||||
{ 0x0012, 0x5f0c },
|
||||
{ 0x0013, 0xada5 },
|
||||
{ 0x0014, 0x0080 },
|
||||
{ 0x0015, 0x0000 },
|
||||
{ 0x0016, 0x0600 },
|
||||
{ 0x0017, 0x0000 },
|
||||
{ 0x0018, 0x2693 },
|
||||
{ 0x0019, 0x0004 },
|
||||
{ 0x001a, 0x4280 },
|
||||
{ 0x001b, 0x0060 },
|
||||
{ 0x001c, 0x2094 },
|
||||
{ 0x001d, 0x0020 },
|
||||
{ 0x001e, 0x0001 },
|
||||
{ 0x001f, 0x0100 },
|
||||
{ 0x0020, 0x0320 },
|
||||
{ 0x0021, 0x0A13 },
|
||||
{ 0x0022, 0x0320 },
|
||||
{ 0x0023, 0x0113 },
|
||||
{ 0x0024, 0x0000 },
|
||||
{ 0x0025, 0x2412 },
|
||||
{ 0x0026, 0x2412 },
|
||||
{ 0x0027, 0x0022 },
|
||||
{ 0x0028, 0x0000 },
|
||||
{ 0x0029, 0x0300 },
|
||||
{ 0x002a, 0x0700 },
|
||||
{ 0x002b, 0x0600 },
|
||||
{ 0x002c, 0x6000 },
|
||||
{ 0x002d, 0x4000 },
|
||||
{ 0x002e, 0x0000 },
|
||||
{ 0x002f, 0x0000 },
|
||||
{ 0x0030, 0x0000 },
|
||||
{ 0x0031, 0x0000 },
|
||||
{ 0x0032, 0x0040 },
|
||||
{ 0x0033, 0x0008 },
|
||||
{ 0x0034, 0xE400 },
|
||||
{ 0x0038, 0x8080 },
|
||||
{ 0x0039, 0x8080 },
|
||||
{ 0x003a, 0x2000 },
|
||||
{ 0x003b, 0x1f00 },
|
||||
{ 0x003c, 0x2000 },
|
||||
{ 0x003d, 0x2000 },
|
||||
{ 0x003e, 0x0000 },
|
||||
{ 0x0040, 0x8069 },
|
||||
{ 0x0041, 0x1f2f },
|
||||
{ 0x0042, 0x4000 },
|
||||
{ 0x0043, 0x0000 },
|
||||
{ 0x0044, 0x0008 },
|
||||
{ 0x0046, 0x0000 },
|
||||
{ 0x0048, 0x00ef },
|
||||
{ 0x0049, 0x0000 },
|
||||
{ 0x0045, 0x0000 },
|
||||
};
|
||||
|
||||
static const int adux1020_rates[][2] = {
|
||||
{ 0, 100000 },
|
||||
{ 0, 200000 },
|
||||
{ 0, 500000 },
|
||||
{ 1, 0 },
|
||||
{ 2, 0 },
|
||||
{ 5, 0 },
|
||||
{ 10, 0 },
|
||||
{ 20, 0 },
|
||||
{ 50, 0 },
|
||||
{ 100, 0 },
|
||||
{ 190, 0 },
|
||||
{ 450, 0 },
|
||||
{ 820, 0 },
|
||||
{ 1400, 0 },
|
||||
};
|
||||
|
||||
static const int adux1020_led_currents[][2] = {
|
||||
{ 0, 25000 },
|
||||
{ 0, 40000 },
|
||||
{ 0, 55000 },
|
||||
{ 0, 70000 },
|
||||
{ 0, 85000 },
|
||||
{ 0, 100000 },
|
||||
{ 0, 115000 },
|
||||
{ 0, 130000 },
|
||||
{ 0, 145000 },
|
||||
{ 0, 160000 },
|
||||
{ 0, 175000 },
|
||||
{ 0, 190000 },
|
||||
{ 0, 205000 },
|
||||
{ 0, 220000 },
|
||||
{ 0, 235000 },
|
||||
{ 0, 250000 },
|
||||
};
|
||||
|
||||
static int adux1020_flush_fifo(struct adux1020_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Force Idle mode */
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_FORCE_MODE,
|
||||
ADUX1020_ACTIVE_4_STATE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
|
||||
ADUX1020_OP_MODE_MASK, ADUX1020_MODE_FORCE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
|
||||
ADUX1020_OP_MODE_MASK, ADUX1020_MODE_IDLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Flush FIFO */
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
|
||||
ADUX1020_FORCE_CLOCK_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS,
|
||||
ADUX1020_FIFO_FLUSH);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
|
||||
ADUX1020_FORCE_CLOCK_RESET);
|
||||
}
|
||||
|
||||
static int adux1020_read_fifo(struct adux1020_data *data, u16 *buf, u8 buf_len)
|
||||
{
|
||||
unsigned int regval;
|
||||
int i, ret;
|
||||
|
||||
/* Enable 32MHz clock */
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
|
||||
ADUX1020_FORCE_CLOCK_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < buf_len; i++) {
|
||||
ret = regmap_read(data->regmap, ADUX1020_REG_DATA_BUFFER,
|
||||
®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
buf[i] = regval;
|
||||
}
|
||||
|
||||
/* Set 32MHz clock to be controlled by internal state machine */
|
||||
return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
|
||||
ADUX1020_FORCE_CLOCK_RESET);
|
||||
}
|
||||
|
||||
static int adux1020_set_mode(struct adux1020_data *data,
|
||||
enum adux1020_op_modes mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Switch to standby mode before changing the mode */
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_OP_MODE,
|
||||
ADUX1020_MODE_STANDBY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set data out and switch to the desired mode */
|
||||
switch (mode) {
|
||||
case ADUX1020_MODE_PROX_I:
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
|
||||
ADUX1020_DATA_OUT_MODE_MASK,
|
||||
ADUX1020_DATA_OUT_PROX_I);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
|
||||
ADUX1020_OP_MODE_MASK,
|
||||
ADUX1020_MODE_PROX_I);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adux1020_measure(struct adux1020_data *data,
|
||||
enum adux1020_op_modes mode,
|
||||
u16 *val)
|
||||
{
|
||||
unsigned int status;
|
||||
int ret, tries = 50;
|
||||
|
||||
/* Disable INT pin as polling is going to be used */
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE,
|
||||
ADUX1020_INT_DISABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable mode interrupt */
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
|
||||
ADUX1020_MODE_INT_MASK,
|
||||
adux1020_modes[mode].int_en);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
while (tries--) {
|
||||
ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS,
|
||||
&status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
status &= ADUX1020_FIFO_STATUS_MASK;
|
||||
if (status >= adux1020_modes[mode].bytes)
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
if (tries < 0)
|
||||
return -EIO;
|
||||
|
||||
ret = adux1020_read_fifo(data, val, adux1020_modes[mode].buf_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Clear mode interrupt */
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS,
|
||||
(~adux1020_modes[mode].int_en));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Disable mode interrupts */
|
||||
return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
|
||||
ADUX1020_MODE_INT_MASK,
|
||||
ADUX1020_MODE_INT_DISABLE);
|
||||
}
|
||||
|
||||
static int adux1020_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct adux1020_data *data = iio_priv(indio_dev);
|
||||
u16 buf[3];
|
||||
int ret = -EINVAL;
|
||||
unsigned int regval;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = adux1020_measure(data, ADUX1020_MODE_PROX_I, buf);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
*val = buf[0];
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
switch (chan->type) {
|
||||
case IIO_CURRENT:
|
||||
ret = regmap_read(data->regmap,
|
||||
ADUX1020_REG_LED_CURRENT, ®val);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
regval = regval & ADUX1020_LED_CURRENT_MASK;
|
||||
|
||||
*val = adux1020_led_currents[regval][0];
|
||||
*val2 = adux1020_led_currents[regval][1];
|
||||
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
ret = regmap_read(data->regmap, ADUX1020_REG_FREQUENCY,
|
||||
®val);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
regval = FIELD_GET(ADUX1020_PROX_FREQ_MASK, regval);
|
||||
|
||||
*val = adux1020_rates[regval][0];
|
||||
*val2 = adux1020_rates[regval][1];
|
||||
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fail:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
static inline int adux1020_find_index(const int array[][2], int count, int val,
|
||||
int val2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (val == array[i][0] && val2 == array[i][1])
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adux1020_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct adux1020_data *data = iio_priv(indio_dev);
|
||||
int i, ret = -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (chan->type == IIO_PROXIMITY) {
|
||||
i = adux1020_find_index(adux1020_rates,
|
||||
ARRAY_SIZE(adux1020_rates),
|
||||
val, val2);
|
||||
if (i < 0) {
|
||||
ret = i;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap,
|
||||
ADUX1020_REG_FREQUENCY,
|
||||
ADUX1020_PROX_FREQ_MASK,
|
||||
ADUX1020_PROX_FREQ(i));
|
||||
}
|
||||
break;
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
if (chan->type == IIO_CURRENT) {
|
||||
i = adux1020_find_index(adux1020_led_currents,
|
||||
ARRAY_SIZE(adux1020_led_currents),
|
||||
val, val2);
|
||||
if (i < 0) {
|
||||
ret = i;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap,
|
||||
ADUX1020_REG_LED_CURRENT,
|
||||
ADUX1020_LED_CURRENT_MASK, i);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fail:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adux1020_write_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct adux1020_data *data = iio_priv(indio_dev);
|
||||
int ret, mask;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE,
|
||||
ADUX1020_INT_ENABLE);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = regmap_write(data->regmap, ADUX1020_REG_INT_POLARITY, 0);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
mask = ADUX1020_PROX_ON1_INT;
|
||||
else
|
||||
mask = ADUX1020_PROX_OFF1_INT;
|
||||
|
||||
if (state)
|
||||
state = 0;
|
||||
else
|
||||
state = mask;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
|
||||
mask, state);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Trigger proximity interrupt when the intensity is above
|
||||
* or below threshold
|
||||
*/
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE,
|
||||
ADUX1020_PROX_TYPE,
|
||||
ADUX1020_PROX_TYPE);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
/* Set proximity mode */
|
||||
ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
fail:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adux1020_read_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct adux1020_data *data = iio_priv(indio_dev);
|
||||
int ret, mask;
|
||||
unsigned int regval;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
mask = ADUX1020_PROX_ON1_INT;
|
||||
else
|
||||
mask = ADUX1020_PROX_OFF1_INT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, ADUX1020_REG_INT_MASK, ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !(regval & mask);
|
||||
}
|
||||
|
||||
static int adux1020_read_thresh(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info, int *val, int *val2)
|
||||
{
|
||||
struct adux1020_data *data = iio_priv(indio_dev);
|
||||
u8 reg;
|
||||
int ret;
|
||||
unsigned int regval;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
reg = ADUX1020_REG_PROX_TH_ON1;
|
||||
else
|
||||
reg = ADUX1020_REG_PROX_TH_OFF1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, reg, ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = regval;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int adux1020_write_thresh(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info, int val, int val2)
|
||||
{
|
||||
struct adux1020_data *data = iio_priv(indio_dev);
|
||||
u8 reg;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
reg = ADUX1020_REG_PROX_TH_ON1;
|
||||
else
|
||||
reg = ADUX1020_REG_PROX_TH_OFF1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Full scale threshold value is 0-65535 */
|
||||
if (val < 0 || val > 65535)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_write(data->regmap, reg, val);
|
||||
}
|
||||
|
||||
static const struct iio_event_spec adux1020_proximity_event[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adux1020_channels[] = {
|
||||
{
|
||||
.type = IIO_PROXIMITY,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.event_spec = adux1020_proximity_event,
|
||||
.num_event_specs = ARRAY_SIZE(adux1020_proximity_event),
|
||||
},
|
||||
{
|
||||
.type = IIO_CURRENT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
.extend_name = "led",
|
||||
.output = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
|
||||
"0.1 0.2 0.5 1 2 5 10 20 50 100 190 450 820 1400");
|
||||
|
||||
static struct attribute *adux1020_attributes[] = {
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adux1020_attribute_group = {
|
||||
.attrs = adux1020_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info adux1020_info = {
|
||||
.attrs = &adux1020_attribute_group,
|
||||
.read_raw = adux1020_read_raw,
|
||||
.write_raw = adux1020_write_raw,
|
||||
.read_event_config = adux1020_read_event_config,
|
||||
.write_event_config = adux1020_write_event_config,
|
||||
.read_event_value = adux1020_read_thresh,
|
||||
.write_event_value = adux1020_write_thresh,
|
||||
};
|
||||
|
||||
static irqreturn_t adux1020_interrupt_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct adux1020_data *data = iio_priv(indio_dev);
|
||||
int ret, status;
|
||||
|
||||
ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS, &status);
|
||||
if (ret < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
status &= ADUX1020_MODE_INT_STATUS_MASK;
|
||||
|
||||
if (status & ADUX1020_INT_PROX_ON1) {
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
if (status & ADUX1020_INT_PROX_OFF1) {
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
regmap_update_bits(data->regmap, ADUX1020_REG_INT_STATUS,
|
||||
ADUX1020_MODE_INT_MASK, ADUX1020_INT_CLEAR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adux1020_chip_init(struct adux1020_data *data)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
ret = regmap_read(data->regmap, ADUX1020_REG_CHIP_ID, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if ((val & ADUX1020_CHIP_ID_MASK) != ADUX1020_CHIP_ID) {
|
||||
dev_err(&client->dev, "invalid chip id 0x%04x\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val);
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET,
|
||||
ADUX1020_SW_RESET, ADUX1020_SW_RESET);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Load default configuration */
|
||||
ret = regmap_multi_reg_write(data->regmap, adux1020_def_conf,
|
||||
ARRAY_SIZE(adux1020_def_conf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adux1020_flush_fifo(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Use LED_IREF for proximity mode */
|
||||
ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT,
|
||||
ADUX1020_LED_PIREF_EN, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Mask all interrupts */
|
||||
return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
|
||||
ADUX1020_MODE_INT_MASK, ADUX1020_MODE_INT_DISABLE);
|
||||
}
|
||||
|
||||
static int adux1020_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adux1020_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &adux1020_info;
|
||||
indio_dev->name = ADUX1020_DRV_NAME;
|
||||
indio_dev->channels = adux1020_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adux1020_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, &adux1020_regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
dev_err(&client->dev, "regmap initialization failed.\n");
|
||||
return PTR_ERR(data->regmap);
|
||||
}
|
||||
|
||||
data->client = client;
|
||||
data->indio_dev = indio_dev;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
ret = adux1020_chip_init(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (client->irq) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, adux1020_interrupt_handler,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
ADUX1020_DRV_NAME, indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "irq request error %d\n", -ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adux1020_id[] = {
|
||||
{ "adux1020", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adux1020_id);
|
||||
|
||||
static const struct of_device_id adux1020_of_match[] = {
|
||||
{ .compatible = "adi,adux1020" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adux1020_of_match);
|
||||
|
||||
static struct i2c_driver adux1020_driver = {
|
||||
.driver = {
|
||||
.name = ADUX1020_DRV_NAME,
|
||||
.of_match_table = adux1020_of_match,
|
||||
},
|
||||
.probe = adux1020_probe,
|
||||
.id_table = adux1020_id,
|
||||
};
|
||||
module_i2c_driver(adux1020_driver);
|
||||
|
||||
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
|
||||
MODULE_DESCRIPTION("ADUX1020 photometric sensor");
|
||||
MODULE_LICENSE("GPL");
|
@ -14,7 +14,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -74,6 +74,12 @@ struct bmp280_calib {
|
||||
s8 H6;
|
||||
};
|
||||
|
||||
static const char *const bmp280_supply_names[] = {
|
||||
"vddd", "vdda"
|
||||
};
|
||||
|
||||
#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names)
|
||||
|
||||
struct bmp280_data {
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
@ -85,8 +91,7 @@ struct bmp280_data {
|
||||
struct bmp180_calib bmp180;
|
||||
struct bmp280_calib bmp280;
|
||||
} calib;
|
||||
struct regulator *vddd;
|
||||
struct regulator *vdda;
|
||||
struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES];
|
||||
unsigned int start_up_time; /* in microseconds */
|
||||
|
||||
/* log of base 2 of oversampling rate */
|
||||
@ -148,6 +153,8 @@ static int bmp280_read_calib(struct bmp280_data *data,
|
||||
{
|
||||
int ret;
|
||||
unsigned int tmp;
|
||||
__le16 l16;
|
||||
__be16 b16;
|
||||
struct device *dev = data->dev;
|
||||
__le16 t_buf[BMP280_COMP_TEMP_REG_COUNT / 2];
|
||||
__le16 p_buf[BMP280_COMP_PRESS_REG_COUNT / 2];
|
||||
@ -207,12 +214,12 @@ static int bmp280_read_calib(struct bmp280_data *data,
|
||||
}
|
||||
calib->H1 = tmp;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &tmp, 2);
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &l16, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H2 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
calib->H2 = sign_extend32(le16_to_cpu(tmp), 15);
|
||||
calib->H2 = sign_extend32(le16_to_cpu(l16), 15);
|
||||
|
||||
ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &tmp);
|
||||
if (ret < 0) {
|
||||
@ -221,20 +228,20 @@ static int bmp280_read_calib(struct bmp280_data *data,
|
||||
}
|
||||
calib->H3 = tmp;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &tmp, 2);
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &b16, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H4 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
calib->H4 = sign_extend32(((be16_to_cpu(tmp) >> 4) & 0xff0) |
|
||||
(be16_to_cpu(tmp) & 0xf), 11);
|
||||
calib->H4 = sign_extend32(((be16_to_cpu(b16) >> 4) & 0xff0) |
|
||||
(be16_to_cpu(b16) & 0xf), 11);
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &tmp, 2);
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &l16, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H5 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
calib->H5 = sign_extend32(((le16_to_cpu(tmp) >> 4) & 0xfff), 11);
|
||||
calib->H5 = sign_extend32(((le16_to_cpu(l16) >> 4) & 0xfff), 11);
|
||||
|
||||
ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp);
|
||||
if (ret < 0) {
|
||||
@ -979,6 +986,22 @@ static int bmp085_fetch_eoc_irq(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bmp280_pm_disable(void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
static void bmp280_regulators_disable(void *data)
|
||||
{
|
||||
struct regulator_bulk_data *supplies = data;
|
||||
|
||||
regulator_bulk_disable(BMP280_NUM_SUPPLIES, supplies);
|
||||
}
|
||||
|
||||
int bmp280_common_probe(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
unsigned int chip,
|
||||
@ -1033,27 +1056,28 @@ int bmp280_common_probe(struct device *dev,
|
||||
}
|
||||
|
||||
/* Bring up regulators */
|
||||
data->vddd = devm_regulator_get(dev, "vddd");
|
||||
if (IS_ERR(data->vddd)) {
|
||||
dev_err(dev, "failed to get VDDD regulator\n");
|
||||
return PTR_ERR(data->vddd);
|
||||
}
|
||||
ret = regulator_enable(data->vddd);
|
||||
regulator_bulk_set_supply_names(data->supplies,
|
||||
bmp280_supply_names,
|
||||
BMP280_NUM_SUPPLIES);
|
||||
|
||||
ret = devm_regulator_bulk_get(dev,
|
||||
BMP280_NUM_SUPPLIES, data->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable VDDD regulator\n");
|
||||
dev_err(dev, "failed to get regulators\n");
|
||||
return ret;
|
||||
}
|
||||
data->vdda = devm_regulator_get(dev, "vdda");
|
||||
if (IS_ERR(data->vdda)) {
|
||||
dev_err(dev, "failed to get VDDA regulator\n");
|
||||
ret = PTR_ERR(data->vdda);
|
||||
goto out_disable_vddd;
|
||||
}
|
||||
ret = regulator_enable(data->vdda);
|
||||
|
||||
ret = regulator_bulk_enable(BMP280_NUM_SUPPLIES, data->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable VDDA regulator\n");
|
||||
goto out_disable_vddd;
|
||||
dev_err(dev, "failed to enable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(dev, bmp280_regulators_disable,
|
||||
data->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Wait to make sure we started up properly */
|
||||
usleep_range(data->start_up_time, data->start_up_time + 100);
|
||||
|
||||
@ -1068,17 +1092,16 @@ int bmp280_common_probe(struct device *dev,
|
||||
data->regmap = regmap;
|
||||
ret = regmap_read(regmap, BMP280_REG_ID, &chip_id);
|
||||
if (ret < 0)
|
||||
goto out_disable_vdda;
|
||||
return ret;
|
||||
if (chip_id != chip) {
|
||||
dev_err(dev, "bad chip id: expected %x got %x\n",
|
||||
chip, chip_id);
|
||||
ret = -EINVAL;
|
||||
goto out_disable_vdda;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = data->chip_info->chip_config(data);
|
||||
if (ret < 0)
|
||||
goto out_disable_vdda;
|
||||
return ret;
|
||||
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
|
||||
@ -1092,14 +1115,14 @@ int bmp280_common_probe(struct device *dev,
|
||||
if (ret < 0) {
|
||||
dev_err(data->dev,
|
||||
"failed to read calibration coefficients\n");
|
||||
goto out_disable_vdda;
|
||||
return ret;
|
||||
}
|
||||
} else if (chip_id == BMP280_CHIP_ID || chip_id == BME280_CHIP_ID) {
|
||||
ret = bmp280_read_calib(data, &data->calib.bmp280, chip_id);
|
||||
if (ret < 0) {
|
||||
dev_err(data->dev,
|
||||
"failed to read calibration coefficients\n");
|
||||
goto out_disable_vdda;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1111,7 +1134,7 @@ int bmp280_common_probe(struct device *dev,
|
||||
if (irq > 0 || (chip_id == BMP180_CHIP_ID)) {
|
||||
ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
|
||||
if (ret)
|
||||
goto out_disable_vdda;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable runtime PM */
|
||||
@ -1126,50 +1149,21 @@ int bmp280_common_probe(struct device *dev,
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
ret = devm_add_action_or_reset(dev, bmp280_pm_disable, dev);
|
||||
if (ret)
|
||||
goto out_runtime_pm_disable;
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
out_runtime_pm_disable:
|
||||
pm_runtime_get_sync(data->dev);
|
||||
pm_runtime_put_noidle(data->dev);
|
||||
pm_runtime_disable(data->dev);
|
||||
out_disable_vdda:
|
||||
regulator_disable(data->vdda);
|
||||
out_disable_vddd:
|
||||
regulator_disable(data->vddd);
|
||||
return ret;
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(bmp280_common_probe);
|
||||
|
||||
int bmp280_common_remove(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bmp280_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
pm_runtime_get_sync(data->dev);
|
||||
pm_runtime_put_noidle(data->dev);
|
||||
pm_runtime_disable(data->dev);
|
||||
regulator_disable(data->vdda);
|
||||
regulator_disable(data->vddd);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bmp280_common_remove);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bmp280_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bmp280_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_disable(data->vdda);
|
||||
if (ret)
|
||||
return ret;
|
||||
return regulator_disable(data->vddd);
|
||||
return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies);
|
||||
}
|
||||
|
||||
static int bmp280_runtime_resume(struct device *dev)
|
||||
@ -1178,10 +1172,7 @@ static int bmp280_runtime_resume(struct device *dev)
|
||||
struct bmp280_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(data->vddd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regulator_enable(data->vdda);
|
||||
ret = regulator_bulk_enable(BMP280_NUM_SUPPLIES, data->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
usleep_range(data->start_up_time, data->start_up_time + 100);
|
||||
|
@ -38,11 +38,6 @@ static int bmp280_i2c_probe(struct i2c_client *client,
|
||||
client->irq);
|
||||
}
|
||||
|
||||
static int bmp280_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
return bmp280_common_remove(&client->dev);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id bmp280_acpi_i2c_match[] = {
|
||||
{"BMP0280", BMP280_CHIP_ID },
|
||||
{"BMP0180", BMP180_CHIP_ID },
|
||||
@ -82,7 +77,6 @@ static struct i2c_driver bmp280_i2c_driver = {
|
||||
.pm = &bmp280_dev_pm_ops,
|
||||
},
|
||||
.probe = bmp280_i2c_probe,
|
||||
.remove = bmp280_i2c_remove,
|
||||
.id_table = bmp280_i2c_id,
|
||||
};
|
||||
module_i2c_driver(bmp280_i2c_driver);
|
||||
|
@ -86,11 +86,6 @@ static int bmp280_spi_probe(struct spi_device *spi)
|
||||
spi->irq);
|
||||
}
|
||||
|
||||
static int bmp280_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return bmp280_common_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id bmp280_of_spi_match[] = {
|
||||
{ .compatible = "bosch,bmp085", },
|
||||
{ .compatible = "bosch,bmp180", },
|
||||
@ -118,7 +113,6 @@ static struct spi_driver bmp280_spi_driver = {
|
||||
},
|
||||
.id_table = bmp280_spi_id,
|
||||
.probe = bmp280_spi_probe,
|
||||
.remove = bmp280_spi_remove,
|
||||
};
|
||||
module_spi_driver(bmp280_spi_driver);
|
||||
|
||||
|
@ -112,7 +112,6 @@ int bmp280_common_probe(struct device *dev,
|
||||
unsigned int chip,
|
||||
const char *name,
|
||||
int irq);
|
||||
int bmp280_common_remove(struct device *dev);
|
||||
|
||||
/* PM ops */
|
||||
extern const struct dev_pm_ops bmp280_dev_pm_ops;
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -1243,6 +1243,11 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev)
|
||||
const struct zpa2326_private *priv = iio_priv(indio_dev);
|
||||
int err;
|
||||
|
||||
/* Plug our own trigger event handler. */
|
||||
err = iio_triggered_buffer_postenable(indio_dev);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
if (!priv->waken) {
|
||||
/*
|
||||
* We were already power supplied. Just clear hardware FIFO to
|
||||
@ -1250,7 +1255,7 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev)
|
||||
*/
|
||||
err = zpa2326_clear_fifo(indio_dev, 0);
|
||||
if (err)
|
||||
goto err;
|
||||
goto err_buffer_predisable;
|
||||
}
|
||||
|
||||
if (!iio_trigger_using_own(indio_dev) && priv->waken) {
|
||||
@ -1260,16 +1265,13 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev)
|
||||
*/
|
||||
err = zpa2326_config_oneshot(indio_dev, priv->irq);
|
||||
if (err)
|
||||
goto err;
|
||||
goto err_buffer_predisable;
|
||||
}
|
||||
|
||||
/* Plug our own trigger event handler. */
|
||||
err = iio_triggered_buffer_postenable(indio_dev);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err_buffer_predisable:
|
||||
iio_triggered_buffer_predisable(indio_dev);
|
||||
err:
|
||||
zpa2326_err(indio_dev, "failed to enable buffering (%d)", err);
|
||||
|
||||
|
@ -136,12 +136,13 @@ static inline int lidar_write_power(struct lidar_data *data, int val)
|
||||
|
||||
static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
|
||||
{
|
||||
__be16 value;
|
||||
int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
|
||||
(data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
|
||||
(u8 *) reg, 2);
|
||||
(u8 *) &value, 2);
|
||||
|
||||
if (!ret)
|
||||
*reg = be16_to_cpu(*reg);
|
||||
*reg = be16_to_cpu(value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -4,6 +4,17 @@
|
||||
#
|
||||
menu "Temperature sensors"
|
||||
|
||||
config LTC2983
|
||||
tristate "Analog Devices Multi-Sensor Digital Temperature Measurement System"
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to build support for the LTC2983 Multi-Sensor
|
||||
high accuracy digital temperature measurement system.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ltc2983.
|
||||
|
||||
config MAXIM_THERMOCOUPLE
|
||||
tristate "Maxim thermocouple sensors"
|
||||
depends on SPI
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Makefile for industrial I/O temperature drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_LTC2983) += ltc2983.o
|
||||
obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
|
||||
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
|
||||
obj-$(CONFIG_MAX31856) += max31856.o
|
||||
|
1557
drivers/iio/temperature/ltc2983.c
Normal file
1557
drivers/iio/temperature/ltc2983.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -194,7 +194,7 @@ static int maxim_thermocouple_read_raw(struct iio_dev *indio_dev,
|
||||
default:
|
||||
*val = 250; /* 1000 * 0.25 */
|
||||
ret = IIO_VAL_INT;
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1210,13 +1210,6 @@ config AB8500_DEBUG
|
||||
Select this option if you want debug information using the debug
|
||||
filesystem, debugfs.
|
||||
|
||||
config AB8500_GPADC
|
||||
bool "ST-Ericsson AB8500 GPADC driver"
|
||||
depends on AB8500_CORE && REGULATOR_AB8500
|
||||
default y
|
||||
help
|
||||
AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage
|
||||
|
||||
config MFD_DB8500_PRCMU
|
||||
bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
|
||||
depends on UX500_SOC_DB8500
|
||||
|
@ -177,7 +177,6 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
|
||||
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
|
||||
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
|
||||
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
|
||||
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
|
||||
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
|
||||
# ab8500-core need to come after db8500-prcmu (which provides the channel)
|
||||
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
|
||||
|
@ -84,7 +84,6 @@
|
||||
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/string.h>
|
||||
@ -103,11 +102,6 @@ static int num_irqs;
|
||||
static struct device_attribute **dev_attr;
|
||||
static char **event_name;
|
||||
|
||||
static u8 avg_sample = SAMPLE_16;
|
||||
static u8 trig_edge = RISING_EDGE;
|
||||
static u8 conv_type = ADC_SW;
|
||||
static u8 trig_timer;
|
||||
|
||||
/**
|
||||
* struct ab8500_reg_range
|
||||
* @first: the first address of the range
|
||||
@ -152,7 +146,6 @@ static struct hwreg_cfg hwreg_cfg = {
|
||||
};
|
||||
|
||||
#define AB8500_NAME_STRING "ab8500"
|
||||
#define AB8500_ADC_NAME_STRING "gpadc"
|
||||
#define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST
|
||||
|
||||
#define AB8500_REV_REG 0x80
|
||||
@ -1646,633 +1639,6 @@ report_write_failure:
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_modem);
|
||||
|
||||
static int ab8500_gpadc_bat_ctrl_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bat_ctrl_raw;
|
||||
int bat_ctrl_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
BAT_CTRL, bat_ctrl_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", bat_ctrl_convert, bat_ctrl_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bat_ctrl);
|
||||
|
||||
static int ab8500_gpadc_btemp_ball_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int btemp_ball_raw;
|
||||
int btemp_ball_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
|
||||
btemp_ball_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_btemp_ball);
|
||||
|
||||
static int ab8500_gpadc_main_charger_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int main_charger_v_raw;
|
||||
int main_charger_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
MAIN_CHARGER_V, main_charger_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", main_charger_v_convert, main_charger_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_v);
|
||||
|
||||
static int ab8500_gpadc_acc_detect1_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int acc_detect1_raw;
|
||||
int acc_detect1_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
|
||||
acc_detect1_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", acc_detect1_convert, acc_detect1_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect1);
|
||||
|
||||
static int ab8500_gpadc_acc_detect2_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int acc_detect2_raw;
|
||||
int acc_detect2_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
ACC_DETECT2, acc_detect2_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", acc_detect2_convert, acc_detect2_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect2);
|
||||
|
||||
static int ab8500_gpadc_aux1_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int aux1_raw;
|
||||
int aux1_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
|
||||
aux1_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", aux1_convert, aux1_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux1);
|
||||
|
||||
static int ab8500_gpadc_aux2_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int aux2_raw;
|
||||
int aux2_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
|
||||
aux2_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", aux2_convert, aux2_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux2);
|
||||
|
||||
static int ab8500_gpadc_main_bat_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int main_bat_v_raw;
|
||||
int main_bat_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
|
||||
main_bat_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", main_bat_v_convert, main_bat_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_bat_v);
|
||||
|
||||
static int ab8500_gpadc_vbus_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbus_v_raw;
|
||||
int vbus_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
|
||||
vbus_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", vbus_v_convert, vbus_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_vbus_v);
|
||||
|
||||
static int ab8500_gpadc_main_charger_c_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int main_charger_c_raw;
|
||||
int main_charger_c_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
MAIN_CHARGER_C, main_charger_c_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", main_charger_c_convert, main_charger_c_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_c);
|
||||
|
||||
static int ab8500_gpadc_usb_charger_c_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int usb_charger_c_raw;
|
||||
int usb_charger_c_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
USB_CHARGER_C, usb_charger_c_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", usb_charger_c_convert, usb_charger_c_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_charger_c);
|
||||
|
||||
static int ab8500_gpadc_bk_bat_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bk_bat_v_raw;
|
||||
int bk_bat_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
BK_BAT_V, bk_bat_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", bk_bat_v_convert, bk_bat_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bk_bat_v);
|
||||
|
||||
static int ab8500_gpadc_die_temp_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int die_temp_raw;
|
||||
int die_temp_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
|
||||
die_temp_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", die_temp_convert, die_temp_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_die_temp);
|
||||
|
||||
static int ab8500_gpadc_usb_id_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int usb_id_raw;
|
||||
int usb_id_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
usb_id_raw = ab8500_gpadc_read_raw(gpadc, USB_ID,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
usb_id_convert = ab8500_gpadc_ad_to_voltage(gpadc, USB_ID,
|
||||
usb_id_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", usb_id_convert, usb_id_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_id);
|
||||
|
||||
static int ab8540_gpadc_xtal_temp_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int xtal_temp_raw;
|
||||
int xtal_temp_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
xtal_temp_raw = ab8500_gpadc_read_raw(gpadc, XTAL_TEMP,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
xtal_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, XTAL_TEMP,
|
||||
xtal_temp_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", xtal_temp_convert, xtal_temp_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_xtal_temp);
|
||||
|
||||
static int ab8540_gpadc_vbat_true_meas_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbat_true_meas_raw;
|
||||
int vbat_true_meas_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbat_true_meas_raw = ab8500_gpadc_read_raw(gpadc, VBAT_TRUE_MEAS,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
vbat_true_meas_convert =
|
||||
ab8500_gpadc_ad_to_voltage(gpadc, VBAT_TRUE_MEAS,
|
||||
vbat_true_meas_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", vbat_true_meas_convert, vbat_true_meas_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas);
|
||||
|
||||
static int ab8540_gpadc_bat_ctrl_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bat_ctrl_raw;
|
||||
int bat_ctrl_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bat_ctrl_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_CTRL_AND_IBAT,
|
||||
avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
|
||||
|
||||
bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc, BAT_CTRL,
|
||||
bat_ctrl_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
bat_ctrl_convert, bat_ctrl_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_ctrl_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_vbat_meas_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbat_meas_raw;
|
||||
int vbat_meas_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbat_meas_raw = ab8500_gpadc_double_read_raw(gpadc, VBAT_MEAS_AND_IBAT,
|
||||
avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
|
||||
vbat_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
|
||||
vbat_meas_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
vbat_meas_convert, vbat_meas_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_meas_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_vbat_true_meas_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbat_true_meas_raw;
|
||||
int vbat_true_meas_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbat_true_meas_raw = ab8500_gpadc_double_read_raw(gpadc,
|
||||
VBAT_TRUE_MEAS_AND_IBAT, avg_sample, trig_edge,
|
||||
trig_timer, conv_type, &ibat_raw);
|
||||
vbat_true_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
VBAT_TRUE_MEAS, vbat_true_meas_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
vbat_true_meas_convert, vbat_true_meas_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_bat_temp_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bat_temp_raw;
|
||||
int bat_temp_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bat_temp_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_TEMP_AND_IBAT,
|
||||
avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
|
||||
bat_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
|
||||
bat_temp_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
bat_temp_convert, bat_temp_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_temp_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_otp_calib_show(struct seq_file *s, void *p)
|
||||
{
|
||||
struct ab8500_gpadc *gpadc;
|
||||
u16 vmain_l, vmain_h, btemp_l, btemp_h;
|
||||
u16 vbat_l, vbat_h, ibat_l, ibat_h;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
ab8540_gpadc_get_otp(gpadc, &vmain_l, &vmain_h, &btemp_l, &btemp_h,
|
||||
&vbat_l, &vbat_h, &ibat_l, &ibat_h);
|
||||
seq_printf(s,
|
||||
"VMAIN_L:0x%X\n"
|
||||
"VMAIN_H:0x%X\n"
|
||||
"BTEMP_L:0x%X\n"
|
||||
"BTEMP_H:0x%X\n"
|
||||
"VBAT_L:0x%X\n"
|
||||
"VBAT_H:0x%X\n"
|
||||
"IBAT_L:0x%X\n"
|
||||
"IBAT_H:0x%X\n",
|
||||
vmain_l, vmain_h, btemp_l, btemp_h,
|
||||
vbat_l, vbat_h, ibat_l, ibat_h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_otp_calib);
|
||||
|
||||
static int ab8500_gpadc_avg_sample_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", avg_sample);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_avg_sample_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_avg_sample_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_avg_sample_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_avg_sample;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_avg_sample);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((user_avg_sample == SAMPLE_1) || (user_avg_sample == SAMPLE_4)
|
||||
|| (user_avg_sample == SAMPLE_8)
|
||||
|| (user_avg_sample == SAMPLE_16)) {
|
||||
avg_sample = (u8) user_avg_sample;
|
||||
} else {
|
||||
dev_err(dev,
|
||||
"debugfs err input: should be egal to 1, 4, 8 or 16\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_avg_sample_fops = {
|
||||
.open = ab8500_gpadc_avg_sample_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_avg_sample_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ab8500_gpadc_trig_edge_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", trig_edge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_trig_edge_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_trig_edge_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_trig_edge_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_trig_edge;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_trig_edge);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((user_trig_edge == RISING_EDGE)
|
||||
|| (user_trig_edge == FALLING_EDGE)) {
|
||||
trig_edge = (u8) user_trig_edge;
|
||||
} else {
|
||||
dev_err(dev, "Wrong input:\n"
|
||||
"Enter 0. Rising edge\n"
|
||||
"Enter 1. Falling edge\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_trig_edge_fops = {
|
||||
.open = ab8500_gpadc_trig_edge_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_trig_edge_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ab8500_gpadc_trig_timer_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", trig_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_trig_timer_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_trig_timer_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_trig_timer_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_trig_timer;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_trig_timer);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (user_trig_timer & ~0xFF) {
|
||||
dev_err(dev,
|
||||
"debugfs error input: should be between 0 to 255\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trig_timer = (u8) user_trig_timer;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_trig_timer_fops = {
|
||||
.open = ab8500_gpadc_trig_timer_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_trig_timer_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ab8500_gpadc_conv_type_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", conv_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_conv_type_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_conv_type_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_conv_type_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_conv_type;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_conv_type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((user_conv_type == ADC_SW)
|
||||
|| (user_conv_type == ADC_HW)) {
|
||||
conv_type = (u8) user_conv_type;
|
||||
} else {
|
||||
dev_err(dev, "Wrong input:\n"
|
||||
"Enter 0. ADC SW conversion\n"
|
||||
"Enter 1. ADC HW conversion\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_conv_type_fops = {
|
||||
.open = ab8500_gpadc_conv_type_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_conv_type_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
/*
|
||||
* return length of an ASCII numerical value, 0 is string is not a
|
||||
* numerical value.
|
||||
@ -2647,7 +2013,6 @@ static const struct file_operations ab8500_hwreg_fops = {
|
||||
static int ab8500_debug_probe(struct platform_device *plf)
|
||||
{
|
||||
struct dentry *ab8500_dir;
|
||||
struct dentry *ab8500_gpadc_dir;
|
||||
struct ab8500 *ab8500;
|
||||
struct resource *res;
|
||||
|
||||
@ -2689,9 +2054,6 @@ static int ab8500_debug_probe(struct platform_device *plf)
|
||||
|
||||
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
|
||||
|
||||
ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
|
||||
ab8500_dir);
|
||||
|
||||
debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir,
|
||||
&plf->dev, &ab8500_bank_registers_fops);
|
||||
debugfs_create_file("all-banks", S_IRUGO, ab8500_dir,
|
||||
@ -2727,83 +2089,6 @@ static int ab8500_debug_probe(struct platform_device *plf)
|
||||
&plf->dev, &ab8500_hwreg_fops);
|
||||
debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_dir, &plf->dev, &ab8500_modem_fops);
|
||||
debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_bat_ctrl_fops);
|
||||
debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_btemp_ball_fops);
|
||||
debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_main_charger_v_fops);
|
||||
debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_acc_detect1_fops);
|
||||
debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_acc_detect2_fops);
|
||||
debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_aux1_fops);
|
||||
debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_aux2_fops);
|
||||
debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_main_bat_v_fops);
|
||||
debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_vbus_v_fops);
|
||||
debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_main_charger_c_fops);
|
||||
debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_usb_charger_c_fops);
|
||||
debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_bk_bat_v_fops);
|
||||
debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_die_temp_fops);
|
||||
debugfs_create_file("usb_id", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_usb_id_fops);
|
||||
if (is_ab8540(ab8500)) {
|
||||
debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_xtal_temp_fops);
|
||||
debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_vbat_true_meas_fops);
|
||||
debugfs_create_file("batctrl_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_bat_ctrl_and_ibat_fops);
|
||||
debugfs_create_file("vbatmeas_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_vbat_meas_and_ibat_fops);
|
||||
debugfs_create_file("vbattruemeas_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_vbat_true_meas_and_ibat_fops);
|
||||
debugfs_create_file("battemp_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_bat_temp_and_ibat_fops);
|
||||
debugfs_create_file("otp_calib", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_otp_calib_fops);
|
||||
}
|
||||
debugfs_create_file("avg_sample", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_avg_sample_fops);
|
||||
debugfs_create_file("trig_edge", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_trig_edge_fops);
|
||||
debugfs_create_file("trig_timer", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_trig_timer_fops);
|
||||
debugfs_create_file("conv_type", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_conv_type_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -629,7 +629,7 @@ config BATTERY_GAUGE_LTC2941
|
||||
|
||||
config AB8500_BM
|
||||
bool "AB8500 Battery Management Driver"
|
||||
depends on AB8500_CORE && AB8500_GPADC
|
||||
depends on AB8500_CORE && AB8500_GPADC && (IIO = y)
|
||||
help
|
||||
Say Y to include support for AB8500 battery management.
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
|
||||
#define VTVOUT_V 1800
|
||||
|
||||
@ -79,7 +79,8 @@ struct ab8500_btemp_ranges {
|
||||
* @bat_temp: Dispatched battery temperature in degree Celsius
|
||||
* @prev_bat_temp Last measured battery temperature in degree Celsius
|
||||
* @parent: Pointer to the struct ab8500
|
||||
* @gpadc: Pointer to the struct gpadc
|
||||
* @adc_btemp_ball: ADC channel for the battery ball temperature
|
||||
* @adc_bat_ctrl: ADC channel for the battery control
|
||||
* @fg: Pointer to the struct fg
|
||||
* @bm: Platform specific battery management information
|
||||
* @btemp_psy: Structure for BTEMP specific battery properties
|
||||
@ -96,7 +97,8 @@ struct ab8500_btemp {
|
||||
int bat_temp;
|
||||
int prev_bat_temp;
|
||||
struct ab8500 *parent;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct iio_channel *btemp_ball;
|
||||
struct iio_channel *bat_ctrl;
|
||||
struct ab8500_fg *fg;
|
||||
struct abx500_bm_data *bm;
|
||||
struct power_supply *btemp_psy;
|
||||
@ -177,13 +179,13 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
|
||||
*/
|
||||
static int ab8500_btemp_read_batctrl_voltage(struct ab8500_btemp *di)
|
||||
{
|
||||
int vbtemp;
|
||||
int vbtemp, ret;
|
||||
static int prev;
|
||||
|
||||
vbtemp = ab8500_gpadc_convert(di->gpadc, BAT_CTRL);
|
||||
if (vbtemp < 0) {
|
||||
ret = iio_read_channel_processed(di->bat_ctrl, &vbtemp);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev,
|
||||
"%s gpadc conversion failed, using previous value",
|
||||
"%s ADC conversion failed, using previous value",
|
||||
__func__);
|
||||
return prev;
|
||||
}
|
||||
@ -455,7 +457,7 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
|
||||
*/
|
||||
static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
|
||||
{
|
||||
int temp;
|
||||
int temp, ret;
|
||||
static int prev;
|
||||
int rbat, rntc, vntc;
|
||||
u8 id;
|
||||
@ -480,10 +482,10 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
|
||||
di->bm->bat_type[id].r_to_t_tbl,
|
||||
di->bm->bat_type[id].n_temp_tbl_elements, rbat);
|
||||
} else {
|
||||
vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL);
|
||||
if (vntc < 0) {
|
||||
ret = iio_read_channel_processed(di->btemp_ball, &vntc);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev,
|
||||
"%s gpadc conversion failed,"
|
||||
"%s ADC conversion failed,"
|
||||
" using previous value\n", __func__);
|
||||
return prev;
|
||||
}
|
||||
@ -1024,7 +1026,22 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
|
||||
/* Get ADC channels */
|
||||
di->btemp_ball = devm_iio_channel_get(&pdev->dev, "btemp_ball");
|
||||
if (IS_ERR(di->btemp_ball)) {
|
||||
if (PTR_ERR(di->btemp_ball) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get BTEMP BALL ADC channel\n");
|
||||
return PTR_ERR(di->btemp_ball);
|
||||
}
|
||||
di->bat_ctrl = devm_iio_channel_get(&pdev->dev, "bat_ctrl");
|
||||
if (IS_ERR(di->bat_ctrl)) {
|
||||
if (PTR_ERR(di->bat_ctrl) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get BAT CTRL ADC channel\n");
|
||||
return PTR_ERR(di->bat_ctrl);
|
||||
}
|
||||
|
||||
di->initialized = false;
|
||||
|
||||
|
@ -29,10 +29,10 @@
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
#include <linux/mfd/abx500/ux500_chargalg.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
|
||||
/* Charger constants */
|
||||
#define NO_PW_CONN 0
|
||||
@ -233,7 +233,10 @@ struct ab8500_charger_max_usb_in_curr {
|
||||
* @current_stepping_sessions:
|
||||
* Counter for current stepping sessions
|
||||
* @parent: Pointer to the struct ab8500
|
||||
* @gpadc: Pointer to the struct gpadc
|
||||
* @adc_main_charger_v ADC channel for main charger voltage
|
||||
* @adc_main_charger_c ADC channel for main charger current
|
||||
* @adc_vbus_v ADC channel for USB charger voltage
|
||||
* @adc_usb_charger_c ADC channel for USB charger current
|
||||
* @bm: Platform specific battery management information
|
||||
* @flags: Structure for information about events triggered
|
||||
* @usb_state: Structure for usb stack information
|
||||
@ -283,7 +286,10 @@ struct ab8500_charger {
|
||||
int is_aca_rid;
|
||||
atomic_t current_stepping_sessions;
|
||||
struct ab8500 *parent;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct iio_channel *adc_main_charger_v;
|
||||
struct iio_channel *adc_main_charger_c;
|
||||
struct iio_channel *adc_vbus_v;
|
||||
struct iio_channel *adc_usb_charger_c;
|
||||
struct abx500_bm_data *bm;
|
||||
struct ab8500_charger_event_flags flags;
|
||||
struct ab8500_charger_usb_state usb_state;
|
||||
@ -459,13 +465,13 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
|
||||
*/
|
||||
static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di)
|
||||
{
|
||||
int vch;
|
||||
int vch, ret;
|
||||
|
||||
/* Only measure voltage if the charger is connected */
|
||||
if (di->ac.charger_connected) {
|
||||
vch = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_V);
|
||||
if (vch < 0)
|
||||
dev_err(di->dev, "%s gpadc conv failed,\n", __func__);
|
||||
ret = iio_read_channel_processed(di->adc_main_charger_v, &vch);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
} else {
|
||||
vch = 0;
|
||||
}
|
||||
@ -510,13 +516,13 @@ static int ab8500_charger_ac_cv(struct ab8500_charger *di)
|
||||
*/
|
||||
static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di)
|
||||
{
|
||||
int vch;
|
||||
int vch, ret;
|
||||
|
||||
/* Only measure voltage if the charger is connected */
|
||||
if (di->usb.charger_connected) {
|
||||
vch = ab8500_gpadc_convert(di->gpadc, VBUS_V);
|
||||
if (vch < 0)
|
||||
dev_err(di->dev, "%s gpadc conv failed\n", __func__);
|
||||
ret = iio_read_channel_processed(di->adc_vbus_v, &vch);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
} else {
|
||||
vch = 0;
|
||||
}
|
||||
@ -532,13 +538,13 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di)
|
||||
*/
|
||||
static int ab8500_charger_get_usb_current(struct ab8500_charger *di)
|
||||
{
|
||||
int ich;
|
||||
int ich, ret;
|
||||
|
||||
/* Only measure current if the charger is online */
|
||||
if (di->usb.charger_online) {
|
||||
ich = ab8500_gpadc_convert(di->gpadc, USB_CHARGER_C);
|
||||
if (ich < 0)
|
||||
dev_err(di->dev, "%s gpadc conv failed\n", __func__);
|
||||
ret = iio_read_channel_processed(di->adc_usb_charger_c, &ich);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
} else {
|
||||
ich = 0;
|
||||
}
|
||||
@ -554,13 +560,13 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di)
|
||||
*/
|
||||
static int ab8500_charger_get_ac_current(struct ab8500_charger *di)
|
||||
{
|
||||
int ich;
|
||||
int ich, ret;
|
||||
|
||||
/* Only measure current if the charger is online */
|
||||
if (di->ac.charger_online) {
|
||||
ich = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_C);
|
||||
if (ich < 0)
|
||||
dev_err(di->dev, "%s gpadc conv failed\n", __func__);
|
||||
ret = iio_read_channel_processed(di->adc_main_charger_c, &ich);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
} else {
|
||||
ich = 0;
|
||||
}
|
||||
@ -3371,7 +3377,39 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
|
||||
/* Get ADC channels */
|
||||
di->adc_main_charger_v = devm_iio_channel_get(&pdev->dev,
|
||||
"main_charger_v");
|
||||
if (IS_ERR(di->adc_main_charger_v)) {
|
||||
if (PTR_ERR(di->adc_main_charger_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC main charger voltage\n");
|
||||
return PTR_ERR(di->adc_main_charger_v);
|
||||
}
|
||||
di->adc_main_charger_c = devm_iio_channel_get(&pdev->dev,
|
||||
"main_charger_c");
|
||||
if (IS_ERR(di->adc_main_charger_c)) {
|
||||
if (PTR_ERR(di->adc_main_charger_c) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC main charger current\n");
|
||||
return PTR_ERR(di->adc_main_charger_v);
|
||||
}
|
||||
di->adc_vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
|
||||
if (IS_ERR(di->adc_vbus_v)) {
|
||||
if (PTR_ERR(di->adc_vbus_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC USB charger voltage\n");
|
||||
return PTR_ERR(di->adc_vbus_v);
|
||||
}
|
||||
di->adc_usb_charger_c = devm_iio_channel_get(&pdev->dev,
|
||||
"usb_charger_c");
|
||||
if (IS_ERR(di->adc_usb_charger_c)) {
|
||||
if (PTR_ERR(di->adc_usb_charger_c) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC USB charger current\n");
|
||||
return PTR_ERR(di->adc_usb_charger_c);
|
||||
}
|
||||
|
||||
/* initialize lock */
|
||||
spin_lock_init(&di->usb_state.usb_lock);
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define MILLI_TO_MICRO 1000
|
||||
@ -182,7 +182,7 @@ struct inst_curr_result_list {
|
||||
* @bat_cap: Structure for battery capacity specific parameters
|
||||
* @avg_cap: Average capacity filter
|
||||
* @parent: Pointer to the struct ab8500
|
||||
* @gpadc: Pointer to the struct gpadc
|
||||
* @main_bat_v: ADC channel for the main battery voltage
|
||||
* @bm: Platform specific battery management information
|
||||
* @fg_psy: Structure that holds the FG specific battery properties
|
||||
* @fg_wq: Work queue for running the FG algorithm
|
||||
@ -224,7 +224,7 @@ struct ab8500_fg {
|
||||
struct ab8500_fg_battery_capacity bat_cap;
|
||||
struct ab8500_fg_avg_cap avg_cap;
|
||||
struct ab8500 *parent;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct iio_channel *main_bat_v;
|
||||
struct abx500_bm_data *bm;
|
||||
struct power_supply *fg_psy;
|
||||
struct workqueue_struct *fg_wq;
|
||||
@ -829,13 +829,13 @@ exit:
|
||||
*/
|
||||
static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
|
||||
{
|
||||
int vbat;
|
||||
int vbat, ret;
|
||||
static int prev;
|
||||
|
||||
vbat = ab8500_gpadc_convert(di->gpadc, MAIN_BAT_V);
|
||||
if (vbat < 0) {
|
||||
ret = iio_read_channel_processed(di->main_bat_v, &vbat);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev,
|
||||
"%s gpadc conversion failed, using previous value\n",
|
||||
"%s ADC conversion failed, using previous value\n",
|
||||
__func__);
|
||||
return prev;
|
||||
}
|
||||
@ -3066,7 +3066,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
|
||||
di->main_bat_v = devm_iio_channel_get(&pdev->dev, "main_bat_v");
|
||||
if (IS_ERR(di->main_bat_v)) {
|
||||
if (PTR_ERR(di->main_bat_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get main battery ADC channel\n");
|
||||
return PTR_ERR(di->main_bat_v);
|
||||
}
|
||||
|
||||
psy_cfg.supplied_to = supply_interface;
|
||||
psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
|
||||
|
@ -508,15 +508,6 @@ config PWM_TIEHRPWM
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-tiehrpwm.
|
||||
|
||||
config PWM_TIPWMSS
|
||||
bool
|
||||
default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM)
|
||||
help
|
||||
PWM Subsystem driver support for AM33xx SOC.
|
||||
|
||||
PWM submodules require PWM config space access from submodule
|
||||
drivers and require common parent driver support.
|
||||
|
||||
config PWM_TWL
|
||||
tristate "TWL4030/6030 PWM support"
|
||||
depends on TWL4030_CORE
|
||||
|
@ -50,7 +50,6 @@ obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
|
||||
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
|
||||
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
|
||||
obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
|
||||
obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o
|
||||
obj-$(CONFIG_PWM_TWL) += pwm-twl.o
|
||||
obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o
|
||||
obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
|
||||
|
@ -417,6 +417,10 @@ static int ad9834_probe(struct spi_device *spi)
|
||||
st = iio_priv(indio_dev);
|
||||
mutex_init(&st->lock);
|
||||
st->mclk = devm_clk_get(&spi->dev, NULL);
|
||||
if (IS_ERR(st->mclk)) {
|
||||
ret = PTR_ERR(st->mclk);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(st->mclk);
|
||||
if (ret) {
|
||||
|
@ -290,53 +290,22 @@ struct counter_device_state {
|
||||
const struct attribute_group **groups;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct counter_signal_read_value - Opaque Signal read value
|
||||
* @buf: string representation of Signal read value
|
||||
* @len: length of string in @buf
|
||||
*/
|
||||
struct counter_signal_read_value {
|
||||
char *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct counter_count_read_value - Opaque Count read value
|
||||
* @buf: string representation of Count read value
|
||||
* @len: length of string in @buf
|
||||
*/
|
||||
struct counter_count_read_value {
|
||||
char *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct counter_count_write_value - Opaque Count write value
|
||||
* @buf: string representation of Count write value
|
||||
*/
|
||||
struct counter_count_write_value {
|
||||
const char *buf;
|
||||
enum counter_signal_value {
|
||||
COUNTER_SIGNAL_LOW = 0,
|
||||
COUNTER_SIGNAL_HIGH
|
||||
};
|
||||
|
||||
/**
|
||||
* struct counter_ops - Callbacks from driver
|
||||
* @signal_read: optional read callback for Signal attribute. The read
|
||||
* value of the respective Signal should be passed back via
|
||||
* the val parameter. val points to an opaque type which
|
||||
* should be set only by calling the
|
||||
* counter_signal_read_value_set function from within the
|
||||
* signal_read callback.
|
||||
* the val parameter.
|
||||
* @count_read: optional read callback for Count attribute. The read
|
||||
* value of the respective Count should be passed back via
|
||||
* the val parameter. val points to an opaque type which
|
||||
* should be set only by calling the
|
||||
* counter_count_read_value_set function from within the
|
||||
* count_read callback.
|
||||
* the val parameter.
|
||||
* @count_write: optional write callback for Count attribute. The write
|
||||
* value for the respective Count is passed in via the val
|
||||
* parameter. val points to an opaque type which should be
|
||||
* accessed only by calling the
|
||||
* counter_count_write_value_get function.
|
||||
* parameter.
|
||||
* @function_get: function to get the current count function mode. Returns
|
||||
* 0 on success and negative error code on error. The index
|
||||
* of the respective Count's returned function mode should
|
||||
@ -346,7 +315,7 @@ struct counter_count_write_value {
|
||||
* Count's functions_list array.
|
||||
* @action_get: function to get the current action mode. Returns 0 on
|
||||
* success and negative error code on error. The index of
|
||||
* the respective Signal's returned action mode should be
|
||||
* the respective Synapse's returned action mode should be
|
||||
* passed back via the action parameter.
|
||||
* @action_set: function to set the action mode. action is the index of
|
||||
* the requested action mode from the respective Synapse's
|
||||
@ -355,13 +324,11 @@ struct counter_count_write_value {
|
||||
struct counter_ops {
|
||||
int (*signal_read)(struct counter_device *counter,
|
||||
struct counter_signal *signal,
|
||||
struct counter_signal_read_value *val);
|
||||
enum counter_signal_value *val);
|
||||
int (*count_read)(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_count_read_value *val);
|
||||
struct counter_count *count, unsigned long *val);
|
||||
int (*count_write)(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_count_write_value *val);
|
||||
struct counter_count *count, unsigned long val);
|
||||
int (*function_get)(struct counter_device *counter,
|
||||
struct counter_count *count, size_t *function);
|
||||
int (*function_set)(struct counter_device *counter,
|
||||
@ -477,29 +444,6 @@ struct counter_device {
|
||||
void *priv;
|
||||
};
|
||||
|
||||
enum counter_signal_level {
|
||||
COUNTER_SIGNAL_LEVEL_LOW = 0,
|
||||
COUNTER_SIGNAL_LEVEL_HIGH
|
||||
};
|
||||
|
||||
enum counter_signal_value_type {
|
||||
COUNTER_SIGNAL_LEVEL = 0
|
||||
};
|
||||
|
||||
enum counter_count_value_type {
|
||||
COUNTER_COUNT_POSITION = 0,
|
||||
};
|
||||
|
||||
void counter_signal_read_value_set(struct counter_signal_read_value *const val,
|
||||
const enum counter_signal_value_type type,
|
||||
void *const data);
|
||||
void counter_count_read_value_set(struct counter_count_read_value *const val,
|
||||
const enum counter_count_value_type type,
|
||||
void *const data);
|
||||
int counter_count_write_value_get(void *const data,
|
||||
const enum counter_count_value_type type,
|
||||
const struct counter_count_write_value *const val);
|
||||
|
||||
int counter_register(struct counter_device *const counter);
|
||||
void counter_unregister(struct counter_device *const counter);
|
||||
int devm_counter_register(struct device *dev,
|
||||
|
@ -1,75 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2010 ST-Ericsson SA
|
||||
*
|
||||
* Author: Arun R Murthy <arun.murthy@stericsson.com>
|
||||
* Author: Daniel Willerud <daniel.willerud@stericsson.com>
|
||||
* Author: M'boumba Cedric Madianga <cedric.madianga@stericsson.com>
|
||||
*/
|
||||
|
||||
#ifndef _AB8500_GPADC_H
|
||||
#define _AB8500_GPADC_H
|
||||
|
||||
/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2
|
||||
* and ADCHwSel[4:0] in GPADCCtrl3 ) */
|
||||
#define BAT_CTRL 0x01
|
||||
#define BTEMP_BALL 0x02
|
||||
#define MAIN_CHARGER_V 0x03
|
||||
#define ACC_DETECT1 0x04
|
||||
#define ACC_DETECT2 0x05
|
||||
#define ADC_AUX1 0x06
|
||||
#define ADC_AUX2 0x07
|
||||
#define MAIN_BAT_V 0x08
|
||||
#define VBUS_V 0x09
|
||||
#define MAIN_CHARGER_C 0x0A
|
||||
#define USB_CHARGER_C 0x0B
|
||||
#define BK_BAT_V 0x0C
|
||||
#define DIE_TEMP 0x0D
|
||||
#define USB_ID 0x0E
|
||||
#define XTAL_TEMP 0x12
|
||||
#define VBAT_TRUE_MEAS 0x13
|
||||
#define BAT_CTRL_AND_IBAT 0x1C
|
||||
#define VBAT_MEAS_AND_IBAT 0x1D
|
||||
#define VBAT_TRUE_MEAS_AND_IBAT 0x1E
|
||||
#define BAT_TEMP_AND_IBAT 0x1F
|
||||
|
||||
/* Virtual channel used only for ibat convertion to ampere
|
||||
* Battery current conversion (ibat) cannot be requested as a single conversion
|
||||
* but it is always in combination with other input requests
|
||||
*/
|
||||
#define IBAT_VIRTUAL_CHANNEL 0xFF
|
||||
|
||||
#define SAMPLE_1 1
|
||||
#define SAMPLE_4 4
|
||||
#define SAMPLE_8 8
|
||||
#define SAMPLE_16 16
|
||||
#define RISING_EDGE 0
|
||||
#define FALLING_EDGE 1
|
||||
|
||||
/* Arbitrary ADC conversion type constants */
|
||||
#define ADC_SW 0
|
||||
#define ADC_HW 1
|
||||
|
||||
struct ab8500_gpadc;
|
||||
|
||||
struct ab8500_gpadc *ab8500_gpadc_get(char *name);
|
||||
int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel,
|
||||
u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
|
||||
static inline int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
|
||||
{
|
||||
return ab8500_gpadc_sw_hw_convert(gpadc, channel,
|
||||
SAMPLE_16, 0, 0, ADC_SW);
|
||||
}
|
||||
|
||||
int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
|
||||
u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
|
||||
int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
|
||||
u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type,
|
||||
int *ibat);
|
||||
int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
|
||||
u8 channel, int ad_value);
|
||||
void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
|
||||
u16 *vmain_l, u16 *vmain_h, u16 *btemp_l, u16 *btemp_h,
|
||||
u16 *vbat_l, u16 *vbat_h, u16 *ibat_l, u16 *ibat_h);
|
||||
|
||||
#endif /* _AB8500_GPADC_H */
|
@ -18,12 +18,14 @@
|
||||
* @open_drain: set the interrupt line to be open drain if possible.
|
||||
* @spi_3wire: enable spi-3wire mode.
|
||||
* @pullups: enable/disable i2c controller pullup resistors.
|
||||
* @wakeup_source: enable/disable device as wakeup generator.
|
||||
*/
|
||||
struct st_sensors_platform_data {
|
||||
u8 drdy_int_pin;
|
||||
bool open_drain;
|
||||
bool spi_3wire;
|
||||
bool pullups;
|
||||
bool wakeup_source;
|
||||
};
|
||||
|
||||
#endif /* ST_SENSORS_PDATA_H */
|
||||
|
Loading…
Reference in New Issue
Block a user