2nd set of IIO new driver, cleanups and features for the 5.16 cycle
New device support * adrf6780 microwave upconverter. - New driver for this interesting device including bindings. Features * lite-on ltr501 - Add dt-bindings including vendor ID and of_device_id table. - Add regulator support. * sensiron,scd4x - Add reporting of channel scale. Cleanups including fixes for things in this cycle * Tree wide: Another set of dev_err_probe() introductions to reduce noise in logs when deferred probing is needed and provide more debug info. Devices included this time: - amlogic,meson_saradc - capella,cm3605 - fsl,imx7d - maxim,max1118 - maxim,max1241 - nxp,lpc18xx - qcom,pm8xxxx-xoadc - rockchip,saradc - sharp,gp2ap002 - sterricson,ab8500 - ti,ads7950 * core - iio:buffer - Fix a path where a ret value is not intialized. * channel-mux - Add support to mux core subsystem for a settling delay and use it in the iio-channel-mux driver. - Fix a few dt binding warnings. * nxp,lpc18xx - Convert to devm_ functions for all of probe and drop remove() * st,lsm6dsx - Suppress a warning due to lack of handling of an enum *_MAX entry that is just there to get the size. * st,stm32-adc - Add generic channel binding, deprecating the old approach. - Add nvmem support to get calibration data for the vrefint channel and use it to perform such calibration. - Add a binding for sample-time to the generic channel description as it can be per channel. * ti,adc128s052 - Use devm_ managed functions and drop remove() * vti,sca3000 - Use sign_extend32() rather than opencoding. * xilinx,xadc - Drop irq field from state structure as now just used in probe. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmFxyHIRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FojRCBAAgIbn0CdCVo5cmYZNV1cIcc1ReGBbfgHq HopVcs9XDO4aHfzTLSa8bRhAp+bWCLq+ld/3vQ4tWDAJCXM4wh6VW9GOOMhqtDhr TWYPC9jlH+/z5PWzySozCJ6CsHjU5Z96q+SbQGSfoQZr1xelCO9J51gbT0hZS3Dr LntwcWQWCCC3LW0WGj4ApKJnW4exqi30ty09Qwfujpa9X5nO2soawSBApfIlInR8 rUrE0WBaE8/rx8ORwngrj+Tfz5F3WNz77KooFR6oGkXOuMOxSLIWS77nUntEQbUc SRfHUJTTUbL5uI+8ZWZe7IWZzL/OX6uyicsJwcrLxzhw0Z/+i714fIMVLxAEHWqD D+JgcKiGYO/aPgl23XDOYb8I010TF9tf0bkbNcxzOBa4xdhixBLeg5PyWOMhwUKt uaslEGKduoJ4S7olcebZJAt3wEHp8YXn71LSkHt6M+fC7rRtzpfSK/L35ZHTb7PI JxzWGYaD7ZdIHd4y3f7KOU/B2/aEv+ez6NLC+yb8+Bs15nZ/B17zLDAmcd+THvxi QOBpm/K12rDfqSGV663UCtIq+elScx0J7bIuZG1JwPIfZAiwzBNrOTLZG0o+b3bD JIYIoZX+45tCR5i3Lukk27QhJ2hJ/7VVOcSQ3aPcgoMTl6QCTV8Fo2oofAZ1JIMo yHjv28K4ZyA= =XWvW -----END PGP SIGNATURE----- Merge tag 'iio-for-5.16b' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next Jonathan writes: 2nd set of IIO new driver, cleanups and features for the 5.16 cycle New device support * adrf6780 microwave upconverter. - New driver for this interesting device including bindings. Features * lite-on ltr501 - Add dt-bindings including vendor ID and of_device_id table. - Add regulator support. * sensiron,scd4x - Add reporting of channel scale. Cleanups including fixes for things in this cycle * Tree wide: Another set of dev_err_probe() introductions to reduce noise in logs when deferred probing is needed and provide more debug info. Devices included this time: - amlogic,meson_saradc - capella,cm3605 - fsl,imx7d - maxim,max1118 - maxim,max1241 - nxp,lpc18xx - qcom,pm8xxxx-xoadc - rockchip,saradc - sharp,gp2ap002 - sterricson,ab8500 - ti,ads7950 * core - iio:buffer - Fix a path where a ret value is not intialized. * channel-mux - Add support to mux core subsystem for a settling delay and use it in the iio-channel-mux driver. - Fix a few dt binding warnings. * nxp,lpc18xx - Convert to devm_ functions for all of probe and drop remove() * st,lsm6dsx - Suppress a warning due to lack of handling of an enum *_MAX entry that is just there to get the size. * st,stm32-adc - Add generic channel binding, deprecating the old approach. - Add nvmem support to get calibration data for the vrefint channel and use it to perform such calibration. - Add a binding for sample-time to the generic channel description as it can be per channel. * ti,adc128s052 - Use devm_ managed functions and drop remove() * vti,sca3000 - Use sign_extend32() rather than opencoding. * xilinx,xadc - Drop irq field from state structure as now just used in probe. * tag 'iio-for-5.16b' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (36 commits) dt-bindings: iio: frequency: add adrf6780 doc iio: frequency: adrf6780: add support for ADRF6780 iio: chemical: scd4x: Add a scale for the co2 concentration reading dt-bindings: iio: io-channel-mux: allow duplicate channel, labels dt-bindings: iio: io-channel-mux: add optional #io-channel-cells iio: adc: adc128s052: Simplify adc128_probe() iio: multiplexer: iio-mux: Support settle-time-us property dt-bindings: iio: io-channel-mux: Add property for settle time mux: add support for delay after muxing iio: adc: stm32-adc: use generic binding for sample-time iio: adc: stm32-adc: add vrefint calibration support iio: adc: stm32-adc: add support of internal channels iio: adc: stm32-adc: add support of generic channels binding iio: adc: stm32-adc: split channel init into several routines dt-bindings: iio: stm32-adc: add nvmem support for vrefint internal channel dt-bindings: iio: stm32-adc: add generic channel binding iio: accel: sca3000: Use sign_extend32() instead of opencoding sign extension. iio: xilinx-xadc: Remove `irq` field from state struct iio: imu: st_lsm6dsx: Avoid potential array overflow in st_lsm6dsx_set_odr() iio: light: gp2ap002: Make use of the helper function dev_err_probe() ...
This commit is contained in:
commit
b6df1fc1e3
@ -222,6 +222,12 @@ patternProperties:
|
||||
'#io-channel-cells':
|
||||
const: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
interrupts:
|
||||
description: |
|
||||
IRQ Line for the ADC instance. Valid values are:
|
||||
@ -256,6 +262,7 @@ patternProperties:
|
||||
- 20 channels, numbered from 0 to 19 (for in0..in19) on stm32h7 and
|
||||
stm32mp1.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
deprecated: true
|
||||
|
||||
st,adc-diff-channels:
|
||||
description: |
|
||||
@ -265,7 +272,9 @@ patternProperties:
|
||||
<vinp vinn>, <vinp vinn>,... vinp and vinn are numbered from 0 to 19.
|
||||
|
||||
Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is
|
||||
required. Both properties can be used together. Some channels can be
|
||||
required if no adc generic channel is defined. These legacy channel
|
||||
properties are exclusive with adc generic channel bindings.
|
||||
Both properties can be used together. Some channels can be
|
||||
used as single-ended and some other ones as differential (mixed). But
|
||||
channels can't be configured both as single-ended and differential.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
@ -279,6 +288,7 @@ patternProperties:
|
||||
"vinn" indicates negative input number
|
||||
minimum: 0
|
||||
maximum: 19
|
||||
deprecated: true
|
||||
|
||||
st,min-sample-time-nsecs:
|
||||
description:
|
||||
@ -289,6 +299,50 @@ patternProperties:
|
||||
list, to set sample time resp. for all channels, or independently for
|
||||
each channel.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
deprecated: true
|
||||
|
||||
nvmem-cells:
|
||||
items:
|
||||
- description: Phandle to the calibration vrefint data provided by otp
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: vrefint
|
||||
|
||||
patternProperties:
|
||||
"^channel@([0-9]|1[0-9])$":
|
||||
type: object
|
||||
$ref: "adc.yaml"
|
||||
description: Represents the external channels which are connected to the ADC.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 19
|
||||
|
||||
label:
|
||||
description: |
|
||||
Unique name to identify which channel this is.
|
||||
Reserved label names "vddcore", "vrefint" and "vbat"
|
||||
are used to identify internal channels with matching names.
|
||||
|
||||
diff-channels:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 19
|
||||
|
||||
st,min-sample-time-ns:
|
||||
description: |
|
||||
Minimum sampling time in nanoseconds. Depending on hardware (board)
|
||||
e.g. high/low analog input source impedance, fine tune of ADC
|
||||
sampling time may be recommended.
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
@ -369,12 +423,6 @@ patternProperties:
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
anyOf:
|
||||
- required:
|
||||
- st,adc-channels
|
||||
- required:
|
||||
- st,adc-diff-channels
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -451,4 +499,50 @@ examples:
|
||||
// other adc child node follow...
|
||||
};
|
||||
|
||||
- |
|
||||
// Example 3: with stm32mp157c to setup ADC2 with:
|
||||
// - internal channels 13, 14, 15.
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/stm32mp1-clks.h>
|
||||
adc122: adc@48003000 {
|
||||
compatible = "st,stm32mp1-adc-core";
|
||||
reg = <0x48003000 0x400>;
|
||||
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&rcc ADC12>, <&rcc ADC12_K>;
|
||||
clock-names = "bus", "adc";
|
||||
booster-supply = <&booster>;
|
||||
vdd-supply = <&vdd>;
|
||||
vdda-supply = <&vdda>;
|
||||
vref-supply = <&vref>;
|
||||
st,syscfg = <&syscfg>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
adc@100 {
|
||||
compatible = "st,stm32mp1-adc";
|
||||
#io-channel-cells = <1>;
|
||||
reg = <0x100>;
|
||||
interrupts = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
channel@13 {
|
||||
reg = <13>;
|
||||
label = "vrefint";
|
||||
st,min-sample-time-ns = <9000>;
|
||||
};
|
||||
channel@14 {
|
||||
reg = <14>;
|
||||
label = "vddcore";
|
||||
st,min-sample-time-ns = <9000>;
|
||||
};
|
||||
channel@15 {
|
||||
reg = <15>;
|
||||
label = "vbat";
|
||||
st,min-sample-time-ns = <9000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
@ -0,0 +1,131 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/frequency/adi,adrf6780.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ADRF6780 Microwave Upconverter
|
||||
|
||||
maintainers:
|
||||
- Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
|
||||
description: |
|
||||
Wideband, microwave upconverter optimized for point to point microwave
|
||||
radio designs operating in the 5.9 GHz to 23.6 GHz frequency range.
|
||||
|
||||
https://www.analog.com/en/products/adrf6780.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adrf6780
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 1000000
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Definition of the external clock.
|
||||
minItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: lo_in
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
adi,vga-buff-en:
|
||||
description:
|
||||
RF Variable Gain Amplifier Buffer Enable. Gain is controlled by
|
||||
the voltage on the VATT pin.
|
||||
type: boolean
|
||||
|
||||
adi,lo-buff-en:
|
||||
description:
|
||||
Local Oscillator Amplifier Enable. Disable to put the part in
|
||||
a power down state.
|
||||
type: boolean
|
||||
|
||||
adi,if-mode-en:
|
||||
description:
|
||||
Intermediate Frequency Mode Enable. Either IF Mode or I/Q Mode
|
||||
can be enabled at a time.
|
||||
type: boolean
|
||||
|
||||
adi,iq-mode-en:
|
||||
description:
|
||||
I/Q Mode Enable. Either IF Mode or I/Q Mode can be enabled at a
|
||||
time.
|
||||
type: boolean
|
||||
|
||||
adi,lo-x2-en:
|
||||
description:
|
||||
Double the Local Oscillator output frequency from the Local
|
||||
Oscillator Input Frequency. Either LOx1 or LOx2 can be enabled
|
||||
at a time.
|
||||
type: boolean
|
||||
|
||||
adi,lo-ppf-en:
|
||||
description:
|
||||
Local Oscillator input frequency equal to the Local Oscillator
|
||||
output frequency (LO x1). Either LOx1 or LOx2 can be enabled
|
||||
at a time.
|
||||
type: boolean
|
||||
|
||||
adi,lo-en:
|
||||
description:
|
||||
Enable additional cirtuitry in the LO chain. Disable to put the
|
||||
part in a power down state.
|
||||
type: boolean
|
||||
|
||||
adi,uc-bias-en:
|
||||
description:
|
||||
Enable all bias circuitry thourghout the entire part.
|
||||
Disable to put the part in a power down state.
|
||||
type: boolean
|
||||
|
||||
adi,lo-sideband:
|
||||
description:
|
||||
Switch to the Lower LO Sideband. By default the Upper LO
|
||||
sideband is enabled.
|
||||
type: boolean
|
||||
|
||||
adi,vdet-out-en:
|
||||
description:
|
||||
VDET Output Select Enable. Expose the RF detector output to the
|
||||
VDET external pin.
|
||||
type: boolean
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
dependencies:
|
||||
adi,lo-x2-en: [ "adi,lo-en" ]
|
||||
adi,lo-ppf-en: [ "adi,lo-en" ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
adrf6780@0 {
|
||||
compatible = "adi,adrf6780";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
clocks = <&adrf6780_lo>;
|
||||
clock-names = "lo_in";
|
||||
};
|
||||
};
|
||||
...
|
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/liteon,ltr501.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: LiteON LTR501 I2C Proximity and Light sensor
|
||||
|
||||
maintainers:
|
||||
- Nikita Travkin <nikita@trvn.ru>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- liteon,ltr501
|
||||
- liteon,ltr559
|
||||
- liteon,ltr301
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
vddio-supply: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
light-sensor@23 {
|
||||
compatible = "liteon,ltr559";
|
||||
reg = <0x23>;
|
||||
vdd-supply = <&pm8916_l17>;
|
||||
vddio-supply = <&pm8916_l6>;
|
||||
|
||||
interrupt-parent = <&msmgpio>;
|
||||
interrupts = <115 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
@ -35,9 +35,18 @@ properties:
|
||||
mux-control-names: true
|
||||
|
||||
channels:
|
||||
$ref: /schemas/types.yaml#/definitions/string-array
|
||||
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
description:
|
||||
List of strings, labeling the mux controller states.
|
||||
List of strings, labeling the mux controller states. An empty
|
||||
string for a state means that the channel is not available.
|
||||
|
||||
settle-time-us:
|
||||
default: 0
|
||||
description:
|
||||
Time required for analog signals to settle after muxing.
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -653,6 +653,8 @@ patternProperties:
|
||||
description: Linux-specific binding
|
||||
"^linx,.*":
|
||||
description: Linx Technologies
|
||||
"^liteon,.*":
|
||||
description: LITE-ON Technology Corp.
|
||||
"^litex,.*":
|
||||
description: LiteX SoC builder
|
||||
"^lltc,.*":
|
||||
|
@ -731,8 +731,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
*val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF;
|
||||
*val = ((*val) << (sizeof(*val) * 8 - 13)) >>
|
||||
(sizeof(*val) * 8 - 13);
|
||||
*val = sign_extend32(*val, 12);
|
||||
} else {
|
||||
/* get the temperature when available */
|
||||
ret = sca3000_read_data_short(st,
|
||||
|
@ -1103,17 +1103,15 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
gpadc->irq_sw = platform_get_irq_byname(pdev, "SW_CONV_END");
|
||||
if (gpadc->irq_sw < 0) {
|
||||
dev_err(dev, "failed to get platform sw_conv_end irq\n");
|
||||
return gpadc->irq_sw;
|
||||
}
|
||||
if (gpadc->irq_sw < 0)
|
||||
return dev_err_probe(dev, gpadc->irq_sw,
|
||||
"failed to get platform sw_conv_end irq\n");
|
||||
|
||||
if (is_ab8500(gpadc->ab8500)) {
|
||||
gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END");
|
||||
if (gpadc->irq_hw < 0) {
|
||||
dev_err(dev, "failed to get platform hw_conv_end irq\n");
|
||||
return gpadc->irq_hw;
|
||||
}
|
||||
if (gpadc->irq_hw < 0)
|
||||
return dev_err_probe(dev, gpadc->irq_hw,
|
||||
"failed to get platform hw_conv_end irq\n");
|
||||
} else {
|
||||
gpadc->irq_hw = 0;
|
||||
}
|
||||
@ -1146,11 +1144,9 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
|
||||
/* The VTVout LDO used to power the AB8500 GPADC */
|
||||
gpadc->vddadc = devm_regulator_get(dev, "vddadc");
|
||||
if (IS_ERR(gpadc->vddadc)) {
|
||||
ret = PTR_ERR(gpadc->vddadc);
|
||||
dev_err(dev, "failed to get vddadc\n");
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(gpadc->vddadc))
|
||||
return dev_err_probe(dev, PTR_ERR(gpadc->vddadc),
|
||||
"failed to get vddadc\n");
|
||||
|
||||
ret = regulator_enable(gpadc->vddadc);
|
||||
if (ret) {
|
||||
|
@ -493,22 +493,16 @@ static int imx7d_adc_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
return dev_err_probe(dev, irq, "Failed getting irq\n");
|
||||
|
||||
info->clk = devm_clk_get(dev, "adc");
|
||||
if (IS_ERR(info->clk)) {
|
||||
ret = PTR_ERR(info->clk);
|
||||
dev_err(dev, "Failed getting clock, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(info->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(info->clk), "Failed getting clock\n");
|
||||
|
||||
info->vref = devm_regulator_get(dev, "vref");
|
||||
if (IS_ERR(info->vref)) {
|
||||
ret = PTR_ERR(info->vref);
|
||||
dev_err(dev,
|
||||
"Failed getting reference voltage, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(info->vref))
|
||||
return dev_err_probe(dev, PTR_ERR(info->vref),
|
||||
"Failed getting reference voltage\n");
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
|
@ -115,6 +115,23 @@ static const struct iio_info lpc18xx_adc_info = {
|
||||
.read_raw = lpc18xx_adc_read_raw,
|
||||
};
|
||||
|
||||
static void lpc18xx_clear_cr_reg(void *data)
|
||||
{
|
||||
struct lpc18xx_adc *adc = data;
|
||||
|
||||
writel(0, adc->base + LPC18XX_ADC_CR);
|
||||
}
|
||||
|
||||
static void lpc18xx_clk_disable(void *clk)
|
||||
{
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
static void lpc18xx_regulator_disable(void *vref)
|
||||
{
|
||||
regulator_disable(vref);
|
||||
}
|
||||
|
||||
static int lpc18xx_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
@ -127,7 +144,6 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->dev = &pdev->dev;
|
||||
mutex_init(&adc->lock);
|
||||
@ -137,19 +153,17 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(adc->base);
|
||||
|
||||
adc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(adc->clk)) {
|
||||
dev_err(&pdev->dev, "error getting clock\n");
|
||||
return PTR_ERR(adc->clk);
|
||||
}
|
||||
if (IS_ERR(adc->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(adc->clk),
|
||||
"error getting clock\n");
|
||||
|
||||
rate = clk_get_rate(adc->clk);
|
||||
clkdiv = DIV_ROUND_UP(rate, LPC18XX_ADC_CLK_TARGET);
|
||||
|
||||
adc->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(adc->vref)) {
|
||||
dev_err(&pdev->dev, "error getting regulator\n");
|
||||
return PTR_ERR(adc->vref);
|
||||
}
|
||||
if (IS_ERR(adc->vref))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(adc->vref),
|
||||
"error getting regulator\n");
|
||||
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->info = &lpc18xx_adc_info;
|
||||
@ -163,44 +177,30 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_regulator_disable, adc->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable clock\n");
|
||||
goto dis_reg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_clk_disable,
|
||||
adc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adc->cr_reg = (clkdiv << LPC18XX_ADC_CR_CLKDIV_SHIFT) |
|
||||
LPC18XX_ADC_CR_PDN;
|
||||
writel(adc->cr_reg, adc->base + LPC18XX_ADC_CR);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
goto dis_clk;
|
||||
}
|
||||
ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_clear_cr_reg, adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
dis_clk:
|
||||
writel(0, adc->base + LPC18XX_ADC_CR);
|
||||
clk_disable_unprepare(adc->clk);
|
||||
dis_reg:
|
||||
regulator_disable(adc->vref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpc18xx_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct lpc18xx_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
writel(0, adc->base + LPC18XX_ADC_CR);
|
||||
clk_disable_unprepare(adc->clk);
|
||||
regulator_disable(adc->vref);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc18xx_adc_match[] = {
|
||||
@ -211,7 +211,6 @@ MODULE_DEVICE_TABLE(of, lpc18xx_adc_match);
|
||||
|
||||
static struct platform_driver lpc18xx_adc_driver = {
|
||||
.probe = lpc18xx_adc_probe,
|
||||
.remove = lpc18xx_adc_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-adc",
|
||||
.of_match_table = lpc18xx_adc_match,
|
||||
|
@ -221,10 +221,9 @@ static int max1118_probe(struct spi_device *spi)
|
||||
|
||||
if (id->driver_data == max1118) {
|
||||
adc->reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(adc->reg)) {
|
||||
dev_err(&spi->dev, "failed to get vref regulator\n");
|
||||
return PTR_ERR(adc->reg);
|
||||
}
|
||||
if (IS_ERR(adc->reg))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(adc->reg),
|
||||
"failed to get vref regulator\n");
|
||||
ret = regulator_enable(adc->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -148,10 +148,9 @@ static int max1241_probe(struct spi_device *spi)
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
adc->vdd = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(adc->vdd)) {
|
||||
dev_err(dev, "failed to get vdd regulator\n");
|
||||
return PTR_ERR(adc->vdd);
|
||||
}
|
||||
if (IS_ERR(adc->vdd))
|
||||
return dev_err_probe(dev, PTR_ERR(adc->vdd),
|
||||
"failed to get vdd regulator\n");
|
||||
|
||||
ret = regulator_enable(adc->vdd);
|
||||
if (ret)
|
||||
@ -164,10 +163,9 @@ static int max1241_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
adc->vref = devm_regulator_get(dev, "vref");
|
||||
if (IS_ERR(adc->vref)) {
|
||||
dev_err(dev, "failed to get vref regulator\n");
|
||||
return PTR_ERR(adc->vref);
|
||||
}
|
||||
if (IS_ERR(adc->vref))
|
||||
return dev_err_probe(dev, PTR_ERR(adc->vref),
|
||||
"failed to get vref regulator\n");
|
||||
|
||||
ret = regulator_enable(adc->vref);
|
||||
if (ret)
|
||||
@ -182,7 +180,8 @@ static int max1241_probe(struct spi_device *spi)
|
||||
adc->shutdown = devm_gpiod_get_optional(dev, "shutdown",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(adc->shutdown))
|
||||
return PTR_ERR(adc->shutdown);
|
||||
return dev_err_probe(dev, PTR_ERR(adc->shutdown),
|
||||
"cannot get shutdown gpio\n");
|
||||
|
||||
if (adc->shutdown)
|
||||
dev_dbg(dev, "shutdown pin passed, low-power mode enabled");
|
||||
|
@ -1230,35 +1230,31 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
priv->clkin = devm_clk_get(&pdev->dev, "clkin");
|
||||
if (IS_ERR(priv->clkin)) {
|
||||
dev_err(&pdev->dev, "failed to get clkin\n");
|
||||
return PTR_ERR(priv->clkin);
|
||||
}
|
||||
if (IS_ERR(priv->clkin))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->clkin),
|
||||
"failed to get clkin\n");
|
||||
|
||||
priv->core_clk = devm_clk_get(&pdev->dev, "core");
|
||||
if (IS_ERR(priv->core_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get core clk\n");
|
||||
return PTR_ERR(priv->core_clk);
|
||||
}
|
||||
if (IS_ERR(priv->core_clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->core_clk),
|
||||
"failed to get core clk\n");
|
||||
|
||||
priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
|
||||
if (IS_ERR(priv->adc_clk)) {
|
||||
if (PTR_ERR(priv->adc_clk) == -ENOENT) {
|
||||
if (PTR_ERR(priv->adc_clk) == -ENOENT)
|
||||
priv->adc_clk = NULL;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "failed to get adc clk\n");
|
||||
return PTR_ERR(priv->adc_clk);
|
||||
}
|
||||
else
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->adc_clk),
|
||||
"failed to get adc clk\n");
|
||||
}
|
||||
|
||||
priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
|
||||
if (IS_ERR(priv->adc_sel_clk)) {
|
||||
if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
|
||||
if (PTR_ERR(priv->adc_sel_clk) == -ENOENT)
|
||||
priv->adc_sel_clk = NULL;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "failed to get adc_sel clk\n");
|
||||
return PTR_ERR(priv->adc_sel_clk);
|
||||
}
|
||||
else
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->adc_sel_clk),
|
||||
"failed to get adc_sel clk\n");
|
||||
}
|
||||
|
||||
/* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
|
||||
@ -1269,10 +1265,9 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
priv->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(priv->vref)) {
|
||||
dev_err(&pdev->dev, "failed to get vref regulator\n");
|
||||
return PTR_ERR(priv->vref);
|
||||
}
|
||||
if (IS_ERR(priv->vref))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->vref),
|
||||
"failed to get vref regulator\n");
|
||||
|
||||
priv->calibscale = MILLION;
|
||||
|
||||
|
@ -910,16 +910,15 @@ static int pm8xxx_xoadc_probe(struct platform_device *pdev)
|
||||
map = dev_get_regmap(dev->parent, NULL);
|
||||
if (!map) {
|
||||
dev_err(dev, "parent regmap unavailable.\n");
|
||||
return -ENXIO;
|
||||
return -ENODEV;
|
||||
}
|
||||
adc->map = map;
|
||||
|
||||
/* Bring up regulator */
|
||||
adc->vref = devm_regulator_get(dev, "xoadc-ref");
|
||||
if (IS_ERR(adc->vref)) {
|
||||
dev_err(dev, "failed to get XOADC VREF regulator\n");
|
||||
return PTR_ERR(adc->vref);
|
||||
}
|
||||
if (IS_ERR(adc->vref))
|
||||
return dev_err_probe(dev, PTR_ERR(adc->vref),
|
||||
"failed to get XOADC VREF regulator\n");
|
||||
ret = regulator_enable(adc->vref);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable XOADC VREF regulator\n");
|
||||
|
@ -360,7 +360,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(info->reset)) {
|
||||
ret = PTR_ERR(info->reset);
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to get saradc-apb\n");
|
||||
|
||||
dev_dbg(&pdev->dev, "no reset control found\n");
|
||||
info->reset = NULL;
|
||||
@ -370,7 +371,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
return dev_err_probe(&pdev->dev, irq, "failed to get irq\n");
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
|
||||
0, dev_name(&pdev->dev), info);
|
||||
@ -380,23 +381,19 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
info->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
|
||||
if (IS_ERR(info->pclk)) {
|
||||
dev_err(&pdev->dev, "failed to get pclk\n");
|
||||
return PTR_ERR(info->pclk);
|
||||
}
|
||||
if (IS_ERR(info->pclk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
|
||||
"failed to get pclk\n");
|
||||
|
||||
info->clk = devm_clk_get(&pdev->dev, "saradc");
|
||||
if (IS_ERR(info->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get adc clock\n");
|
||||
return PTR_ERR(info->clk);
|
||||
}
|
||||
if (IS_ERR(info->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
|
||||
"failed to get adc clock\n");
|
||||
|
||||
info->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(info->vref)) {
|
||||
dev_err(&pdev->dev, "failed to get regulator, %ld\n",
|
||||
PTR_ERR(info->vref));
|
||||
return PTR_ERR(info->vref);
|
||||
}
|
||||
if (IS_ERR(info->vref))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(info->vref),
|
||||
"failed to get regulator\n");
|
||||
|
||||
if (info->reset)
|
||||
rockchip_saradc_reset_controller(info->reset);
|
||||
|
@ -659,6 +659,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
|
||||
priv->cfg = (const struct stm32_adc_priv_cfg *)
|
||||
of_match_device(dev->driver->of_match_table, dev)->data;
|
||||
spin_lock_init(&priv->common.lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->common.base = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
@ -102,6 +102,9 @@
|
||||
#define STM32H7_ADC_CALFACT 0xC4
|
||||
#define STM32H7_ADC_CALFACT2 0xC8
|
||||
|
||||
/* STM32MP1 - ADC2 instance option register */
|
||||
#define STM32MP1_ADC2_OR 0xD0
|
||||
|
||||
/* 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)
|
||||
@ -168,23 +171,30 @@ enum stm32h7_adc_dmngt {
|
||||
#define STM32H7_EOC_MST BIT(2)
|
||||
|
||||
/* STM32H7_ADC_CCR - bit fields */
|
||||
#define STM32H7_VBATEN BIT(24)
|
||||
#define STM32H7_VREFEN BIT(22)
|
||||
#define STM32H7_PRESC_SHIFT 18
|
||||
#define STM32H7_PRESC_MASK GENMASK(21, 18)
|
||||
#define STM32H7_CKMODE_SHIFT 16
|
||||
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
|
||||
|
||||
/* STM32MP1_ADC2_OR - bit fields */
|
||||
#define STM32MP1_VDDCOREEN BIT(0)
|
||||
|
||||
/**
|
||||
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
|
||||
* @base: control registers base cpu addr
|
||||
* @phys_base: control registers base physical addr
|
||||
* @rate: clock rate used for analog circuitry
|
||||
* @vref_mv: vref voltage (mv)
|
||||
* @lock: spinlock
|
||||
*/
|
||||
struct stm32_adc_common {
|
||||
void __iomem *base;
|
||||
phys_addr_t phys_base;
|
||||
unsigned long rate;
|
||||
int vref_mv;
|
||||
spinlock_t lock; /* lock for common register */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
@ -35,12 +36,13 @@
|
||||
#define STM32H7_BOOST_CLKRATE 20000000UL
|
||||
|
||||
#define STM32_ADC_CH_MAX 20 /* max number of channels */
|
||||
#define STM32_ADC_CH_SZ 10 /* max channel name size */
|
||||
#define STM32_ADC_CH_SZ 16 /* max channel name size */
|
||||
#define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */
|
||||
#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */
|
||||
#define STM32_ADC_TIMEOUT_US 100000
|
||||
#define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
|
||||
#define STM32_ADC_HW_STOP_DELAY_MS 100
|
||||
#define STM32_ADC_VREFINT_VOLTAGE 3300
|
||||
|
||||
#define STM32_DMA_BUFFER_SIZE PAGE_SIZE
|
||||
|
||||
@ -77,6 +79,30 @@ enum stm32_adc_extsel {
|
||||
STM32_EXT20,
|
||||
};
|
||||
|
||||
enum stm32_adc_int_ch {
|
||||
STM32_ADC_INT_CH_NONE = -1,
|
||||
STM32_ADC_INT_CH_VDDCORE,
|
||||
STM32_ADC_INT_CH_VREFINT,
|
||||
STM32_ADC_INT_CH_VBAT,
|
||||
STM32_ADC_INT_CH_NB,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32_adc_ic - ADC internal channels
|
||||
* @name: name of the internal channel
|
||||
* @idx: internal channel enum index
|
||||
*/
|
||||
struct stm32_adc_ic {
|
||||
const char *name;
|
||||
u32 idx;
|
||||
};
|
||||
|
||||
static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = {
|
||||
{ "vddcore", STM32_ADC_INT_CH_VDDCORE },
|
||||
{ "vrefint", STM32_ADC_INT_CH_VREFINT },
|
||||
{ "vbat", STM32_ADC_INT_CH_VBAT },
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32_adc_trig_info - ADC trigger info
|
||||
* @name: name of the trigger, corresponding to its source
|
||||
@ -113,6 +139,16 @@ struct stm32_adc_regs {
|
||||
int shift;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32_adc_vrefint - stm32 ADC internal reference voltage data
|
||||
* @vrefint_cal: vrefint calibration value from nvmem
|
||||
* @vrefint_data: vrefint actual value
|
||||
*/
|
||||
struct stm32_adc_vrefint {
|
||||
u32 vrefint_cal;
|
||||
u32 vrefint_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32_adc_regspec - stm32 registers definition
|
||||
* @dr: data register offset
|
||||
@ -126,6 +162,9 @@ struct stm32_adc_regs {
|
||||
* @res: resolution selection register & bitfield
|
||||
* @smpr: smpr1 & smpr2 registers offset array
|
||||
* @smp_bits: smpr1 & smpr2 index and bitfields
|
||||
* @or_vdd: option register & vddcore bitfield
|
||||
* @ccr_vbat: common register & vbat bitfield
|
||||
* @ccr_vref: common register & vrefint bitfield
|
||||
*/
|
||||
struct stm32_adc_regspec {
|
||||
const u32 dr;
|
||||
@ -139,6 +178,9 @@ struct stm32_adc_regspec {
|
||||
const struct stm32_adc_regs res;
|
||||
const u32 smpr[2];
|
||||
const struct stm32_adc_regs *smp_bits;
|
||||
const struct stm32_adc_regs or_vdd;
|
||||
const struct stm32_adc_regs ccr_vbat;
|
||||
const struct stm32_adc_regs ccr_vref;
|
||||
};
|
||||
|
||||
struct stm32_adc;
|
||||
@ -156,6 +198,7 @@ struct stm32_adc;
|
||||
* @unprepare: optional unprepare routine (disable, power-down)
|
||||
* @irq_clear: routine to clear irqs
|
||||
* @smp_cycles: programmable sampling time (ADC clock cycles)
|
||||
* @ts_vrefint_ns: vrefint minimum sampling time in ns
|
||||
*/
|
||||
struct stm32_adc_cfg {
|
||||
const struct stm32_adc_regspec *regs;
|
||||
@ -169,6 +212,7 @@ struct stm32_adc_cfg {
|
||||
void (*unprepare)(struct iio_dev *);
|
||||
void (*irq_clear)(struct iio_dev *indio_dev, u32 msk);
|
||||
const unsigned int *smp_cycles;
|
||||
const unsigned int ts_vrefint_ns;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -193,7 +237,10 @@ struct stm32_adc_cfg {
|
||||
* @pcsel: bitmask to preselect channels on some devices
|
||||
* @smpr_val: sampling time settings (e.g. smpr1 / smpr2)
|
||||
* @cal: optional calibration data on some devices
|
||||
* @vrefint: internal reference voltage data
|
||||
* @chan_name: channel name array
|
||||
* @num_diff: number of differential channels
|
||||
* @int_ch: internal channel indexes array
|
||||
*/
|
||||
struct stm32_adc {
|
||||
struct stm32_adc_common *common;
|
||||
@ -216,7 +263,10 @@ struct stm32_adc {
|
||||
u32 pcsel;
|
||||
u32 smpr_val[2];
|
||||
struct stm32_adc_calib cal;
|
||||
struct stm32_adc_vrefint vrefint;
|
||||
char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
|
||||
u32 num_diff;
|
||||
int int_ch[STM32_ADC_INT_CH_NB];
|
||||
};
|
||||
|
||||
struct stm32_adc_diff_channel {
|
||||
@ -449,6 +499,24 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
|
||||
.smp_bits = stm32h7_smp_bits,
|
||||
};
|
||||
|
||||
static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
|
||||
.dr = STM32H7_ADC_DR,
|
||||
.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
|
||||
.ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
|
||||
.isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
|
||||
.isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
|
||||
.sqr = stm32h7_sq,
|
||||
.exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
|
||||
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
|
||||
STM32H7_EXTSEL_SHIFT },
|
||||
.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
|
||||
.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
|
||||
.smp_bits = stm32h7_smp_bits,
|
||||
.or_vdd = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
|
||||
.ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
|
||||
.ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
|
||||
};
|
||||
|
||||
/*
|
||||
* STM32 ADC registers access routines
|
||||
* @adc: stm32 adc instance
|
||||
@ -487,6 +555,14 @@ static void stm32_adc_set_bits(struct stm32_adc *adc, u32 reg, u32 bits)
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
}
|
||||
|
||||
static void stm32_adc_set_bits_common(struct stm32_adc *adc, u32 reg, u32 bits)
|
||||
{
|
||||
spin_lock(&adc->common->lock);
|
||||
writel_relaxed(readl_relaxed(adc->common->base + reg) | bits,
|
||||
adc->common->base + reg);
|
||||
spin_unlock(&adc->common->lock);
|
||||
}
|
||||
|
||||
static void stm32_adc_clr_bits(struct stm32_adc *adc, u32 reg, u32 bits)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -496,6 +572,14 @@ static void stm32_adc_clr_bits(struct stm32_adc *adc, u32 reg, u32 bits)
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
}
|
||||
|
||||
static void stm32_adc_clr_bits_common(struct stm32_adc *adc, u32 reg, u32 bits)
|
||||
{
|
||||
spin_lock(&adc->common->lock);
|
||||
writel_relaxed(readl_relaxed(adc->common->base + reg) & ~bits,
|
||||
adc->common->base + reg);
|
||||
spin_unlock(&adc->common->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_adc_conv_irq_enable() - Enable end of conversion interrupt
|
||||
* @adc: stm32 adc instance
|
||||
@ -577,6 +661,60 @@ err_clk_dis:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
|
||||
if (adc->int_ch[i] == STM32_ADC_INT_CH_NONE)
|
||||
continue;
|
||||
|
||||
switch (i) {
|
||||
case STM32_ADC_INT_CH_VDDCORE:
|
||||
dev_dbg(&indio_dev->dev, "Enable VDDCore\n");
|
||||
stm32_adc_set_bits(adc, adc->cfg->regs->or_vdd.reg,
|
||||
adc->cfg->regs->or_vdd.mask);
|
||||
break;
|
||||
case STM32_ADC_INT_CH_VREFINT:
|
||||
dev_dbg(&indio_dev->dev, "Enable VREFInt\n");
|
||||
stm32_adc_set_bits_common(adc, adc->cfg->regs->ccr_vref.reg,
|
||||
adc->cfg->regs->ccr_vref.mask);
|
||||
break;
|
||||
case STM32_ADC_INT_CH_VBAT:
|
||||
dev_dbg(&indio_dev->dev, "Enable VBAT\n");
|
||||
stm32_adc_set_bits_common(adc, adc->cfg->regs->ccr_vbat.reg,
|
||||
adc->cfg->regs->ccr_vbat.mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stm32_adc_int_ch_disable(struct stm32_adc *adc)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
|
||||
if (adc->int_ch[i] == STM32_ADC_INT_CH_NONE)
|
||||
continue;
|
||||
|
||||
switch (i) {
|
||||
case STM32_ADC_INT_CH_VDDCORE:
|
||||
stm32_adc_clr_bits(adc, adc->cfg->regs->or_vdd.reg,
|
||||
adc->cfg->regs->or_vdd.mask);
|
||||
break;
|
||||
case STM32_ADC_INT_CH_VREFINT:
|
||||
stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vref.reg,
|
||||
adc->cfg->regs->ccr_vref.mask);
|
||||
break;
|
||||
case STM32_ADC_INT_CH_VBAT:
|
||||
stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vbat.reg,
|
||||
adc->cfg->regs->ccr_vbat.mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_adc_start_conv() - Start conversions for regular channels.
|
||||
* @indio_dev: IIO device instance
|
||||
@ -945,11 +1083,13 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
|
||||
goto pwr_dwn;
|
||||
calib = ret;
|
||||
|
||||
stm32_adc_int_ch_enable(indio_dev);
|
||||
|
||||
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
|
||||
|
||||
ret = stm32h7_adc_enable(indio_dev);
|
||||
if (ret)
|
||||
goto pwr_dwn;
|
||||
goto ch_disable;
|
||||
|
||||
/* Either restore or read calibration result for future reference */
|
||||
if (calib)
|
||||
@ -965,6 +1105,8 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
|
||||
|
||||
disable:
|
||||
stm32h7_adc_disable(indio_dev);
|
||||
ch_disable:
|
||||
stm32_adc_int_ch_disable(adc);
|
||||
pwr_dwn:
|
||||
stm32h7_adc_enter_pwr_down(adc);
|
||||
|
||||
@ -976,6 +1118,7 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
stm32h7_adc_disable(indio_dev);
|
||||
stm32_adc_int_ch_disable(adc);
|
||||
stm32h7_adc_enter_pwr_down(adc);
|
||||
}
|
||||
|
||||
@ -1212,6 +1355,7 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1219,6 +1363,10 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
|
||||
ret = stm32_adc_single_conv(indio_dev, chan, val);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
if (mask == IIO_CHAN_INFO_PROCESSED && adc->vrefint.vrefint_cal)
|
||||
*val = STM32_ADC_VREFINT_VOLTAGE * adc->vrefint.vrefint_cal / *val;
|
||||
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
|
||||
@ -1657,6 +1805,13 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
|
||||
u32 period_ns, shift = smpr->shift, mask = smpr->mask;
|
||||
unsigned int smp, r = smpr->reg;
|
||||
|
||||
/*
|
||||
* For vrefint channel, ensure that the sampling time cannot
|
||||
* be lower than the one specified in the datasheet
|
||||
*/
|
||||
if (channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT])
|
||||
smp_ns = max(smp_ns, adc->cfg->ts_vrefint_ns);
|
||||
|
||||
/* Determine sampling time (ADC clock cycles) */
|
||||
period_ns = NSEC_PER_SEC / adc->common->rate;
|
||||
for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++)
|
||||
@ -1688,7 +1843,10 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
chan->datasheet_name = name;
|
||||
chan->scan_index = scan_index;
|
||||
chan->indexed = 1;
|
||||
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
if (chan->channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT])
|
||||
chan->info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED);
|
||||
else
|
||||
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET);
|
||||
chan->scan_type.sign = 'u';
|
||||
@ -1706,17 +1864,11 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm32_adc *adc)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
|
||||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
struct iio_chan_spec *channels;
|
||||
int scan_index = 0, num_channels = 0, num_diff = 0, ret, i;
|
||||
u32 val, smp = 0;
|
||||
int num_channels = 0, ret;
|
||||
|
||||
ret = of_property_count_u32_elems(node, "st,adc-channels");
|
||||
if (ret > adc_info->max_channels) {
|
||||
@ -1727,24 +1879,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
}
|
||||
|
||||
ret = of_property_count_elems_of_size(node, "st,adc-diff-channels",
|
||||
sizeof(*diff));
|
||||
sizeof(struct stm32_adc_diff_channel));
|
||||
if (ret > adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n");
|
||||
return -EINVAL;
|
||||
} else if (ret > 0) {
|
||||
int size = ret * sizeof(*diff) / sizeof(u32);
|
||||
|
||||
num_diff = ret;
|
||||
adc->num_diff = ret;
|
||||
num_channels += ret;
|
||||
ret = of_property_read_u32_array(node, "st,adc-diff-channels",
|
||||
(u32 *)diff, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!num_channels) {
|
||||
dev_err(&indio_dev->dev, "No channels configured\n");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/* Optional sample time is provided either for each, or all channels */
|
||||
@ -1754,6 +1895,227 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return num_channels;
|
||||
}
|
||||
|
||||
static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev,
|
||||
struct stm32_adc *adc,
|
||||
struct iio_chan_spec *channels)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
|
||||
u32 num_diff = adc->num_diff;
|
||||
int size = num_diff * sizeof(*diff) / sizeof(u32);
|
||||
int scan_index = 0, val, ret, i;
|
||||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
u32 smp = 0;
|
||||
|
||||
if (num_diff) {
|
||||
ret = of_property_read_u32_array(node, "st,adc-diff-channels",
|
||||
(u32 *)diff, size);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Failed to get diff channels %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_diff; i++) {
|
||||
if (diff[i].vinp >= adc_info->max_channels ||
|
||||
diff[i].vinn >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
|
||||
diff[i].vinp, diff[i].vinn);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
|
||||
diff[i].vinp, diff[i].vinn,
|
||||
scan_index, true);
|
||||
scan_index++;
|
||||
}
|
||||
}
|
||||
|
||||
of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) {
|
||||
if (val >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Channel can't be configured both as single-ended & diff */
|
||||
for (i = 0; i < num_diff; i++) {
|
||||
if (val == diff[i].vinp) {
|
||||
dev_err(&indio_dev->dev, "channel %d misconfigured\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
|
||||
0, scan_index, false);
|
||||
scan_index++;
|
||||
}
|
||||
|
||||
for (i = 0; i < scan_index; i++) {
|
||||
/*
|
||||
* Using of_property_read_u32_index(), smp value will only be
|
||||
* modified if valid u32 value can be decoded. This allows to
|
||||
* get either no value, 1 shared value for all indexes, or one
|
||||
* value per channel.
|
||||
*/
|
||||
of_property_read_u32_index(node, "st,min-sample-time-nsecs", i, &smp);
|
||||
|
||||
/* Prepare sampling time settings */
|
||||
stm32_adc_smpr_init(adc, channels[i].channel, smp);
|
||||
}
|
||||
|
||||
return scan_index;
|
||||
}
|
||||
|
||||
static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_name,
|
||||
int chan)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
u16 vrefint;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
|
||||
if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) {
|
||||
adc->int_ch[i] = chan;
|
||||
|
||||
if (stm32_adc_ic[i].idx != STM32_ADC_INT_CH_VREFINT)
|
||||
continue;
|
||||
|
||||
/* Get calibration data for vrefint channel */
|
||||
ret = nvmem_cell_read_u16(&indio_dev->dev, "vrefint", &vrefint);
|
||||
if (ret && ret != -ENOENT) {
|
||||
return dev_err_probe(&indio_dev->dev, ret,
|
||||
"nvmem access error\n");
|
||||
}
|
||||
if (ret == -ENOENT)
|
||||
dev_dbg(&indio_dev->dev, "vrefint calibration not found\n");
|
||||
else
|
||||
adc->vrefint.vrefint_cal = vrefint;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
|
||||
struct stm32_adc *adc,
|
||||
struct iio_chan_spec *channels)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
struct device_node *child;
|
||||
const char *name;
|
||||
int val, scan_index = 0, ret;
|
||||
bool differential;
|
||||
u32 vin[2];
|
||||
|
||||
for_each_available_child_of_node(node, child) {
|
||||
ret = of_property_read_u32(child, "reg", &val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Missing channel index %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = of_property_read_string(child, "label", &name);
|
||||
/* label is optional */
|
||||
if (!ret) {
|
||||
if (strlen(name) >= STM32_ADC_CH_SZ) {
|
||||
dev_err(&indio_dev->dev, "Label %s exceeds %d characters\n",
|
||||
name, STM32_ADC_CH_SZ);
|
||||
return -EINVAL;
|
||||
}
|
||||
strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ);
|
||||
ret = stm32_adc_populate_int_ch(indio_dev, name, val);
|
||||
if (ret)
|
||||
goto err;
|
||||
} else if (ret != -EINVAL) {
|
||||
dev_err(&indio_dev->dev, "Invalid label %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (val >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
differential = false;
|
||||
ret = of_property_read_u32_array(child, "diff-channels", vin, 2);
|
||||
/* diff-channels is optional */
|
||||
if (!ret) {
|
||||
differential = true;
|
||||
if (vin[0] != val || vin[1] >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
|
||||
vin[0], vin[1]);
|
||||
goto err;
|
||||
}
|
||||
} else if (ret != -EINVAL) {
|
||||
dev_err(&indio_dev->dev, "Invalid diff-channels property %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
|
||||
vin[1], scan_index, differential);
|
||||
|
||||
ret = of_property_read_u32(child, "st,min-sample-time-ns", &val);
|
||||
/* st,min-sample-time-ns is optional */
|
||||
if (!ret) {
|
||||
stm32_adc_smpr_init(adc, channels[scan_index].channel, val);
|
||||
if (differential)
|
||||
stm32_adc_smpr_init(adc, vin[1], val);
|
||||
} else if (ret != -EINVAL) {
|
||||
dev_err(&indio_dev->dev, "Invalid st,min-sample-time-ns property %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
scan_index++;
|
||||
}
|
||||
|
||||
return scan_index;
|
||||
|
||||
err:
|
||||
of_node_put(child);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
struct iio_chan_spec *channels;
|
||||
int scan_index = 0, num_channels = 0, ret, i;
|
||||
bool legacy = false;
|
||||
|
||||
for (i = 0; i < STM32_ADC_INT_CH_NB; i++)
|
||||
adc->int_ch[i] = STM32_ADC_INT_CH_NONE;
|
||||
|
||||
num_channels = of_get_available_child_count(node);
|
||||
/* If no channels have been found, fallback to channels legacy properties. */
|
||||
if (!num_channels) {
|
||||
legacy = true;
|
||||
|
||||
ret = stm32_adc_get_legacy_chan_count(indio_dev, adc);
|
||||
if (!ret) {
|
||||
dev_err(indio_dev->dev.parent, "No channel found\n");
|
||||
return -ENODATA;
|
||||
} else if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
num_channels = ret;
|
||||
}
|
||||
|
||||
if (num_channels > adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Channel number [%d] exceeds %d\n",
|
||||
num_channels, adc_info->max_channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (timestamping)
|
||||
num_channels++;
|
||||
|
||||
@ -1762,50 +2124,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) {
|
||||
if (val >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Channel can't be configured both as single-ended & diff */
|
||||
for (i = 0; i < num_diff; i++) {
|
||||
if (val == diff[i].vinp) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"channel %d miss-configured\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
|
||||
0, scan_index, false);
|
||||
scan_index++;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_diff; i++) {
|
||||
if (diff[i].vinp >= adc_info->max_channels ||
|
||||
diff[i].vinn >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
|
||||
diff[i].vinp, diff[i].vinn);
|
||||
return -EINVAL;
|
||||
}
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
|
||||
diff[i].vinp, diff[i].vinn, scan_index,
|
||||
true);
|
||||
scan_index++;
|
||||
}
|
||||
|
||||
for (i = 0; i < scan_index; i++) {
|
||||
/*
|
||||
* Using of_property_read_u32_index(), smp value will only be
|
||||
* modified if valid u32 value can be decoded. This allows to
|
||||
* get either no value, 1 shared value for all indexes, or one
|
||||
* value per channel.
|
||||
*/
|
||||
of_property_read_u32_index(node, "st,min-sample-time-nsecs",
|
||||
i, &smp);
|
||||
/* Prepare sampling time settings */
|
||||
stm32_adc_smpr_init(adc, channels[i].channel, smp);
|
||||
}
|
||||
if (legacy)
|
||||
ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels);
|
||||
else
|
||||
ret = stm32_adc_generic_chan_init(indio_dev, adc, channels);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
scan_index = ret;
|
||||
|
||||
if (timestamping) {
|
||||
struct iio_chan_spec *timestamp = &channels[scan_index];
|
||||
@ -2099,7 +2424,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
|
||||
};
|
||||
|
||||
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
|
||||
.regs = &stm32h7_adc_regspec,
|
||||
.regs = &stm32mp1_adc_regspec,
|
||||
.adc_info = &stm32h7_adc_info,
|
||||
.trigs = stm32h7_adc_trigs,
|
||||
.has_vregready = true,
|
||||
@ -2109,6 +2434,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
|
||||
.unprepare = stm32h7_adc_unprepare,
|
||||
.smp_cycles = stm32h7_adc_smp_cycles,
|
||||
.irq_clear = stm32h7_adc_irq_clear,
|
||||
.ts_vrefint_ns = 4300,
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_adc_of_match[] = {
|
||||
|
@ -132,6 +132,11 @@ static const struct iio_info adc128_info = {
|
||||
.read_raw = adc128_read_raw,
|
||||
};
|
||||
|
||||
static void adc128_disable_regulator(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int adc128_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
@ -151,8 +156,6 @@ static int adc128_probe(struct spi_device *spi)
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->spi = spi;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &adc128_info;
|
||||
@ -167,29 +170,14 @@ static int adc128_probe(struct spi_device *spi)
|
||||
ret = regulator_enable(adc->reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = devm_add_action_or_reset(&spi->dev, adc128_disable_regulator,
|
||||
adc->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto err_disable_regulator;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_regulator:
|
||||
regulator_disable(adc->reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc128_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct adc128 *adc = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
regulator_disable(adc->reg);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id adc128_of_match[] = {
|
||||
@ -231,7 +219,6 @@ static struct spi_driver adc128_driver = {
|
||||
.acpi_match_table = ACPI_PTR(adc128_acpi_match),
|
||||
},
|
||||
.probe = adc128_probe,
|
||||
.remove = adc128_remove,
|
||||
.id_table = adc128_id,
|
||||
};
|
||||
module_spi_driver(adc128_driver);
|
||||
|
@ -600,8 +600,8 @@ static int ti_ads7950_probe(struct spi_device *spi)
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(st->reg)) {
|
||||
dev_err(&spi->dev, "Failed to get regulator \"vref\"\n");
|
||||
ret = PTR_ERR(st->reg);
|
||||
ret = dev_err_probe(&spi->dev, PTR_ERR(st->reg),
|
||||
"Failed to get regulator \"vref\"\n");
|
||||
goto error_destroy_mutex;
|
||||
}
|
||||
|
||||
|
@ -1332,7 +1332,6 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
|
||||
xadc = iio_priv(indio_dev);
|
||||
xadc->ops = id->data;
|
||||
xadc->irq = irq;
|
||||
init_completion(&xadc->completion);
|
||||
mutex_init(&xadc->mutex);
|
||||
spin_lock_init(&xadc->lock);
|
||||
@ -1397,7 +1396,7 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, xadc->irq, xadc->ops->interrupt_handler, 0,
|
||||
ret = devm_request_irq(dev, irq, xadc->ops->interrupt_handler, 0,
|
||||
dev_name(dev), indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1407,7 +1406,7 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xadc->ops->setup(pdev, indio_dev, xadc->irq);
|
||||
ret = xadc->ops->setup(pdev, indio_dev, irq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -67,7 +67,6 @@ struct xadc {
|
||||
spinlock_t lock;
|
||||
|
||||
struct completion completion;
|
||||
int irq;
|
||||
};
|
||||
|
||||
enum xadc_type {
|
||||
|
@ -353,7 +353,11 @@ static int scd4x_read_raw(struct iio_dev *indio_dev,
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (chan->type == IIO_TEMP) {
|
||||
if (chan->type == IIO_CONCENTRATION) {
|
||||
*val = 0;
|
||||
*val2 = 100;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
} else if (chan->type == IIO_TEMP) {
|
||||
*val = 175000;
|
||||
*val2 = 65536;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
@ -503,7 +507,8 @@ static const struct iio_chan_spec scd4x_channels[] = {
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_CO2,
|
||||
.modified = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = SCD4X_CO2,
|
||||
.scan_index = SCD4X_CO2,
|
||||
.scan_type = {
|
||||
|
@ -49,5 +49,17 @@ config ADF4371
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adf4371.
|
||||
|
||||
config ADRF6780
|
||||
tristate "Analog Devices ADRF6780 Microwave Upconverter"
|
||||
depends on SPI
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
Say yes here to build support for Analog Devices ADRF6780
|
||||
5.9 GHz to 23.6 GHz, Wideband, Microwave Upconverter.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adrf6780.
|
||||
|
||||
endmenu
|
||||
endmenu
|
||||
|
@ -7,3 +7,4 @@
|
||||
obj-$(CONFIG_AD9523) += ad9523.o
|
||||
obj-$(CONFIG_ADF4350) += adf4350.o
|
||||
obj-$(CONFIG_ADF4371) += adf4371.o
|
||||
obj-$(CONFIG_ADRF6780) += adrf6780.o
|
||||
|
527
drivers/iio/frequency/adrf6780.c
Normal file
527
drivers/iio/frequency/adrf6780.c
Normal file
@ -0,0 +1,527 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* ADRF6780 driver
|
||||
*
|
||||
* Copyright 2021 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/* ADRF6780 Register Map */
|
||||
#define ADRF6780_REG_CONTROL 0x00
|
||||
#define ADRF6780_REG_ALARM_READBACK 0x01
|
||||
#define ADRF6780_REG_ALARM_MASKS 0x02
|
||||
#define ADRF6780_REG_ENABLE 0x03
|
||||
#define ADRF6780_REG_LINEARIZE 0x04
|
||||
#define ADRF6780_REG_LO_PATH 0x05
|
||||
#define ADRF6780_REG_ADC_CONTROL 0x06
|
||||
#define ADRF6780_REG_ADC_OUTPUT 0x0C
|
||||
|
||||
/* ADRF6780_REG_CONTROL Map */
|
||||
#define ADRF6780_PARITY_EN_MSK BIT(15)
|
||||
#define ADRF6780_SOFT_RESET_MSK BIT(14)
|
||||
#define ADRF6780_CHIP_ID_MSK GENMASK(11, 4)
|
||||
#define ADRF6780_CHIP_ID 0xA
|
||||
#define ADRF6780_CHIP_REVISION_MSK GENMASK(3, 0)
|
||||
|
||||
/* ADRF6780_REG_ALARM_READBACK Map */
|
||||
#define ADRF6780_PARITY_ERROR_MSK BIT(15)
|
||||
#define ADRF6780_TOO_FEW_ERRORS_MSK BIT(14)
|
||||
#define ADRF6780_TOO_MANY_ERRORS_MSK BIT(13)
|
||||
#define ADRF6780_ADDRESS_RANGE_ERROR_MSK BIT(12)
|
||||
|
||||
/* ADRF6780_REG_ENABLE Map */
|
||||
#define ADRF6780_VGA_BUFFER_EN_MSK BIT(8)
|
||||
#define ADRF6780_DETECTOR_EN_MSK BIT(7)
|
||||
#define ADRF6780_LO_BUFFER_EN_MSK BIT(6)
|
||||
#define ADRF6780_IF_MODE_EN_MSK BIT(5)
|
||||
#define ADRF6780_IQ_MODE_EN_MSK BIT(4)
|
||||
#define ADRF6780_LO_X2_EN_MSK BIT(3)
|
||||
#define ADRF6780_LO_PPF_EN_MSK BIT(2)
|
||||
#define ADRF6780_LO_EN_MSK BIT(1)
|
||||
#define ADRF6780_UC_BIAS_EN_MSK BIT(0)
|
||||
|
||||
/* ADRF6780_REG_LINEARIZE Map */
|
||||
#define ADRF6780_RDAC_LINEARIZE_MSK GENMASK(7, 0)
|
||||
|
||||
/* ADRF6780_REG_LO_PATH Map */
|
||||
#define ADRF6780_LO_SIDEBAND_MSK BIT(10)
|
||||
#define ADRF6780_Q_PATH_PHASE_ACCURACY_MSK GENMASK(7, 4)
|
||||
#define ADRF6780_I_PATH_PHASE_ACCURACY_MSK GENMASK(3, 0)
|
||||
|
||||
/* ADRF6780_REG_ADC_CONTROL Map */
|
||||
#define ADRF6780_VDET_OUTPUT_SELECT_MSK BIT(3)
|
||||
#define ADRF6780_ADC_START_MSK BIT(2)
|
||||
#define ADRF6780_ADC_EN_MSK BIT(1)
|
||||
#define ADRF6780_ADC_CLOCK_EN_MSK BIT(0)
|
||||
|
||||
/* ADRF6780_REG_ADC_OUTPUT Map */
|
||||
#define ADRF6780_ADC_STATUS_MSK BIT(8)
|
||||
#define ADRF6780_ADC_VALUE_MSK GENMASK(7, 0)
|
||||
|
||||
struct adrf6780_state {
|
||||
struct spi_device *spi;
|
||||
struct clk *clkin;
|
||||
/* Protect against concurrent accesses to the device */
|
||||
struct mutex lock;
|
||||
bool vga_buff_en;
|
||||
bool lo_buff_en;
|
||||
bool if_mode_en;
|
||||
bool iq_mode_en;
|
||||
bool lo_x2_en;
|
||||
bool lo_ppf_en;
|
||||
bool lo_en;
|
||||
bool uc_bias_en;
|
||||
bool lo_sideband;
|
||||
bool vdet_out_en;
|
||||
u8 data[3] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static int __adrf6780_spi_read(struct adrf6780_state *st, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
int ret;
|
||||
struct spi_transfer t = {0};
|
||||
|
||||
st->data[0] = 0x80 | (reg << 1);
|
||||
st->data[1] = 0x0;
|
||||
st->data[2] = 0x0;
|
||||
|
||||
t.rx_buf = &st->data[0];
|
||||
t.tx_buf = &st->data[0];
|
||||
t.len = 3;
|
||||
|
||||
ret = spi_sync_transfer(st->spi, &t, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = (get_unaligned_be24(&st->data[0]) >> 1) & GENMASK(15, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adrf6780_spi_read(struct adrf6780_state *st, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = adrf6780_spi_read(st, reg, val);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __adrf6780_spi_write(struct adrf6780_state *st,
|
||||
unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
put_unaligned_be24((val << 1) | (reg << 17), &st->data[0]);
|
||||
|
||||
return spi_write(st->spi, &st->data[0], 3);
|
||||
}
|
||||
|
||||
static int adrf6780_spi_write(struct adrf6780_state *st, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = adrf6780_spi_write(st, reg, val);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __adrf6780_spi_update_bits(struct adrf6780_state *st,
|
||||
unsigned int reg, unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
unsigned int data, temp;
|
||||
|
||||
ret = __adrf6780_spi_read(st, reg, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
temp = (data & ~mask) | (val & mask);
|
||||
|
||||
return __adrf6780_spi_write(st, reg, temp);
|
||||
}
|
||||
|
||||
static int adrf6780_spi_update_bits(struct adrf6780_state *st, unsigned int reg,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = __adrf6780_spi_update_bits(st, reg, mask, val);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adrf6780_read_adc_raw(struct adrf6780_state *st, unsigned int *read_val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_ADC_CONTROL,
|
||||
ADRF6780_ADC_EN_MSK |
|
||||
ADRF6780_ADC_CLOCK_EN_MSK |
|
||||
ADRF6780_ADC_START_MSK,
|
||||
FIELD_PREP(ADRF6780_ADC_EN_MSK, 1) |
|
||||
FIELD_PREP(ADRF6780_ADC_CLOCK_EN_MSK, 1) |
|
||||
FIELD_PREP(ADRF6780_ADC_START_MSK, 1));
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/* Recommended delay for the ADC to be ready*/
|
||||
usleep_range(200, 250);
|
||||
|
||||
ret = __adrf6780_spi_read(st, ADRF6780_REG_ADC_OUTPUT, read_val);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
if (!(*read_val & ADRF6780_ADC_STATUS_MSK)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_ADC_CONTROL,
|
||||
ADRF6780_ADC_START_MSK,
|
||||
FIELD_PREP(ADRF6780_ADC_START_MSK, 0));
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
ret = __adrf6780_spi_read(st, ADRF6780_REG_ADC_OUTPUT, read_val);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adrf6780_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long info)
|
||||
{
|
||||
struct adrf6780_state *dev = iio_priv(indio_dev);
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = adrf6780_read_adc_raw(dev, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = data & ADRF6780_ADC_VALUE_MSK;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = adrf6780_spi_read(dev, ADRF6780_REG_LINEARIZE, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = data & ADRF6780_RDAC_LINEARIZE_MSK;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_PHASE:
|
||||
ret = adrf6780_spi_read(dev, ADRF6780_REG_LO_PATH, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_I:
|
||||
*val = data & ADRF6780_I_PATH_PHASE_ACCURACY_MSK;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_MOD_Q:
|
||||
*val = FIELD_GET(ADRF6780_Q_PATH_PHASE_ACCURACY_MSK,
|
||||
data);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adrf6780_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long info)
|
||||
{
|
||||
struct adrf6780_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return adrf6780_spi_write(st, ADRF6780_REG_LINEARIZE, val);
|
||||
case IIO_CHAN_INFO_PHASE:
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_I:
|
||||
return adrf6780_spi_update_bits(st,
|
||||
ADRF6780_REG_LO_PATH,
|
||||
ADRF6780_I_PATH_PHASE_ACCURACY_MSK,
|
||||
FIELD_PREP(ADRF6780_I_PATH_PHASE_ACCURACY_MSK, val));
|
||||
case IIO_MOD_Q:
|
||||
return adrf6780_spi_update_bits(st,
|
||||
ADRF6780_REG_LO_PATH,
|
||||
ADRF6780_Q_PATH_PHASE_ACCURACY_MSK,
|
||||
FIELD_PREP(ADRF6780_Q_PATH_PHASE_ACCURACY_MSK, val));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adrf6780_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned int reg,
|
||||
unsigned int write_val,
|
||||
unsigned int *read_val)
|
||||
{
|
||||
struct adrf6780_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (read_val)
|
||||
return adrf6780_spi_read(st, reg, read_val);
|
||||
else
|
||||
return adrf6780_spi_write(st, reg, write_val);
|
||||
}
|
||||
|
||||
static const struct iio_info adrf6780_info = {
|
||||
.read_raw = adrf6780_read_raw,
|
||||
.write_raw = adrf6780_write_raw,
|
||||
.debugfs_reg_access = &adrf6780_reg_access,
|
||||
};
|
||||
|
||||
#define ADRF6780_CHAN_ADC(_channel) { \
|
||||
.type = IIO_ALTVOLTAGE, \
|
||||
.output = 0, \
|
||||
.indexed = 1, \
|
||||
.channel = _channel, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
|
||||
}
|
||||
|
||||
#define ADRF6780_CHAN_RDAC(_channel) { \
|
||||
.type = IIO_ALTVOLTAGE, \
|
||||
.output = 1, \
|
||||
.indexed = 1, \
|
||||
.channel = _channel, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) \
|
||||
}
|
||||
|
||||
#define ADRF6780_CHAN_IQ_PHASE(_channel, rf_comp) { \
|
||||
.type = IIO_ALTVOLTAGE, \
|
||||
.modified = 1, \
|
||||
.output = 1, \
|
||||
.indexed = 1, \
|
||||
.channel2 = IIO_MOD_##rf_comp, \
|
||||
.channel = _channel, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PHASE) \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adrf6780_channels[] = {
|
||||
ADRF6780_CHAN_ADC(0),
|
||||
ADRF6780_CHAN_RDAC(0),
|
||||
ADRF6780_CHAN_IQ_PHASE(0, I),
|
||||
ADRF6780_CHAN_IQ_PHASE(0, Q),
|
||||
};
|
||||
|
||||
static int adrf6780_reset(struct adrf6780_state *st)
|
||||
{
|
||||
int ret;
|
||||
struct spi_device *spi = st->spi;
|
||||
|
||||
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL,
|
||||
ADRF6780_SOFT_RESET_MSK,
|
||||
FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 1));
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "ADRF6780 SPI software reset failed.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL,
|
||||
ADRF6780_SOFT_RESET_MSK,
|
||||
FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 0));
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "ADRF6780 SPI software reset disable failed.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adrf6780_init(struct adrf6780_state *st)
|
||||
{
|
||||
int ret;
|
||||
unsigned int chip_id, enable_reg, enable_reg_msk;
|
||||
struct spi_device *spi = st->spi;
|
||||
|
||||
/* Perform a software reset */
|
||||
ret = adrf6780_reset(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __adrf6780_spi_read(st, ADRF6780_REG_CONTROL, &chip_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chip_id = FIELD_GET(ADRF6780_CHIP_ID_MSK, chip_id);
|
||||
if (chip_id != ADRF6780_CHIP_ID) {
|
||||
dev_err(&spi->dev, "ADRF6780 Invalid Chip ID.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
enable_reg_msk = ADRF6780_VGA_BUFFER_EN_MSK |
|
||||
ADRF6780_DETECTOR_EN_MSK |
|
||||
ADRF6780_LO_BUFFER_EN_MSK |
|
||||
ADRF6780_IF_MODE_EN_MSK |
|
||||
ADRF6780_IQ_MODE_EN_MSK |
|
||||
ADRF6780_LO_X2_EN_MSK |
|
||||
ADRF6780_LO_PPF_EN_MSK |
|
||||
ADRF6780_LO_EN_MSK |
|
||||
ADRF6780_UC_BIAS_EN_MSK;
|
||||
|
||||
enable_reg = FIELD_PREP(ADRF6780_VGA_BUFFER_EN_MSK, st->vga_buff_en) |
|
||||
FIELD_PREP(ADRF6780_DETECTOR_EN_MSK, 1) |
|
||||
FIELD_PREP(ADRF6780_LO_BUFFER_EN_MSK, st->lo_buff_en) |
|
||||
FIELD_PREP(ADRF6780_IF_MODE_EN_MSK, st->if_mode_en) |
|
||||
FIELD_PREP(ADRF6780_IQ_MODE_EN_MSK, st->iq_mode_en) |
|
||||
FIELD_PREP(ADRF6780_LO_X2_EN_MSK, st->lo_x2_en) |
|
||||
FIELD_PREP(ADRF6780_LO_PPF_EN_MSK, st->lo_ppf_en) |
|
||||
FIELD_PREP(ADRF6780_LO_EN_MSK, st->lo_en) |
|
||||
FIELD_PREP(ADRF6780_UC_BIAS_EN_MSK, st->uc_bias_en);
|
||||
|
||||
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_ENABLE,
|
||||
enable_reg_msk, enable_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_LO_PATH,
|
||||
ADRF6780_LO_SIDEBAND_MSK,
|
||||
FIELD_PREP(ADRF6780_LO_SIDEBAND_MSK, st->lo_sideband));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __adrf6780_spi_update_bits(st, ADRF6780_REG_ADC_CONTROL,
|
||||
ADRF6780_VDET_OUTPUT_SELECT_MSK,
|
||||
FIELD_PREP(ADRF6780_VDET_OUTPUT_SELECT_MSK, st->vdet_out_en));
|
||||
}
|
||||
|
||||
static void adrf6780_properties_parse(struct adrf6780_state *st)
|
||||
{
|
||||
struct spi_device *spi = st->spi;
|
||||
|
||||
st->vga_buff_en = device_property_read_bool(&spi->dev, "adi,vga-buff-en");
|
||||
st->lo_buff_en = device_property_read_bool(&spi->dev, "adi,lo-buff-en");
|
||||
st->if_mode_en = device_property_read_bool(&spi->dev, "adi,if-mode-en");
|
||||
st->iq_mode_en = device_property_read_bool(&spi->dev, "adi,iq-mode-en");
|
||||
st->lo_x2_en = device_property_read_bool(&spi->dev, "adi,lo-x2-en");
|
||||
st->lo_ppf_en = device_property_read_bool(&spi->dev, "adi,lo-ppf-en");
|
||||
st->lo_en = device_property_read_bool(&spi->dev, "adi,lo-en");
|
||||
st->uc_bias_en = device_property_read_bool(&spi->dev, "adi,uc-bias-en");
|
||||
st->lo_sideband = device_property_read_bool(&spi->dev, "adi,lo-sideband");
|
||||
st->vdet_out_en = device_property_read_bool(&spi->dev, "adi,vdet-out-en");
|
||||
}
|
||||
|
||||
static void adrf6780_clk_disable(void *data)
|
||||
{
|
||||
clk_disable_unprepare(data);
|
||||
}
|
||||
|
||||
static void adrf6780_powerdown(void *data)
|
||||
{
|
||||
/* Disable all components in the Enable Register */
|
||||
adrf6780_spi_write(data, ADRF6780_REG_ENABLE, 0x0);
|
||||
}
|
||||
|
||||
static int adrf6780_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct adrf6780_state *st;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
indio_dev->info = &adrf6780_info;
|
||||
indio_dev->name = "adrf6780";
|
||||
indio_dev->channels = adrf6780_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adrf6780_channels);
|
||||
|
||||
st->spi = spi;
|
||||
|
||||
adrf6780_properties_parse(st);
|
||||
|
||||
st->clkin = devm_clk_get(&spi->dev, "lo_in");
|
||||
if (IS_ERR(st->clkin))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
|
||||
"failed to get the LO input clock\n");
|
||||
|
||||
ret = clk_prepare_enable(st->clkin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, adrf6780_clk_disable,
|
||||
st->clkin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
ret = adrf6780_init(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, adrf6780_powerdown, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id adrf6780_id[] = {
|
||||
{ "adrf6780", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adrf6780_id);
|
||||
|
||||
static const struct of_device_id adrf6780_of_match[] = {
|
||||
{ .compatible = "adi,adrf6780" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adrf6780_of_match);
|
||||
|
||||
static struct spi_driver adrf6780_driver = {
|
||||
.driver = {
|
||||
.name = "adrf6780",
|
||||
.of_match_table = adrf6780_of_match,
|
||||
},
|
||||
.probe = adrf6780_probe,
|
||||
.id_table = adrf6780_id,
|
||||
};
|
||||
module_spi_driver(adrf6780_driver);
|
||||
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com");
|
||||
MODULE_DESCRIPTION("Analog Devices ADRF6780");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1281,6 +1281,8 @@ st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
|
||||
int err;
|
||||
|
||||
switch (sensor->id) {
|
||||
case ST_LSM6DSX_ID_GYRO:
|
||||
break;
|
||||
case ST_LSM6DSX_ID_EXT0:
|
||||
case ST_LSM6DSX_ID_EXT1:
|
||||
case ST_LSM6DSX_ID_EXT2:
|
||||
@ -1306,8 +1308,8 @@ st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
default: /* should never occur */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (req_odr > 0) {
|
||||
|
@ -179,7 +179,7 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf,
|
||||
struct iio_buffer *rb = ib->buffer;
|
||||
struct iio_dev *indio_dev = ib->indio_dev;
|
||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||
int ret;
|
||||
int ret = 0;
|
||||
size_t written;
|
||||
|
||||
if (!indio_dev->info)
|
||||
|
@ -159,6 +159,7 @@ static int cm3605_probe(struct platform_device *pdev)
|
||||
struct device_node *np = dev->of_node;
|
||||
enum iio_chan_type ch_type;
|
||||
u32 rset;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*cm3605));
|
||||
@ -195,12 +196,9 @@ static int cm3605_probe(struct platform_device *pdev)
|
||||
|
||||
cm3605->aout = devm_iio_channel_get(dev, "aout");
|
||||
if (IS_ERR(cm3605->aout)) {
|
||||
if (PTR_ERR(cm3605->aout) == -ENODEV) {
|
||||
dev_err(dev, "no ADC, deferring...\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
dev_err(dev, "failed to get AOUT ADC channel\n");
|
||||
return PTR_ERR(cm3605->aout);
|
||||
ret = PTR_ERR(cm3605->aout);
|
||||
ret = (ret == -ENODEV) ? -EPROBE_DEFER : ret;
|
||||
return dev_err_probe(dev, ret, "failed to get AOUT ADC channel\n");
|
||||
}
|
||||
ret = iio_get_channel_type(cm3605->aout, &ch_type);
|
||||
if (ret < 0)
|
||||
@ -211,10 +209,10 @@ static int cm3605_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
cm3605->vdd = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(cm3605->vdd)) {
|
||||
dev_err(dev, "failed to get VDD regulator\n");
|
||||
return PTR_ERR(cm3605->vdd);
|
||||
}
|
||||
if (IS_ERR(cm3605->vdd))
|
||||
return dev_err_probe(dev, PTR_ERR(cm3605->vdd),
|
||||
"failed to get VDD regulator\n");
|
||||
|
||||
ret = regulator_enable(cm3605->vdd);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable VDD regulator\n");
|
||||
@ -223,13 +221,16 @@ static int cm3605_probe(struct platform_device *pdev)
|
||||
|
||||
cm3605->aset = devm_gpiod_get(dev, "aset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(cm3605->aset)) {
|
||||
dev_err(dev, "no ASET GPIO\n");
|
||||
ret = PTR_ERR(cm3605->aset);
|
||||
ret = dev_err_probe(dev, PTR_ERR(cm3605->aset), "no ASET GPIO\n");
|
||||
goto out_disable_vdd;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
|
||||
cm3605_prox_irq, NULL, 0, "cm3605", indio_dev);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return dev_err_probe(dev, irq, "failed to get irq\n");
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, cm3605_prox_irq,
|
||||
NULL, 0, "cm3605", indio_dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to request IRQ\n");
|
||||
goto out_disable_aset;
|
||||
|
@ -503,12 +503,9 @@ static int gp2ap002_probe(struct i2c_client *client,
|
||||
if (!gp2ap002->is_gp2ap002s00f) {
|
||||
gp2ap002->alsout = devm_iio_channel_get(dev, "alsout");
|
||||
if (IS_ERR(gp2ap002->alsout)) {
|
||||
if (PTR_ERR(gp2ap002->alsout) == -ENODEV) {
|
||||
dev_err(dev, "no ADC, deferring...\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
dev_err(dev, "failed to get ALSOUT ADC channel\n");
|
||||
return PTR_ERR(gp2ap002->alsout);
|
||||
ret = PTR_ERR(gp2ap002->alsout);
|
||||
ret = (ret == -ENODEV) ? -EPROBE_DEFER : ret;
|
||||
return dev_err_probe(dev, ret, "failed to get ALSOUT ADC channel\n");
|
||||
}
|
||||
ret = iio_get_channel_type(gp2ap002->alsout, &ch_type);
|
||||
if (ret < 0)
|
||||
@ -521,15 +518,14 @@ static int gp2ap002_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
gp2ap002->vdd = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(gp2ap002->vdd)) {
|
||||
dev_err(dev, "failed to get VDD regulator\n");
|
||||
return PTR_ERR(gp2ap002->vdd);
|
||||
}
|
||||
if (IS_ERR(gp2ap002->vdd))
|
||||
return dev_err_probe(dev, PTR_ERR(gp2ap002->vdd),
|
||||
"failed to get VDD regulator\n");
|
||||
|
||||
gp2ap002->vio = devm_regulator_get(dev, "vio");
|
||||
if (IS_ERR(gp2ap002->vio)) {
|
||||
dev_err(dev, "failed to get VIO regulator\n");
|
||||
return PTR_ERR(gp2ap002->vio);
|
||||
}
|
||||
if (IS_ERR(gp2ap002->vio))
|
||||
return dev_err_probe(dev, PTR_ERR(gp2ap002->vio),
|
||||
"failed to get VIO regulator\n");
|
||||
|
||||
/* Operating voltage 2.4V .. 3.6V according to datasheet */
|
||||
ret = regulator_set_voltage(gp2ap002->vdd, 2400000, 3600000);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/events.h>
|
||||
@ -151,6 +152,7 @@ struct ltr501_chip_info {
|
||||
|
||||
struct ltr501_data {
|
||||
struct i2c_client *client;
|
||||
struct regulator_bulk_data regulators[2];
|
||||
struct mutex lock_als, lock_ps;
|
||||
const struct ltr501_chip_info *chip_info;
|
||||
u8 als_contr, ps_contr;
|
||||
@ -1379,6 +1381,13 @@ static const struct regmap_config ltr501_regmap_config = {
|
||||
.volatile_reg = ltr501_is_volatile_reg,
|
||||
};
|
||||
|
||||
static void ltr501_disable_regulators(void *d)
|
||||
{
|
||||
struct ltr501_data *data = d;
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
|
||||
}
|
||||
|
||||
static int ltr501_powerdown(struct ltr501_data *data)
|
||||
{
|
||||
return ltr501_write_contr(data, data->als_contr &
|
||||
@ -1423,6 +1432,25 @@ static int ltr501_probe(struct i2c_client *client,
|
||||
mutex_init(&data->lock_als);
|
||||
mutex_init(&data->lock_ps);
|
||||
|
||||
data->regulators[0].supply = "vdd";
|
||||
data->regulators[1].supply = "vddio";
|
||||
ret = devm_regulator_bulk_get(&client->dev,
|
||||
ARRAY_SIZE(data->regulators),
|
||||
data->regulators);
|
||||
if (ret)
|
||||
return dev_err_probe(&client->dev, ret,
|
||||
"Failed to get regulators\n");
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
|
||||
data->regulators);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&client->dev,
|
||||
ltr501_disable_regulators, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->reg_it = devm_regmap_field_alloc(&client->dev, regmap,
|
||||
reg_field_it);
|
||||
if (IS_ERR(data->reg_it)) {
|
||||
@ -1581,9 +1609,18 @@ static const struct i2c_device_id ltr501_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltr501_id);
|
||||
|
||||
static const struct of_device_id ltr501_of_match[] = {
|
||||
{ .compatible = "liteon,ltr501", },
|
||||
{ .compatible = "liteon,ltr559", },
|
||||
{ .compatible = "liteon,ltr301", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltr501_of_match);
|
||||
|
||||
static struct i2c_driver ltr501_driver = {
|
||||
.driver = {
|
||||
.name = LTR501_DRV_NAME,
|
||||
.of_match_table = ltr501_of_match,
|
||||
.pm = <r501_pm_ops,
|
||||
.acpi_match_table = ACPI_PTR(ltr_acpi_match),
|
||||
},
|
||||
|
@ -33,6 +33,7 @@ struct mux {
|
||||
struct iio_chan_spec *chan;
|
||||
struct iio_chan_spec_ext_info *ext_info;
|
||||
struct mux_child *child;
|
||||
u32 delay_us;
|
||||
};
|
||||
|
||||
static int iio_mux_select(struct mux *mux, int idx)
|
||||
@ -42,7 +43,8 @@ static int iio_mux_select(struct mux *mux, int idx)
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = mux_control_select(mux->control, chan->channel);
|
||||
ret = mux_control_select_delay(mux->control, chan->channel,
|
||||
mux->delay_us);
|
||||
if (ret < 0) {
|
||||
mux->cached_state = -1;
|
||||
return ret;
|
||||
@ -392,6 +394,9 @@ static int mux_probe(struct platform_device *pdev)
|
||||
mux->parent = parent;
|
||||
mux->cached_state = -1;
|
||||
|
||||
mux->delay_us = 0;
|
||||
of_property_read_u32(np, "settle-time-us", &mux->delay_us);
|
||||
|
||||
indio_dev->name = dev_name(dev);
|
||||
indio_dev->info = &mux_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#define pr_fmt(fmt) "mux-core: " fmt
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
@ -116,6 +117,7 @@ struct mux_chip *mux_chip_alloc(struct device *dev,
|
||||
sema_init(&mux->lock, 1);
|
||||
mux->cached_state = MUX_CACHE_UNKNOWN;
|
||||
mux->idle_state = MUX_IDLE_AS_IS;
|
||||
mux->last_change = ktime_get();
|
||||
}
|
||||
|
||||
device_initialize(&mux_chip->dev);
|
||||
@ -129,6 +131,8 @@ static int mux_control_set(struct mux_control *mux, int state)
|
||||
int ret = mux->chip->ops->set(mux, state);
|
||||
|
||||
mux->cached_state = ret < 0 ? MUX_CACHE_UNKNOWN : state;
|
||||
if (ret >= 0)
|
||||
mux->last_change = ktime_get();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -314,10 +318,25 @@ static int __mux_control_select(struct mux_control *mux, int state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mux_control_delay(struct mux_control *mux, unsigned int delay_us)
|
||||
{
|
||||
ktime_t delayend;
|
||||
s64 remaining;
|
||||
|
||||
if (!delay_us)
|
||||
return;
|
||||
|
||||
delayend = ktime_add_us(mux->last_change, delay_us);
|
||||
remaining = ktime_us_delta(delayend, ktime_get());
|
||||
if (remaining > 0)
|
||||
fsleep(remaining);
|
||||
}
|
||||
|
||||
/**
|
||||
* mux_control_select() - Select the given multiplexer state.
|
||||
* mux_control_select_delay() - Select the given multiplexer state.
|
||||
* @mux: The mux-control to request a change of state from.
|
||||
* @state: The new requested state.
|
||||
* @delay_us: The time to delay (in microseconds) if the mux state is changed.
|
||||
*
|
||||
* On successfully selecting the mux-control state, it will be locked until
|
||||
* there is a call to mux_control_deselect(). If the mux-control is already
|
||||
@ -331,7 +350,8 @@ static int __mux_control_select(struct mux_control *mux, int state)
|
||||
* Return: 0 when the mux-control state has the requested state or a negative
|
||||
* errno on error.
|
||||
*/
|
||||
int mux_control_select(struct mux_control *mux, unsigned int state)
|
||||
int mux_control_select_delay(struct mux_control *mux, unsigned int state,
|
||||
unsigned int delay_us)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -340,18 +360,21 @@ int mux_control_select(struct mux_control *mux, unsigned int state)
|
||||
return ret;
|
||||
|
||||
ret = __mux_control_select(mux, state);
|
||||
if (ret >= 0)
|
||||
mux_control_delay(mux, delay_us);
|
||||
|
||||
if (ret < 0)
|
||||
up(&mux->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mux_control_select);
|
||||
EXPORT_SYMBOL_GPL(mux_control_select_delay);
|
||||
|
||||
/**
|
||||
* mux_control_try_select() - Try to select the given multiplexer state.
|
||||
* mux_control_try_select_delay() - Try to select the given multiplexer state.
|
||||
* @mux: The mux-control to request a change of state from.
|
||||
* @state: The new requested state.
|
||||
* @delay_us: The time to delay (in microseconds) if the mux state is changed.
|
||||
*
|
||||
* On successfully selecting the mux-control state, it will be locked until
|
||||
* mux_control_deselect() called.
|
||||
@ -363,7 +386,8 @@ EXPORT_SYMBOL_GPL(mux_control_select);
|
||||
* Return: 0 when the mux-control state has the requested state or a negative
|
||||
* errno on error. Specifically -EBUSY if the mux-control is contended.
|
||||
*/
|
||||
int mux_control_try_select(struct mux_control *mux, unsigned int state)
|
||||
int mux_control_try_select_delay(struct mux_control *mux, unsigned int state,
|
||||
unsigned int delay_us)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -371,13 +395,15 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state)
|
||||
return -EBUSY;
|
||||
|
||||
ret = __mux_control_select(mux, state);
|
||||
if (ret >= 0)
|
||||
mux_control_delay(mux, delay_us);
|
||||
|
||||
if (ret < 0)
|
||||
up(&mux->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mux_control_try_select);
|
||||
EXPORT_SYMBOL_GPL(mux_control_try_select_delay);
|
||||
|
||||
/**
|
||||
* mux_control_deselect() - Deselect the previously selected multiplexer state.
|
||||
|
@ -16,10 +16,25 @@ struct device;
|
||||
struct mux_control;
|
||||
|
||||
unsigned int mux_control_states(struct mux_control *mux);
|
||||
int __must_check mux_control_select(struct mux_control *mux,
|
||||
unsigned int state);
|
||||
int __must_check mux_control_try_select(struct mux_control *mux,
|
||||
unsigned int state);
|
||||
int __must_check mux_control_select_delay(struct mux_control *mux,
|
||||
unsigned int state,
|
||||
unsigned int delay_us);
|
||||
int __must_check mux_control_try_select_delay(struct mux_control *mux,
|
||||
unsigned int state,
|
||||
unsigned int delay_us);
|
||||
|
||||
static inline int __must_check mux_control_select(struct mux_control *mux,
|
||||
unsigned int state)
|
||||
{
|
||||
return mux_control_select_delay(mux, state, 0);
|
||||
}
|
||||
|
||||
static inline int __must_check mux_control_try_select(struct mux_control *mux,
|
||||
unsigned int state)
|
||||
{
|
||||
return mux_control_try_select_delay(mux, state, 0);
|
||||
}
|
||||
|
||||
int mux_control_deselect(struct mux_control *mux);
|
||||
|
||||
struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <dt-bindings/mux/mux.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
struct mux_chip;
|
||||
@ -33,6 +34,7 @@ struct mux_control_ops {
|
||||
* @states: The number of mux controller states.
|
||||
* @idle_state: The mux controller state to use when inactive, or one
|
||||
* of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
|
||||
* @last_change: Timestamp of last change
|
||||
*
|
||||
* Mux drivers may only change @states and @idle_state, and may only do so
|
||||
* between allocation and registration of the mux controller. Specifically,
|
||||
@ -47,6 +49,8 @@ struct mux_control {
|
||||
|
||||
unsigned int states;
|
||||
int idle_state;
|
||||
|
||||
ktime_t last_change;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user