提交 cbcd4f08 编写于 作者: L Linus Torvalds

Merge tag 'staging-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging/IIO updates from Greg KH:
 "Here's the large set of staging and iio driver patches for 4.13-rc1.

  After over 500 patches, we removed about 200 more lines of code than
  we added, not great, but we added some new IIO drivers for unsupported
  hardware, so it's an overall win.

  Also here are lots of small fixes, and some tty core api additions
  (with the tty maintainer's ack) for the speakup drivers, those are
  finally getting some much needed cleanups and are looking much better
  now than before. Full details in the shortlog.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'staging-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (529 commits)
  staging: lustre: replace kmalloc with kmalloc_array
  Staging: ion: fix code style warning from NULL comparisons
  staging: fsl-mc: make dprc.h header private
  staging: fsl-mc: move mc-cmd.h contents in the public header
  staging: fsl-mc: move mc-sys.h contents in the public header
  staging: fsl-mc: fix a few implicit includes
  staging: fsl-mc: remove dpmng API files
  staging: fsl-mc: move rest of mc-bus.h to private header
  staging: fsl-mc: move couple of definitions to public header
  staging: fsl-mc: move irq domain creation prototype to public header
  staging: fsl-mc: turn several exported functions static
  staging: fsl-mc: delete prototype of unimplemented function
  staging: fsl-mc: delete duplicated function prototypes
  staging: fsl-mc: decouple the mc-bus public headers from dprc.h
  staging: fsl-mc: drop useless #includes
  staging: fsl-mc: be consistent when checking strcmp() return
  staging: fsl-mc: move comparison before strcmp() call
  staging: speakup: make function ser_to_dev static
  staging: ks7010: fix spelling mistake: "errror" -> "error"
  staging: rtl8192e: fix spelling mistake: "respose" -> "response"
  ...
...@@ -1425,6 +1425,17 @@ Description: ...@@ -1425,6 +1425,17 @@ Description:
guarantees that the hardware fifo is flushed to the device guarantees that the hardware fifo is flushed to the device
buffer. buffer.
What: /sys/bus/iio/devices/iio:device*/buffer/hwfifo_timeout
KernelVersion: 4.12
Contact: linux-iio@vger.kernel.org
Description:
A read/write property to provide capability to delay reporting of
samples till a timeout is reached. This allows host processors to
sleep, while the sensor is storing samples in its internal fifo.
The maximum timeout in seconds can be specified by setting
hwfifo_timeout.The current delay can be read by reading
hwfifo_timeout. A value of 0 means that there is no timeout.
What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark
KernelVersion: 4.2 KernelVersion: 4.2
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
......
...@@ -5,4 +5,3 @@ Description: ...@@ -5,4 +5,3 @@ Description:
Reading returns either '1' or '0'. '1' means that the Reading returns either '1' or '0'. '1' means that the
battery level supplied to sensor is below 2.25V. battery level supplied to sensor is below 2.25V.
This ABI is available for tsys02d, htu21, ms8607 This ABI is available for tsys02d, htu21, ms8607
This ABI is available for htu21, ms8607
...@@ -16,6 +16,54 @@ Description: ...@@ -16,6 +16,54 @@ Description:
- "OC2REF" : OC2REF signal is used as trigger output. - "OC2REF" : OC2REF signal is used as trigger output.
- "OC3REF" : OC3REF signal is used as trigger output. - "OC3REF" : OC3REF signal is used as trigger output.
- "OC4REF" : OC4REF signal is used as trigger output. - "OC4REF" : OC4REF signal is used as trigger output.
Additional modes (on TRGO2 only):
- "OC5REF" : OC5REF signal is used as trigger output.
- "OC6REF" : OC6REF signal is used as trigger output.
- "compare_pulse_OC4REF":
OC4REF rising or falling edges generate pulses.
- "compare_pulse_OC6REF":
OC6REF rising or falling edges generate pulses.
- "compare_pulse_OC4REF_r_or_OC6REF_r":
OC4REF or OC6REF rising edges generate pulses.
- "compare_pulse_OC4REF_r_or_OC6REF_f":
OC4REF rising or OC6REF falling edges generate pulses.
- "compare_pulse_OC5REF_r_or_OC6REF_r":
OC5REF or OC6REF rising edges generate pulses.
- "compare_pulse_OC5REF_r_or_OC6REF_f":
OC5REF rising or OC6REF falling edges generate pulses.
+-----------+ +-------------+ +---------+
| Prescaler +-> | Counter | +-> | Master | TRGO(2)
+-----------+ +--+--------+-+ |-> | Control +-->
| | || +---------+
+--v--------+-+ OCxREF || +---------+
| Chx compare +----------> | Output | ChX
+-----------+-+ | | Control +-->
. | | +---------+
. | | .
+-----------v-+ OC6REF | .
| Ch6 compare +---------+>
+-------------+
Example with: "compare_pulse_OC4REF_r_or_OC6REF_r":
X
X X
X . . X
X . . X
X . . X
count X . . . . X
. . . .
. . . .
+---------------+
OC4REF | . . |
+-+ . . +-+
. +---+ .
OC6REF . | | .
+-------+ +-------+
+-+ +-+
TRGO2 | | | |
+-+ +---+ +---------+
What: /sys/bus/iio/devices/triggerX/master_mode What: /sys/bus/iio/devices/triggerX/master_mode
KernelVersion: 4.11 KernelVersion: 4.11
...@@ -90,3 +138,18 @@ Description: ...@@ -90,3 +138,18 @@ Description:
Counting is enabled on rising edge of the connected Counting is enabled on rising edge of the connected
trigger, and remains enabled for the duration of this trigger, and remains enabled for the duration of this
selected mode. selected mode.
What: /sys/bus/iio/devices/iio:deviceX/in_count_trigger_mode_available
KernelVersion: 4.13
Contact: benjamin.gaignard@st.com
Description:
Reading returns the list possible trigger modes.
What: /sys/bus/iio/devices/iio:deviceX/in_count0_trigger_mode
KernelVersion: 4.13
Contact: benjamin.gaignard@st.com
Description:
Configure the device counter trigger mode
counting direction is set by in_count0_count_direction
attribute and the counter is clocked by the connected trigger
rising edges.
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
Required properties: Required properties:
- compatible: depending on the SoC this should be one of: - compatible: depending on the SoC this should be one of:
- "amlogic,meson8-saradc" for Meson8
- "amlogic,meson8b-saradc" for Meson8b
- "amlogic,meson-gxbb-saradc" for GXBB - "amlogic,meson-gxbb-saradc" for GXBB
- "amlogic,meson-gxl-saradc" for GXL - "amlogic,meson-gxl-saradc" for GXL
- "amlogic,meson-gxm-saradc" for GXM - "amlogic,meson-gxm-saradc" for GXM
......
* Renesas RCar GyroADC device driver * Renesas R-Car GyroADC device driver
The GyroADC block is a reduced SPI block with up to 8 chipselect lines, The GyroADC block is a reduced SPI block with up to 8 chipselect lines,
which supports the SPI protocol of a selected few SPI ADCs. The SPI ADCs which supports the SPI protocol of a selected few SPI ADCs. The SPI ADCs
...@@ -16,8 +16,7 @@ Required properties: ...@@ -16,8 +16,7 @@ Required properties:
- clocks: References to all the clocks specified in the clock-names - clocks: References to all the clocks specified in the clock-names
property as specified in property as specified in
Documentation/devicetree/bindings/clock/clock-bindings.txt. Documentation/devicetree/bindings/clock/clock-bindings.txt.
- clock-names: Shall contain "fck" and "if". The "fck" is the GyroADC block - clock-names: Shall contain "fck". The "fck" is the GyroADC block clock.
clock, the "if" is the interface clock.
- power-domains: Must contain a reference to the PM domain, if available. - power-domains: Must contain a reference to the PM domain, if available.
- #address-cells: Should be <1> (setting for the subnodes) for all ADCs - #address-cells: Should be <1> (setting for the subnodes) for all ADCs
except for "fujitsu,mb88101a". Should be <0> (setting for except for "fujitsu,mb88101a". Should be <0> (setting for
...@@ -75,8 +74,8 @@ Example: ...@@ -75,8 +74,8 @@ Example:
adc@e6e54000 { adc@e6e54000 {
compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc"; compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc";
reg = <0 0xe6e54000 0 64>; reg = <0 0xe6e54000 0 64>;
clocks = <&mstp9_clks R8A7791_CLK_GYROADC>, <&clk_65m>; clocks = <&mstp9_clks R8A7791_CLK_GYROADC>;
clock-names = "fck", "if"; clock-names = "fck";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
pinctrl-0 = <&adc_pins>; pinctrl-0 = <&adc_pins>;
......
...@@ -21,11 +21,19 @@ own configurable sequence and trigger: ...@@ -21,11 +21,19 @@ own configurable sequence and trigger:
Contents of a stm32 adc root node: Contents of a stm32 adc root node:
----------------------------------- -----------------------------------
Required properties: Required properties:
- compatible: Should be "st,stm32f4-adc-core". - compatible: Should be one of:
"st,stm32f4-adc-core"
"st,stm32h7-adc-core"
- reg: Offset and length of the ADC block register set. - reg: Offset and length of the ADC block register set.
- interrupts: Must contain the interrupt for ADC block. - interrupts: Must contain the interrupt for ADC block.
- clocks: Clock for the analog circuitry (common to all ADCs). - clocks: Core can use up to two clocks, depending on part used:
- clock-names: Must be "adc". - "adc" clock: for the analog circuitry, common to all ADCs.
It's required on stm32f4.
It's optional on stm32h7.
- "bus" clock: for registers access, common to all ADCs.
It's not present on stm32f4.
It's required on stm32h7.
- clock-names: Must be "adc" and/or "bus" depending on part used.
- interrupt-controller: Identifies the controller node as interrupt-parent - interrupt-controller: Identifies the controller node as interrupt-parent
- vref-supply: Phandle to the vref input analog reference voltage. - vref-supply: Phandle to the vref input analog reference voltage.
- #interrupt-cells = <1>; - #interrupt-cells = <1>;
...@@ -42,14 +50,18 @@ An ADC block node should contain at least one subnode, representing an ...@@ -42,14 +50,18 @@ An ADC block node should contain at least one subnode, representing an
ADC instance available on the machine. ADC instance available on the machine.
Required properties: Required properties:
- compatible: Should be "st,stm32f4-adc". - compatible: Should be one of:
"st,stm32f4-adc"
"st,stm32h7-adc"
- reg: Offset of ADC instance in ADC block (e.g. may be 0x0, 0x100, 0x200). - reg: Offset of ADC instance in ADC block (e.g. may be 0x0, 0x100, 0x200).
- clocks: Input clock private to this ADC instance. - clocks: Input clock private to this ADC instance. It's required only on
stm32f4, that has per instance clock input for registers access.
- interrupt-parent: Phandle to the parent interrupt controller. - interrupt-parent: Phandle to the parent interrupt controller.
- interrupts: IRQ Line for the ADC (e.g. may be 0 for adc@0, 1 for adc@100 or - interrupts: IRQ Line for the ADC (e.g. may be 0 for adc@0, 1 for adc@100 or
2 for adc@200). 2 for adc@200).
- st,adc-channels: List of single-ended channels muxed for this ADC. - st,adc-channels: List of single-ended channels muxed for this ADC.
It can have up to 16 channels, numbered from 0 to 15 (resp. for in0..in15). It can have up to 16 channels on stm32f4 or 20 channels on stm32h7, numbered
from 0 to 15 or 19 (resp. for in0..in15 or in0..in19).
- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in - #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
Documentation/devicetree/bindings/iio/iio-bindings.txt Documentation/devicetree/bindings/iio/iio-bindings.txt
...@@ -58,7 +70,9 @@ Optional properties: ...@@ -58,7 +70,9 @@ Optional properties:
See ../../dma/dma.txt for details. See ../../dma/dma.txt for details.
- dma-names: Must be "rx" when dmas property is being used. - dma-names: Must be "rx" when dmas property is being used.
- assigned-resolution-bits: Resolution (bits) to use for conversions. Must - assigned-resolution-bits: Resolution (bits) to use for conversions. Must
match device available resolutions (e.g. can be 6, 8, 10 or 12 on stm32f4). match device available resolutions:
* can be 6, 8, 10 or 12 on stm32f4
* can be 8, 10, 12, 14 or 16 on stm32h7
Default is maximum resolution if unset. Default is maximum resolution if unset.
Example: Example:
......
* Texas Instruments' ADC084S021
Required properties:
- compatible : Must be "ti,adc084s021"
- reg : SPI chip select number for the device
- vref-supply : The regulator supply for ADC reference voltage
- spi-cpol : Per spi-bus bindings
- spi-cpha : Per spi-bus bindings
- spi-max-frequency : Per spi-bus bindings
Example:
adc@0 {
compatible = "ti,adc084s021";
reg = <0>;
vref-supply = <&adc_vref>;
spi-cpol;
spi-cpha;
spi-max-frequency = <16000000>;
};
* Texas Instruments' ADC108S102 and ADC128S102 ADC chip
Required properties:
- compatible: Should be "ti,adc108s102"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,adc108s102";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
};
...@@ -13,7 +13,8 @@ Optional properties: ...@@ -13,7 +13,8 @@ Optional properties:
"data ready" (valid values: 1 or 2). "data ready" (valid values: 1 or 2).
- interrupt-parent: should be the phandle for the interrupt controller - interrupt-parent: should be the phandle for the interrupt controller
- interrupts: interrupt mapping for IRQ. It should be configured with - interrupts: interrupt mapping for IRQ. It should be configured with
flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING. flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
IRQ_TYPE_EDGE_FALLING.
Refer to interrupt-controller/interrupts.txt for generic interrupt Refer to interrupt-controller/interrupts.txt for generic interrupt
client node bindings. client node bindings.
......
...@@ -55,6 +55,7 @@ gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire In ...@@ -55,6 +55,7 @@ gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire In
infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz)
isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor
isil,isl29030 Intersil ISL29030 Ambient Light and Proximity Sensor
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
......
...@@ -10553,6 +10553,7 @@ M: Laurentiu Tudor <laurentiu.tudor@nxp.com> ...@@ -10553,6 +10553,7 @@ M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained
F: drivers/staging/fsl-mc/ F: drivers/staging/fsl-mc/
F: Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
QT1010 MEDIA DRIVER QT1010 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi> M: Antti Palosaari <crope@iki.fi>
......
...@@ -347,7 +347,7 @@ static int accel_3d_parse_report(struct platform_device *pdev, ...@@ -347,7 +347,7 @@ static int accel_3d_parse_report(struct platform_device *pdev,
static int hid_accel_3d_probe(struct platform_device *pdev) static int hid_accel_3d_probe(struct platform_device *pdev)
{ {
int ret = 0; int ret = 0;
static const char *name; const char *name;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
struct accel_3d_state *accel_state; struct accel_3d_state *accel_state;
const struct iio_chan_spec *channel_spec; const struct iio_chan_spec *channel_spec;
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#define MMA9551_DRV_NAME "mma9551" #define MMA9551_DRV_NAME "mma9551"
#define MMA9551_IRQ_NAME "mma9551_event" #define MMA9551_IRQ_NAME "mma9551_event"
#define MMA9551_GPIO_NAME "mma9551_int"
#define MMA9551_GPIO_COUNT 4 #define MMA9551_GPIO_COUNT 4
/* Tilt application (inclination in IIO terms). */ /* Tilt application (inclination in IIO terms). */
...@@ -418,8 +417,7 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev) ...@@ -418,8 +417,7 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev)
struct device *dev = &data->client->dev; struct device *dev = &data->client->dev;
for (i = 0; i < MMA9551_GPIO_COUNT; i++) { for (i = 0; i < MMA9551_GPIO_COUNT; i++) {
gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i, gpio = devm_gpiod_get_index(dev, NULL, i, GPIOD_IN);
GPIOD_IN);
if (IS_ERR(gpio)) { if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n"); dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio); return PTR_ERR(gpio);
......
...@@ -710,6 +710,8 @@ static const struct iio_trigger_ops st_accel_trigger_ops = { ...@@ -710,6 +710,8 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
int st_accel_common_probe(struct iio_dev *indio_dev) int st_accel_common_probe(struct iio_dev *indio_dev)
{ {
struct st_sensor_data *adata = iio_priv(indio_dev); struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata =
(struct st_sensors_platform_data *)adata->dev->platform_data;
int irq = adata->get_irq_data_ready(indio_dev); int irq = adata->get_irq_data_ready(indio_dev);
int err; int err;
...@@ -736,9 +738,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev) ...@@ -736,9 +738,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
&adata->sensor_settings->fs.fs_avl[0]; &adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz; adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
if (!adata->dev->platform_data) if (!pdata)
adata->dev->platform_data = pdata = (struct st_sensors_platform_data *)&default_accel_pdata;
(struct st_sensors_platform_data *)&default_accel_pdata;
err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data); err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
if (err < 0) if (err < 0)
......
...@@ -47,15 +47,11 @@ static int st_accel_spi_remove(struct spi_device *spi) ...@@ -47,15 +47,11 @@ static int st_accel_spi_remove(struct spi_device *spi)
} }
static const struct spi_device_id st_accel_id_table[] = { static const struct spi_device_id st_accel_id_table[] = {
{ LSM303DLH_ACCEL_DEV_NAME },
{ LSM303DLHC_ACCEL_DEV_NAME },
{ LIS3DH_ACCEL_DEV_NAME }, { LIS3DH_ACCEL_DEV_NAME },
{ LSM330D_ACCEL_DEV_NAME }, { LSM330D_ACCEL_DEV_NAME },
{ LSM330DL_ACCEL_DEV_NAME }, { LSM330DL_ACCEL_DEV_NAME },
{ LSM330DLC_ACCEL_DEV_NAME }, { LSM330DLC_ACCEL_DEV_NAME },
{ LIS331DLH_ACCEL_DEV_NAME }, { LIS331DLH_ACCEL_DEV_NAME },
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME }, { LSM303AGR_ACCEL_DEV_NAME },
{ LIS2DH12_ACCEL_DEV_NAME }, { LIS2DH12_ACCEL_DEV_NAME },
......
...@@ -679,6 +679,18 @@ config TI_ADC0832 ...@@ -679,6 +679,18 @@ config TI_ADC0832
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called ti-adc0832. called ti-adc0832.
config TI_ADC084S021
tristate "Texas Instruments ADC084S021"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for Texas Instruments ADC084S021
chips.
This driver can also be built as a module. If so, the module will be
called ti-adc084s021.
config TI_ADC12138 config TI_ADC12138
tristate "Texas Instruments ADC12130/ADC12132/ADC12138" tristate "Texas Instruments ADC12130/ADC12132/ADC12138"
depends on SPI depends on SPI
...@@ -691,6 +703,18 @@ config TI_ADC12138 ...@@ -691,6 +703,18 @@ config TI_ADC12138
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called ti-adc12138. called ti-adc12138.
config TI_ADC108S102
tristate "Texas Instruments ADC108S102 and ADC128S102 driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Texas Instruments ADC108S102 and
ADC128S102 ADC.
To compile this driver as a module, choose M here: the module will
be called ti-adc108s102.
config TI_ADC128S052 config TI_ADC128S052
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021" tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
depends on SPI depends on SPI
......
...@@ -62,7 +62,9 @@ obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o ...@@ -62,7 +62,9 @@ obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
obj-$(CONFIG_STM32_ADC) += stm32-adc.o obj-$(CONFIG_STM32_ADC) += stm32-adc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o
obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
......
...@@ -272,11 +272,9 @@ static ssize_t ad7791_write_frequency(struct device *dev, ...@@ -272,11 +272,9 @@ static ssize_t ad7791_write_frequency(struct device *dev,
struct ad7791_state *st = iio_priv(indio_dev); struct ad7791_state *st = iio_priv(indio_dev);
int i, ret; int i, ret;
for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) i = sysfs_match_string(ad7791_sample_freq_avail, buf);
if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) if (i < 0)
break; return i;
if (i == ARRAY_SIZE(ad7791_sample_freq_avail))
return -EINVAL;
ret = iio_device_claim_direct_mode(indio_dev); ret = iio_device_claim_direct_mode(indio_dev);
if (ret) if (ret)
......
...@@ -212,7 +212,10 @@ static int aspeed_adc_probe(struct platform_device *pdev) ...@@ -212,7 +212,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
} }
/* Start all channels in normal mode. */ /* Start all channels in normal mode. */
clk_prepare_enable(data->clk_scaler->clk); ret = clk_prepare_enable(data->clk_scaler->clk);
if (ret)
goto clk_enable_error;
adc_engine_control_reg_val = GENMASK(31, 16) | adc_engine_control_reg_val = GENMASK(31, 16) |
ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE; ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
writel(adc_engine_control_reg_val, writel(adc_engine_control_reg_val,
...@@ -236,6 +239,7 @@ static int aspeed_adc_probe(struct platform_device *pdev) ...@@ -236,6 +239,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
writel(ASPEED_OPERATION_MODE_POWER_DOWN, writel(ASPEED_OPERATION_MODE_POWER_DOWN,
data->base + ASPEED_REG_ENGINE_CONTROL); data->base + ASPEED_REG_ENGINE_CONTROL);
clk_disable_unprepare(data->clk_scaler->clk); clk_disable_unprepare(data->clk_scaler->clk);
clk_enable_error:
clk_hw_unregister_divider(data->clk_scaler); clk_hw_unregister_divider(data->clk_scaler);
scaler_error: scaler_error:
......
...@@ -52,6 +52,10 @@ ...@@ -52,6 +52,10 @@
#define CPCAP_BIT_RAND0 BIT(1) /* Set with CAL_MODE */ #define CPCAP_BIT_RAND0 BIT(1) /* Set with CAL_MODE */
#define CPCAP_BIT_ADEN BIT(0) /* Currently unused */ #define CPCAP_BIT_ADEN BIT(0) /* Currently unused */
#define CPCAP_REG_ADCC1_DEFAULTS (CPCAP_BIT_ADEN_AUTO_CLR | \
CPCAP_BIT_ADC_CLK_SEL0 | \
CPCAP_BIT_RAND1)
/* Register CPCAP_REG_ADCC2 bits */ /* Register CPCAP_REG_ADCC2 bits */
#define CPCAP_BIT_CAL_FACTOR_ENABLE BIT(15) /* Currently unused */ #define CPCAP_BIT_CAL_FACTOR_ENABLE BIT(15) /* Currently unused */
#define CPCAP_BIT_BATDETB_EN BIT(14) /* Currently unused */ #define CPCAP_BIT_BATDETB_EN BIT(14) /* Currently unused */
...@@ -62,7 +66,7 @@ ...@@ -62,7 +66,7 @@
#define CPCAP_BIT_ADC_PS_FACTOR0 BIT(9) #define CPCAP_BIT_ADC_PS_FACTOR0 BIT(9)
#define CPCAP_BIT_AD4_SELECT BIT(8) /* Currently unused */ #define CPCAP_BIT_AD4_SELECT BIT(8) /* Currently unused */
#define CPCAP_BIT_ADC_BUSY BIT(7) /* Currently unused */ #define CPCAP_BIT_ADC_BUSY BIT(7) /* Currently unused */
#define CPCAP_BIT_THERMBIAS_EN BIT(6) /* Currently unused */ #define CPCAP_BIT_THERMBIAS_EN BIT(6) /* Bias for AD0_BATTDETB */
#define CPCAP_BIT_ADTRIG_DIS BIT(5) /* Disable interrupt */ #define CPCAP_BIT_ADTRIG_DIS BIT(5) /* Disable interrupt */
#define CPCAP_BIT_LIADC BIT(4) /* Currently unused */ #define CPCAP_BIT_LIADC BIT(4) /* Currently unused */
#define CPCAP_BIT_TS_REFEN BIT(3) /* Currently unused */ #define CPCAP_BIT_TS_REFEN BIT(3) /* Currently unused */
...@@ -70,6 +74,12 @@ ...@@ -70,6 +74,12 @@
#define CPCAP_BIT_TS_M1 BIT(1) /* Currently unused */ #define CPCAP_BIT_TS_M1 BIT(1) /* Currently unused */
#define CPCAP_BIT_TS_M0 BIT(0) /* Currently unused */ #define CPCAP_BIT_TS_M0 BIT(0) /* Currently unused */
#define CPCAP_REG_ADCC2_DEFAULTS (CPCAP_BIT_AD4_SELECT | \
CPCAP_BIT_ADTRIG_DIS | \
CPCAP_BIT_LIADC | \
CPCAP_BIT_TS_M2 | \
CPCAP_BIT_TS_M1)
#define CPCAP_MAX_TEMP_LVL 27 #define CPCAP_MAX_TEMP_LVL 27
#define CPCAP_FOUR_POINT_TWO_ADC 801 #define CPCAP_FOUR_POINT_TWO_ADC 801
#define ST_ADC_CAL_CHRGI_HIGH_THRESHOLD 530 #define ST_ADC_CAL_CHRGI_HIGH_THRESHOLD 530
...@@ -78,7 +88,7 @@ ...@@ -78,7 +88,7 @@
#define ST_ADC_CAL_BATTI_LOW_THRESHOLD 494 #define ST_ADC_CAL_BATTI_LOW_THRESHOLD 494
#define ST_ADC_CALIBRATE_DIFF_THRESHOLD 3 #define ST_ADC_CALIBRATE_DIFF_THRESHOLD 3
#define CPCAP_ADC_MAX_RETRIES 5 /* Calibration and quirk */ #define CPCAP_ADC_MAX_RETRIES 5 /* Calibration */
/** /**
* struct cpcap_adc_ato - timing settings for cpcap adc * struct cpcap_adc_ato - timing settings for cpcap adc
...@@ -124,10 +134,10 @@ struct cpcap_adc { ...@@ -124,10 +134,10 @@ struct cpcap_adc {
*/ */
enum cpcap_adc_channel { enum cpcap_adc_channel {
/* Bank0 channels */ /* Bank0 channels */
CPCAP_ADC_AD0_BATTDETB, /* Battery detection */ CPCAP_ADC_AD0, /* Battery temperature */
CPCAP_ADC_BATTP, /* Battery voltage */ CPCAP_ADC_BATTP, /* Battery voltage */
CPCAP_ADC_VBUS, /* USB VBUS voltage */ CPCAP_ADC_VBUS, /* USB VBUS voltage */
CPCAP_ADC_AD3, /* Battery temperature when charging */ CPCAP_ADC_AD3, /* Die temperature when charging */
CPCAP_ADC_BPLUS_AD4, /* Another battery or system voltage */ CPCAP_ADC_BPLUS_AD4, /* Another battery or system voltage */
CPCAP_ADC_CHG_ISENSE, /* Calibrated charge current */ CPCAP_ADC_CHG_ISENSE, /* Calibrated charge current */
CPCAP_ADC_BATTI, /* Calibrated system current */ CPCAP_ADC_BATTI, /* Calibrated system current */
...@@ -217,7 +227,7 @@ struct cpcap_adc_request { ...@@ -217,7 +227,7 @@ struct cpcap_adc_request {
/* Phasing table for channels. Note that channels 16 & 17 use BATTP and BATTI */ /* Phasing table for channels. Note that channels 16 & 17 use BATTP and BATTI */
static const struct cpcap_adc_phasing_tbl bank_phasing[] = { static const struct cpcap_adc_phasing_tbl bank_phasing[] = {
/* Bank0 */ /* Bank0 */
[CPCAP_ADC_AD0_BATTDETB] = {0, 0x80, 0x80, 0, 1023}, [CPCAP_ADC_AD0] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_BATTP] = {0, 0x80, 0x80, 0, 1023}, [CPCAP_ADC_BATTP] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_VBUS] = {0, 0x80, 0x80, 0, 1023}, [CPCAP_ADC_VBUS] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_AD3] = {0, 0x80, 0x80, 0, 1023}, [CPCAP_ADC_AD3] = {0, 0x80, 0x80, 0, 1023},
...@@ -243,7 +253,7 @@ static const struct cpcap_adc_phasing_tbl bank_phasing[] = { ...@@ -243,7 +253,7 @@ static const struct cpcap_adc_phasing_tbl bank_phasing[] = {
*/ */
static struct cpcap_adc_conversion_tbl bank_conversion[] = { static struct cpcap_adc_conversion_tbl bank_conversion[] = {
/* Bank0 */ /* Bank0 */
[CPCAP_ADC_AD0_BATTDETB] = { [CPCAP_ADC_AD0] = {
IIO_CHAN_INFO_PROCESSED, 0, 0, 0, 1, 1, IIO_CHAN_INFO_PROCESSED, 0, 0, 0, 1, 1,
}, },
[CPCAP_ADC_BATTP] = { [CPCAP_ADC_BATTP] = {
...@@ -541,6 +551,15 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata, ...@@ -541,6 +551,15 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
return; return;
switch (req->channel) { switch (req->channel) {
case CPCAP_ADC_AD0:
value2 |= CPCAP_BIT_THERMBIAS_EN;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_THERMBIAS_EN,
value2);
if (error)
return;
usleep_range(800, 1000);
break;
case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15: case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15:
value1 |= CPCAP_BIT_AD_SEL1; value1 |= CPCAP_BIT_AD_SEL1;
break; break;
...@@ -583,7 +602,8 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata, ...@@ -583,7 +602,8 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2, error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ATOX_PS_FACTOR | CPCAP_BIT_ATOX_PS_FACTOR |
CPCAP_BIT_ADC_PS_FACTOR1 | CPCAP_BIT_ADC_PS_FACTOR1 |
CPCAP_BIT_ADC_PS_FACTOR0, CPCAP_BIT_ADC_PS_FACTOR0 |
CPCAP_BIT_THERMBIAS_EN,
value2); value2);
if (error) if (error)
return; return;
...@@ -614,27 +634,6 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata, ...@@ -614,27 +634,6 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
} }
} }
/*
* Occasionally the ADC does not seem to start and there will be no
* interrupt. Let's re-init interrupt to prevent the ADC from hanging
* for the next request. It is unclear why this happens, but the next
* request will usually work after doing this.
*/
static void cpcap_adc_quirk_reset_lost_irq(struct cpcap_adc *ddata)
{
int error;
dev_info(ddata->dev, "lost ADC irq, attempting to reinit\n");
disable_irq(ddata->irq);
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
if (error)
dev_warn(ddata->dev, "%s reset failed: %i\n",
__func__, error);
enable_irq(ddata->irq);
}
static int cpcap_adc_start_bank(struct cpcap_adc *ddata, static int cpcap_adc_start_bank(struct cpcap_adc *ddata,
struct cpcap_adc_request *req) struct cpcap_adc_request *req)
{ {
...@@ -652,7 +651,6 @@ static int cpcap_adc_start_bank(struct cpcap_adc *ddata, ...@@ -652,7 +651,6 @@ static int cpcap_adc_start_bank(struct cpcap_adc *ddata,
return 0; return 0;
if (error == 0) { if (error == 0) {
cpcap_adc_quirk_reset_lost_irq(ddata);
error = -ETIMEDOUT; error = -ETIMEDOUT;
continue; continue;
} }
...@@ -664,6 +662,21 @@ static int cpcap_adc_start_bank(struct cpcap_adc *ddata, ...@@ -664,6 +662,21 @@ static int cpcap_adc_start_bank(struct cpcap_adc *ddata,
return error; return error;
} }
static int cpcap_adc_stop_bank(struct cpcap_adc *ddata)
{
int error;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
0xffff,
CPCAP_REG_ADCC1_DEFAULTS);
if (error)
return error;
return regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
0xffff,
CPCAP_REG_ADCC2_DEFAULTS);
}
static void cpcap_adc_phase(struct cpcap_adc_request *req) static void cpcap_adc_phase(struct cpcap_adc_request *req)
{ {
const struct cpcap_adc_conversion_tbl *conv_tbl = req->conv_tbl; const struct cpcap_adc_conversion_tbl *conv_tbl = req->conv_tbl;
...@@ -758,7 +771,7 @@ static void cpcap_adc_convert(struct cpcap_adc_request *req) ...@@ -758,7 +771,7 @@ static void cpcap_adc_convert(struct cpcap_adc_request *req)
return; return;
/* Temperatures use a lookup table instead of conversion table */ /* Temperatures use a lookup table instead of conversion table */
if ((req->channel == CPCAP_ADC_AD0_BATTDETB) || if ((req->channel == CPCAP_ADC_AD0) ||
(req->channel == CPCAP_ADC_AD3)) { (req->channel == CPCAP_ADC_AD3)) {
req->result = req->result =
cpcap_adc_table_to_millicelcius(req->result); cpcap_adc_table_to_millicelcius(req->result);
...@@ -820,7 +833,7 @@ static int cpcap_adc_init_request(struct cpcap_adc_request *req, ...@@ -820,7 +833,7 @@ static int cpcap_adc_init_request(struct cpcap_adc_request *req,
req->conv_tbl = bank_conversion; req->conv_tbl = bank_conversion;
switch (channel) { switch (channel) {
case CPCAP_ADC_AD0_BATTDETB ... CPCAP_ADC_USB_ID: case CPCAP_ADC_AD0 ... CPCAP_ADC_USB_ID:
req->bank_index = channel; req->bank_index = channel;
break; break;
case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15: case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15:
...@@ -839,6 +852,22 @@ static int cpcap_adc_init_request(struct cpcap_adc_request *req, ...@@ -839,6 +852,22 @@ static int cpcap_adc_init_request(struct cpcap_adc_request *req,
return 0; return 0;
} }
static int cpcap_adc_read_st_die_temp(struct cpcap_adc *ddata,
int addr, int *val)
{
int error;
error = regmap_read(ddata->reg, addr, val);
if (error)
return error;
*val -= 282;
*val *= 114;
*val += 25000;
return 0;
}
static int cpcap_adc_read(struct iio_dev *indio_dev, static int cpcap_adc_read(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, struct iio_chan_spec const *chan,
int *val, int *val2, long mask) int *val, int *val2, long mask)
...@@ -858,6 +887,9 @@ static int cpcap_adc_read(struct iio_dev *indio_dev, ...@@ -858,6 +887,9 @@ static int cpcap_adc_read(struct iio_dev *indio_dev,
if (error) if (error)
goto err_unlock; goto err_unlock;
error = regmap_read(ddata->reg, chan->address, val); error = regmap_read(ddata->reg, chan->address, val);
if (error)
goto err_unlock;
error = cpcap_adc_stop_bank(ddata);
if (error) if (error)
goto err_unlock; goto err_unlock;
mutex_unlock(&ddata->lock); mutex_unlock(&ddata->lock);
...@@ -867,7 +899,19 @@ static int cpcap_adc_read(struct iio_dev *indio_dev, ...@@ -867,7 +899,19 @@ static int cpcap_adc_read(struct iio_dev *indio_dev,
error = cpcap_adc_start_bank(ddata, &req); error = cpcap_adc_start_bank(ddata, &req);
if (error) if (error)
goto err_unlock; goto err_unlock;
error = cpcap_adc_read_bank_scaled(ddata, &req); if ((ddata->vendor == CPCAP_VENDOR_ST) &&
(chan->channel == CPCAP_ADC_AD3)) {
error = cpcap_adc_read_st_die_temp(ddata,
chan->address,
&req.result);
if (error)
goto err_unlock;
} else {
error = cpcap_adc_read_bank_scaled(ddata, &req);
if (error)
goto err_unlock;
}
error = cpcap_adc_stop_bank(ddata);
if (error) if (error)
goto err_unlock; goto err_unlock;
mutex_unlock(&ddata->lock); mutex_unlock(&ddata->lock);
......
...@@ -105,6 +105,26 @@ static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val) ...@@ -105,6 +105,26 @@ static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val)
return spi_write(priv->spi, priv->reg_buffer, 3); return spi_write(priv->spi, priv->reg_buffer, 3);
} }
static int hi8435_read_raw(struct iio_dev *idev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct hi8435_priv *priv = iio_priv(idev);
u32 tmp;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
if (ret < 0)
return ret;
*val = !!(tmp & BIT(chan->channel));
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int hi8435_read_event_config(struct iio_dev *idev, static int hi8435_read_event_config(struct iio_dev *idev,
const struct iio_chan_spec *chan, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_type type,
...@@ -121,10 +141,21 @@ static int hi8435_write_event_config(struct iio_dev *idev, ...@@ -121,10 +141,21 @@ static int hi8435_write_event_config(struct iio_dev *idev,
enum iio_event_direction dir, int state) enum iio_event_direction dir, int state)
{ {
struct hi8435_priv *priv = iio_priv(idev); struct hi8435_priv *priv = iio_priv(idev);
int ret;
u32 tmp;
if (state) {
ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
if (ret < 0)
return ret;
if (tmp & BIT(chan->channel))
priv->event_prev_val |= BIT(chan->channel);
else
priv->event_prev_val &= ~BIT(chan->channel);
priv->event_scan_mask &= ~BIT(chan->channel);
if (state)
priv->event_scan_mask |= BIT(chan->channel); priv->event_scan_mask |= BIT(chan->channel);
} else
priv->event_scan_mask &= ~BIT(chan->channel);
return 0; return 0;
} }
...@@ -325,6 +356,7 @@ static const struct iio_enum hi8435_sensing_mode = { ...@@ -325,6 +356,7 @@ static const struct iio_enum hi8435_sensing_mode = {
static const struct iio_chan_spec_ext_info hi8435_ext_info[] = { static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode), IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode),
IIO_ENUM_AVAILABLE("sensing_mode", &hi8435_sensing_mode),
{}, {},
}; };
...@@ -333,6 +365,7 @@ static const struct iio_chan_spec_ext_info hi8435_ext_info[] = { ...@@ -333,6 +365,7 @@ static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.channel = num, \ .channel = num, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.event_spec = hi8435_events, \ .event_spec = hi8435_events, \
.num_event_specs = ARRAY_SIZE(hi8435_events), \ .num_event_specs = ARRAY_SIZE(hi8435_events), \
.ext_info = hi8435_ext_info, \ .ext_info = hi8435_ext_info, \
...@@ -376,11 +409,12 @@ static const struct iio_chan_spec hi8435_channels[] = { ...@@ -376,11 +409,12 @@ static const struct iio_chan_spec hi8435_channels[] = {
static const struct iio_info hi8435_info = { static const struct iio_info hi8435_info = {
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
.read_event_config = &hi8435_read_event_config, .read_raw = hi8435_read_raw,
.read_event_config = hi8435_read_event_config,
.write_event_config = hi8435_write_event_config, .write_event_config = hi8435_write_event_config,
.read_event_value = &hi8435_read_event_value, .read_event_value = hi8435_read_event_value,
.write_event_value = &hi8435_write_event_value, .write_event_value = hi8435_write_event_value,
.debugfs_reg_access = &hi8435_debugfs_reg_access, .debugfs_reg_access = hi8435_debugfs_reg_access,
}; };
static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val) static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val)
......
...@@ -42,13 +42,14 @@ ...@@ -42,13 +42,14 @@
#define INA2XX_CURRENT 0x04 /* readonly */ #define INA2XX_CURRENT 0x04 /* readonly */
#define INA2XX_CALIBRATION 0x05 #define INA2XX_CALIBRATION 0x05
#define INA226_ALERT_MASK GENMASK(2, 1) #define INA226_MASK_ENABLE 0x06
#define INA266_CVRF BIT(3) #define INA226_CVRF BIT(3)
#define INA2XX_MAX_REGISTERS 8 #define INA2XX_MAX_REGISTERS 8
/* settings - depend on use case */ /* settings - depend on use case */
#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
#define INA219_DEFAULT_IT 532
#define INA226_CONFIG_DEFAULT 0x4327 #define INA226_CONFIG_DEFAULT 0x4327
#define INA226_DEFAULT_AVG 4 #define INA226_DEFAULT_AVG 4
#define INA226_DEFAULT_IT 1110 #define INA226_DEFAULT_IT 1110
...@@ -56,19 +57,24 @@ ...@@ -56,19 +57,24 @@
#define INA2XX_RSHUNT_DEFAULT 10000 #define INA2XX_RSHUNT_DEFAULT 10000
/* /*
* bit mask for reading the averaging setting in the configuration register * bit masks for reading the settings in the configuration register
* FIXME: use regmap_fields. * FIXME: use regmap_fields.
*/ */
#define INA2XX_MODE_MASK GENMASK(3, 0) #define INA2XX_MODE_MASK GENMASK(3, 0)
/* Averaging for VBus/VShunt/Power */
#define INA226_AVG_MASK GENMASK(11, 9) #define INA226_AVG_MASK GENMASK(11, 9)
#define INA226_SHIFT_AVG(val) ((val) << 9) #define INA226_SHIFT_AVG(val) ((val) << 9)
/* Integration time for VBus */ /* Integration time for VBus */
#define INA219_ITB_MASK GENMASK(10, 7)
#define INA219_SHIFT_ITB(val) ((val) << 7)
#define INA226_ITB_MASK GENMASK(8, 6) #define INA226_ITB_MASK GENMASK(8, 6)
#define INA226_SHIFT_ITB(val) ((val) << 6) #define INA226_SHIFT_ITB(val) ((val) << 6)
/* Integration time for VShunt */ /* Integration time for VShunt */
#define INA219_ITS_MASK GENMASK(6, 3)
#define INA219_SHIFT_ITS(val) ((val) << 3)
#define INA226_ITS_MASK GENMASK(5, 3) #define INA226_ITS_MASK GENMASK(5, 3)
#define INA226_SHIFT_ITS(val) ((val) << 3) #define INA226_SHIFT_ITS(val) ((val) << 3)
...@@ -108,6 +114,7 @@ struct ina2xx_config { ...@@ -108,6 +114,7 @@ struct ina2xx_config {
int bus_voltage_shift; int bus_voltage_shift;
int bus_voltage_lsb; /* uV */ int bus_voltage_lsb; /* uV */
int power_lsb; /* uW */ int power_lsb; /* uW */
enum ina2xx_ids chip_id;
}; };
struct ina2xx_chip_info { struct ina2xx_chip_info {
...@@ -130,6 +137,7 @@ static const struct ina2xx_config ina2xx_config[] = { ...@@ -130,6 +137,7 @@ static const struct ina2xx_config ina2xx_config[] = {
.bus_voltage_shift = 3, .bus_voltage_shift = 3,
.bus_voltage_lsb = 4000, .bus_voltage_lsb = 4000,
.power_lsb = 20000, .power_lsb = 20000,
.chip_id = ina219,
}, },
[ina226] = { [ina226] = {
.config_default = INA226_CONFIG_DEFAULT, .config_default = INA226_CONFIG_DEFAULT,
...@@ -138,6 +146,7 @@ static const struct ina2xx_config ina2xx_config[] = { ...@@ -138,6 +146,7 @@ static const struct ina2xx_config ina2xx_config[] = {
.bus_voltage_shift = 0, .bus_voltage_shift = 0,
.bus_voltage_lsb = 1250, .bus_voltage_lsb = 1250,
.power_lsb = 25000, .power_lsb = 25000,
.chip_id = ina226,
}, },
}; };
...@@ -283,6 +292,66 @@ static int ina226_set_int_time_vshunt(struct ina2xx_chip_info *chip, ...@@ -283,6 +292,66 @@ static int ina226_set_int_time_vshunt(struct ina2xx_chip_info *chip,
return 0; return 0;
} }
/* Conversion times in uS. */
static const int ina219_conv_time_tab_subsample[] = { 84, 148, 276, 532 };
static const int ina219_conv_time_tab_average[] = { 532, 1060, 2130, 4260,
8510, 17020, 34050, 68100};
static int ina219_lookup_int_time(unsigned int *val_us, int *bits)
{
if (*val_us > 68100 || *val_us < 84)
return -EINVAL;
if (*val_us <= 532) {
*bits = find_closest(*val_us, ina219_conv_time_tab_subsample,
ARRAY_SIZE(ina219_conv_time_tab_subsample));
*val_us = ina219_conv_time_tab_subsample[*bits];
} else {
*bits = find_closest(*val_us, ina219_conv_time_tab_average,
ARRAY_SIZE(ina219_conv_time_tab_average));
*val_us = ina219_conv_time_tab_average[*bits];
*bits |= 0x8;
}
return 0;
}
static int ina219_set_int_time_vbus(struct ina2xx_chip_info *chip,
unsigned int val_us, unsigned int *config)
{
int bits, ret;
unsigned int val_us_best = val_us;
ret = ina219_lookup_int_time(&val_us_best, &bits);
if (ret)
return ret;
chip->int_time_vbus = val_us_best;
*config &= ~INA219_ITB_MASK;
*config |= INA219_SHIFT_ITB(bits) & INA219_ITB_MASK;
return 0;
}
static int ina219_set_int_time_vshunt(struct ina2xx_chip_info *chip,
unsigned int val_us, unsigned int *config)
{
int bits, ret;
unsigned int val_us_best = val_us;
ret = ina219_lookup_int_time(&val_us_best, &bits);
if (ret)
return ret;
chip->int_time_vshunt = val_us_best;
*config &= ~INA219_ITS_MASK;
*config |= INA219_SHIFT_ITS(bits) & INA219_ITS_MASK;
return 0;
}
static int ina2xx_write_raw(struct iio_dev *indio_dev, static int ina2xx_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, struct iio_chan_spec const *chan,
int val, int val2, long mask) int val, int val2, long mask)
...@@ -308,10 +377,21 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev, ...@@ -308,10 +377,21 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
break; break;
case IIO_CHAN_INFO_INT_TIME: case IIO_CHAN_INFO_INT_TIME:
if (chan->address == INA2XX_SHUNT_VOLTAGE) if (chip->config->chip_id == ina226) {
ret = ina226_set_int_time_vshunt(chip, val2, &tmp); if (chan->address == INA2XX_SHUNT_VOLTAGE)
else ret = ina226_set_int_time_vshunt(chip, val2,
ret = ina226_set_int_time_vbus(chip, val2, &tmp); &tmp);
else
ret = ina226_set_int_time_vbus(chip, val2,
&tmp);
} else {
if (chan->address == INA2XX_SHUNT_VOLTAGE)
ret = ina219_set_int_time_vshunt(chip, val2,
&tmp);
else
ret = ina219_set_int_time_vbus(chip, val2,
&tmp);
}
break; break;
default: default:
...@@ -412,13 +492,30 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, ...@@ -412,13 +492,30 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
return len; return len;
} }
#define INA2XX_CHAN(_type, _index, _address) { \ #define INA219_CHAN(_type, _index, _address) { \
.type = (_type), \
.address = (_address), \
.indexed = 1, \
.channel = (_index), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = (_index), \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_CPU, \
} \
}
#define INA226_CHAN(_type, _index, _address) { \
.type = (_type), \ .type = (_type), \
.address = (_address), \ .address = (_address), \
.indexed = 1, \ .indexed = 1, \
.channel = (_index), \ .channel = (_index), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
| BIT(IIO_CHAN_INFO_SCALE), \ BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.scan_index = (_index), \ .scan_index = (_index), \
...@@ -434,7 +531,25 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, ...@@ -434,7 +531,25 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
* Sampling Freq is a consequence of the integration times of * Sampling Freq is a consequence of the integration times of
* the Voltage channels. * the Voltage channels.
*/ */
#define INA2XX_CHAN_VOLTAGE(_index, _address) { \ #define INA219_CHAN_VOLTAGE(_index, _address) { \
.type = IIO_VOLTAGE, \
.address = (_address), \
.indexed = 1, \
.channel = (_index), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_INT_TIME), \
.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = (_index), \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE, \
} \
}
#define INA226_CHAN_VOLTAGE(_index, _address) { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.address = (_address), \ .address = (_address), \
.indexed = 1, \ .indexed = 1, \
...@@ -442,6 +557,8 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, ...@@ -442,6 +557,8 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_INT_TIME), \ BIT(IIO_CHAN_INFO_INT_TIME), \
.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.scan_index = (_index), \ .scan_index = (_index), \
.scan_type = { \ .scan_type = { \
.sign = 'u', \ .sign = 'u', \
...@@ -451,11 +568,20 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, ...@@ -451,11 +568,20 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
} \ } \
} }
static const struct iio_chan_spec ina2xx_channels[] = {
INA2XX_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE), static const struct iio_chan_spec ina226_channels[] = {
INA2XX_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE), INA226_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE),
INA2XX_CHAN(IIO_POWER, 2, INA2XX_POWER), INA226_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE),
INA2XX_CHAN(IIO_CURRENT, 3, INA2XX_CURRENT), INA226_CHAN(IIO_POWER, 2, INA2XX_POWER),
INA226_CHAN(IIO_CURRENT, 3, INA2XX_CURRENT),
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct iio_chan_spec ina219_channels[] = {
INA219_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE),
INA219_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE),
INA219_CHAN(IIO_POWER, 2, INA2XX_POWER),
INA219_CHAN(IIO_CURRENT, 3, INA2XX_CURRENT),
IIO_CHAN_SOFT_TIMESTAMP(4), IIO_CHAN_SOFT_TIMESTAMP(4),
}; };
...@@ -481,12 +607,12 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) ...@@ -481,12 +607,12 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
*/ */
if (!chip->allow_async_readout) if (!chip->allow_async_readout)
do { do {
ret = regmap_read(chip->regmap, INA226_ALERT_MASK, ret = regmap_read(chip->regmap, INA226_MASK_ENABLE,
&alert); &alert);
if (ret < 0) if (ret < 0)
return ret; return ret;
alert &= INA266_CVRF; alert &= INA226_CVRF;
} while (!alert); } while (!alert);
/* /*
...@@ -590,7 +716,14 @@ static int ina2xx_debug_reg(struct iio_dev *indio_dev, ...@@ -590,7 +716,14 @@ static int ina2xx_debug_reg(struct iio_dev *indio_dev,
} }
/* Possible integration times for vshunt and vbus */ /* Possible integration times for vshunt and vbus */
static IIO_CONST_ATTR_INT_TIME_AVAIL("0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244"); static IIO_CONST_ATTR_NAMED(ina219_integration_time_available,
integration_time_available,
"0.000084 0.000148 0.000276 0.000532 0.001060 0.002130 0.004260 0.008510 0.017020 0.034050 0.068100");
static IIO_CONST_ATTR_NAMED(ina226_integration_time_available,
integration_time_available,
"0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244");
static IIO_DEVICE_ATTR(in_allow_async_readout, S_IRUGO | S_IWUSR, static IIO_DEVICE_ATTR(in_allow_async_readout, S_IRUGO | S_IWUSR,
ina2xx_allow_async_readout_show, ina2xx_allow_async_readout_show,
...@@ -600,20 +733,39 @@ static IIO_DEVICE_ATTR(in_shunt_resistor, S_IRUGO | S_IWUSR, ...@@ -600,20 +733,39 @@ static IIO_DEVICE_ATTR(in_shunt_resistor, S_IRUGO | S_IWUSR,
ina2xx_shunt_resistor_show, ina2xx_shunt_resistor_show,
ina2xx_shunt_resistor_store, 0); ina2xx_shunt_resistor_store, 0);
static struct attribute *ina2xx_attributes[] = { static struct attribute *ina219_attributes[] = {
&iio_dev_attr_in_allow_async_readout.dev_attr.attr,
&iio_const_attr_ina219_integration_time_available.dev_attr.attr,
&iio_dev_attr_in_shunt_resistor.dev_attr.attr,
NULL,
};
static struct attribute *ina226_attributes[] = {
&iio_dev_attr_in_allow_async_readout.dev_attr.attr, &iio_dev_attr_in_allow_async_readout.dev_attr.attr,
&iio_const_attr_integration_time_available.dev_attr.attr, &iio_const_attr_ina226_integration_time_available.dev_attr.attr,
&iio_dev_attr_in_shunt_resistor.dev_attr.attr, &iio_dev_attr_in_shunt_resistor.dev_attr.attr,
NULL, NULL,
}; };
static const struct attribute_group ina2xx_attribute_group = { static const struct attribute_group ina219_attribute_group = {
.attrs = ina2xx_attributes, .attrs = ina219_attributes,
};
static const struct attribute_group ina226_attribute_group = {
.attrs = ina226_attributes,
}; };
static const struct iio_info ina2xx_info = { static const struct iio_info ina219_info = {
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
.attrs = &ina2xx_attribute_group, .attrs = &ina219_attribute_group,
.read_raw = ina2xx_read_raw,
.write_raw = ina2xx_write_raw,
.debugfs_reg_access = ina2xx_debug_reg,
};
static const struct iio_info ina226_info = {
.driver_module = THIS_MODULE,
.attrs = &ina226_attribute_group,
.read_raw = ina2xx_read_raw, .read_raw = ina2xx_read_raw,
.write_raw = ina2xx_write_raw, .write_raw = ina2xx_write_raw,
.debugfs_reg_access = ina2xx_debug_reg, .debugfs_reg_access = ina2xx_debug_reg,
...@@ -684,6 +836,10 @@ static int ina2xx_probe(struct i2c_client *client, ...@@ -684,6 +836,10 @@ static int ina2xx_probe(struct i2c_client *client,
ina226_set_average(chip, INA226_DEFAULT_AVG, &val); ina226_set_average(chip, INA226_DEFAULT_AVG, &val);
ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val); ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val);
ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val); ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val);
} else {
chip->avg = 1;
ina219_set_int_time_vbus(chip, INA219_DEFAULT_IT, &val);
ina219_set_int_time_vshunt(chip, INA219_DEFAULT_IT, &val);
} }
ret = ina2xx_init(chip, val); ret = ina2xx_init(chip, val);
...@@ -695,10 +851,16 @@ static int ina2xx_probe(struct i2c_client *client, ...@@ -695,10 +851,16 @@ static int ina2xx_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = &client->dev;
indio_dev->dev.of_node = client->dev.of_node; indio_dev->dev.of_node = client->dev.of_node;
indio_dev->channels = ina2xx_channels; if (id->driver_data == ina226) {
indio_dev->num_channels = ARRAY_SIZE(ina2xx_channels); indio_dev->channels = ina226_channels;
indio_dev->num_channels = ARRAY_SIZE(ina226_channels);
indio_dev->info = &ina226_info;
} else {
indio_dev->channels = ina219_channels;
indio_dev->num_channels = ARRAY_SIZE(ina219_channels);
indio_dev->info = &ina219_info;
}
indio_dev->name = id->name; indio_dev->name = id->name;
indio_dev->info = &ina2xx_info;
indio_dev->setup_ops = &ina2xx_setup_ops; indio_dev->setup_ops = &ina2xx_setup_ops;
buffer = devm_iio_kfifo_allocate(&indio_dev->dev); buffer = devm_iio_kfifo_allocate(&indio_dev->dev);
......
...@@ -76,10 +76,14 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, ...@@ -76,10 +76,14 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
long mask) long mask)
{ {
struct lpc32xx_adc_state *st = iio_priv(indio_dev); struct lpc32xx_adc_state *st = iio_priv(indio_dev);
int ret;
if (mask == IIO_CHAN_INFO_RAW) { if (mask == IIO_CHAN_INFO_RAW) {
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
clk_prepare_enable(st->clk); ret = clk_prepare_enable(st->clk);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
/* Measurement setup */ /* Measurement setup */
__raw_writel(LPC32XXAD_INTERNAL | (chan->address) | __raw_writel(LPC32XXAD_INTERNAL | (chan->address) |
LPC32XXAD_REFp | LPC32XXAD_REFm, LPC32XXAD_REFp | LPC32XXAD_REFm,
......
...@@ -220,6 +220,7 @@ enum meson_sar_adc_chan7_mux_sel { ...@@ -220,6 +220,7 @@ enum meson_sar_adc_chan7_mux_sel {
}; };
struct meson_sar_adc_data { struct meson_sar_adc_data {
bool has_bl30_integration;
unsigned int resolution; unsigned int resolution;
const char *name; const char *name;
}; };
...@@ -437,19 +438,24 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) ...@@ -437,19 +438,24 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
/* prevent BL30 from using the SAR ADC while we are using it */ if (priv->data->has_bl30_integration) {
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, /* prevent BL30 from using the SAR ADC while we are using it */
MESON_SAR_ADC_DELAY_KERNEL_BUSY, regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY); MESON_SAR_ADC_DELAY_KERNEL_BUSY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY);
/* wait until BL30 releases it's lock (so we can use the SAR ADC) */
do { /*
udelay(1); * wait until BL30 releases it's lock (so we can use the SAR
regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); * ADC)
} while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); */
do {
if (timeout < 0) udelay(1);
return -ETIMEDOUT; regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
} while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
if (timeout < 0)
return -ETIMEDOUT;
}
return 0; return 0;
} }
...@@ -458,9 +464,10 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) ...@@ -458,9 +464,10 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
{ {
struct meson_sar_adc_priv *priv = iio_priv(indio_dev); struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
/* allow BL30 to use the SAR ADC again */ if (priv->data->has_bl30_integration)
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, /* allow BL30 to use the SAR ADC again */
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
} }
...@@ -614,14 +621,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) ...@@ -614,14 +621,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
*/ */
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
/* if (priv->data->has_bl30_integration) {
* leave sampling delay and the input clocks as configured by BL30 to /*
* make sure BL30 gets the values it expects when reading the * leave sampling delay and the input clocks as configured by
* temperature sensor. * BL30 to make sure BL30 gets the values it expects when
*/ * reading the temperature sensor.
regmap_read(priv->regmap, MESON_SAR_ADC_REG3, &regval); */
if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED) regmap_read(priv->regmap, MESON_SAR_ADC_REG3, &regval);
return 0; if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED)
return 0;
}
meson_sar_adc_stop_sample_engine(indio_dev); meson_sar_adc_stop_sample_engine(indio_dev);
...@@ -834,22 +843,45 @@ static const struct iio_info meson_sar_adc_iio_info = { ...@@ -834,22 +843,45 @@ static const struct iio_info meson_sar_adc_iio_info = {
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
struct meson_sar_adc_data meson_sar_adc_gxbb_data = { static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
.has_bl30_integration = false,
.resolution = 10,
.name = "meson-meson8-saradc",
};
static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = {
.has_bl30_integration = false,
.resolution = 10,
.name = "meson-meson8b-saradc",
};
static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
.has_bl30_integration = true,
.resolution = 10, .resolution = 10,
.name = "meson-gxbb-saradc", .name = "meson-gxbb-saradc",
}; };
struct meson_sar_adc_data meson_sar_adc_gxl_data = { static const struct meson_sar_adc_data meson_sar_adc_gxl_data = {
.has_bl30_integration = true,
.resolution = 12, .resolution = 12,
.name = "meson-gxl-saradc", .name = "meson-gxl-saradc",
}; };
struct meson_sar_adc_data meson_sar_adc_gxm_data = { static const struct meson_sar_adc_data meson_sar_adc_gxm_data = {
.has_bl30_integration = true,
.resolution = 12, .resolution = 12,
.name = "meson-gxm-saradc", .name = "meson-gxm-saradc",
}; };
static const struct of_device_id meson_sar_adc_of_match[] = { static const struct of_device_id meson_sar_adc_of_match[] = {
{
.compatible = "amlogic,meson8-saradc",
.data = &meson_sar_adc_meson8_data,
},
{
.compatible = "amlogic,meson8b-saradc",
.data = &meson_sar_adc_meson8b_data,
},
{ {
.compatible = "amlogic,meson-gxbb-saradc", .compatible = "amlogic,meson-gxbb-saradc",
.data = &meson_sar_adc_gxbb_data, .data = &meson_sar_adc_gxbb_data,
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
#define VREF_MV_BASE 1850 #define VREF_MV_BASE 1850
const char *mx23_lradc_adc_irq_names[] = { static const char *mx23_lradc_adc_irq_names[] = {
"mxs-lradc-channel0", "mxs-lradc-channel0",
"mxs-lradc-channel1", "mxs-lradc-channel1",
"mxs-lradc-channel2", "mxs-lradc-channel2",
...@@ -57,7 +57,7 @@ const char *mx23_lradc_adc_irq_names[] = { ...@@ -57,7 +57,7 @@ const char *mx23_lradc_adc_irq_names[] = {
"mxs-lradc-channel5", "mxs-lradc-channel5",
}; };
const char *mx28_lradc_adc_irq_names[] = { static const char *mx28_lradc_adc_irq_names[] = {
"mxs-lradc-thresh0", "mxs-lradc-thresh0",
"mxs-lradc-thresh1", "mxs-lradc-thresh1",
"mxs-lradc-channel0", "mxs-lradc-channel0",
...@@ -344,20 +344,20 @@ static ssize_t mxs_lradc_adc_show_scale_avail(struct device *dev, ...@@ -344,20 +344,20 @@ static ssize_t mxs_lradc_adc_show_scale_avail(struct device *dev,
IIO_DEVICE_ATTR(in_voltage##ch##_scale_available, 0444,\ IIO_DEVICE_ATTR(in_voltage##ch##_scale_available, 0444,\
mxs_lradc_adc_show_scale_avail, NULL, ch) mxs_lradc_adc_show_scale_avail, NULL, ch)
SHOW_SCALE_AVAILABLE_ATTR(0); static SHOW_SCALE_AVAILABLE_ATTR(0);
SHOW_SCALE_AVAILABLE_ATTR(1); static SHOW_SCALE_AVAILABLE_ATTR(1);
SHOW_SCALE_AVAILABLE_ATTR(2); static SHOW_SCALE_AVAILABLE_ATTR(2);
SHOW_SCALE_AVAILABLE_ATTR(3); static SHOW_SCALE_AVAILABLE_ATTR(3);
SHOW_SCALE_AVAILABLE_ATTR(4); static SHOW_SCALE_AVAILABLE_ATTR(4);
SHOW_SCALE_AVAILABLE_ATTR(5); static SHOW_SCALE_AVAILABLE_ATTR(5);
SHOW_SCALE_AVAILABLE_ATTR(6); static SHOW_SCALE_AVAILABLE_ATTR(6);
SHOW_SCALE_AVAILABLE_ATTR(7); static SHOW_SCALE_AVAILABLE_ATTR(7);
SHOW_SCALE_AVAILABLE_ATTR(10); static SHOW_SCALE_AVAILABLE_ATTR(10);
SHOW_SCALE_AVAILABLE_ATTR(11); static SHOW_SCALE_AVAILABLE_ATTR(11);
SHOW_SCALE_AVAILABLE_ATTR(12); static SHOW_SCALE_AVAILABLE_ATTR(12);
SHOW_SCALE_AVAILABLE_ATTR(13); static SHOW_SCALE_AVAILABLE_ATTR(13);
SHOW_SCALE_AVAILABLE_ATTR(14); static SHOW_SCALE_AVAILABLE_ATTR(14);
SHOW_SCALE_AVAILABLE_ATTR(15); static SHOW_SCALE_AVAILABLE_ATTR(15);
static struct attribute *mxs_lradc_adc_attributes[] = { static struct attribute *mxs_lradc_adc_attributes[] = {
&iio_dev_attr_in_voltage0_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage0_scale_available.dev_attr.attr,
......
...@@ -73,7 +73,7 @@ enum rcar_gyroadc_model { ...@@ -73,7 +73,7 @@ enum rcar_gyroadc_model {
struct rcar_gyroadc { struct rcar_gyroadc {
struct device *dev; struct device *dev;
void __iomem *regs; void __iomem *regs;
struct clk *iclk; struct clk *clk;
struct regulator *vref[8]; struct regulator *vref[8];
unsigned int num_channels; unsigned int num_channels;
enum rcar_gyroadc_model model; enum rcar_gyroadc_model model;
...@@ -83,7 +83,7 @@ struct rcar_gyroadc { ...@@ -83,7 +83,7 @@ struct rcar_gyroadc {
static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv) static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv)
{ {
const unsigned long clk_mhz = clk_get_rate(priv->iclk) / 1000000; const unsigned long clk_mhz = clk_get_rate(priv->clk) / 1000000;
const unsigned long clk_mul = const unsigned long clk_mul =
(priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5; (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5;
unsigned long clk_len = clk_mhz * clk_mul; unsigned long clk_len = clk_mhz * clk_mul;
...@@ -510,9 +510,9 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) ...@@ -510,9 +510,9 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
if (IS_ERR(priv->regs)) if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs); return PTR_ERR(priv->regs);
priv->iclk = devm_clk_get(dev, "if"); priv->clk = devm_clk_get(dev, "fck");
if (IS_ERR(priv->iclk)) { if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->iclk); ret = PTR_ERR(priv->clk);
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret); dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret);
return ret; return ret;
...@@ -536,7 +536,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) ...@@ -536,7 +536,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
indio_dev->info = &rcar_gyroadc_iio_info; indio_dev->info = &rcar_gyroadc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = clk_prepare_enable(priv->iclk); ret = clk_prepare_enable(priv->clk);
if (ret) { if (ret) {
dev_err(dev, "Could not prepare or enable the IF clock.\n"); dev_err(dev, "Could not prepare or enable the IF clock.\n");
goto err_clk_if_enable; goto err_clk_if_enable;
...@@ -565,7 +565,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) ...@@ -565,7 +565,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
pm_runtime_disable(dev); pm_runtime_disable(dev);
pm_runtime_set_suspended(dev); pm_runtime_set_suspended(dev);
clk_disable_unprepare(priv->iclk); clk_disable_unprepare(priv->clk);
err_clk_if_enable: err_clk_if_enable:
rcar_gyroadc_deinit_supplies(indio_dev); rcar_gyroadc_deinit_supplies(indio_dev);
...@@ -584,7 +584,7 @@ static int rcar_gyroadc_remove(struct platform_device *pdev) ...@@ -584,7 +584,7 @@ static int rcar_gyroadc_remove(struct platform_device *pdev)
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
pm_runtime_disable(dev); pm_runtime_disable(dev);
pm_runtime_set_suspended(dev); pm_runtime_set_suspended(dev);
clk_disable_unprepare(priv->iclk); clk_disable_unprepare(priv->clk);
rcar_gyroadc_deinit_supplies(indio_dev); rcar_gyroadc_deinit_supplies(indio_dev);
return 0; return 0;
......
...@@ -49,19 +49,66 @@ ...@@ -49,19 +49,66 @@
/* STM32 F4 maximum analog clock rate (from datasheet) */ /* STM32 F4 maximum analog clock rate (from datasheet) */
#define STM32F4_ADC_MAX_CLK_RATE 36000000 #define STM32F4_ADC_MAX_CLK_RATE 36000000
/* STM32H7 - common registers for all ADC instances */
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
/* STM32H7_ADC_CSR - bit fields */
#define STM32H7_EOC_SLV BIT(18)
#define STM32H7_EOC_MST BIT(2)
/* STM32H7_ADC_CCR - bit fields */
#define STM32H7_PRESC_SHIFT 18
#define STM32H7_PRESC_MASK GENMASK(21, 18)
#define STM32H7_CKMODE_SHIFT 16
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
/* STM32 H7 maximum analog clock rate (from datasheet) */
#define STM32H7_ADC_MAX_CLK_RATE 72000000
/**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
* @csr: common status 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
*/
struct stm32_adc_common_regs {
u32 csr;
u32 eoc1_msk;
u32 eoc2_msk;
u32 eoc3_msk;
};
struct stm32_adc_priv;
/**
* stm32_adc_priv_cfg - stm32 core compatible configuration data
* @regs: common registers for all instances
* @clk_sel: clock selection routine
*/
struct stm32_adc_priv_cfg {
const struct stm32_adc_common_regs *regs;
int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
};
/** /**
* struct stm32_adc_priv - stm32 ADC core private data * struct stm32_adc_priv - stm32 ADC core private data
* @irq: irq for ADC block * @irq: irq for ADC block
* @domain: irq domain reference * @domain: irq domain reference
* @aclk: clock reference for the analog circuitry * @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used
* @vref: regulator reference * @vref: regulator reference
* @cfg: compatible configuration data
* @common: common data for all ADC instances * @common: common data for all ADC instances
*/ */
struct stm32_adc_priv { struct stm32_adc_priv {
int irq; int irq;
struct irq_domain *domain; struct irq_domain *domain;
struct clk *aclk; struct clk *aclk;
struct clk *bclk;
struct regulator *vref; struct regulator *vref;
const struct stm32_adc_priv_cfg *cfg;
struct stm32_adc_common common; struct stm32_adc_common common;
}; };
...@@ -85,14 +132,23 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, ...@@ -85,14 +132,23 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev,
u32 val; u32 val;
int i; int i;
/* stm32f4 has one clk input for analog (mandatory), enforce it here */
if (!priv->aclk) {
dev_err(&pdev->dev, "No 'adc' clock found\n");
return -ENOENT;
}
rate = clk_get_rate(priv->aclk); rate = clk_get_rate(priv->aclk);
for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) {
if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE) if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE)
break; break;
} }
if (i >= ARRAY_SIZE(stm32f4_pclk_div)) if (i >= ARRAY_SIZE(stm32f4_pclk_div)) {
dev_err(&pdev->dev, "adc clk selection failed\n");
return -EINVAL; return -EINVAL;
}
priv->common.rate = rate;
val = readl_relaxed(priv->common.base + STM32F4_ADC_CCR); val = readl_relaxed(priv->common.base + STM32F4_ADC_CCR);
val &= ~STM32F4_ADC_ADCPRE_MASK; val &= ~STM32F4_ADC_ADCPRE_MASK;
val |= i << STM32F4_ADC_ADCPRE_SHIFT; val |= i << STM32F4_ADC_ADCPRE_SHIFT;
...@@ -104,6 +160,126 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, ...@@ -104,6 +160,126 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev,
return 0; return 0;
} }
/**
* struct stm32h7_adc_ck_spec - specification for stm32h7 adc clock
* @ckmode: ADC clock mode, Async or sync with prescaler.
* @presc: prescaler bitfield for async clock mode
* @div: prescaler division ratio
*/
struct stm32h7_adc_ck_spec {
u32 ckmode;
u32 presc;
int div;
};
const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
/* 00: CK_ADC[1..3]: Asynchronous clock modes */
{ 0, 0, 1 },
{ 0, 1, 2 },
{ 0, 2, 4 },
{ 0, 3, 6 },
{ 0, 4, 8 },
{ 0, 5, 10 },
{ 0, 6, 12 },
{ 0, 7, 16 },
{ 0, 8, 32 },
{ 0, 9, 64 },
{ 0, 10, 128 },
{ 0, 11, 256 },
/* HCLK used: Synchronous clock modes (1, 2 or 4 prescaler) */
{ 1, 0, 1 },
{ 2, 0, 2 },
{ 3, 0, 4 },
};
static int stm32h7_adc_clk_sel(struct platform_device *pdev,
struct stm32_adc_priv *priv)
{
u32 ckmode, presc, val;
unsigned long rate;
int i, div;
/* stm32h7 bus clock is common for all ADC instances (mandatory) */
if (!priv->bclk) {
dev_err(&pdev->dev, "No 'bus' clock found\n");
return -ENOENT;
}
/*
* stm32h7 can use either 'bus' or 'adc' clock for analog circuitry.
* So, choice is to have bus clock mandatory and adc clock optional.
* If optional 'adc' clock has been found, then try to use it first.
*/
if (priv->aclk) {
/*
* Asynchronous clock modes (e.g. ckmode == 0)
* From spec: PLL output musn't exceed max rate
*/
rate = clk_get_rate(priv->aclk);
for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
presc = stm32h7_adc_ckmodes_spec[i].presc;
div = stm32h7_adc_ckmodes_spec[i].div;
if (ckmode)
continue;
if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
goto out;
}
}
/* Synchronous clock modes (e.g. ckmode is 1, 2 or 3) */
rate = clk_get_rate(priv->bclk);
for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
presc = stm32h7_adc_ckmodes_spec[i].presc;
div = stm32h7_adc_ckmodes_spec[i].div;
if (!ckmode)
continue;
if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
goto out;
}
dev_err(&pdev->dev, "adc clk selection failed\n");
return -EINVAL;
out:
/* rate used later by each ADC instance to control BOOST mode */
priv->common.rate = rate;
/* Set common clock mode and prescaler */
val = readl_relaxed(priv->common.base + STM32H7_ADC_CCR);
val &= ~(STM32H7_CKMODE_MASK | STM32H7_PRESC_MASK);
val |= ckmode << STM32H7_CKMODE_SHIFT;
val |= presc << STM32H7_PRESC_SHIFT;
writel_relaxed(val, priv->common.base + STM32H7_ADC_CCR);
dev_dbg(&pdev->dev, "Using %s clock/%d source at %ld kHz\n",
ckmode ? "bus" : "adc", div, rate / (div * 1000));
return 0;
}
/* STM32F4 common registers definitions */
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.eoc1_msk = STM32F4_EOC1,
.eoc2_msk = STM32F4_EOC2,
.eoc3_msk = STM32F4_EOC3,
};
/* STM32H7 common registers definitions */
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.eoc1_msk = STM32H7_EOC_MST,
.eoc2_msk = STM32H7_EOC_SLV,
};
/* ADC common interrupt for all instances */ /* ADC common interrupt for all instances */
static void stm32_adc_irq_handler(struct irq_desc *desc) static void stm32_adc_irq_handler(struct irq_desc *desc)
{ {
...@@ -112,15 +288,15 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) ...@@ -112,15 +288,15 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
u32 status; u32 status;
chained_irq_enter(chip, desc); chained_irq_enter(chip, desc);
status = readl_relaxed(priv->common.base + STM32F4_ADC_CSR); status = readl_relaxed(priv->common.base + priv->cfg->regs->csr);
if (status & STM32F4_EOC1) if (status & priv->cfg->regs->eoc1_msk)
generic_handle_irq(irq_find_mapping(priv->domain, 0)); generic_handle_irq(irq_find_mapping(priv->domain, 0));
if (status & STM32F4_EOC2) if (status & priv->cfg->regs->eoc2_msk)
generic_handle_irq(irq_find_mapping(priv->domain, 1)); generic_handle_irq(irq_find_mapping(priv->domain, 1));
if (status & STM32F4_EOC3) if (status & priv->cfg->regs->eoc3_msk)
generic_handle_irq(irq_find_mapping(priv->domain, 2)); generic_handle_irq(irq_find_mapping(priv->domain, 2));
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);
...@@ -186,6 +362,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, ...@@ -186,6 +362,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
static int stm32_adc_probe(struct platform_device *pdev) static int stm32_adc_probe(struct platform_device *pdev)
{ {
struct stm32_adc_priv *priv; struct stm32_adc_priv *priv;
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct resource *res; struct resource *res;
int ret; int ret;
...@@ -197,6 +374,9 @@ static int stm32_adc_probe(struct platform_device *pdev) ...@@ -197,6 +374,9 @@ static int stm32_adc_probe(struct platform_device *pdev)
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
priv->cfg = (const struct stm32_adc_priv_cfg *)
of_match_device(dev->driver->of_match_table, dev)->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->common.base = devm_ioremap_resource(&pdev->dev, res); priv->common.base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->common.base)) if (IS_ERR(priv->common.base))
...@@ -227,25 +407,48 @@ static int stm32_adc_probe(struct platform_device *pdev) ...@@ -227,25 +407,48 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->aclk = devm_clk_get(&pdev->dev, "adc"); priv->aclk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(priv->aclk)) { if (IS_ERR(priv->aclk)) {
ret = PTR_ERR(priv->aclk); ret = PTR_ERR(priv->aclk);
dev_err(&pdev->dev, "Can't get 'adc' clock\n"); if (ret == -ENOENT) {
goto err_regulator_disable; priv->aclk = NULL;
} else {
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
goto err_regulator_disable;
}
} }
ret = clk_prepare_enable(priv->aclk); if (priv->aclk) {
if (ret < 0) { ret = clk_prepare_enable(priv->aclk);
dev_err(&pdev->dev, "adc clk enable failed\n"); if (ret < 0) {
goto err_regulator_disable; dev_err(&pdev->dev, "adc clk enable failed\n");
goto err_regulator_disable;
}
} }
ret = stm32f4_adc_clk_sel(pdev, priv); priv->bclk = devm_clk_get(&pdev->dev, "bus");
if (ret < 0) { if (IS_ERR(priv->bclk)) {
dev_err(&pdev->dev, "adc clk selection failed\n"); ret = PTR_ERR(priv->bclk);
goto err_clk_disable; if (ret == -ENOENT) {
priv->bclk = NULL;
} else {
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
goto err_aclk_disable;
}
}
if (priv->bclk) {
ret = clk_prepare_enable(priv->bclk);
if (ret < 0) {
dev_err(&pdev->dev, "adc clk enable failed\n");
goto err_aclk_disable;
}
} }
ret = priv->cfg->clk_sel(pdev, priv);
if (ret < 0)
goto err_bclk_disable;
ret = stm32_adc_irq_probe(pdev, priv); ret = stm32_adc_irq_probe(pdev, priv);
if (ret < 0) if (ret < 0)
goto err_clk_disable; goto err_bclk_disable;
platform_set_drvdata(pdev, &priv->common); platform_set_drvdata(pdev, &priv->common);
...@@ -260,8 +463,13 @@ static int stm32_adc_probe(struct platform_device *pdev) ...@@ -260,8 +463,13 @@ static int stm32_adc_probe(struct platform_device *pdev)
err_irq_remove: err_irq_remove:
stm32_adc_irq_remove(pdev, priv); stm32_adc_irq_remove(pdev, priv);
err_clk_disable: err_bclk_disable:
clk_disable_unprepare(priv->aclk); if (priv->bclk)
clk_disable_unprepare(priv->bclk);
err_aclk_disable:
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
err_regulator_disable: err_regulator_disable:
regulator_disable(priv->vref); regulator_disable(priv->vref);
...@@ -276,15 +484,34 @@ static int stm32_adc_remove(struct platform_device *pdev) ...@@ -276,15 +484,34 @@ static int stm32_adc_remove(struct platform_device *pdev)
of_platform_depopulate(&pdev->dev); of_platform_depopulate(&pdev->dev);
stm32_adc_irq_remove(pdev, priv); stm32_adc_irq_remove(pdev, priv);
clk_disable_unprepare(priv->aclk); if (priv->bclk)
clk_disable_unprepare(priv->bclk);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
regulator_disable(priv->vref); regulator_disable(priv->vref);
return 0; return 0;
} }
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
.regs = &stm32f4_adc_common_regs,
.clk_sel = stm32f4_adc_clk_sel,
};
static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
.regs = &stm32h7_adc_common_regs,
.clk_sel = stm32h7_adc_clk_sel,
};
static const struct of_device_id stm32_adc_of_match[] = { static const struct of_device_id stm32_adc_of_match[] = {
{ .compatible = "st,stm32f4-adc-core" }, {
{}, .compatible = "st,stm32f4-adc-core",
.data = (void *)&stm32f4_adc_priv_cfg
}, {
.compatible = "st,stm32h7-adc-core",
.data = (void *)&stm32h7_adc_priv_cfg
}, {
},
}; };
MODULE_DEVICE_TABLE(of, stm32_adc_of_match); MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
......
...@@ -43,11 +43,13 @@ ...@@ -43,11 +43,13 @@
* struct stm32_adc_common - stm32 ADC driver common data (for all instances) * struct stm32_adc_common - stm32 ADC driver common data (for all instances)
* @base: control registers base cpu addr * @base: control registers base cpu addr
* @phys_base: control registers base physical addr * @phys_base: control registers base physical addr
* @rate: clock rate used for analog circuitry
* @vref_mv: vref voltage (mv) * @vref_mv: vref voltage (mv)
*/ */
struct stm32_adc_common { struct stm32_adc_common {
void __iomem *base; void __iomem *base;
phys_addr_t phys_base; phys_addr_t phys_base;
unsigned long rate;
int vref_mv; int vref_mv;
}; };
......
此差异已折叠。
/**
* Copyright (C) 2017 Axis Communications AB
*
* Driver for Texas Instruments' ADC084S021 ADC chip.
* Datasheets can be found here:
* http://www.ti.com/lit/ds/symlink/adc084s021.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/regulator/consumer.h>
#define ADC084S021_DRIVER_NAME "adc084s021"
struct adc084s021 {
struct spi_device *spi;
struct spi_message message;
struct spi_transfer spi_trans;
struct regulator *reg;
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache line.
*/
u16 tx_buf[4] ____cacheline_aligned;
__be16 rx_buf[5]; /* First 16-bits are trash */
};
#define ADC084S021_VOLTAGE_CHANNEL(num) \
{ \
.type = IIO_VOLTAGE, \
.channel = (num), \
.indexed = 1, \
.scan_index = (num), \
.scan_type = { \
.sign = 'u', \
.realbits = 8, \
.storagebits = 16, \
.shift = 4, \
.endianness = IIO_BE, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
}
static const struct iio_chan_spec adc084s021_channels[] = {
ADC084S021_VOLTAGE_CHANNEL(0),
ADC084S021_VOLTAGE_CHANNEL(1),
ADC084S021_VOLTAGE_CHANNEL(2),
ADC084S021_VOLTAGE_CHANNEL(3),
IIO_CHAN_SOFT_TIMESTAMP(4),
};
/**
* Read an ADC channel and return its value.
*
* @adc: The ADC SPI data.
* @data: Buffer for converted data.
*/
static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data)
{
int n_words = (adc->spi_trans.len >> 1) - 1; /* Discard first word */
int ret, i = 0;
u16 *p = data;
/* Do the transfer */
ret = spi_sync(adc->spi, &adc->message);
if (ret < 0)
return ret;
for (; i < n_words; i++)
*(p + i) = adc->rx_buf[i + 1];
return ret;
}
static int adc084s021_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct adc084s021 *adc = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret < 0)
return ret;
ret = regulator_enable(adc->reg);
if (ret) {
iio_device_release_direct_mode(indio_dev);
return ret;
}
adc->tx_buf[0] = channel->channel << 3;
ret = adc084s021_adc_conversion(adc, val);
iio_device_release_direct_mode(indio_dev);
regulator_disable(adc->reg);
if (ret < 0)
return ret;
*val = be16_to_cpu(*val);
*val = (*val >> channel->scan_type.shift) & 0xff;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_enable(adc->reg);
if (ret)
return ret;
ret = regulator_get_voltage(adc->reg);
regulator_disable(adc->reg);
if (ret < 0)
return ret;
*val = ret / 1000;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
/**
* Read enabled ADC channels and push data to the buffer.
*
* @irq: The interrupt number (not used).
* @pollfunc: Pointer to the poll func.
*/
static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc)
{
struct iio_poll_func *pf = pollfunc;
struct iio_dev *indio_dev = pf->indio_dev;
struct adc084s021 *adc = iio_priv(indio_dev);
__be16 data[8] = {0}; /* 4 * 16-bit words of data + 8 bytes timestamp */
mutex_lock(&adc->lock);
if (adc084s021_adc_conversion(adc, &data) < 0)
dev_err(&adc->spi->dev, "Failed to read data\n");
iio_push_to_buffers_with_timestamp(indio_dev, data,
iio_get_time_ns(indio_dev));
mutex_unlock(&adc->lock);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int adc084s021_buffer_preenable(struct iio_dev *indio_dev)
{
struct adc084s021 *adc = iio_priv(indio_dev);
int scan_index;
int i = 0;
for_each_set_bit(scan_index, indio_dev->active_scan_mask,
indio_dev->masklength) {
const struct iio_chan_spec *channel =
&indio_dev->channels[scan_index];
adc->tx_buf[i++] = channel->channel << 3;
}
adc->spi_trans.len = 2 + (i * sizeof(__be16)); /* Trash + channels */
return regulator_enable(adc->reg);
}
static int adc084s021_buffer_postdisable(struct iio_dev *indio_dev)
{
struct adc084s021 *adc = iio_priv(indio_dev);
adc->spi_trans.len = 4; /* Trash + single channel */
return regulator_disable(adc->reg);
}
static const struct iio_info adc084s021_info = {
.read_raw = adc084s021_read_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_buffer_setup_ops adc084s021_buffer_setup_ops = {
.preenable = adc084s021_buffer_preenable,
.postenable = iio_triggered_buffer_postenable,
.predisable = iio_triggered_buffer_predisable,
.postdisable = adc084s021_buffer_postdisable,
};
static int adc084s021_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adc084s021 *adc;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev) {
dev_err(&spi->dev, "Failed to allocate IIO device\n");
return -ENOMEM;
}
adc = iio_priv(indio_dev);
adc->spi = spi;
/* Connect the SPI device and the iio dev */
spi_set_drvdata(spi, indio_dev);
/* Initiate the Industrial I/O device */
indio_dev->dev.parent = &spi->dev;
indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &adc084s021_info;
indio_dev->channels = adc084s021_channels;
indio_dev->num_channels = ARRAY_SIZE(adc084s021_channels);
/* Create SPI transfer for channel reads */
adc->spi_trans.tx_buf = adc->tx_buf;
adc->spi_trans.rx_buf = adc->rx_buf;
adc->spi_trans.len = 4; /* Trash + single channel */
spi_message_init_with_transfers(&adc->message, &adc->spi_trans, 1);
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
mutex_init(&adc->lock);
/* Setup triggered buffer with pollfunction */
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
adc084s021_buffer_trigger_handler,
&adc084s021_buffer_setup_ops);
if (ret) {
dev_err(&spi->dev, "Failed to setup triggered buffer\n");
return ret;
}
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id adc084s021_of_match[] = {
{ .compatible = "ti,adc084s021", },
{},
};
MODULE_DEVICE_TABLE(of, adc084s021_of_match);
static const struct spi_device_id adc084s021_id[] = {
{ ADC084S021_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(spi, adc084s021_id);
static struct spi_driver adc084s021_driver = {
.driver = {
.name = ADC084S021_DRIVER_NAME,
.of_match_table = of_match_ptr(adc084s021_of_match),
},
.probe = adc084s021_probe,
.id_table = adc084s021_id,
};
module_spi_driver(adc084s021_driver);
MODULE_AUTHOR("Mårten Lindahl <martenli@axis.com>");
MODULE_DESCRIPTION("Texas Instruments ADC084S021");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");
/*
* TI ADC108S102 SPI ADC driver
*
* Copyright (c) 2013-2015 Intel Corporation.
* Copyright (c) 2017 Siemens AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* This IIO device driver is designed to work with the following
* analog to digital converters from Texas Instruments:
* ADC108S102
* ADC128S102
* The communication with ADC chip is via the SPI bus (mode 3).
*/
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/types.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
/*
* In case of ACPI, we use the hard-wired 5000 mV of the Galileo and IOT2000
* boards as default for the reference pin VA. Device tree users encode that
* via the vref-supply regulator.
*/
#define ADC108S102_VA_MV_ACPI_DEFAULT 5000
/*
* Defining the ADC resolution being 12 bits, we can use the same driver for
* both ADC108S102 (10 bits resolution) and ADC128S102 (12 bits resolution)
* chips. The ADC108S102 effectively returns a 12-bit result with the 2
* least-significant bits unset.
*/
#define ADC108S102_BITS 12
#define ADC108S102_MAX_CHANNELS 8
/*
* 16-bit SPI command format:
* [15:14] Ignored
* [13:11] 3-bit channel address
* [10:0] Ignored
*/
#define ADC108S102_CMD(ch) ((u16)(ch) << 11)
/*
* 16-bit SPI response format:
* [15:12] Zeros
* [11:0] 12-bit ADC sample (for ADC108S102, [1:0] will always be 0).
*/
#define ADC108S102_RES_DATA(res) ((u16)res & GENMASK(11, 0))
struct adc108s102_state {
struct spi_device *spi;
struct regulator *reg;
u32 va_millivolt;
/* SPI transfer used by triggered buffer handler*/
struct spi_transfer ring_xfer;
/* SPI transfer used by direct scan */
struct spi_transfer scan_single_xfer;
/* SPI message used by ring_xfer SPI transfer */
struct spi_message ring_msg;
/* SPI message used by scan_single_xfer SPI transfer */
struct spi_message scan_single_msg;
/*
* SPI message buffers:
* tx_buf: |C0|C1|C2|C3|C4|C5|C6|C7|XX|
* rx_buf: |XX|R0|R1|R2|R3|R4|R5|R6|R7|tt|tt|tt|tt|
*
* tx_buf: 8 channel read commands, plus 1 dummy command
* rx_buf: 1 dummy response, 8 channel responses, plus 64-bit timestamp
*/
__be16 rx_buf[13] ____cacheline_aligned;
__be16 tx_buf[9] ____cacheline_aligned;
};
#define ADC108S102_V_CHAN(index) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = ADC108S102_BITS, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec adc108s102_channels[] = {
ADC108S102_V_CHAN(0),
ADC108S102_V_CHAN(1),
ADC108S102_V_CHAN(2),
ADC108S102_V_CHAN(3),
ADC108S102_V_CHAN(4),
ADC108S102_V_CHAN(5),
ADC108S102_V_CHAN(6),
ADC108S102_V_CHAN(7),
IIO_CHAN_SOFT_TIMESTAMP(8),
};
static int adc108s102_update_scan_mode(struct iio_dev *indio_dev,
unsigned long const *active_scan_mask)
{
struct adc108s102_state *st = iio_priv(indio_dev);
unsigned int bit, cmds;
/*
* Fill in the first x shorts of tx_buf with the number of channels
* enabled for sampling by the triggered buffer.
*/
cmds = 0;
for_each_set_bit(bit, active_scan_mask, ADC108S102_MAX_CHANNELS)
st->tx_buf[cmds++] = cpu_to_be16(ADC108S102_CMD(bit));
/* One dummy command added, to clock in the last response */
st->tx_buf[cmds++] = 0x00;
/* build SPI ring message */
st->ring_xfer.tx_buf = &st->tx_buf[0];
st->ring_xfer.rx_buf = &st->rx_buf[0];
st->ring_xfer.len = cmds * sizeof(st->tx_buf[0]);
spi_message_init_with_transfers(&st->ring_msg, &st->ring_xfer, 1);
return 0;
}
static irqreturn_t adc108s102_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adc108s102_state *st = iio_priv(indio_dev);
int ret;
ret = spi_sync(st->spi, &st->ring_msg);
if (ret < 0)
goto out_notify;
/* Skip the dummy response in the first slot */
iio_push_to_buffers_with_timestamp(indio_dev,
(u8 *)&st->rx_buf[1],
iio_get_time_ns(indio_dev));
out_notify:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int adc108s102_scan_direct(struct adc108s102_state *st, unsigned int ch)
{
int ret;
st->tx_buf[0] = cpu_to_be16(ADC108S102_CMD(ch));
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
return ret;
/* Skip the dummy response in the first slot */
return be16_to_cpu(st->rx_buf[1]);
}
static int adc108s102_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long m)
{
struct adc108s102_state *st = iio_priv(indio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = adc108s102_scan_direct(st, chan->address);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = ADC108S102_RES_DATA(ret);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (chan->type != IIO_VOLTAGE)
break;
*val = st->va_millivolt;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static const struct iio_info adc108s102_info = {
.read_raw = &adc108s102_read_raw,
.update_scan_mode = &adc108s102_update_scan_mode,
.driver_module = THIS_MODULE,
};
static int adc108s102_probe(struct spi_device *spi)
{
struct adc108s102_state *st;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
if (ACPI_COMPANION(&spi->dev)) {
st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT;
} else {
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret < 0) {
dev_err(&spi->dev, "Cannot enable vref regulator\n");
return ret;
}
ret = regulator_get_voltage(st->reg);
if (ret < 0) {
dev_err(&spi->dev, "vref get voltage failed\n");
return ret;
}
st->va_millivolt = ret / 1000;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->name = spi->modalias;
indio_dev->dev.parent = &spi->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adc108s102_channels;
indio_dev->num_channels = ARRAY_SIZE(adc108s102_channels);
indio_dev->info = &adc108s102_info;
/* Setup default message */
st->scan_single_xfer.tx_buf = st->tx_buf;
st->scan_single_xfer.rx_buf = st->rx_buf;
st->scan_single_xfer.len = 2 * sizeof(st->tx_buf[0]);
spi_message_init_with_transfers(&st->scan_single_msg,
&st->scan_single_xfer, 1);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&adc108s102_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register IIO device\n");
goto error_cleanup_triggered_buffer;
}
return 0;
error_cleanup_triggered_buffer:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int adc108s102_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adc108s102_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id adc108s102_of_match[] = {
{ .compatible = "ti,adc108s102" },
{ }
};
MODULE_DEVICE_TABLE(of, adc108s102_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id adc108s102_acpi_ids[] = {
{ "INT3495", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids);
#endif
static const struct spi_device_id adc108s102_id[] = {
{ "adc108s102", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, adc108s102_id);
static struct spi_driver adc108s102_driver = {
.driver = {
.name = "adc108s102",
.of_match_table = of_match_ptr(adc108s102_of_match),
.acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
},
.probe = adc108s102_probe,
.remove = adc108s102_remove,
.id_table = adc108s102_id,
};
module_spi_driver(adc108s102_driver);
MODULE_AUTHOR("Bogdan Pricop <bogdan.pricop@emutex.com>");
MODULE_DESCRIPTION("Texas Instruments ADC108S102 and ADC128S102 driver");
MODULE_LICENSE("GPL v2");
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c/twl.h> #include <linux/i2c/twl.h>
#include <linux/i2c/twl4030-madc.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/mutex.h> #include <linux/mutex.h>
...@@ -49,9 +48,121 @@ ...@@ -49,9 +48,121 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#define TWL4030_MADC_MAX_CHANNELS 16
#define TWL4030_MADC_CTRL1 0x00
#define TWL4030_MADC_CTRL2 0x01
#define TWL4030_MADC_RTSELECT_LSB 0x02
#define TWL4030_MADC_SW1SELECT_LSB 0x06
#define TWL4030_MADC_SW2SELECT_LSB 0x0A
#define TWL4030_MADC_RTAVERAGE_LSB 0x04
#define TWL4030_MADC_SW1AVERAGE_LSB 0x08
#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C
#define TWL4030_MADC_CTRL_SW1 0x12
#define TWL4030_MADC_CTRL_SW2 0x13
#define TWL4030_MADC_RTCH0_LSB 0x17
#define TWL4030_MADC_GPCH0_LSB 0x37
#define TWL4030_MADC_MADCON (1 << 0) /* MADC power on */
#define TWL4030_MADC_BUSY (1 << 0) /* MADC busy */
/* MADC conversion completion */
#define TWL4030_MADC_EOC_SW (1 << 1)
/* MADC SWx start conversion */
#define TWL4030_MADC_SW_START (1 << 5)
#define TWL4030_MADC_ADCIN0 (1 << 0)
#define TWL4030_MADC_ADCIN1 (1 << 1)
#define TWL4030_MADC_ADCIN2 (1 << 2)
#define TWL4030_MADC_ADCIN3 (1 << 3)
#define TWL4030_MADC_ADCIN4 (1 << 4)
#define TWL4030_MADC_ADCIN5 (1 << 5)
#define TWL4030_MADC_ADCIN6 (1 << 6)
#define TWL4030_MADC_ADCIN7 (1 << 7)
#define TWL4030_MADC_ADCIN8 (1 << 8)
#define TWL4030_MADC_ADCIN9 (1 << 9)
#define TWL4030_MADC_ADCIN10 (1 << 10)
#define TWL4030_MADC_ADCIN11 (1 << 11)
#define TWL4030_MADC_ADCIN12 (1 << 12)
#define TWL4030_MADC_ADCIN13 (1 << 13)
#define TWL4030_MADC_ADCIN14 (1 << 14)
#define TWL4030_MADC_ADCIN15 (1 << 15)
/* Fixed channels */
#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1
#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8
#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9
#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10
#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11
#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12
/* Step size and prescaler ratio */
#define TEMP_STEP_SIZE 147
#define TEMP_PSR_R 100
#define CURR_STEP_SIZE 147
#define CURR_PSR_R1 44
#define CURR_PSR_R2 88
#define TWL4030_BCI_BCICTL1 0x23
#define TWL4030_BCI_CGAIN 0x020
#define TWL4030_BCI_MESBAT (1 << 1)
#define TWL4030_BCI_TYPEN (1 << 4)
#define TWL4030_BCI_ITHEN (1 << 3)
#define REG_BCICTL2 0x024
#define TWL4030_BCI_ITHSENS 0x007
/* Register and bits for GPBR1 register */
#define TWL4030_REG_GPBR1 0x0c
#define TWL4030_GPBR1_MADC_HFCLK_EN (1 << 7)
#define TWL4030_USB_SEL_MADC_MCPC (1<<3) #define TWL4030_USB_SEL_MADC_MCPC (1<<3)
#define TWL4030_USB_CARKIT_ANA_CTRL 0xBB #define TWL4030_USB_CARKIT_ANA_CTRL 0xBB
struct twl4030_madc_conversion_method {
u8 sel;
u8 avg;
u8 rbase;
u8 ctrl;
};
/**
* struct twl4030_madc_request - madc request packet for channel conversion
* @channels: 16 bit bitmap for individual channels
* @do_avg: sample the input channel for 4 consecutive cycles
* @method: RT, SW1, SW2
* @type: Polling or interrupt based method
* @active: Flag if request is active
* @result_pending: Flag from irq handler, that result is ready
* @raw: Return raw value, do not convert it
* @rbuf: Result buffer
*/
struct twl4030_madc_request {
unsigned long channels;
bool do_avg;
u16 method;
u16 type;
bool active;
bool result_pending;
bool raw;
int rbuf[TWL4030_MADC_MAX_CHANNELS];
};
enum conversion_methods {
TWL4030_MADC_RT,
TWL4030_MADC_SW1,
TWL4030_MADC_SW2,
TWL4030_MADC_NUM_METHODS
};
enum sample_type {
TWL4030_MADC_WAIT,
TWL4030_MADC_IRQ_ONESHOT,
TWL4030_MADC_IRQ_REARM
};
/** /**
* struct twl4030_madc_data - a container for madc info * struct twl4030_madc_data - a container for madc info
* @dev: Pointer to device structure for madc * @dev: Pointer to device structure for madc
...@@ -72,6 +183,8 @@ struct twl4030_madc_data { ...@@ -72,6 +183,8 @@ struct twl4030_madc_data {
u8 isr; u8 isr;
}; };
static int twl4030_madc_conversion(struct twl4030_madc_request *req);
static int twl4030_madc_read(struct iio_dev *iio_dev, static int twl4030_madc_read(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan, const struct iio_chan_spec *chan,
int *val, int *val2, long mask) int *val, int *val2, long mask)
...@@ -84,7 +197,6 @@ static int twl4030_madc_read(struct iio_dev *iio_dev, ...@@ -84,7 +197,6 @@ static int twl4030_madc_read(struct iio_dev *iio_dev,
req.channels = BIT(chan->channel); req.channels = BIT(chan->channel);
req.active = false; req.active = false;
req.func_cb = NULL;
req.type = TWL4030_MADC_WAIT; req.type = TWL4030_MADC_WAIT;
req.raw = !(mask == IIO_CHAN_INFO_PROCESSED); req.raw = !(mask == IIO_CHAN_INFO_PROCESSED);
req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW); req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW);
...@@ -340,37 +452,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, ...@@ -340,37 +452,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
return count; return count;
} }
/*
* Enables irq.
* @madc - pointer to twl4030_madc_data struct
* @id - irq number to be enabled
* can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
* corresponding to RT, SW1, SW2 conversion requests.
* If the i2c read fails it returns an error else returns 0.
*/
static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
{
u8 val;
int ret;
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
if (ret) {
dev_err(madc->dev, "unable to read imr register 0x%X\n",
madc->imr);
return ret;
}
val &= ~(1 << id);
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
if (ret) {
dev_err(madc->dev,
"unable to write imr register 0x%X\n", madc->imr);
return ret;
}
return 0;
}
/* /*
* Disables irq. * Disables irq.
* @madc - pointer to twl4030_madc_data struct * @madc - pointer to twl4030_madc_data struct
...@@ -440,11 +521,6 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) ...@@ -440,11 +521,6 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
/* Read results */ /* Read results */
len = twl4030_madc_read_channels(madc, method->rbase, len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw); r->channels, r->rbuf, r->raw);
/* Return results to caller */
if (r->func_cb != NULL) {
r->func_cb(len, r->channels, r->rbuf);
r->func_cb = NULL;
}
/* Free request */ /* Free request */
r->result_pending = 0; r->result_pending = 0;
r->active = 0; r->active = 0;
...@@ -466,11 +542,6 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) ...@@ -466,11 +542,6 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
/* Read results */ /* Read results */
len = twl4030_madc_read_channels(madc, method->rbase, len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw); r->channels, r->rbuf, r->raw);
/* Return results to caller */
if (r->func_cb != NULL) {
r->func_cb(len, r->channels, r->rbuf);
r->func_cb = NULL;
}
/* Free request */ /* Free request */
r->result_pending = 0; r->result_pending = 0;
r->active = 0; r->active = 0;
...@@ -480,23 +551,6 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) ...@@ -480,23 +551,6 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
struct twl4030_madc_request *req)
{
struct twl4030_madc_request *p;
int ret;
p = &madc->requests[req->method];
memcpy(p, req, sizeof(*req));
ret = twl4030_madc_enable_irq(madc, req->method);
if (ret < 0) {
dev_err(madc->dev, "enable irq failed!!\n");
return ret;
}
return 0;
}
/* /*
* Function which enables the madc conversion * Function which enables the madc conversion
* by writing to the control register. * by writing to the control register.
...@@ -568,7 +622,7 @@ static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc, ...@@ -568,7 +622,7 @@ static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
* be a negative error value in the corresponding array element. * be a negative error value in the corresponding array element.
* returns 0 if succeeds else error value * returns 0 if succeeds else error value
*/ */
int twl4030_madc_conversion(struct twl4030_madc_request *req) static int twl4030_madc_conversion(struct twl4030_madc_request *req)
{ {
const struct twl4030_madc_conversion_method *method; const struct twl4030_madc_conversion_method *method;
int ret; int ret;
...@@ -605,17 +659,6 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) ...@@ -605,17 +659,6 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
goto out; goto out;
} }
} }
if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
ret = twl4030_madc_set_irq(twl4030_madc, req);
if (ret < 0)
goto out;
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
if (ret < 0)
goto out;
twl4030_madc->requests[req->method].active = 1;
ret = 0;
goto out;
}
/* With RT method we should not be here anymore */ /* With RT method we should not be here anymore */
if (req->method == TWL4030_MADC_RT) { if (req->method == TWL4030_MADC_RT) {
ret = -EINVAL; ret = -EINVAL;
...@@ -640,28 +683,6 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) ...@@ -640,28 +683,6 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
int twl4030_get_madc_conversion(int channel_no)
{
struct twl4030_madc_request req;
int temp = 0;
int ret;
req.channels = (1 << channel_no);
req.method = TWL4030_MADC_SW2;
req.active = 0;
req.raw = 0;
req.func_cb = NULL;
ret = twl4030_madc_conversion(&req);
if (ret < 0)
return ret;
if (req.rbuf[channel_no] > 0)
temp = req.rbuf[channel_no];
return temp;
}
EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
/** /**
* twl4030_madc_set_current_generator() - setup bias current * twl4030_madc_set_current_generator() - setup bias current
......
...@@ -1204,7 +1204,10 @@ static int xadc_probe(struct platform_device *pdev) ...@@ -1204,7 +1204,10 @@ static int xadc_probe(struct platform_device *pdev)
ret = PTR_ERR(xadc->clk); ret = PTR_ERR(xadc->clk);
goto err_free_samplerate_trigger; goto err_free_samplerate_trigger;
} }
clk_prepare_enable(xadc->clk);
ret = clk_prepare_enable(xadc->clk);
if (ret)
goto err_free_samplerate_trigger;
ret = xadc->ops->setup(pdev, indio_dev, irq); ret = xadc->ops->setup(pdev, indio_dev, irq);
if (ret) if (ret)
......
...@@ -16,7 +16,7 @@ config HID_SENSOR_IIO_COMMON ...@@ -16,7 +16,7 @@ config HID_SENSOR_IIO_COMMON
config HID_SENSOR_IIO_TRIGGER config HID_SENSOR_IIO_TRIGGER
tristate "Common module (trigger) for all HID Sensor IIO drivers" tristate "Common module (trigger) for all HID Sensor IIO drivers"
depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON && IIO_BUFFER
select IIO_TRIGGER select IIO_TRIGGER
help help
Say yes here to build trigger support for HID sensors. Say yes here to build trigger support for HID sensors.
......
...@@ -69,6 +69,12 @@ static struct { ...@@ -69,6 +69,12 @@ static struct {
{HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND, {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND,
1000000, 0}, 1000000, 0},
{HID_USAGE_SENSOR_DEVICE_ORIENTATION, 0, 1, 0},
{HID_USAGE_SENSOR_RELATIVE_ORIENTATION, 0, 1, 0},
{HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION, 0, 1, 0},
{HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0}, {HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0},
{HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0}, {HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0},
...@@ -230,7 +236,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, ...@@ -230,7 +236,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id, ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id,
st->poll.index, sizeof(value), &value); st->poll.index, sizeof(value), &value);
if (ret < 0 || value < 0) if (ret < 0 || value < 0)
ret = -EINVAL; return -EINVAL;
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id, st->poll.report_id,
...@@ -283,7 +289,7 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, ...@@ -283,7 +289,7 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
st->sensitivity.index, sizeof(value), st->sensitivity.index, sizeof(value),
&value); &value);
if (ret < 0 || value < 0) if (ret < 0 || value < 0)
ret = -EINVAL; return -EINVAL;
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id, st->sensitivity.report_id,
...@@ -404,6 +410,48 @@ int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, ...@@ -404,6 +410,48 @@ int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
} }
static void hid_sensor_get_report_latency_info(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_common *st)
{
sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT,
usage_id,
HID_USAGE_SENSOR_PROP_REPORT_LATENCY,
&st->report_latency);
hid_dbg(hsdev->hdev, "Report latency attributes: %x:%x\n",
st->report_latency.index, st->report_latency.report_id);
}
int hid_sensor_get_report_latency(struct hid_sensor_common *st)
{
int ret;
int value;
ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id,
st->report_latency.index, sizeof(value),
&value);
if (ret < 0)
return ret;
return value;
}
EXPORT_SYMBOL(hid_sensor_get_report_latency);
int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms)
{
return sensor_hub_set_feature(st->hsdev, st->report_latency.report_id,
st->report_latency.index,
sizeof(latency_ms), &latency_ms);
}
EXPORT_SYMBOL(hid_sensor_set_report_latency);
bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st)
{
return st->report_latency.index > 0 && st->report_latency.report_id > 0;
}
EXPORT_SYMBOL(hid_sensor_batch_mode_supported);
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id, u32 usage_id,
struct hid_sensor_common *st) struct hid_sensor_common *st)
...@@ -445,6 +493,8 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, ...@@ -445,6 +493,8 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
} else } else
st->timestamp_ns_scale = 1000000000; st->timestamp_ns_scale = 1000000000;
hid_sensor_get_report_latency_info(hsdev, usage_id, st);
hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n", hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n",
st->poll.index, st->poll.report_id, st->poll.index, st->poll.report_id,
st->report_state.index, st->report_state.report_id, st->report_state.index, st->report_state.report_id,
......
...@@ -26,9 +26,84 @@ ...@@ -26,9 +26,84 @@
#include <linux/hid-sensor-hub.h> #include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/trigger.h> #include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include "hid-sensor-trigger.h" #include "hid-sensor-trigger.h"
static ssize_t _hid_sensor_set_report_latency(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
int integer, fract, ret;
int latency;
ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract);
if (ret)
return ret;
latency = integer * 1000 + fract / 1000;
ret = hid_sensor_set_report_latency(attrb, latency);
if (ret < 0)
return len;
attrb->latency_ms = hid_sensor_get_report_latency(attrb);
return len;
}
static ssize_t _hid_sensor_get_report_latency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
int latency;
latency = hid_sensor_get_report_latency(attrb);
if (latency < 0)
return latency;
return sprintf(buf, "%d.%06u\n", latency / 1000, (latency % 1000) * 1000);
}
static ssize_t _hid_sensor_get_fifo_state(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
int latency;
latency = hid_sensor_get_report_latency(attrb);
if (latency < 0)
return latency;
return sprintf(buf, "%d\n", !!latency);
}
static IIO_DEVICE_ATTR(hwfifo_timeout, 0644,
_hid_sensor_get_report_latency,
_hid_sensor_set_report_latency, 0);
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
_hid_sensor_get_fifo_state, NULL, 0);
static const struct attribute *hid_sensor_fifo_attributes[] = {
&iio_dev_attr_hwfifo_timeout.dev_attr.attr,
&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
NULL,
};
static void hid_sensor_setup_batch_mode(struct iio_dev *indio_dev,
struct hid_sensor_common *st)
{
if (!hid_sensor_batch_mode_supported(st))
return;
iio_buffer_set_attrs(indio_dev->buffer, hid_sensor_fifo_attributes);
}
static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state) static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
{ {
int state_val; int state_val;
...@@ -141,6 +216,9 @@ static void hid_sensor_set_power_work(struct work_struct *work) ...@@ -141,6 +216,9 @@ static void hid_sensor_set_power_work(struct work_struct *work)
sizeof(attrb->raw_hystersis), sizeof(attrb->raw_hystersis),
&attrb->raw_hystersis); &attrb->raw_hystersis);
if (attrb->latency_ms > 0)
hid_sensor_set_report_latency(attrb, attrb->latency_ms);
_hid_sensor_power_state(attrb, true); _hid_sensor_power_state(attrb, true);
} }
...@@ -192,6 +270,8 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, ...@@ -192,6 +270,8 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
attrb->trigger = trig; attrb->trigger = trig;
indio_dev->trig = iio_trigger_get(trig); indio_dev->trig = iio_trigger_get(trig);
hid_sensor_setup_batch_mode(indio_dev, attrb);
ret = pm_runtime_set_active(&indio_dev->dev); ret = pm_runtime_set_active(&indio_dev->dev);
if (ret) if (ret)
goto error_unreg_trigger; goto error_unreg_trigger;
......
...@@ -13,7 +13,8 @@ config AD5064 ...@@ -13,7 +13,8 @@ config AD5064
AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, AD5627, AD5627R, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, AD5627, AD5627R,
AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, AD5666, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, AD5666,
AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616,
LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to Analog Converter. LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635
Digital to Analog Converter.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ad5064. module will be called ad5064.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R,
* AD5627, AD5627R, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, * AD5627, AD5627R, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R,
* AD5666, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616, * AD5666, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616,
* LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to analog converters * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635
* driver * Digital to analog converters driver
* *
* Copyright 2011 Analog Devices Inc. * Copyright 2011 Analog Devices Inc.
* *
...@@ -168,6 +168,24 @@ enum ad5064_type { ...@@ -168,6 +168,24 @@ enum ad5064_type {
ID_LTC2626, ID_LTC2626,
ID_LTC2627, ID_LTC2627,
ID_LTC2629, ID_LTC2629,
ID_LTC2631_L12,
ID_LTC2631_H12,
ID_LTC2631_L10,
ID_LTC2631_H10,
ID_LTC2631_L8,
ID_LTC2631_H8,
ID_LTC2633_L12,
ID_LTC2633_H12,
ID_LTC2633_L10,
ID_LTC2633_H10,
ID_LTC2633_L8,
ID_LTC2633_H8,
ID_LTC2635_L12,
ID_LTC2635_H12,
ID_LTC2635_L10,
ID_LTC2635_H10,
ID_LTC2635_L8,
ID_LTC2635_H8,
}; };
static int ad5064_write(struct ad5064_state *st, unsigned int cmd, static int ad5064_write(struct ad5064_state *st, unsigned int cmd,
...@@ -425,6 +443,19 @@ static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0, ad5064_ext_info); ...@@ -425,6 +443,19 @@ static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0, ad5064_ext_info);
static DECLARE_AD5064_CHANNELS(ltc2607_channels, 16, 0, ltc2617_ext_info); static DECLARE_AD5064_CHANNELS(ltc2607_channels, 16, 0, ltc2617_ext_info);
static DECLARE_AD5064_CHANNELS(ltc2617_channels, 14, 2, ltc2617_ext_info); static DECLARE_AD5064_CHANNELS(ltc2617_channels, 14, 2, ltc2617_ext_info);
static DECLARE_AD5064_CHANNELS(ltc2627_channels, 12, 4, ltc2617_ext_info); static DECLARE_AD5064_CHANNELS(ltc2627_channels, 12, 4, ltc2617_ext_info);
#define ltc2631_12_channels ltc2627_channels
static DECLARE_AD5064_CHANNELS(ltc2631_10_channels, 10, 6, ltc2617_ext_info);
static DECLARE_AD5064_CHANNELS(ltc2631_8_channels, 8, 8, ltc2617_ext_info);
#define LTC2631_INFO(vref, pchannels, nchannels) \
{ \
.shared_vref = true, \
.internal_vref = vref, \
.channels = pchannels, \
.num_channels = nchannels, \
.regmap_type = AD5064_REGMAP_LTC, \
}
static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
[ID_AD5024] = { [ID_AD5024] = {
...@@ -724,6 +755,24 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { ...@@ -724,6 +755,24 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
.num_channels = 4, .num_channels = 4,
.regmap_type = AD5064_REGMAP_LTC, .regmap_type = AD5064_REGMAP_LTC,
}, },
[ID_LTC2631_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 1),
[ID_LTC2631_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 1),
[ID_LTC2631_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 1),
[ID_LTC2631_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 1),
[ID_LTC2631_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 1),
[ID_LTC2631_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 1),
[ID_LTC2633_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 2),
[ID_LTC2633_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 2),
[ID_LTC2633_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 2),
[ID_LTC2633_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 2),
[ID_LTC2633_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 2),
[ID_LTC2633_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 2),
[ID_LTC2635_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 4),
[ID_LTC2635_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 4),
[ID_LTC2635_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 4),
[ID_LTC2635_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 4),
[ID_LTC2635_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 4),
[ID_LTC2635_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 4),
}; };
static inline unsigned int ad5064_num_vref(struct ad5064_state *st) static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
...@@ -982,6 +1031,24 @@ static const struct i2c_device_id ad5064_i2c_ids[] = { ...@@ -982,6 +1031,24 @@ static const struct i2c_device_id ad5064_i2c_ids[] = {
{"ltc2626", ID_LTC2626}, {"ltc2626", ID_LTC2626},
{"ltc2627", ID_LTC2627}, {"ltc2627", ID_LTC2627},
{"ltc2629", ID_LTC2629}, {"ltc2629", ID_LTC2629},
{"ltc2631-l12", ID_LTC2631_L12},
{"ltc2631-h12", ID_LTC2631_H12},
{"ltc2631-l10", ID_LTC2631_L10},
{"ltc2631-h10", ID_LTC2631_H10},
{"ltc2631-l8", ID_LTC2631_L8},
{"ltc2631-h8", ID_LTC2631_H8},
{"ltc2633-l12", ID_LTC2633_L12},
{"ltc2633-h12", ID_LTC2633_H12},
{"ltc2633-l10", ID_LTC2633_L10},
{"ltc2633-h10", ID_LTC2633_H10},
{"ltc2633-l8", ID_LTC2633_L8},
{"ltc2633-h8", ID_LTC2633_H8},
{"ltc2635-l12", ID_LTC2635_L12},
{"ltc2635-h12", ID_LTC2635_H12},
{"ltc2635-l10", ID_LTC2635_L10},
{"ltc2635-h10", ID_LTC2635_H10},
{"ltc2635-l8", ID_LTC2635_L8},
{"ltc2635-h8", ID_LTC2635_H8},
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
......
...@@ -57,12 +57,15 @@ struct hts221_hw { ...@@ -57,12 +57,15 @@ struct hts221_hw {
struct hts221_sensor sensors[HTS221_SENSOR_MAX]; struct hts221_sensor sensors[HTS221_SENSOR_MAX];
bool enabled;
u8 odr; u8 odr;
const struct hts221_transfer_function *tf; const struct hts221_transfer_function *tf;
struct hts221_transfer_buffer tb; struct hts221_transfer_buffer tb;
}; };
extern const struct dev_pm_ops hts221_pm_ops;
int hts221_config_drdy(struct hts221_hw *hw, bool enable); int hts221_config_drdy(struct hts221_hw *hw, bool enable);
int hts221_probe(struct iio_dev *iio_dev); int hts221_probe(struct iio_dev *iio_dev);
int hts221_power_on(struct hts221_hw *hw); int hts221_power_on(struct hts221_hw *hw);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "hts221.h" #include "hts221.h"
...@@ -307,15 +308,30 @@ hts221_sysfs_temp_oversampling_avail(struct device *dev, ...@@ -307,15 +308,30 @@ hts221_sysfs_temp_oversampling_avail(struct device *dev,
int hts221_power_on(struct hts221_hw *hw) int hts221_power_on(struct hts221_hw *hw)
{ {
return hts221_update_odr(hw, hw->odr); int err;
err = hts221_update_odr(hw, hw->odr);
if (err < 0)
return err;
hw->enabled = true;
return 0;
} }
int hts221_power_off(struct hts221_hw *hw) int hts221_power_off(struct hts221_hw *hw)
{ {
u8 data[] = {0x00, 0x00}; __le16 data = 0;
int err;
return hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data), err = hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data),
data); (u8 *)&data);
if (err < 0)
return err;
hw->enabled = false;
return 0;
} }
static int hts221_parse_temp_caldata(struct hts221_hw *hw) static int hts221_parse_temp_caldata(struct hts221_hw *hw)
...@@ -682,6 +698,36 @@ int hts221_probe(struct iio_dev *iio_dev) ...@@ -682,6 +698,36 @@ int hts221_probe(struct iio_dev *iio_dev)
} }
EXPORT_SYMBOL(hts221_probe); EXPORT_SYMBOL(hts221_probe);
static int __maybe_unused hts221_suspend(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct hts221_hw *hw = iio_priv(iio_dev);
__le16 data = 0;
int err;
err = hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data),
(u8 *)&data);
return err < 0 ? err : 0;
}
static int __maybe_unused hts221_resume(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct hts221_hw *hw = iio_priv(iio_dev);
int err = 0;
if (hw->enabled)
err = hts221_update_odr(hw, hw->odr);
return err;
}
const struct dev_pm_ops hts221_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(hts221_suspend, hts221_resume)
};
EXPORT_SYMBOL(hts221_pm_ops);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver"); MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table); ...@@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table);
static struct i2c_driver hts221_driver = { static struct i2c_driver hts221_driver = {
.driver = { .driver = {
.name = "hts221_i2c", .name = "hts221_i2c",
.pm = &hts221_pm_ops,
.of_match_table = of_match_ptr(hts221_i2c_of_match), .of_match_table = of_match_ptr(hts221_i2c_of_match),
.acpi_match_table = ACPI_PTR(hts221_acpi_match), .acpi_match_table = ACPI_PTR(hts221_acpi_match),
}, },
......
...@@ -113,6 +113,7 @@ MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); ...@@ -113,6 +113,7 @@ MODULE_DEVICE_TABLE(spi, hts221_spi_id_table);
static struct spi_driver hts221_driver = { static struct spi_driver hts221_driver = {
.driver = { .driver = {
.name = "hts221_spi", .name = "hts221_spi",
.pm = &hts221_pm_ops,
.of_match_table = of_match_ptr(hts221_spi_of_match), .of_match_table = of_match_ptr(hts221_spi_of_match),
}, },
.probe = hts221_spi_probe, .probe = hts221_spi_probe,
......
...@@ -188,7 +188,6 @@ int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) ...@@ -188,7 +188,6 @@ int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
int result = 0; int result = 0;
if (power_on) { if (power_on) {
/* Already under indio-dev->mlock mutex */
if (!st->powerup_count) if (!st->powerup_count)
result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
if (!result) if (!result)
...@@ -329,50 +328,37 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, ...@@ -329,50 +328,37 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
int result; int result;
ret = IIO_VAL_INT; ret = IIO_VAL_INT;
result = 0; mutex_lock(&st->lock);
mutex_lock(&indio_dev->mlock); result = iio_device_claim_direct_mode(indio_dev);
if (!st->chip_config.enable) { if (result)
result = inv_mpu6050_set_power_itg(st, true); goto error_read_raw_unlock;
if (result) result = inv_mpu6050_set_power_itg(st, true);
goto error_read_raw; if (result)
} goto error_read_raw_release;
/* when enable is on, power is already on */
switch (chan->type) { switch (chan->type) {
case IIO_ANGL_VEL: case IIO_ANGL_VEL:
if (!st->chip_config.gyro_fifo_enable || result = inv_mpu6050_switch_engine(st, true,
!st->chip_config.enable) { INV_MPU6050_BIT_PWR_GYRO_STBY);
result = inv_mpu6050_switch_engine(st, true, if (result)
INV_MPU6050_BIT_PWR_GYRO_STBY); goto error_read_raw_power_off;
if (result)
goto error_read_raw;
}
ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
chan->channel2, val); chan->channel2, val);
if (!st->chip_config.gyro_fifo_enable || result = inv_mpu6050_switch_engine(st, false,
!st->chip_config.enable) { INV_MPU6050_BIT_PWR_GYRO_STBY);
result = inv_mpu6050_switch_engine(st, false, if (result)
INV_MPU6050_BIT_PWR_GYRO_STBY); goto error_read_raw_power_off;
if (result)
goto error_read_raw;
}
break; break;
case IIO_ACCEL: case IIO_ACCEL:
if (!st->chip_config.accl_fifo_enable || result = inv_mpu6050_switch_engine(st, true,
!st->chip_config.enable) { INV_MPU6050_BIT_PWR_ACCL_STBY);
result = inv_mpu6050_switch_engine(st, true, if (result)
INV_MPU6050_BIT_PWR_ACCL_STBY); goto error_read_raw_power_off;
if (result)
goto error_read_raw;
}
ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
chan->channel2, val); chan->channel2, val);
if (!st->chip_config.accl_fifo_enable || result = inv_mpu6050_switch_engine(st, false,
!st->chip_config.enable) { INV_MPU6050_BIT_PWR_ACCL_STBY);
result = inv_mpu6050_switch_engine(st, false, if (result)
INV_MPU6050_BIT_PWR_ACCL_STBY); goto error_read_raw_power_off;
if (result)
goto error_read_raw;
}
break; break;
case IIO_TEMP: case IIO_TEMP:
/* wait for stablization */ /* wait for stablization */
...@@ -384,10 +370,12 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, ...@@ -384,10 +370,12 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
error_read_raw: error_read_raw_power_off:
if (!st->chip_config.enable) result |= inv_mpu6050_set_power_itg(st, false);
result |= inv_mpu6050_set_power_itg(st, false); error_read_raw_release:
mutex_unlock(&indio_dev->mlock); iio_device_release_direct_mode(indio_dev);
error_read_raw_unlock:
mutex_unlock(&st->lock);
if (result) if (result)
return result; return result;
...@@ -396,13 +384,17 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, ...@@ -396,13 +384,17 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_ANGL_VEL: case IIO_ANGL_VEL:
mutex_lock(&st->lock);
*val = 0; *val = 0;
*val2 = gyro_scale_6050[st->chip_config.fsr]; *val2 = gyro_scale_6050[st->chip_config.fsr];
mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO; return IIO_VAL_INT_PLUS_NANO;
case IIO_ACCEL: case IIO_ACCEL:
mutex_lock(&st->lock);
*val = 0; *val = 0;
*val2 = accel_scale[st->chip_config.accl_fs]; *val2 = accel_scale[st->chip_config.accl_fs];
mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
...@@ -425,12 +417,16 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, ...@@ -425,12 +417,16 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) { switch (chan->type) {
case IIO_ANGL_VEL: case IIO_ANGL_VEL:
mutex_lock(&st->lock);
ret = inv_mpu6050_sensor_show(st, st->reg->gyro_offset, ret = inv_mpu6050_sensor_show(st, st->reg->gyro_offset,
chan->channel2, val); chan->channel2, val);
mutex_unlock(&st->lock);
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_ACCEL: case IIO_ACCEL:
mutex_lock(&st->lock);
ret = inv_mpu6050_sensor_show(st, st->reg->accl_offset, ret = inv_mpu6050_sensor_show(st, st->reg->accl_offset,
chan->channel2, val); chan->channel2, val);
mutex_unlock(&st->lock);
return IIO_VAL_INT; return IIO_VAL_INT;
default: default:
...@@ -506,18 +502,17 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, ...@@ -506,18 +502,17 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
struct inv_mpu6050_state *st = iio_priv(indio_dev); struct inv_mpu6050_state *st = iio_priv(indio_dev);
int result; int result;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
/* /*
* we should only update scale when the chip is disabled, i.e. * we should only update scale when the chip is disabled, i.e.
* not running * not running
*/ */
if (st->chip_config.enable) { result = iio_device_claim_direct_mode(indio_dev);
result = -EBUSY; if (result)
goto error_write_raw; goto error_write_raw_unlock;
}
result = inv_mpu6050_set_power_itg(st, true); result = inv_mpu6050_set_power_itg(st, true);
if (result) if (result)
goto error_write_raw; goto error_write_raw_release;
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
...@@ -553,9 +548,11 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, ...@@ -553,9 +548,11 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
break; break;
} }
error_write_raw:
result |= inv_mpu6050_set_power_itg(st, false); result |= inv_mpu6050_set_power_itg(st, false);
mutex_unlock(&indio_dev->mlock); error_write_raw_release:
iio_device_release_direct_mode(indio_dev);
error_write_raw_unlock:
mutex_unlock(&st->lock);
return result; return result;
} }
...@@ -611,31 +608,35 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, ...@@ -611,31 +608,35 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE || if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE ||
fifo_rate > INV_MPU6050_MAX_FIFO_RATE) fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
return -EINVAL; return -EINVAL;
if (fifo_rate == st->chip_config.fifo_rate)
return count;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
if (st->chip_config.enable) { if (fifo_rate == st->chip_config.fifo_rate) {
result = -EBUSY; result = 0;
goto fifo_rate_fail; goto fifo_rate_fail_unlock;
} }
result = iio_device_claim_direct_mode(indio_dev);
if (result)
goto fifo_rate_fail_unlock;
result = inv_mpu6050_set_power_itg(st, true); result = inv_mpu6050_set_power_itg(st, true);
if (result) if (result)
goto fifo_rate_fail; goto fifo_rate_fail_release;
d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1; d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1;
result = regmap_write(st->map, st->reg->sample_rate_div, d); result = regmap_write(st->map, st->reg->sample_rate_div, d);
if (result) if (result)
goto fifo_rate_fail; goto fifo_rate_fail_power_off;
st->chip_config.fifo_rate = fifo_rate; st->chip_config.fifo_rate = fifo_rate;
result = inv_mpu6050_set_lpf(st, fifo_rate); result = inv_mpu6050_set_lpf(st, fifo_rate);
if (result) if (result)
goto fifo_rate_fail; goto fifo_rate_fail_power_off;
fifo_rate_fail: fifo_rate_fail_power_off:
result |= inv_mpu6050_set_power_itg(st, false); result |= inv_mpu6050_set_power_itg(st, false);
mutex_unlock(&indio_dev->mlock); fifo_rate_fail_release:
iio_device_release_direct_mode(indio_dev);
fifo_rate_fail_unlock:
mutex_unlock(&st->lock);
if (result) if (result)
return result; return result;
...@@ -650,8 +651,13 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr, ...@@ -650,8 +651,13 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned fifo_rate;
mutex_lock(&st->lock);
fifo_rate = st->chip_config.fifo_rate;
mutex_unlock(&st->lock);
return sprintf(buf, "%d\n", st->chip_config.fifo_rate); return scnprintf(buf, PAGE_SIZE, "%u\n", fifo_rate);
} }
/** /**
...@@ -678,7 +684,8 @@ static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr, ...@@ -678,7 +684,8 @@ static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr,
case ATTR_ACCL_MATRIX: case ATTR_ACCL_MATRIX:
m = st->plat_data.orientation; m = st->plat_data.orientation;
return sprintf(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n", return scnprintf(buf, PAGE_SIZE,
"%d, %d, %d; %d, %d, %d; %d, %d, %d\n",
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
default: default:
return -EINVAL; return -EINVAL;
...@@ -803,27 +810,42 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) ...@@ -803,27 +810,42 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
{ {
int result; int result;
unsigned int regval; unsigned int regval;
int i;
st->hw = &hw_info[st->chip_type]; st->hw = &hw_info[st->chip_type];
st->reg = hw_info[st->chip_type].reg; st->reg = hw_info[st->chip_type].reg;
/* reset to make sure previous state are not there */
result = regmap_write(st->map, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_H_RESET);
if (result)
return result;
msleep(INV_MPU6050_POWER_UP_TIME);
/* check chip self-identification */ /* check chip self-identification */
result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, &regval); result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, &regval);
if (result) if (result)
return result; return result;
if (regval != st->hw->whoami) { if (regval != st->hw->whoami) {
dev_warn(regmap_get_device(st->map), /* check whoami against all possible values */
"whoami mismatch got %#02x expected %#02hhx for %s\n", for (i = 0; i < INV_NUM_PARTS; ++i) {
if (regval == hw_info[i].whoami) {
dev_warn(regmap_get_device(st->map),
"whoami mismatch got %#02x (%s)"
"expected %#02hhx (%s)\n",
regval, hw_info[i].name,
st->hw->whoami, st->hw->name);
break;
}
}
if (i >= INV_NUM_PARTS) {
dev_err(regmap_get_device(st->map),
"invalid whoami %#02x expected %#02hhx (%s)\n",
regval, st->hw->whoami, st->hw->name); regval, st->hw->whoami, st->hw->name);
return -ENODEV;
}
} }
/* reset to make sure previous state are not there */
result = regmap_write(st->map, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_H_RESET);
if (result)
return result;
msleep(INV_MPU6050_POWER_UP_TIME);
/* /*
* toggle power state. After reset, the sleep bit could be on * toggle power state. After reset, the sleep bit could be on
* or off depending on the OTP settings. Toggling power would * or off depending on the OTP settings. Toggling power would
...@@ -869,6 +891,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, ...@@ -869,6 +891,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return -ENODEV; return -ENODEV;
} }
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
mutex_init(&st->lock);
st->chip_type = chip_type; st->chip_type = chip_type;
st->powerup_count = 0; st->powerup_count = 0;
st->irq = irq; st->irq = irq;
...@@ -962,12 +985,26 @@ EXPORT_SYMBOL_GPL(inv_mpu_core_remove); ...@@ -962,12 +985,26 @@ EXPORT_SYMBOL_GPL(inv_mpu_core_remove);
static int inv_mpu_resume(struct device *dev) static int inv_mpu_resume(struct device *dev)
{ {
return inv_mpu6050_set_power_itg(iio_priv(dev_get_drvdata(dev)), true); struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
int result;
mutex_lock(&st->lock);
result = inv_mpu6050_set_power_itg(st, true);
mutex_unlock(&st->lock);
return result;
} }
static int inv_mpu_suspend(struct device *dev) static int inv_mpu_suspend(struct device *dev)
{ {
return inv_mpu6050_set_power_itg(iio_priv(dev_get_drvdata(dev)), false); struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
int result;
mutex_lock(&st->lock);
result = inv_mpu6050_set_power_itg(st, false);
mutex_unlock(&st->lock);
return result;
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
......
...@@ -32,7 +32,7 @@ static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id) ...@@ -32,7 +32,7 @@ static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
int ret = 0; int ret = 0;
/* Use the same mutex which was used everywhere to protect power-op */ /* Use the same mutex which was used everywhere to protect power-op */
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
if (!st->powerup_count) { if (!st->powerup_count) {
ret = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); ret = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
if (ret) if (ret)
...@@ -48,7 +48,7 @@ static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id) ...@@ -48,7 +48,7 @@ static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
INV_MPU6050_BIT_BYPASS_EN); INV_MPU6050_BIT_BYPASS_EN);
} }
write_error: write_error:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
return ret; return ret;
} }
...@@ -58,14 +58,14 @@ static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id) ...@@ -58,14 +58,14 @@ static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
struct iio_dev *indio_dev = i2c_mux_priv(muxc); struct iio_dev *indio_dev = i2c_mux_priv(muxc);
struct inv_mpu6050_state *st = iio_priv(indio_dev); struct inv_mpu6050_state *st = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
/* It doesn't really mattter, if any of the calls fails */ /* It doesn't really mattter, if any of the calls fails */
regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG); regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG);
st->powerup_count--; st->powerup_count--;
if (!st->powerup_count) if (!st->powerup_count)
regmap_write(st->map, st->reg->pwr_mgmt_1, regmap_write(st->map, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP); INV_MPU6050_BIT_SLEEP);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
return 0; return 0;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/i2c-mux.h> #include <linux/i2c-mux.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
#include <linux/regmap.h> #include <linux/regmap.h>
...@@ -82,7 +83,6 @@ enum inv_devices { ...@@ -82,7 +83,6 @@ enum inv_devices {
* @fsr: Full scale range. * @fsr: Full scale range.
* @lpf: Digital low pass filter frequency. * @lpf: Digital low pass filter frequency.
* @accl_fs: accel full scale range. * @accl_fs: accel full scale range.
* @enable: master enable state.
* @accl_fifo_enable: enable accel data output * @accl_fifo_enable: enable accel data output
* @gyro_fifo_enable: enable gyro data output * @gyro_fifo_enable: enable gyro data output
* @fifo_rate: FIFO update rate. * @fifo_rate: FIFO update rate.
...@@ -91,7 +91,6 @@ struct inv_mpu6050_chip_config { ...@@ -91,7 +91,6 @@ struct inv_mpu6050_chip_config {
unsigned int fsr:2; unsigned int fsr:2;
unsigned int lpf:3; unsigned int lpf:3;
unsigned int accl_fs:2; unsigned int accl_fs:2;
unsigned int enable:1;
unsigned int accl_fifo_enable:1; unsigned int accl_fifo_enable:1;
unsigned int gyro_fifo_enable:1; unsigned int gyro_fifo_enable:1;
u16 fifo_rate; u16 fifo_rate;
...@@ -114,6 +113,7 @@ struct inv_mpu6050_hw { ...@@ -114,6 +113,7 @@ struct inv_mpu6050_hw {
/* /*
* struct inv_mpu6050_state - Driver state variables. * struct inv_mpu6050_state - Driver state variables.
* @TIMESTAMP_FIFO_SIZE: fifo size for timestamp. * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp.
* @lock: Chip access lock.
* @trig: IIO trigger. * @trig: IIO trigger.
* @chip_config: Cached attribute information. * @chip_config: Cached attribute information.
* @reg: Map of important registers. * @reg: Map of important registers.
...@@ -128,6 +128,7 @@ struct inv_mpu6050_hw { ...@@ -128,6 +128,7 @@ struct inv_mpu6050_hw {
*/ */
struct inv_mpu6050_state { struct inv_mpu6050_state {
#define TIMESTAMP_FIFO_SIZE 16 #define TIMESTAMP_FIFO_SIZE 16
struct mutex lock;
struct iio_trigger *trig; struct iio_trigger *trig;
struct inv_mpu6050_chip_config chip_config; struct inv_mpu6050_chip_config chip_config;
const struct inv_mpu6050_reg_map *reg; const struct inv_mpu6050_reg_map *reg;
......
...@@ -128,7 +128,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) ...@@ -128,7 +128,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
u16 fifo_count; u16 fifo_count;
s64 timestamp; s64 timestamp;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
if (!(st->chip_config.accl_fifo_enable | if (!(st->chip_config.accl_fifo_enable |
st->chip_config.gyro_fifo_enable)) st->chip_config.gyro_fifo_enable))
goto end_session; goto end_session;
...@@ -178,7 +178,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) ...@@ -178,7 +178,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
} }
end_session: end_session:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
iio_trigger_notify_done(indio_dev->trig); iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -186,7 +186,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) ...@@ -186,7 +186,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
flush_fifo: flush_fifo:
/* Flush HW and SW FIFOs. */ /* Flush HW and SW FIFOs. */
inv_reset_fifo(indio_dev); inv_reset_fifo(indio_dev);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
iio_trigger_notify_done(indio_dev->trig); iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -90,7 +90,6 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) ...@@ -90,7 +90,6 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
if (result) if (result)
return result; return result;
} }
st->chip_config.enable = enable;
return 0; return 0;
} }
...@@ -103,7 +102,15 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) ...@@ -103,7 +102,15 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig, static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state) bool state)
{ {
return inv_mpu6050_set_enable(iio_trigger_get_drvdata(trig), state); struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int result;
mutex_lock(&st->lock);
result = inv_mpu6050_set_enable(indio_dev, state);
mutex_unlock(&st->lock);
return result;
} }
static const struct iio_trigger_ops inv_mpu_trigger_ops = { static const struct iio_trigger_ops inv_mpu_trigger_ops = {
......
...@@ -135,6 +135,8 @@ struct st_lsm6dsx_hw { ...@@ -135,6 +135,8 @@ struct st_lsm6dsx_hw {
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
}; };
extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
const struct st_lsm6dsx_transfer_function *tf_ops); const struct st_lsm6dsx_transfer_function *tf_ops);
int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor); int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
...@@ -144,5 +146,8 @@ int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask, ...@@ -144,5 +146,8 @@ int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
u8 val); u8 val);
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
u16 watermark); u16 watermark);
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode);
#endif /* ST_LSM6DSX_H */ #endif /* ST_LSM6DSX_H */
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#define ST_LSM6DSX_REG_FIFO_THH_ADDR 0x07 #define ST_LSM6DSX_REG_FIFO_THH_ADDR 0x07
#define ST_LSM6DSX_FIFO_TH_MASK GENMASK(11, 0) #define ST_LSM6DSX_FIFO_TH_MASK GENMASK(11, 0)
#define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR 0x08 #define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR 0x08
#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12
#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5)
#define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a #define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a
#define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0) #define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0)
#define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3) #define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
...@@ -130,8 +132,8 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw) ...@@ -130,8 +132,8 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
return 0; return 0;
} }
static int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode) enum st_lsm6dsx_fifo_mode fifo_mode)
{ {
u8 data; u8 data;
int err; int err;
...@@ -303,7 +305,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) ...@@ -303,7 +305,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
return read_len; return read_len;
} }
static int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
{ {
int err; int err;
...@@ -417,6 +419,7 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) ...@@ -417,6 +419,7 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
{ {
struct iio_buffer *buffer; struct iio_buffer *buffer;
unsigned long irq_type; unsigned long irq_type;
bool irq_active_low;
int i, err; int i, err;
irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
...@@ -424,12 +427,23 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) ...@@ -424,12 +427,23 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
switch (irq_type) { switch (irq_type) {
case IRQF_TRIGGER_HIGH: case IRQF_TRIGGER_HIGH:
case IRQF_TRIGGER_RISING: case IRQF_TRIGGER_RISING:
irq_active_low = false;
break;
case IRQF_TRIGGER_LOW:
case IRQF_TRIGGER_FALLING:
irq_active_low = true;
break; break;
default: default:
dev_info(hw->dev, "mode %lx unsupported\n", irq_type); dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
return -EINVAL; return -EINVAL;
} }
err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_HLACTIVE_ADDR,
ST_LSM6DSX_REG_HLACTIVE_MASK,
irq_active_low);
if (err < 0)
return err;
err = devm_request_threaded_irq(hw->dev, hw->irq, err = devm_request_threaded_irq(hw->dev, hw->irq,
st_lsm6dsx_handler_irq, st_lsm6dsx_handler_irq,
st_lsm6dsx_handler_thread, st_lsm6dsx_handler_thread,
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/pm.h>
#include <linux/platform_data/st_sensors_pdata.h> #include <linux/platform_data/st_sensors_pdata.h>
...@@ -731,6 +732,57 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, ...@@ -731,6 +732,57 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
} }
EXPORT_SYMBOL(st_lsm6dsx_probe); EXPORT_SYMBOL(st_lsm6dsx_probe);
static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
{
struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
struct st_lsm6dsx_sensor *sensor;
int i, err = 0;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
sensor = iio_priv(hw->iio_devs[i]);
if (!(hw->enable_mask & BIT(sensor->id)))
continue;
err = st_lsm6dsx_write_with_mask(hw,
st_lsm6dsx_odr_table[sensor->id].reg.addr,
st_lsm6dsx_odr_table[sensor->id].reg.mask, 0);
if (err < 0)
return err;
}
if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS)
err = st_lsm6dsx_flush_fifo(hw);
return err;
}
static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
{
struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
struct st_lsm6dsx_sensor *sensor;
int i, err = 0;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
sensor = iio_priv(hw->iio_devs[i]);
if (!(hw->enable_mask & BIT(sensor->id)))
continue;
err = st_lsm6dsx_set_odr(sensor, sensor->odr);
if (err < 0)
return err;
}
if (hw->enable_mask)
err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
return err;
}
const struct dev_pm_ops st_lsm6dsx_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume)
};
EXPORT_SYMBOL(st_lsm6dsx_pm_ops);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
......
...@@ -98,6 +98,7 @@ MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); ...@@ -98,6 +98,7 @@ MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
static struct i2c_driver st_lsm6dsx_driver = { static struct i2c_driver st_lsm6dsx_driver = {
.driver = { .driver = {
.name = "st_lsm6dsx_i2c", .name = "st_lsm6dsx_i2c",
.pm = &st_lsm6dsx_pm_ops,
.of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match), .of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match),
}, },
.probe = st_lsm6dsx_i2c_probe, .probe = st_lsm6dsx_i2c_probe,
......
...@@ -115,6 +115,7 @@ MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); ...@@ -115,6 +115,7 @@ MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
static struct spi_driver st_lsm6dsx_driver = { static struct spi_driver st_lsm6dsx_driver = {
.driver = { .driver = {
.name = "st_lsm6dsx_spi", .name = "st_lsm6dsx_spi",
.pm = &st_lsm6dsx_pm_ops,
.of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match), .of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match),
}, },
.probe = st_lsm6dsx_spi_probe, .probe = st_lsm6dsx_spi_probe,
......
...@@ -478,21 +478,16 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, ...@@ -478,21 +478,16 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
size_t len) size_t len)
{ {
const struct iio_enum *e = (const struct iio_enum *)priv; const struct iio_enum *e = (const struct iio_enum *)priv;
unsigned int i;
int ret; int ret;
if (!e->set) if (!e->set)
return -EINVAL; return -EINVAL;
for (i = 0; i < e->num_items; i++) { ret = __sysfs_match_string(e->items, e->num_items, buf);
if (sysfs_streq(buf, e->items[i])) if (ret < 0)
break; return ret;
}
if (i == e->num_items)
return -EINVAL;
ret = e->set(indio_dev, chan, i); ret = e->set(indio_dev, chan, ret);
return ret ? ret : len; return ret ? ret : len;
} }
EXPORT_SYMBOL_GPL(iio_enum_write); EXPORT_SYMBOL_GPL(iio_enum_write);
...@@ -1089,7 +1084,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, ...@@ -1089,7 +1084,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
{ {
int i, ret, attrcount = 0; int i, ret, attrcount = 0;
for_each_set_bit(i, infomask, sizeof(infomask)*8) { for_each_set_bit(i, infomask, sizeof(*infomask)*8) {
if (i >= ARRAY_SIZE(iio_chan_info_postfix)) if (i >= ARRAY_SIZE(iio_chan_info_postfix))
return -EINVAL; return -EINVAL;
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
...@@ -1118,7 +1113,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, ...@@ -1118,7 +1113,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
int i, ret, attrcount = 0; int i, ret, attrcount = 0;
char *avail_postfix; char *avail_postfix;
for_each_set_bit(i, infomask, sizeof(infomask) * 8) { for_each_set_bit(i, infomask, sizeof(*infomask) * 8) {
avail_postfix = kasprintf(GFP_KERNEL, avail_postfix = kasprintf(GFP_KERNEL,
"%s_available", "%s_available",
iio_chan_info_postfix[i]); iio_chan_info_postfix[i]);
...@@ -1428,7 +1423,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) ...@@ -1428,7 +1423,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
static void iio_dev_release(struct device *device) static void iio_dev_release(struct device *device)
{ {
struct iio_dev *indio_dev = dev_to_iio_dev(device); struct iio_dev *indio_dev = dev_to_iio_dev(device);
if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES)
iio_device_unregister_trigger_consumer(indio_dev); iio_device_unregister_trigger_consumer(indio_dev);
iio_device_unregister_eventset(indio_dev); iio_device_unregister_eventset(indio_dev);
iio_device_unregister_sysfs(indio_dev); iio_device_unregister_sysfs(indio_dev);
...@@ -1710,7 +1705,7 @@ int iio_device_register(struct iio_dev *indio_dev) ...@@ -1710,7 +1705,7 @@ int iio_device_register(struct iio_dev *indio_dev)
"Failed to register event set\n"); "Failed to register event set\n");
goto error_free_sysfs; goto error_free_sysfs;
} }
if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES)
iio_device_register_trigger_consumer(indio_dev); iio_device_register_trigger_consumer(indio_dev);
if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) && if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
......
...@@ -750,11 +750,9 @@ int iio_read_avail_channel_raw(struct iio_channel *chan, ...@@ -750,11 +750,9 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
err_unlock: err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock); mutex_unlock(&chan->indio_dev->info_exist_lock);
if (ret >= 0 && type != IIO_VAL_INT) { if (ret >= 0 && type != IIO_VAL_INT)
/* raw values are assumed to be IIO_VAL_INT */ /* raw values are assumed to be IIO_VAL_INT */
ret = -EINVAL; ret = -EINVAL;
goto err_unlock;
}
return ret; return ret;
} }
......
...@@ -172,6 +172,16 @@ config SENSORS_ISL29018 ...@@ -172,6 +172,16 @@ config SENSORS_ISL29018
in lux, proximity infrared sensing and normal infrared sensing. in lux, proximity infrared sensing and normal infrared sensing.
Data from sensor is accessible via sysfs. Data from sensor is accessible via sysfs.
config SENSORS_ISL29028
tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor"
depends on I2C
select REGMAP_I2C
help
Provides driver for the Intersil's ISL29028 device.
This driver supports the sysfs interface to get the ALS, IR intensity,
Proximity value via iio. The ISL29028 provides the concurrent sensing
of ambient light and proximity.
config ISL29125 config ISL29125
tristate "Intersil ISL29125 digital color light sensor" tristate "Intersil ISL29125 digital color light sensor"
depends on I2C depends on I2C
......
...@@ -20,6 +20,7 @@ obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o ...@@ -20,6 +20,7 @@ obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_ISL29125) += isl29125.o
obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
......
...@@ -807,6 +807,7 @@ static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); ...@@ -807,6 +807,7 @@ static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume);
#define ISL29018_PM_OPS NULL #define ISL29018_PM_OPS NULL
#endif #endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id isl29018_acpi_match[] = { static const struct acpi_device_id isl29018_acpi_match[] = {
{"ISL29018", isl29018}, {"ISL29018", isl29018},
{"ISL29023", isl29023}, {"ISL29023", isl29023},
...@@ -814,6 +815,7 @@ static const struct acpi_device_id isl29018_acpi_match[] = { ...@@ -814,6 +815,7 @@ static const struct acpi_device_id isl29018_acpi_match[] = {
{}, {},
}; };
MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match);
#endif
static const struct i2c_device_id isl29018_id[] = { static const struct i2c_device_id isl29018_id[] = {
{"isl29018", isl29018}, {"isl29018", isl29018},
......
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Datasheets:
* - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29028.pdf
* - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29030.pdf
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -64,8 +68,25 @@ ...@@ -64,8 +68,25 @@
#define ISL29028_POWER_OFF_DELAY_MS 2000 #define ISL29028_POWER_OFF_DELAY_MS 2000
static const unsigned int isl29028_prox_sleep_time[] = {800, 400, 200, 100, 75, struct isl29028_prox_data {
50, 12, 0}; int sampling_int;
int sampling_fract;
int sleep_time;
};
static const struct isl29028_prox_data isl29028_prox_data[] = {
{ 1, 250000, 800 },
{ 2, 500000, 400 },
{ 5, 0, 200 },
{ 10, 0, 100 },
{ 13, 300000, 75 },
{ 20, 0, 50 },
{ 80, 0, 13 }, /*
* Note: Data sheet lists 12.5 ms sleep time.
* Round up a half millisecond for msleep().
*/
{ 100, 0, 0 }
};
enum isl29028_als_ir_mode { enum isl29028_als_ir_mode {
ISL29028_MODE_NONE = 0, ISL29028_MODE_NONE = 0,
...@@ -76,32 +97,37 @@ enum isl29028_als_ir_mode { ...@@ -76,32 +97,37 @@ enum isl29028_als_ir_mode {
struct isl29028_chip { struct isl29028_chip {
struct mutex lock; struct mutex lock;
struct regmap *regmap; struct regmap *regmap;
unsigned int prox_sampling; int prox_sampling_int;
int prox_sampling_frac;
bool enable_prox; bool enable_prox;
int lux_scale; int lux_scale;
enum isl29028_als_ir_mode als_ir_mode; enum isl29028_als_ir_mode als_ir_mode;
}; };
static int isl29028_find_prox_sleep_time_index(int sampling) static int isl29028_find_prox_sleep_index(int sampling_int, int sampling_fract)
{ {
unsigned int period = DIV_ROUND_UP(1000, sampling);
int i; int i;
for (i = 0; i < ARRAY_SIZE(isl29028_prox_sleep_time); ++i) { for (i = 0; i < ARRAY_SIZE(isl29028_prox_data); ++i) {
if (period >= isl29028_prox_sleep_time[i]) if (isl29028_prox_data[i].sampling_int == sampling_int &&
break; isl29028_prox_data[i].sampling_fract == sampling_fract)
return i;
} }
return i; return -EINVAL;
} }
static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
unsigned int sampling) int sampling_int, int sampling_fract)
{ {
struct device *dev = regmap_get_device(chip->regmap); struct device *dev = regmap_get_device(chip->regmap);
int sleep_index, ret; int sleep_index, ret;
sleep_index = isl29028_find_prox_sleep_time_index(sampling); sleep_index = isl29028_find_prox_sleep_index(sampling_int,
sampling_fract);
if (sleep_index < 0)
return sleep_index;
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
ISL29028_CONF_PROX_SLP_MASK, ISL29028_CONF_PROX_SLP_MASK,
sleep_index << ISL29028_CONF_PROX_SLP_SH); sleep_index << ISL29028_CONF_PROX_SLP_SH);
...@@ -112,16 +138,18 @@ static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, ...@@ -112,16 +138,18 @@ static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
return ret; return ret;
} }
chip->prox_sampling = sampling; chip->prox_sampling_int = sampling_int;
chip->prox_sampling_frac = sampling_fract;
return ret; return ret;
} }
static int isl29028_enable_proximity(struct isl29028_chip *chip) static int isl29028_enable_proximity(struct isl29028_chip *chip)
{ {
int sleep_index, ret; int prox_index, ret;
ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling); ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling_int,
chip->prox_sampling_frac);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -132,8 +160,12 @@ static int isl29028_enable_proximity(struct isl29028_chip *chip) ...@@ -132,8 +160,12 @@ static int isl29028_enable_proximity(struct isl29028_chip *chip)
return ret; return ret;
/* Wait for conversion to be complete for first sample */ /* Wait for conversion to be complete for first sample */
sleep_index = isl29028_find_prox_sleep_time_index(chip->prox_sampling); prox_index = isl29028_find_prox_sleep_index(chip->prox_sampling_int,
msleep(isl29028_prox_sleep_time[sleep_index]); chip->prox_sampling_frac);
if (prox_index < 0)
return prox_index;
msleep(isl29028_prox_data[prox_index].sleep_time);
return 0; return 0;
} }
...@@ -361,7 +393,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev, ...@@ -361,7 +393,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
break; break;
} }
ret = isl29028_set_proxim_sampling(chip, val); ret = isl29028_set_proxim_sampling(chip, val, val2);
break; break;
case IIO_LIGHT: case IIO_LIGHT:
if (mask != IIO_CHAN_INFO_SCALE) { if (mask != IIO_CHAN_INFO_SCALE) {
...@@ -439,7 +471,8 @@ static int isl29028_read_raw(struct iio_dev *indio_dev, ...@@ -439,7 +471,8 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_PROXIMITY) if (chan->type != IIO_PROXIMITY)
break; break;
*val = chip->prox_sampling; *val = chip->prox_sampling_int;
*val2 = chip->prox_sampling_frac;
ret = IIO_VAL_INT; ret = IIO_VAL_INT;
break; break;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
...@@ -472,7 +505,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev, ...@@ -472,7 +505,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
} }
static IIO_CONST_ATTR(in_proximity_sampling_frequency_available, static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
"1 3 5 10 13 20 83 100"); "1.25 2.5 5 10 13.3 20 80 100");
static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000"); static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000");
#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) #define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
...@@ -571,7 +604,8 @@ static int isl29028_probe(struct i2c_client *client, ...@@ -571,7 +604,8 @@ static int isl29028_probe(struct i2c_client *client,
} }
chip->enable_prox = false; chip->enable_prox = false;
chip->prox_sampling = 20; chip->prox_sampling_int = 20;
chip->prox_sampling_frac = 0;
chip->lux_scale = 2000; chip->lux_scale = 2000;
ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0); ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
...@@ -664,6 +698,7 @@ static const struct dev_pm_ops isl29028_pm_ops = { ...@@ -664,6 +698,7 @@ static const struct dev_pm_ops isl29028_pm_ops = {
static const struct i2c_device_id isl29028_id[] = { static const struct i2c_device_id isl29028_id[] = {
{"isl29028", 0}, {"isl29028", 0},
{"isl29030", 0},
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, isl29028_id); MODULE_DEVICE_TABLE(i2c, isl29028_id);
...@@ -671,6 +706,7 @@ MODULE_DEVICE_TABLE(i2c, isl29028_id); ...@@ -671,6 +706,7 @@ MODULE_DEVICE_TABLE(i2c, isl29028_id);
static const struct of_device_id isl29028_of_match[] = { static const struct of_device_id isl29028_of_match[] = {
{ .compatible = "isl,isl29028", }, /* for backward compat., don't use */ { .compatible = "isl,isl29028", }, /* for backward compat., don't use */
{ .compatible = "isil,isl29028", }, { .compatible = "isil,isl29028", },
{ .compatible = "isil,isl29030", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, isl29028_of_match); MODULE_DEVICE_TABLE(of, isl29028_of_match);
......
此差异已折叠。
此差异已折叠。
...@@ -48,8 +48,6 @@ static int st_magn_spi_remove(struct spi_device *spi) ...@@ -48,8 +48,6 @@ static int st_magn_spi_remove(struct spi_device *spi)
} }
static const struct spi_device_id st_magn_id_table[] = { static const struct spi_device_id st_magn_id_table[] = {
{ LSM303DLHC_MAGN_DEV_NAME },
{ LSM303DLM_MAGN_DEV_NAME },
{ LIS3MDL_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME },
{ LSM303AGR_MAGN_DEV_NAME }, { LSM303AGR_MAGN_DEV_NAME },
{}, {},
......
...@@ -23,7 +23,7 @@ config BMP280 ...@@ -23,7 +23,7 @@ config BMP280
select BMP280_SPI if (SPI_MASTER) select BMP280_SPI if (SPI_MASTER)
help help
Say yes here to build support for Bosch Sensortec BMP180 and BMP280 Say yes here to build support for Bosch Sensortec BMP180 and BMP280
pressure and temperature sensors. Also supports the BE280 with pressure and temperature sensors. Also supports the BME280 with
an additional humidity sensor channel. an additional humidity sensor channel.
To compile this driver as a module, choose M here: the core module To compile this driver as a module, choose M here: the core module
......
...@@ -568,6 +568,8 @@ static const struct iio_trigger_ops st_press_trigger_ops = { ...@@ -568,6 +568,8 @@ static const struct iio_trigger_ops st_press_trigger_ops = {
int st_press_common_probe(struct iio_dev *indio_dev) int st_press_common_probe(struct iio_dev *indio_dev)
{ {
struct st_sensor_data *press_data = iio_priv(indio_dev); struct st_sensor_data *press_data = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata =
(struct st_sensors_platform_data *)press_data->dev->platform_data;
int irq = press_data->get_irq_data_ready(indio_dev); int irq = press_data->get_irq_data_ready(indio_dev);
int err; int err;
...@@ -603,10 +605,8 @@ int st_press_common_probe(struct iio_dev *indio_dev) ...@@ -603,10 +605,8 @@ int st_press_common_probe(struct iio_dev *indio_dev)
press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz; press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
/* Some devices don't support a data ready pin. */ /* Some devices don't support a data ready pin. */
if (!press_data->dev->platform_data && if (!pdata && press_data->sensor_settings->drdy_irq.addr)
press_data->sensor_settings->drdy_irq.addr) pdata = (struct st_sensors_platform_data *)&default_press_pdata;
press_data->dev->platform_data =
(struct st_sensors_platform_data *)&default_press_pdata;
err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data); err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
if (err < 0) if (err < 0)
......
...@@ -867,12 +867,13 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, ...@@ -867,12 +867,13 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev,
{ {
int ret; int ret;
unsigned int val; unsigned int val;
long timeout;
zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt"); zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt");
ret = wait_for_completion_interruptible_timeout( timeout = wait_for_completion_interruptible_timeout(
&private->data_ready, ZPA2326_CONVERSION_JIFFIES); &private->data_ready, ZPA2326_CONVERSION_JIFFIES);
if (ret > 0) if (timeout > 0)
/* /*
* Interrupt handler completed before timeout: return operation * Interrupt handler completed before timeout: return operation
* status. * status.
...@@ -882,13 +883,16 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, ...@@ -882,13 +883,16 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev,
/* Clear all interrupts just to be sure. */ /* Clear all interrupts just to be sure. */
regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val); regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val);
if (!ret) if (!timeout) {
/* Timed out. */ /* Timed out. */
zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)",
timeout);
ret = -ETIME; ret = -ETIME;
} else if (timeout < 0) {
if (ret != -ERESTARTSYS) zpa2326_warn(indio_dev,
zpa2326_warn(indio_dev, "no one shot interrupt occurred (%d)", "wait for one shot interrupt cancelled");
ret); ret = -ERESTARTSYS;
}
return ret; return ret;
} }
......
...@@ -176,13 +176,13 @@ static int as3935_read_raw(struct iio_dev *indio_dev, ...@@ -176,13 +176,13 @@ static int as3935_read_raw(struct iio_dev *indio_dev,
if (ret) if (ret)
return ret; return ret;
if (m == IIO_CHAN_INFO_RAW)
return IIO_VAL_INT;
/* storm out of range */ /* storm out of range */
if (*val == AS3935_DATA_MASK) if (*val == AS3935_DATA_MASK)
return -EINVAL; return -EINVAL;
if (m == IIO_CHAN_INFO_RAW)
return IIO_VAL_INT;
if (m == IIO_CHAN_INFO_PROCESSED) if (m == IIO_CHAN_INFO_PROCESSED)
*val *= 1000; *val *= 1000;
break; break;
......
...@@ -878,8 +878,7 @@ static void sx9500_gpio_probe(struct i2c_client *client, ...@@ -878,8 +878,7 @@ static void sx9500_gpio_probe(struct i2c_client *client,
dev = &client->dev; dev = &client->dev;
data->gpiod_rst = devm_gpiod_get_index(dev, SX9500_GPIO_RESET, data->gpiod_rst = devm_gpiod_get(dev, SX9500_GPIO_RESET, GPIOD_OUT_HIGH);
0, GPIOD_OUT_HIGH);
if (IS_ERR(data->gpiod_rst)) { if (IS_ERR(data->gpiod_rst)) {
dev_warn(dev, "gpio get reset pin failed\n"); dev_warn(dev, "gpio get reset pin failed\n");
data->gpiod_rst = NULL; data->gpiod_rst = NULL;
......
...@@ -267,6 +267,7 @@ static int maxim_thermocouple_remove(struct spi_device *spi) ...@@ -267,6 +267,7 @@ static int maxim_thermocouple_remove(struct spi_device *spi)
static const struct spi_device_id maxim_thermocouple_id[] = { static const struct spi_device_id maxim_thermocouple_id[] = {
{"max6675", MAX6675}, {"max6675", MAX6675},
{"max31855", MAX31855}, {"max31855", MAX31855},
{"max31856", MAX31855},
{}, {},
}; };
MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id); MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册