Second set of IIO new device support, features and cleanups for the 4.21 cycle.
Staging graduation * ad2s90 - Driver for this resolver to digital chip. New drivers and device support. * ad5686 - Add support for ad5310r DAC and associated fix in value read back. * exynos-adc - Support for S5PV210 which is slightly different from other parts. * mcp41010 - Driver supporting MCP41010, MCP41050, MCP41100, MCP42010, MCP42050 and MCP42100 microchip potentiometers. New ACPI ids. * ak8975 - AKM9911 ACPI HID. * kxcjk-1013 - KXJ2109 ACPI HID. - KIOX010A ACPI HID. New features * ad5933 - Explicit DT binding. * ad2s90 - Explicit DT binding including dropping spi setup that is done via dt in favour of verifying the settings form DT. * adt7316 - Explicit DT binding and support for gpio, irq_flags etc. * stm32-adc - Runtime power management. Minor fixes and cleanups * core - Protect against missing info structure. * ad2s90 - SPDX - Add documentation fo the mutex. * ad7280a - Check allocation failure. - Fix an accidental replacement of an error return. * adt7316 - Switch some variables to be local and rename for consistency with other drivers. - Revert a false handling of 0 as an error introduced earlier this cycle. * bmi160 - Use devm functions throughout probe() to avoid need for remove(). * hid-sensor-hub - White space cleanup. * hts221 - MAINTAINERS entry. * lis302 - Use generic name in the DT binding doc. * Messon-saradc - Check for allocation error. - Fix some presented clock names that break clk debugfs. * qcom-spmi-adc - A fix for initialization of the prescale property. Came late in the cycle, so merge window is probably the best route for this. * st_lsm6dsx - Allow for variable read length to support wider range of slave devices. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAlwRULkRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FojIIQ/+PSR0V3gW/eXZIoVFcqbjqAYvYQQkK5rH zOstRvKkgs+gTTB1S+dhTQL80PJBrrfSDRB1E85fJ2hx2kh80k0/zukAG73PsIF0 uqJazrHx5W6WeTj4xmN4rpLRG25DwkCHRMmDdfM6atCVhdz1bYSM56vEGAnXfVMf fPMbZ7EviN6EnKTtFSPI4F8BhVzesHAzIYGp+DYpMZdqa4nhr2dZyxVuRz3jpPEI xutODWVKP/0O7vQGBjSlCjx/BMSWGQM5+B0gandKzQULuMwHqi2QMXeD13pxaKQm Vy2cAEd6YLTGxIHKcw93qCWJjDZz06owvwMHvkoUmPTZXvPavLo+TyYia7rOTzPu IimDIPf0ci5qIDksxqtSiEzkFDF5YMyfnDJnAC8Ogm98NRC7FNnD5edXsc9sfI23 CBOH5fdGoIV4lNxvuEarnFJ0VdV8ifY8tubrI2l0kf/v0D5tGbcddClFpennkfjf vjqmkBc2KgD+83SSNgSAcqUKbqxfh4JsXVPpHx8WMLDUA/4S3GcBwVF7fkLqwmCQ jEuF/zYOoGwvmzDNY1LSkhlWCE16MmXhu0yDQgekA0XLQ2ODynbkV3LQCwdq4dNR /ZMoBRJ9PSZC35sGkNcFIKm5Nw6Ibl8R1c7WEqxA8vkLhBjJ99CwIsK0M5YcHaak fCWXUnJzpF4= =+vyl -----END PGP SIGNATURE----- Merge tag 'iio-for-4.21b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Second set of IIO new device support, features and cleanups for the 4.21 cycle. Staging graduation * ad2s90 - Driver for this resolver to digital chip. New drivers and device support. * ad5686 - Add support for ad5310r DAC and associated fix in value read back. * exynos-adc - Support for S5PV210 which is slightly different from other parts. * mcp41010 - Driver supporting MCP41010, MCP41050, MCP41100, MCP42010, MCP42050 and MCP42100 microchip potentiometers. New ACPI ids. * ak8975 - AKM9911 ACPI HID. * kxcjk-1013 - KXJ2109 ACPI HID. - KIOX010A ACPI HID. New features * ad5933 - Explicit DT binding. * ad2s90 - Explicit DT binding including dropping spi setup that is done via dt in favour of verifying the settings form DT. * adt7316 - Explicit DT binding and support for gpio, irq_flags etc. * stm32-adc - Runtime power management. Minor fixes and cleanups * core - Protect against missing info structure. * ad2s90 - SPDX - Add documentation fo the mutex. * ad7280a - Check allocation failure. - Fix an accidental replacement of an error return. * adt7316 - Switch some variables to be local and rename for consistency with other drivers. - Revert a false handling of 0 as an error introduced earlier this cycle. * bmi160 - Use devm functions throughout probe() to avoid need for remove(). * hid-sensor-hub - White space cleanup. * hts221 - MAINTAINERS entry. * lis302 - Use generic name in the DT binding doc. * Messon-saradc - Check for allocation error. - Fix some presented clock names that break clk debugfs. * qcom-spmi-adc - A fix for initialization of the prescale property. Came late in the cycle, so merge window is probably the best route for this. * st_lsm6dsx - Allow for variable read length to support wider range of slave devices. * tag 'iio-for-4.21b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (37 commits) iio: adc: qcom-spmi-adc5: Initialize prescale properly dt-bindings: iio: adc: exynos-adc: Add S5PV210 variant iio: adc: Allow selection of Exynos ADC on S5PV210 iio: adc: exynos-adc: Add S5PV210 variant iio: bmi160: use all devm functions in probe iio: dac: ad5686: fix bit shift read register iio:dac:ad5686: Add AD5310R support Revert "Staging: iio: adt7316: Add an extra check for 'ret' equals to 0" dt-bindings: iio: accel: use a generic node name for lis302 iio: core: check 'info' value before registering the device staging: iio: adc: ad7280a: fix overwrite of the returned value staging: iio: adc: ad7280a: check for devm_kasprint() failure iio: humidity: hts221: add entry in MAINTAINERS file iio: magnetometer: ak8975: Add the "AKM9911" ACPI HID staging:iio:ad2s90: Move out of staging staging:iio:ad2s90: Add comment to device state mutex staging:iio:ad2s90: Replace license text w/ SPDX identifier dt-bindings:iio:resolver: Add docs for ad2s90 staging:iio:ad2s90: Add max frequency check at probe staging:iio:ad2s90: Remove spi setup that should be done via dt ...
This commit is contained in:
commit
c6cbcdea7a
|
@ -64,7 +64,7 @@ Optional properties for all bus drivers:
|
|||
|
||||
Example for a SPI device node:
|
||||
|
||||
lis302@0 {
|
||||
accelerometer@0 {
|
||||
compatible = "st,lis302dl-spi";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
|
@ -89,7 +89,7 @@ Example for a SPI device node:
|
|||
|
||||
Example for a I2C device node:
|
||||
|
||||
lis331dlh: lis331dlh@18 {
|
||||
lis331dlh: accelerometer@18 {
|
||||
compatible = "st,lis331dlh", "st,lis3lv02d";
|
||||
reg = <0x18>;
|
||||
Vdd-supply = <&lis3_reg>;
|
||||
|
|
|
@ -11,7 +11,7 @@ New driver handles the following
|
|||
|
||||
Required properties:
|
||||
- compatible: Must be "samsung,exynos-adc-v1"
|
||||
for exynos4412/5250 and s5pv210 controllers.
|
||||
for exynos4412/5250 controllers.
|
||||
Must be "samsung,exynos-adc-v2" for
|
||||
future controllers.
|
||||
Must be "samsung,exynos3250-adc" for
|
||||
|
@ -28,6 +28,8 @@ Required properties:
|
|||
the ADC in s3c2443 and compatibles
|
||||
Must be "samsung,s3c6410-adc" for
|
||||
the ADC in s3c6410 and compatibles
|
||||
Must be "samsung,s5pv210-adc" for
|
||||
the ADC in s5pv210 and compatibles
|
||||
- reg: List of ADC register address range
|
||||
- The base address and range of ADC register
|
||||
- The base address and range of ADC_PHY register (every
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
* Microchip MCP41010/41050/41100/42010/42050/42100 Digital Potentiometer
|
||||
|
||||
Datasheet publicly available at:
|
||||
http://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf
|
||||
|
||||
The node for this driver must be a child node of a SPI controller, hence
|
||||
all mandatory properties described in
|
||||
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
must be specified.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of the following, depending on the
|
||||
model:
|
||||
"microchip,mcp41010"
|
||||
"microchip,mcp41050"
|
||||
"microchip,mcp41100"
|
||||
"microchip,mcp42010"
|
||||
"microchip,mcp42050"
|
||||
"microchip,mcp42100"
|
||||
|
||||
Example:
|
||||
potentiometer@0 {
|
||||
compatible = "microchip,mcp41010";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <500000>;
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
Analog Devices AD2S90 Resolver-to-Digital Converter
|
||||
|
||||
https://www.analog.com/en/products/ad2s90.html
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "adi,ad2s90"
|
||||
- reg: SPI chip select number for the device
|
||||
- spi-max-frequency: set maximum clock frequency, must be 830000
|
||||
- spi-cpol and spi-cpha:
|
||||
Either SPI mode (0,0) or (1,1) must be used, so specify none or both of
|
||||
spi-cpha, spi-cpol.
|
||||
|
||||
See for more details:
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Note about max frequency:
|
||||
Chip's max frequency, as specified in its datasheet, is 2Mhz. But a 600ns
|
||||
delay is expected between the application of a logic LO to CS and the
|
||||
application of SCLK, as also specified. And since the delay is not
|
||||
implemented in the spi code, to satisfy it, SCLK's period should be at most
|
||||
2 * 600ns, so the max frequency should be 1 / (2 * 6e-7), which gives
|
||||
roughly 830000Hz.
|
||||
|
||||
Example:
|
||||
resolver@0 {
|
||||
compatible = "adi,ad2s90";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <830000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
};
|
|
@ -6866,6 +6866,14 @@ L: linux-input@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/input/touchscreen/htcpen.c
|
||||
|
||||
HTS221 TEMPERATURE-HUMIDITY IIO DRIVER
|
||||
M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
W: http://www.st.com/
|
||||
S: Maintained
|
||||
F: drivers/iio/humidity/hts221*
|
||||
F: Documentation/devicetree/bindings/iio/humidity/hts221.txt
|
||||
|
||||
HUAWEI ETHERNET DRIVER
|
||||
M: Aviad Krawczyk <aviad.krawczyk@huawei.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
|
@ -1491,7 +1491,9 @@ static const struct acpi_device_id kx_acpi_match[] = {
|
|||
{"KXCJ9000", KXCJ91008},
|
||||
{"KIOX0009", KXTJ21009},
|
||||
{"KIOX000A", KXCJ91008},
|
||||
{"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */
|
||||
{"KXTJ1009", KXTJ21009},
|
||||
{"KXJ2109", KXTJ21009},
|
||||
{"SMO8500", KXCJ91008},
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -295,7 +295,7 @@ config EP93XX_ADC
|
|||
|
||||
config EXYNOS_ADC
|
||||
tristate "Exynos ADC driver support"
|
||||
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
|
||||
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || (OF && COMPILE_TEST)
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Core support for the ADC block found in the Samsung EXYNOS series
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
#define MAX_ADC_V2_CHANNELS 10
|
||||
#define MAX_ADC_V1_CHANNELS 8
|
||||
#define MAX_EXYNOS3250_ADC_CHANNELS 2
|
||||
#define MAX_S5PV210_ADC_CHANNELS 10
|
||||
|
||||
/* Bit definitions common for ADC_V1 and ADC_V2 */
|
||||
#define ADC_CON_EN_START (1u << 0)
|
||||
|
@ -282,6 +283,16 @@ static const struct exynos_adc_data exynos_adc_v1_data = {
|
|||
.start_conv = exynos_adc_v1_start_conv,
|
||||
};
|
||||
|
||||
static const struct exynos_adc_data exynos_adc_s5pv210_data = {
|
||||
.num_channels = MAX_S5PV210_ADC_CHANNELS,
|
||||
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
|
||||
|
||||
.init_hw = exynos_adc_v1_init_hw,
|
||||
.exit_hw = exynos_adc_v1_exit_hw,
|
||||
.clear_irq = exynos_adc_v1_clear_irq,
|
||||
.start_conv = exynos_adc_v1_start_conv,
|
||||
};
|
||||
|
||||
static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
|
||||
unsigned long addr)
|
||||
{
|
||||
|
@ -478,6 +489,9 @@ static const struct of_device_id exynos_adc_match[] = {
|
|||
}, {
|
||||
.compatible = "samsung,s3c6410-adc",
|
||||
.data = &exynos_adc_s3c64xx_data,
|
||||
}, {
|
||||
.compatible = "samsung,s5pv210-adc",
|
||||
.data = &exynos_adc_s5pv210_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos-adc-v1",
|
||||
.data = &exynos_adc_v1_data,
|
||||
|
|
|
@ -656,8 +656,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
|
|||
struct clk_init_data init;
|
||||
const char *clk_parents[1];
|
||||
|
||||
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_div",
|
||||
indio_dev->dev.of_node);
|
||||
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div",
|
||||
dev_name(indio_dev->dev.parent));
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
|
||||
init.flags = 0;
|
||||
init.ops = &clk_divider_ops;
|
||||
clk_parents[0] = __clk_get_name(priv->clkin);
|
||||
|
@ -675,8 +678,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
|
|||
if (WARN_ON(IS_ERR(priv->adc_div_clk)))
|
||||
return PTR_ERR(priv->adc_div_clk);
|
||||
|
||||
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_en",
|
||||
indio_dev->dev.of_node);
|
||||
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en",
|
||||
dev_name(indio_dev->dev.parent));
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.ops = &clk_gate_ops;
|
||||
clk_parents[0] = __clk_get_name(priv->adc_div_clk);
|
||||
|
|
|
@ -423,6 +423,7 @@ struct adc5_channels {
|
|||
enum vadc_scale_fn_type scale_fn_type;
|
||||
};
|
||||
|
||||
/* In these definitions, _pre refers to an index into adc5_prescale_ratios. */
|
||||
#define ADC5_CHAN(_dname, _type, _mask, _pre, _scale) \
|
||||
{ \
|
||||
.datasheet_name = _dname, \
|
||||
|
@ -443,63 +444,63 @@ struct adc5_channels {
|
|||
_pre, _scale) \
|
||||
|
||||
static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
|
||||
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
|
||||
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
|
||||
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
|
||||
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
|
||||
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
|
||||
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0,
|
||||
SCALE_HW_CALIB_PMIC_THERM)
|
||||
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 1,
|
||||
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 16,
|
||||
[ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 8,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 1,
|
||||
[ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 0,
|
||||
SCALE_HW_CALIB_PM5_CHG_TEMP)
|
||||
/* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */
|
||||
[ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 3,
|
||||
[ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 6,
|
||||
[ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 3,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 1,
|
||||
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 0,
|
||||
SCALE_HW_CALIB_XOTHERM)
|
||||
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
|
||||
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
|
||||
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
|
||||
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 1,
|
||||
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 0,
|
||||
SCALE_HW_CALIB_PM5_SMB_TEMP)
|
||||
};
|
||||
|
||||
static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
|
||||
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
|
||||
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
|
||||
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
|
||||
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
|
||||
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 3,
|
||||
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
|
||||
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0,
|
||||
SCALE_HW_CALIB_PMIC_THERM)
|
||||
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
|
||||
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
|
||||
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
|
||||
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 1,
|
||||
[ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 1,
|
||||
[ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 1,
|
||||
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
};
|
||||
|
||||
|
@ -558,6 +559,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
|||
return ret;
|
||||
}
|
||||
prop->prescale = ret;
|
||||
} else {
|
||||
prop->prescale =
|
||||
adc->data->adc_chans[prop->channel].prescale_index;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -48,15 +49,19 @@
|
|||
#define STM32H7_CKMODE_SHIFT 16
|
||||
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
|
||||
|
||||
#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000
|
||||
|
||||
/**
|
||||
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
|
||||
* @csr: common status register offset
|
||||
* @ccr: common control register offset
|
||||
* @eoc1: adc1 end of conversion flag in @csr
|
||||
* @eoc2: adc2 end of conversion flag in @csr
|
||||
* @eoc3: adc3 end of conversion flag in @csr
|
||||
*/
|
||||
struct stm32_adc_common_regs {
|
||||
u32 csr;
|
||||
u32 ccr;
|
||||
u32 eoc1_msk;
|
||||
u32 eoc2_msk;
|
||||
u32 eoc3_msk;
|
||||
|
@ -85,6 +90,7 @@ struct stm32_adc_priv_cfg {
|
|||
* @vref: regulator reference
|
||||
* @cfg: compatible configuration data
|
||||
* @common: common data for all ADC instances
|
||||
* @ccr_bak: backup CCR in low power mode
|
||||
*/
|
||||
struct stm32_adc_priv {
|
||||
int irq[STM32_ADC_MAX_ADCS];
|
||||
|
@ -94,6 +100,7 @@ struct stm32_adc_priv {
|
|||
struct regulator *vref;
|
||||
const struct stm32_adc_priv_cfg *cfg;
|
||||
struct stm32_adc_common common;
|
||||
u32 ccr_bak;
|
||||
};
|
||||
|
||||
static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com)
|
||||
|
@ -265,6 +272,7 @@ out:
|
|||
/* STM32F4 common registers definitions */
|
||||
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
|
||||
.csr = STM32F4_ADC_CSR,
|
||||
.ccr = STM32F4_ADC_CCR,
|
||||
.eoc1_msk = STM32F4_EOC1,
|
||||
.eoc2_msk = STM32F4_EOC2,
|
||||
.eoc3_msk = STM32F4_EOC3,
|
||||
|
@ -273,6 +281,7 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
|
|||
/* STM32H7 common registers definitions */
|
||||
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
|
||||
.csr = STM32H7_ADC_CSR,
|
||||
.ccr = STM32H7_ADC_CCR,
|
||||
.eoc1_msk = STM32H7_EOC_MST,
|
||||
.eoc2_msk = STM32H7_EOC_SLV,
|
||||
};
|
||||
|
@ -379,6 +388,61 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
|
|||
}
|
||||
}
|
||||
|
||||
static int stm32_adc_core_hw_start(struct device *dev)
|
||||
{
|
||||
struct stm32_adc_common *common = dev_get_drvdata(dev);
|
||||
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "vref enable failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->bclk) {
|
||||
ret = clk_prepare_enable(priv->bclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "bus clk enable failed\n");
|
||||
goto err_regulator_disable;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->aclk) {
|
||||
ret = clk_prepare_enable(priv->aclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "adc clk enable failed\n");
|
||||
goto err_bclk_disable;
|
||||
}
|
||||
}
|
||||
|
||||
writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr);
|
||||
|
||||
return 0;
|
||||
|
||||
err_bclk_disable:
|
||||
if (priv->bclk)
|
||||
clk_disable_unprepare(priv->bclk);
|
||||
err_regulator_disable:
|
||||
regulator_disable(priv->vref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stm32_adc_core_hw_stop(struct device *dev)
|
||||
{
|
||||
struct stm32_adc_common *common = dev_get_drvdata(dev);
|
||||
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
|
||||
|
||||
/* Backup CCR that may be lost (depends on power state to achieve) */
|
||||
priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr);
|
||||
if (priv->aclk)
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
if (priv->bclk)
|
||||
clk_disable_unprepare(priv->bclk);
|
||||
regulator_disable(priv->vref);
|
||||
}
|
||||
|
||||
static int stm32_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_adc_priv *priv;
|
||||
|
@ -393,6 +457,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
|||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, &priv->common);
|
||||
|
||||
priv->cfg = (const struct stm32_adc_priv_cfg *)
|
||||
of_match_device(dev->driver->of_match_table, dev)->data;
|
||||
|
@ -410,67 +475,51 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_enable(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "vref enable failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
|
||||
goto err_regulator_disable;
|
||||
}
|
||||
priv->common.vref_mv = ret / 1000;
|
||||
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
|
||||
|
||||
priv->aclk = devm_clk_get(&pdev->dev, "adc");
|
||||
if (IS_ERR(priv->aclk)) {
|
||||
ret = PTR_ERR(priv->aclk);
|
||||
if (ret == -ENOENT) {
|
||||
priv->aclk = NULL;
|
||||
} else {
|
||||
if (ret != -ENOENT) {
|
||||
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
|
||||
goto err_regulator_disable;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->aclk) {
|
||||
ret = clk_prepare_enable(priv->aclk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "adc clk enable failed\n");
|
||||
goto err_regulator_disable;
|
||||
return ret;
|
||||
}
|
||||
priv->aclk = NULL;
|
||||
}
|
||||
|
||||
priv->bclk = devm_clk_get(&pdev->dev, "bus");
|
||||
if (IS_ERR(priv->bclk)) {
|
||||
ret = PTR_ERR(priv->bclk);
|
||||
if (ret == -ENOENT) {
|
||||
priv->bclk = NULL;
|
||||
} else {
|
||||
if (ret != -ENOENT) {
|
||||
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
|
||||
goto err_aclk_disable;
|
||||
return ret;
|
||||
}
|
||||
priv->bclk = NULL;
|
||||
}
|
||||
|
||||
if (priv->bclk) {
|
||||
ret = clk_prepare_enable(priv->bclk);
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = stm32_adc_core_hw_start(dev);
|
||||
if (ret)
|
||||
goto err_pm_stop;
|
||||
|
||||
ret = regulator_get_voltage(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "adc clk enable failed\n");
|
||||
goto err_aclk_disable;
|
||||
}
|
||||
dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
|
||||
goto err_hw_stop;
|
||||
}
|
||||
priv->common.vref_mv = ret / 1000;
|
||||
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
|
||||
|
||||
ret = priv->cfg->clk_sel(pdev, priv);
|
||||
if (ret < 0)
|
||||
goto err_bclk_disable;
|
||||
goto err_hw_stop;
|
||||
|
||||
ret = stm32_adc_irq_probe(pdev, priv);
|
||||
if (ret < 0)
|
||||
goto err_bclk_disable;
|
||||
|
||||
platform_set_drvdata(pdev, &priv->common);
|
||||
goto err_hw_stop;
|
||||
|
||||
ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
|
||||
if (ret < 0) {
|
||||
|
@ -478,21 +527,19 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
|||
goto err_irq_remove;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq_remove:
|
||||
stm32_adc_irq_remove(pdev, priv);
|
||||
|
||||
err_bclk_disable:
|
||||
if (priv->bclk)
|
||||
clk_disable_unprepare(priv->bclk);
|
||||
|
||||
err_aclk_disable:
|
||||
if (priv->aclk)
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
|
||||
err_regulator_disable:
|
||||
regulator_disable(priv->vref);
|
||||
err_hw_stop:
|
||||
stm32_adc_core_hw_stop(dev);
|
||||
err_pm_stop:
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -502,17 +549,39 @@ static int stm32_adc_remove(struct platform_device *pdev)
|
|||
struct stm32_adc_common *common = platform_get_drvdata(pdev);
|
||||
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
stm32_adc_irq_remove(pdev, priv);
|
||||
if (priv->bclk)
|
||||
clk_disable_unprepare(priv->bclk);
|
||||
if (priv->aclk)
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
regulator_disable(priv->vref);
|
||||
stm32_adc_core_hw_stop(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int stm32_adc_core_runtime_suspend(struct device *dev)
|
||||
{
|
||||
stm32_adc_core_hw_stop(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_adc_core_runtime_resume(struct device *dev)
|
||||
{
|
||||
return stm32_adc_core_hw_start(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops stm32_adc_core_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
|
||||
stm32_adc_core_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
|
||||
.regs = &stm32f4_adc_common_regs,
|
||||
.clk_sel = stm32f4_adc_clk_sel,
|
||||
|
@ -552,6 +621,7 @@ static struct platform_driver stm32_adc_driver = {
|
|||
.driver = {
|
||||
.name = "stm32-adc-core",
|
||||
.of_match_table = stm32_adc_of_match,
|
||||
.pm = &stm32_adc_core_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(stm32_adc_driver);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
|
@ -148,6 +149,7 @@ enum stm32h7_adc_dmngt {
|
|||
#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_DMA_BUFFER_SIZE PAGE_SIZE
|
||||
|
||||
|
@ -199,11 +201,13 @@ struct stm32_adc_trig_info {
|
|||
* @calfact_s: Calibration offset for single ended channels
|
||||
* @calfact_d: Calibration offset in differential
|
||||
* @lincalfact: Linearity calibration factor
|
||||
* @calibrated: Indicates calibration status
|
||||
*/
|
||||
struct stm32_adc_calib {
|
||||
u32 calfact_s;
|
||||
u32 calfact_d;
|
||||
u32 lincalfact[STM32H7_LINCALFACT_NUM];
|
||||
bool calibrated;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -251,7 +255,6 @@ struct stm32_adc;
|
|||
* @trigs: external trigger sources
|
||||
* @clk_required: clock is required
|
||||
* @has_vregready: vregready status flag presence
|
||||
* @selfcalib: optional routine for self-calibration
|
||||
* @prepare: optional prepare routine (power-up, enable)
|
||||
* @start_conv: routine to start conversions
|
||||
* @stop_conv: routine to stop conversions
|
||||
|
@ -264,7 +267,6 @@ struct stm32_adc_cfg {
|
|||
struct stm32_adc_trig_info *trigs;
|
||||
bool clk_required;
|
||||
bool has_vregready;
|
||||
int (*selfcalib)(struct stm32_adc *);
|
||||
int (*prepare)(struct stm32_adc *);
|
||||
void (*start_conv)(struct stm32_adc *, bool dma);
|
||||
void (*stop_conv)(struct stm32_adc *);
|
||||
|
@ -623,6 +625,47 @@ static void stm32_adc_set_res(struct stm32_adc *adc)
|
|||
stm32_adc_writel(adc, res->reg, val);
|
||||
}
|
||||
|
||||
static int stm32_adc_hw_stop(struct device *dev)
|
||||
{
|
||||
struct stm32_adc *adc = dev_get_drvdata(dev);
|
||||
|
||||
if (adc->cfg->unprepare)
|
||||
adc->cfg->unprepare(adc);
|
||||
|
||||
if (adc->clk)
|
||||
clk_disable_unprepare(adc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_adc_hw_start(struct device *dev)
|
||||
{
|
||||
struct stm32_adc *adc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (adc->clk) {
|
||||
ret = clk_prepare_enable(adc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
stm32_adc_set_res(adc);
|
||||
|
||||
if (adc->cfg->prepare) {
|
||||
ret = adc->cfg->prepare(adc);
|
||||
if (ret)
|
||||
goto err_clk_dis;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_dis:
|
||||
if (adc->clk)
|
||||
clk_disable_unprepare(adc->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_adc_start_conv() - Start conversions for regular channels.
|
||||
* @adc: stm32 adc instance
|
||||
|
@ -777,6 +820,7 @@ static void stm32h7_adc_disable(struct stm32_adc *adc)
|
|||
/**
|
||||
* stm32h7_adc_read_selfcalib() - read calibration shadow regs, save result
|
||||
* @adc: stm32 adc instance
|
||||
* Note: Must be called once ADC is enabled, so LINCALRDYW[1..6] are writable
|
||||
*/
|
||||
static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
|
||||
{
|
||||
|
@ -784,11 +828,6 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
|
|||
int i, ret;
|
||||
u32 lincalrdyw_mask, val;
|
||||
|
||||
/* Enable adc so LINCALRDYW1..6 bits are writable */
|
||||
ret = stm32h7_adc_enable(adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Read linearity calibration */
|
||||
lincalrdyw_mask = STM32H7_LINCALRDYW6;
|
||||
for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) {
|
||||
|
@ -801,7 +840,7 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
|
|||
100, STM32_ADC_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Failed to read calfact\n");
|
||||
goto disable;
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2);
|
||||
|
@ -817,11 +856,9 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
|
|||
adc->cal.calfact_s >>= STM32H7_CALFACT_S_SHIFT;
|
||||
adc->cal.calfact_d = (val & STM32H7_CALFACT_D_MASK);
|
||||
adc->cal.calfact_d >>= STM32H7_CALFACT_D_SHIFT;
|
||||
adc->cal.calibrated = true;
|
||||
|
||||
disable:
|
||||
stm32h7_adc_disable(adc);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -898,9 +935,9 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc)
|
|||
#define STM32H7_ADC_CALIB_TIMEOUT_US 100000
|
||||
|
||||
/**
|
||||
* stm32h7_adc_selfcalib() - Procedure to calibrate ADC (from power down)
|
||||
* stm32h7_adc_selfcalib() - Procedure to calibrate ADC
|
||||
* @adc: stm32 adc instance
|
||||
* Exit from power down, calibrate ADC, then return to power down.
|
||||
* Note: Must be called once ADC is out of power down.
|
||||
*/
|
||||
static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
|
||||
{
|
||||
|
@ -908,9 +945,8 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
|
|||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = stm32h7_adc_exit_pwr_down(adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (adc->cal.calibrated)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Select calibration mode:
|
||||
|
@ -927,7 +963,7 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
|
|||
STM32H7_ADC_CALIB_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "calibration failed\n");
|
||||
goto pwr_dwn;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -944,18 +980,13 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
|
|||
STM32H7_ADC_CALIB_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "calibration failed\n");
|
||||
goto pwr_dwn;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
stm32_adc_clr_bits(adc, STM32H7_ADC_CR,
|
||||
STM32H7_ADCALDIF | STM32H7_ADCALLIN);
|
||||
|
||||
/* Read calibration result for future reference */
|
||||
ret = stm32h7_adc_read_selfcalib(adc);
|
||||
|
||||
pwr_dwn:
|
||||
stm32h7_adc_enter_pwr_down(adc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -972,19 +1003,28 @@ pwr_dwn:
|
|||
*/
|
||||
static int stm32h7_adc_prepare(struct stm32_adc *adc)
|
||||
{
|
||||
int ret;
|
||||
int calib, ret;
|
||||
|
||||
ret = stm32h7_adc_exit_pwr_down(adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = stm32h7_adc_selfcalib(adc);
|
||||
if (ret < 0)
|
||||
goto pwr_dwn;
|
||||
calib = ret;
|
||||
|
||||
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
|
||||
|
||||
ret = stm32h7_adc_enable(adc);
|
||||
if (ret)
|
||||
goto pwr_dwn;
|
||||
|
||||
/* Either restore or read calibration result for future reference */
|
||||
if (calib)
|
||||
ret = stm32h7_adc_restore_selfcalib(adc);
|
||||
else
|
||||
ret = stm32h7_adc_read_selfcalib(adc);
|
||||
if (ret)
|
||||
goto disable;
|
||||
|
||||
|
@ -1174,6 +1214,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
|
|||
int *res)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
const struct stm32_adc_regspec *regs = adc->cfg->regs;
|
||||
long timeout;
|
||||
u32 val;
|
||||
|
@ -1183,9 +1224,9 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
|
|||
|
||||
adc->bufi = 0;
|
||||
|
||||
if (adc->cfg->prepare) {
|
||||
ret = adc->cfg->prepare(adc);
|
||||
if (ret)
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1224,8 +1265,8 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
|
|||
|
||||
stm32_adc_conv_irq_disable(adc);
|
||||
|
||||
if (adc->cfg->unprepare)
|
||||
adc->cfg->unprepare(adc);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1333,15 +1374,22 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev,
|
|||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength);
|
||||
|
||||
ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_adc_of_xlate(struct iio_dev *indio_dev,
|
||||
|
@ -1371,12 +1419,23 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev,
|
|||
unsigned *readval)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!readval)
|
||||
stm32_adc_writel(adc, reg, writeval);
|
||||
else
|
||||
*readval = stm32_adc_readl(adc, reg);
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1459,21 +1518,22 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
|
||||
static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
int ret;
|
||||
|
||||
if (adc->cfg->prepare) {
|
||||
ret = adc->cfg->prepare(adc);
|
||||
if (ret)
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = stm32_adc_set_trig(indio_dev, indio_dev->trig);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Can't set trigger\n");
|
||||
goto err_unprepare;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
ret = stm32_adc_dma_start(indio_dev);
|
||||
|
@ -1482,10 +1542,6 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
|
|||
goto err_clr_trig;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_postenable(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_stop_dma;
|
||||
|
||||
/* Reset adc buffer index */
|
||||
adc->bufi = 0;
|
||||
|
||||
|
@ -1496,39 +1552,58 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_stop_dma:
|
||||
if (adc->dma_chan)
|
||||
dmaengine_terminate_all(adc->dma_chan);
|
||||
err_clr_trig:
|
||||
stm32_adc_set_trig(indio_dev, NULL);
|
||||
err_unprepare:
|
||||
if (adc->cfg->unprepare)
|
||||
adc->cfg->unprepare(adc);
|
||||
err_pm_put:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
|
||||
static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iio_triggered_buffer_postenable(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = __stm32_adc_buffer_postenable(indio_dev);
|
||||
if (ret < 0)
|
||||
iio_triggered_buffer_predisable(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
|
||||
adc->cfg->stop_conv(adc);
|
||||
if (!adc->dma_chan)
|
||||
stm32_adc_conv_irq_disable(adc);
|
||||
|
||||
ret = iio_triggered_buffer_predisable(indio_dev);
|
||||
if (ret < 0)
|
||||
dev_err(&indio_dev->dev, "predisable failed\n");
|
||||
|
||||
if (adc->dma_chan)
|
||||
dmaengine_terminate_all(adc->dma_chan);
|
||||
|
||||
if (stm32_adc_set_trig(indio_dev, NULL))
|
||||
dev_err(&indio_dev->dev, "Can't clear trigger\n");
|
||||
|
||||
if (adc->cfg->unprepare)
|
||||
adc->cfg->unprepare(adc);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__stm32_adc_buffer_predisable(indio_dev);
|
||||
|
||||
ret = iio_triggered_buffer_predisable(indio_dev);
|
||||
if (ret < 0)
|
||||
dev_err(&indio_dev->dev, "predisable failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1867,32 +1942,17 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (adc->clk) {
|
||||
ret = clk_prepare_enable(adc->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "clk enable failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = stm32_adc_of_get_resolution(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_clk_disable;
|
||||
stm32_adc_set_res(adc);
|
||||
|
||||
if (adc->cfg->selfcalib) {
|
||||
ret = adc->cfg->selfcalib(adc);
|
||||
if (ret)
|
||||
goto err_clk_disable;
|
||||
}
|
||||
return ret;
|
||||
|
||||
ret = stm32_adc_chan_of_init(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_clk_disable;
|
||||
return ret;
|
||||
|
||||
ret = stm32_adc_dma_request(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_clk_disable;
|
||||
return ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
|
@ -1903,15 +1963,35 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
|||
goto err_dma_disable;
|
||||
}
|
||||
|
||||
/* Get stm32-adc-core PM online */
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = stm32_adc_hw_start(dev);
|
||||
if (ret)
|
||||
goto err_buffer_cleanup;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "iio dev register failed\n");
|
||||
goto err_buffer_cleanup;
|
||||
goto err_hw_stop;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_hw_stop:
|
||||
stm32_adc_hw_stop(dev);
|
||||
|
||||
err_buffer_cleanup:
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
err_dma_disable:
|
||||
|
@ -1921,9 +2001,6 @@ err_dma_disable:
|
|||
adc->rx_buf, adc->rx_dma_buf);
|
||||
dma_release_channel(adc->dma_chan);
|
||||
}
|
||||
err_clk_disable:
|
||||
if (adc->clk)
|
||||
clk_disable_unprepare(adc->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1933,7 +2010,12 @@ static int stm32_adc_remove(struct platform_device *pdev)
|
|||
struct stm32_adc *adc = platform_get_drvdata(pdev);
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
iio_device_unregister(indio_dev);
|
||||
stm32_adc_hw_stop(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
if (adc->dma_chan) {
|
||||
dma_free_coherent(adc->dma_chan->device->dev,
|
||||
|
@ -1941,12 +2023,62 @@ static int stm32_adc_remove(struct platform_device *pdev)
|
|||
adc->rx_buf, adc->rx_dma_buf);
|
||||
dma_release_channel(adc->dma_chan);
|
||||
}
|
||||
if (adc->clk)
|
||||
clk_disable_unprepare(adc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM_SLEEP)
|
||||
static int stm32_adc_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_adc *adc = dev_get_drvdata(dev);
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
__stm32_adc_buffer_predisable(indio_dev);
|
||||
|
||||
return pm_runtime_force_suspend(dev);
|
||||
}
|
||||
|
||||
static int stm32_adc_resume(struct device *dev)
|
||||
{
|
||||
struct stm32_adc *adc = dev_get_drvdata(dev);
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!iio_buffer_enabled(indio_dev))
|
||||
return 0;
|
||||
|
||||
ret = stm32_adc_update_scan_mode(indio_dev,
|
||||
indio_dev->active_scan_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return __stm32_adc_buffer_postenable(indio_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int stm32_adc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return stm32_adc_hw_stop(dev);
|
||||
}
|
||||
|
||||
static int stm32_adc_runtime_resume(struct device *dev)
|
||||
{
|
||||
return stm32_adc_hw_start(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops stm32_adc_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume)
|
||||
SET_RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct stm32_adc_cfg stm32f4_adc_cfg = {
|
||||
.regs = &stm32f4_adc_regspec,
|
||||
.adc_info = &stm32f4_adc_info,
|
||||
|
@ -1961,7 +2093,6 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
|
|||
.regs = &stm32h7_adc_regspec,
|
||||
.adc_info = &stm32h7_adc_info,
|
||||
.trigs = stm32h7_adc_trigs,
|
||||
.selfcalib = stm32h7_adc_selfcalib,
|
||||
.start_conv = stm32h7_adc_start_conv,
|
||||
.stop_conv = stm32h7_adc_stop_conv,
|
||||
.prepare = stm32h7_adc_prepare,
|
||||
|
@ -1974,7 +2105,6 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
|
|||
.adc_info = &stm32h7_adc_info,
|
||||
.trigs = stm32h7_adc_trigs,
|
||||
.has_vregready = true,
|
||||
.selfcalib = stm32h7_adc_selfcalib,
|
||||
.start_conv = stm32h7_adc_start_conv,
|
||||
.stop_conv = stm32h7_adc_stop_conv,
|
||||
.prepare = stm32h7_adc_prepare,
|
||||
|
@ -1996,6 +2126,7 @@ static struct platform_driver stm32_adc_driver = {
|
|||
.driver = {
|
||||
.name = "stm32-adc",
|
||||
.of_match_table = stm32_adc_of_match,
|
||||
.pm = &stm32_adc_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(stm32_adc_driver);
|
||||
|
|
|
@ -19,6 +19,12 @@ static int ad5686_spi_write(struct ad5686_state *st,
|
|||
u8 tx_len, *buf;
|
||||
|
||||
switch (st->chip_info->regmap_type) {
|
||||
case AD5310_REGMAP:
|
||||
st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) |
|
||||
val);
|
||||
buf = &st->data[0].d8[0];
|
||||
tx_len = 2;
|
||||
break;
|
||||
case AD5683_REGMAP:
|
||||
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
|
||||
AD5683_DATA(val));
|
||||
|
@ -56,10 +62,18 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
|
|||
u8 cmd = 0;
|
||||
int ret;
|
||||
|
||||
if (st->chip_info->regmap_type == AD5686_REGMAP)
|
||||
cmd = AD5686_CMD_READBACK_ENABLE;
|
||||
else if (st->chip_info->regmap_type == AD5683_REGMAP)
|
||||
switch (st->chip_info->regmap_type) {
|
||||
case AD5310_REGMAP:
|
||||
return -ENOTSUPP;
|
||||
case AD5683_REGMAP:
|
||||
cmd = AD5686_CMD_READBACK_ENABLE_V2;
|
||||
break;
|
||||
case AD5686_REGMAP:
|
||||
cmd = AD5686_CMD_READBACK_ENABLE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
|
||||
AD5686_ADDR(addr));
|
||||
|
@ -86,6 +100,7 @@ static int ad5686_spi_remove(struct spi_device *spi)
|
|||
}
|
||||
|
||||
static const struct spi_device_id ad5686_spi_id[] = {
|
||||
{"ad5310r", ID_AD5310R},
|
||||
{"ad5672r", ID_AD5672R},
|
||||
{"ad5676", ID_AD5676},
|
||||
{"ad5676r", ID_AD5676R},
|
||||
|
|
|
@ -83,6 +83,10 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
|
|||
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
|
||||
|
||||
switch (st->chip_info->regmap_type) {
|
||||
case AD5310_REGMAP:
|
||||
shift = 9;
|
||||
ref_bit_msk = AD5310_REF_BIT_MSK;
|
||||
break;
|
||||
case AD5683_REGMAP:
|
||||
shift = 13;
|
||||
ref_bit_msk = AD5683_REF_BIT_MSK;
|
||||
|
@ -124,7 +128,8 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
|
|||
mutex_unlock(&indio_dev->mlock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
*val = (ret >> chan->scan_type.shift) &
|
||||
GENMASK(chan->scan_type.realbits - 1, 0);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = st->vref_mv;
|
||||
|
@ -221,6 +226,7 @@ static struct iio_chan_spec name[] = { \
|
|||
AD5868_CHANNEL(7, 7, bits, _shift), \
|
||||
}
|
||||
|
||||
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
|
||||
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
|
||||
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
|
||||
DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
|
||||
|
@ -232,6 +238,12 @@ DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2);
|
|||
DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4);
|
||||
|
||||
static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
|
||||
[ID_AD5310R] = {
|
||||
.channels = ad5310r_channels,
|
||||
.int_vref_mv = 2500,
|
||||
.num_channels = 1,
|
||||
.regmap_type = AD5310_REGMAP,
|
||||
},
|
||||
[ID_AD5311R] = {
|
||||
.channels = ad5311r_channels,
|
||||
.int_vref_mv = 2500,
|
||||
|
@ -419,6 +431,11 @@ int ad5686_probe(struct device *dev,
|
|||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
|
||||
switch (st->chip_info->regmap_type) {
|
||||
case AD5310_REGMAP:
|
||||
cmd = AD5686_CMD_CONTROL_REG;
|
||||
ref_bit_msk = AD5310_REF_BIT_MSK;
|
||||
st->use_internal_vref = !voltage_uv;
|
||||
break;
|
||||
case AD5683_REGMAP:
|
||||
cmd = AD5686_CMD_CONTROL_REG;
|
||||
ref_bit_msk = AD5683_REF_BIT_MSK;
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define AD5310_CMD(x) ((x) << 12)
|
||||
|
||||
#define AD5683_DATA(x) ((x) << 4)
|
||||
|
||||
#define AD5686_ADDR(x) ((x) << 16)
|
||||
#define AD5686_CMD(x) ((x) << 20)
|
||||
|
||||
|
@ -38,6 +41,8 @@
|
|||
|
||||
#define AD5686_CMD_CONTROL_REG 0x4
|
||||
#define AD5686_CMD_READBACK_ENABLE_V2 0x5
|
||||
|
||||
#define AD5310_REF_BIT_MSK BIT(8)
|
||||
#define AD5683_REF_BIT_MSK BIT(12)
|
||||
#define AD5693_REF_BIT_MSK BIT(12)
|
||||
|
||||
|
@ -45,6 +50,7 @@
|
|||
* ad5686_supported_device_ids:
|
||||
*/
|
||||
enum ad5686_supported_device_ids {
|
||||
ID_AD5310R,
|
||||
ID_AD5311R,
|
||||
ID_AD5671R,
|
||||
ID_AD5672R,
|
||||
|
@ -72,6 +78,7 @@ enum ad5686_supported_device_ids {
|
|||
};
|
||||
|
||||
enum ad5686_regmap_type {
|
||||
AD5310_REGMAP,
|
||||
AD5683_REGMAP,
|
||||
AD5686_REGMAP,
|
||||
AD5693_REGMAP
|
||||
|
|
|
@ -6,6 +6,5 @@ extern const struct regmap_config bmi160_regmap_config;
|
|||
|
||||
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name, bool use_spi);
|
||||
void bmi160_core_remove(struct device *dev);
|
||||
|
||||
#endif /* BMI160_H_ */
|
||||
|
|
|
@ -542,10 +542,12 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bmi160_chip_uninit(struct bmi160_data *data)
|
||||
static void bmi160_chip_uninit(void *data)
|
||||
{
|
||||
bmi160_set_mode(data, BMI160_GYRO, false);
|
||||
bmi160_set_mode(data, BMI160_ACCEL, false);
|
||||
struct bmi160_data *bmi_data = data;
|
||||
|
||||
bmi160_set_mode(bmi_data, BMI160_GYRO, false);
|
||||
bmi160_set_mode(bmi_data, BMI160_ACCEL, false);
|
||||
}
|
||||
|
||||
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
|
||||
|
@ -567,6 +569,10 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, bmi160_chip_uninit, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!name && ACPI_HANDLE(dev))
|
||||
name = bmi160_match_acpi_device(dev);
|
||||
|
||||
|
@ -577,35 +583,19 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &bmi160_info;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
bmi160_trigger_handler, NULL);
|
||||
if (ret < 0)
|
||||
goto uninit;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
ret = devm_iio_device_register(dev, indio_dev);
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
uninit:
|
||||
bmi160_chip_uninit(data);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bmi160_core_probe);
|
||||
|
||||
void bmi160_core_remove(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bmi160_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
bmi160_chip_uninit(data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bmi160_core_remove);
|
||||
|
||||
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
|
||||
MODULE_DESCRIPTION("Bosch BMI160 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -38,13 +38,6 @@ static int bmi160_i2c_probe(struct i2c_client *client,
|
|||
return bmi160_core_probe(&client->dev, regmap, name, false);
|
||||
}
|
||||
|
||||
static int bmi160_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
bmi160_core_remove(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id bmi160_i2c_id[] = {
|
||||
{"bmi160", 0},
|
||||
{}
|
||||
|
@ -72,7 +65,6 @@ static struct i2c_driver bmi160_i2c_driver = {
|
|||
.of_match_table = of_match_ptr(bmi160_of_match),
|
||||
},
|
||||
.probe = bmi160_i2c_probe,
|
||||
.remove = bmi160_i2c_remove,
|
||||
.id_table = bmi160_i2c_id,
|
||||
};
|
||||
module_i2c_driver(bmi160_i2c_driver);
|
||||
|
|
|
@ -29,13 +29,6 @@ static int bmi160_spi_probe(struct spi_device *spi)
|
|||
return bmi160_core_probe(&spi->dev, regmap, id->name, true);
|
||||
}
|
||||
|
||||
static int bmi160_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
bmi160_core_remove(&spi->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id bmi160_spi_id[] = {
|
||||
{"bmi160", 0},
|
||||
{}
|
||||
|
@ -58,7 +51,6 @@ MODULE_DEVICE_TABLE(of, bmi160_of_match);
|
|||
|
||||
static struct spi_driver bmi160_spi_driver = {
|
||||
.probe = bmi160_spi_probe,
|
||||
.remove = bmi160_spi_remove,
|
||||
.id_table = bmi160_spi_id,
|
||||
.driver = {
|
||||
.acpi_match_table = ACPI_PTR(bmi160_acpi_match),
|
||||
|
|
|
@ -432,8 +432,8 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor,
|
|||
struct iio_chan_spec const *ch,
|
||||
int *val)
|
||||
{
|
||||
int err, delay, len = ch->scan_type.realbits >> 3;
|
||||
__le16 data;
|
||||
int err, delay, len;
|
||||
u8 data[4];
|
||||
|
||||
err = st_lsm6dsx_shub_set_enable(sensor, true);
|
||||
if (err < 0)
|
||||
|
@ -442,15 +442,17 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor,
|
|||
delay = 1000000 / sensor->odr;
|
||||
usleep_range(delay, 2 * delay);
|
||||
|
||||
err = st_lsm6dsx_shub_read(sensor, ch->address, (u8 *)&data, len);
|
||||
if (err < 0)
|
||||
return err;
|
||||
len = min_t(int, sizeof(data), ch->scan_type.realbits >> 3);
|
||||
err = st_lsm6dsx_shub_read(sensor, ch->address, data, len);
|
||||
|
||||
st_lsm6dsx_shub_set_enable(sensor, false);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
switch (len) {
|
||||
case 2:
|
||||
*val = (s16)le16_to_cpu(data);
|
||||
*val = (s16)le16_to_cpu(*((__le16 *)data));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
|
@ -1671,6 +1671,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -EINVAL;
|
||||
|
||||
/* configure elements for the chrdev */
|
||||
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
|
||||
|
||||
|
|
|
@ -790,6 +790,7 @@ static const struct acpi_device_id ak_acpi_match[] = {
|
|||
{"INVN6500", AK8963},
|
||||
{"AK009911", AK09911},
|
||||
{"AK09911", AK09911},
|
||||
{"AKM9911", AK09911},
|
||||
{"AK09912", AK09912},
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -90,6 +90,18 @@ config MCP4531
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcp4531.
|
||||
|
||||
config MCP41010
|
||||
tristate "Microchip MCP41xxx/MCP42xxx Digital Potentiometer driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for the Microchip
|
||||
MCP41010, MCP41050, MCP41100,
|
||||
MCP42010, MCP42050, MCP42100
|
||||
digital potentiometer chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcp41010.
|
||||
|
||||
config TPL0102
|
||||
tristate "Texas Instruments digital potentiometer driver"
|
||||
depends on I2C
|
||||
|
|
|
@ -11,4 +11,5 @@ obj-$(CONFIG_MAX5487) += max5487.o
|
|||
obj-$(CONFIG_MCP4018) += mcp4018.o
|
||||
obj-$(CONFIG_MCP4131) += mcp4131.o
|
||||
obj-$(CONFIG_MCP4531) += mcp4531.o
|
||||
obj-$(CONFIG_MCP41010) += mcp41010.o
|
||||
obj-$(CONFIG_TPL0102) += tpl0102.o
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Industrial I/O driver for Microchip digital potentiometers
|
||||
*
|
||||
* Copyright (c) 2018 Chris Coffey <cmc@babblebit.net>
|
||||
* Based on: Slawomir Stepien's code from mcp4131.c
|
||||
*
|
||||
* Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf
|
||||
*
|
||||
* DEVID #Wipers #Positions Resistance (kOhm)
|
||||
* mcp41010 1 256 10
|
||||
* mcp41050 1 256 50
|
||||
* mcp41100 1 256 100
|
||||
* mcp42010 2 256 10
|
||||
* mcp42050 2 256 50
|
||||
* mcp42100 2 256 100
|
||||
*/
|
||||
|
||||
#include <linux/cache.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define MCP41010_MAX_WIPERS 2
|
||||
#define MCP41010_WRITE BIT(4)
|
||||
#define MCP41010_WIPER_MAX 255
|
||||
#define MCP41010_WIPER_CHANNEL BIT(0)
|
||||
|
||||
struct mcp41010_cfg {
|
||||
char name[16];
|
||||
int wipers;
|
||||
int kohms;
|
||||
};
|
||||
|
||||
enum mcp41010_type {
|
||||
MCP41010,
|
||||
MCP41050,
|
||||
MCP41100,
|
||||
MCP42010,
|
||||
MCP42050,
|
||||
MCP42100,
|
||||
};
|
||||
|
||||
static const struct mcp41010_cfg mcp41010_cfg[] = {
|
||||
[MCP41010] = { .name = "mcp41010", .wipers = 1, .kohms = 10, },
|
||||
[MCP41050] = { .name = "mcp41050", .wipers = 1, .kohms = 50, },
|
||||
[MCP41100] = { .name = "mcp41100", .wipers = 1, .kohms = 100, },
|
||||
[MCP42010] = { .name = "mcp42010", .wipers = 2, .kohms = 10, },
|
||||
[MCP42050] = { .name = "mcp42050", .wipers = 2, .kohms = 50, },
|
||||
[MCP42100] = { .name = "mcp42100", .wipers = 2, .kohms = 100, },
|
||||
};
|
||||
|
||||
struct mcp41010_data {
|
||||
struct spi_device *spi;
|
||||
const struct mcp41010_cfg *cfg;
|
||||
struct mutex lock; /* Protect write sequences */
|
||||
unsigned int value[MCP41010_MAX_WIPERS]; /* Cache wiper values */
|
||||
u8 buf[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
#define MCP41010_CHANNEL(ch) { \
|
||||
.type = IIO_RESISTANCE, \
|
||||
.indexed = 1, \
|
||||
.output = 1, \
|
||||
.channel = (ch), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mcp41010_channels[] = {
|
||||
MCP41010_CHANNEL(0),
|
||||
MCP41010_CHANNEL(1),
|
||||
};
|
||||
|
||||
static int mcp41010_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct mcp41010_data *data = iio_priv(indio_dev);
|
||||
int channel = chan->channel;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val = data->value[channel];
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 1000 * data->cfg->kohms;
|
||||
*val2 = MCP41010_WIPER_MAX;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mcp41010_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
int err;
|
||||
struct mcp41010_data *data = iio_priv(indio_dev);
|
||||
int channel = chan->channel;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_RAW)
|
||||
return -EINVAL;
|
||||
|
||||
if (val > MCP41010_WIPER_MAX || val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
data->buf[0] = MCP41010_WIPER_CHANNEL << channel;
|
||||
data->buf[0] |= MCP41010_WRITE;
|
||||
data->buf[1] = val & 0xff;
|
||||
|
||||
err = spi_write(data->spi, data->buf, sizeof(data->buf));
|
||||
if (!err)
|
||||
data->value[channel] = val;
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct iio_info mcp41010_info = {
|
||||
.read_raw = mcp41010_read_raw,
|
||||
.write_raw = mcp41010_write_raw,
|
||||
};
|
||||
|
||||
static int mcp41010_probe(struct spi_device *spi)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = &spi->dev;
|
||||
struct mcp41010_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
data->spi = spi;
|
||||
data->cfg = of_device_get_match_data(&spi->dev);
|
||||
if (!data->cfg)
|
||||
data->cfg = &mcp41010_cfg[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &mcp41010_info;
|
||||
indio_dev->channels = mcp41010_channels;
|
||||
indio_dev->num_channels = data->cfg->wipers;
|
||||
indio_dev->name = data->cfg->name;
|
||||
|
||||
err = devm_iio_device_register(dev, indio_dev);
|
||||
if (err)
|
||||
dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id mcp41010_match[] = {
|
||||
{ .compatible = "microchip,mcp41010", .data = &mcp41010_cfg[MCP41010] },
|
||||
{ .compatible = "microchip,mcp41050", .data = &mcp41010_cfg[MCP41050] },
|
||||
{ .compatible = "microchip,mcp41100", .data = &mcp41010_cfg[MCP41100] },
|
||||
{ .compatible = "microchip,mcp42010", .data = &mcp41010_cfg[MCP42010] },
|
||||
{ .compatible = "microchip,mcp42050", .data = &mcp41010_cfg[MCP42050] },
|
||||
{ .compatible = "microchip,mcp42100", .data = &mcp41010_cfg[MCP42100] },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mcp41010_match);
|
||||
|
||||
static const struct spi_device_id mcp41010_id[] = {
|
||||
{ "mcp41010", MCP41010 },
|
||||
{ "mcp41050", MCP41050 },
|
||||
{ "mcp41100", MCP41100 },
|
||||
{ "mcp42010", MCP42010 },
|
||||
{ "mcp42050", MCP42050 },
|
||||
{ "mcp42100", MCP42100 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, mcp41010_id);
|
||||
|
||||
static struct spi_driver mcp41010_driver = {
|
||||
.driver = {
|
||||
.name = "mcp41010",
|
||||
.of_match_table = mcp41010_match,
|
||||
},
|
||||
.probe = mcp41010_probe,
|
||||
.id_table = mcp41010_id,
|
||||
};
|
||||
|
||||
module_spi_driver(mcp41010_driver);
|
||||
|
||||
MODULE_AUTHOR("Chris Coffey <cmc@babblebit.net>");
|
||||
MODULE_DESCRIPTION("MCP41010 digital potentiometer");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -3,6 +3,16 @@
|
|||
#
|
||||
menu "Resolver to digital converters"
|
||||
|
||||
config AD2S90
|
||||
tristate "Analog Devices ad2s90 driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for Analog Devices spi resolver
|
||||
to digital converters, ad2s90, provides direct access via sysfs.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad2s90.
|
||||
|
||||
config AD2S1200
|
||||
tristate "Analog Devices ad2s1200/ad2s1205 driver"
|
||||
depends on SPI
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
# Makefile for Resolver/Synchro drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AD2S90) += ad2s90.o
|
||||
obj-$(CONFIG_AD2S1200) += ad2s1200.o
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ad2s90.c simple support for the ADI Resolver to Digital Converters: AD2S90
|
||||
*
|
||||
* Copyright (c) 2010-2010 Analog Devices Inc.
|
||||
*
|
||||
* 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/types.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -19,8 +15,14 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
/*
|
||||
* Although chip's max frequency is 2Mhz, it needs 600ns between CS and the
|
||||
* first falling edge of SCLK, so frequency should be at most 1 / (2 * 6e-7)
|
||||
*/
|
||||
#define AD2S90_MAX_SPI_FREQ_HZ 830000
|
||||
|
||||
struct ad2s90_state {
|
||||
struct mutex lock;
|
||||
struct mutex lock; /* lock to protect rx buffer */
|
||||
struct spi_device *sdev;
|
||||
u8 rx[2] ____cacheline_aligned;
|
||||
};
|
||||
|
@ -77,7 +79,12 @@ static int ad2s90_probe(struct spi_device *spi)
|
|||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad2s90_state *st;
|
||||
int ret;
|
||||
|
||||
if (spi->max_speed_hz > AD2S90_MAX_SPI_FREQ_HZ) {
|
||||
dev_err(&spi->dev, "SPI CLK, %d Hz exceeds %d Hz\n",
|
||||
spi->max_speed_hz, AD2S90_MAX_SPI_FREQ_HZ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
|
@ -94,19 +101,15 @@ static int ad2s90_probe(struct spi_device *spi)
|
|||
indio_dev->num_channels = 1;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
|
||||
/* need 600ns between CS and the first falling edge of SCLK */
|
||||
spi->max_speed_hz = 830000;
|
||||
spi->mode = SPI_MODE_3;
|
||||
ret = spi_setup(spi);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "spi_setup failed!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(indio_dev->dev.parent, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ad2s90_of_match[] = {
|
||||
{ .compatible = "adi,ad2s90", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad2s90_of_match);
|
||||
|
||||
static const struct spi_device_id ad2s90_id[] = {
|
||||
{ "ad2s90" },
|
||||
{}
|
||||
|
@ -116,6 +119,7 @@ MODULE_DEVICE_TABLE(spi, ad2s90_id);
|
|||
static struct spi_driver ad2s90_driver = {
|
||||
.driver = {
|
||||
.name = "ad2s90",
|
||||
.of_match_table = ad2s90_of_match,
|
||||
},
|
||||
.probe = ad2s90_probe,
|
||||
.id_table = ad2s90_id,
|
|
@ -561,6 +561,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
|
|||
{
|
||||
int dev, ch, cnt;
|
||||
unsigned int index;
|
||||
struct iio_dev_attr *iio_attr;
|
||||
|
||||
st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) *
|
||||
(st->slave_num + 1) * AD7280A_CELLS_PER_DEV,
|
||||
|
@ -571,37 +572,35 @@ static int ad7280_attr_init(struct ad7280_state *st)
|
|||
for (dev = 0, cnt = 0; dev <= st->slave_num; dev++)
|
||||
for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6;
|
||||
ch++, cnt++) {
|
||||
iio_attr = &st->iio_attr[cnt];
|
||||
index = dev * AD7280A_CELLS_PER_DEV + ch;
|
||||
st->iio_attr[cnt].address =
|
||||
ad7280a_devaddr(dev) << 8 | ch;
|
||||
st->iio_attr[cnt].dev_attr.attr.mode =
|
||||
0644;
|
||||
st->iio_attr[cnt].dev_attr.show =
|
||||
ad7280_show_balance_sw;
|
||||
st->iio_attr[cnt].dev_attr.store =
|
||||
ad7280_store_balance_sw;
|
||||
st->iio_attr[cnt].dev_attr.attr.name =
|
||||
iio_attr->address = ad7280a_devaddr(dev) << 8 | ch;
|
||||
iio_attr->dev_attr.attr.mode = 0644;
|
||||
iio_attr->dev_attr.show = ad7280_show_balance_sw;
|
||||
iio_attr->dev_attr.store = ad7280_store_balance_sw;
|
||||
iio_attr->dev_attr.attr.name =
|
||||
devm_kasprintf(&st->spi->dev, GFP_KERNEL,
|
||||
"in%d-in%d_balance_switch_en",
|
||||
index, index + 1);
|
||||
ad7280_attributes[cnt] =
|
||||
&st->iio_attr[cnt].dev_attr.attr;
|
||||
if (!iio_attr->dev_attr.attr.name)
|
||||
return -ENOMEM;
|
||||
|
||||
ad7280_attributes[cnt] = &iio_attr->dev_attr.attr;
|
||||
cnt++;
|
||||
st->iio_attr[cnt].address =
|
||||
ad7280a_devaddr(dev) << 8 |
|
||||
iio_attr = &st->iio_attr[cnt];
|
||||
iio_attr->address = ad7280a_devaddr(dev) << 8 |
|
||||
(AD7280A_CB1_TIMER + ch);
|
||||
st->iio_attr[cnt].dev_attr.attr.mode =
|
||||
0644;
|
||||
st->iio_attr[cnt].dev_attr.show =
|
||||
ad7280_show_balance_timer;
|
||||
st->iio_attr[cnt].dev_attr.store =
|
||||
ad7280_store_balance_timer;
|
||||
st->iio_attr[cnt].dev_attr.attr.name =
|
||||
iio_attr->dev_attr.attr.mode = 0644;
|
||||
iio_attr->dev_attr.show = ad7280_show_balance_timer;
|
||||
iio_attr->dev_attr.store = ad7280_store_balance_timer;
|
||||
iio_attr->dev_attr.attr.name =
|
||||
devm_kasprintf(&st->spi->dev, GFP_KERNEL,
|
||||
"in%d-in%d_balance_timer",
|
||||
index, index + 1);
|
||||
ad7280_attributes[cnt] =
|
||||
&st->iio_attr[cnt].dev_attr.attr;
|
||||
if (!iio_attr->dev_attr.attr.name)
|
||||
return -ENOMEM;
|
||||
|
||||
ad7280_attributes[cnt] = &iio_attr->dev_attr.attr;
|
||||
}
|
||||
|
||||
ad7280_attributes[cnt] = NULL;
|
||||
|
@ -880,15 +879,15 @@ static int ad7280_probe(struct spi_device *spi)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->slave_num = ret;
|
||||
st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH;
|
||||
st->cell_threshhigh = 0xFF;
|
||||
st->aux_threshhigh = 0xFF;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Total Conversion Time = ((tACQ + tCONV) *
|
||||
* (Number of Conversions per Part)) −
|
||||
|
|
|
@ -30,10 +30,6 @@ static int adt7316_i2c_read(void *client, u8 reg, u8 *data)
|
|||
}
|
||||
|
||||
ret = i2c_smbus_read_byte(client);
|
||||
|
||||
if (!ret)
|
||||
return -EIO;
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&cl->dev, "I2C read error\n");
|
||||
return ret;
|
||||
|
@ -104,7 +100,6 @@ static int adt7316_i2c_probe(struct i2c_client *client,
|
|||
struct adt7316_bus bus = {
|
||||
.client = client,
|
||||
.irq = client->irq,
|
||||
.irq_flags = IRQF_TRIGGER_LOW,
|
||||
.read = adt7316_i2c_read,
|
||||
.write = adt7316_i2c_write,
|
||||
.multi_read = adt7316_i2c_multi_read,
|
||||
|
@ -126,9 +121,22 @@ static const struct i2c_device_id adt7316_i2c_id[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id);
|
||||
|
||||
static const struct of_device_id adt7316_of_match[] = {
|
||||
{ .compatible = "adi,adt7316" },
|
||||
{ .compatible = "adi,adt7317" },
|
||||
{ .compatible = "adi,adt7318" },
|
||||
{ .compatible = "adi,adt7516" },
|
||||
{ .compatible = "adi,adt7517" },
|
||||
{ .compatible = "adi,adt7519" },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, adt7316_of_match);
|
||||
|
||||
static struct i2c_driver adt7316_driver = {
|
||||
.driver = {
|
||||
.name = "adt7316",
|
||||
.of_match_table = adt7316_of_match,
|
||||
.pm = ADT7316_PM_OPS,
|
||||
},
|
||||
.probe = adt7316_i2c_probe,
|
||||
|
|
|
@ -94,7 +94,6 @@ static int adt7316_spi_probe(struct spi_device *spi_dev)
|
|||
struct adt7316_bus bus = {
|
||||
.client = spi_dev,
|
||||
.irq = spi_dev->irq,
|
||||
.irq_flags = IRQF_TRIGGER_LOW,
|
||||
.read = adt7316_spi_read,
|
||||
.write = adt7316_spi_write,
|
||||
.multi_read = adt7316_spi_multi_read,
|
||||
|
|
|
@ -177,7 +177,7 @@
|
|||
|
||||
struct adt7316_chip_info {
|
||||
struct adt7316_bus bus;
|
||||
u16 ldac_pin;
|
||||
struct gpio_desc *ldac_pin;
|
||||
u16 int_mask; /* 0x2f */
|
||||
u8 config1;
|
||||
u8 config2;
|
||||
|
@ -950,8 +950,8 @@ static ssize_t adt7316_store_update_DAC(struct device *dev,
|
|||
if (ret)
|
||||
return -EIO;
|
||||
} else {
|
||||
gpio_set_value(chip->ldac_pin, 0);
|
||||
gpio_set_value(chip->ldac_pin, 1);
|
||||
gpiod_set_value(chip->ldac_pin, 0);
|
||||
gpiod_set_value(chip->ldac_pin, 1);
|
||||
}
|
||||
|
||||
return len;
|
||||
|
@ -2104,6 +2104,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
|
|||
struct adt7316_chip_info *chip;
|
||||
struct iio_dev *indio_dev;
|
||||
unsigned short *adt7316_platform_data = dev->platform_data;
|
||||
int irq_type = IRQF_TRIGGER_LOW;
|
||||
int ret = 0;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
|
||||
|
@ -2122,7 +2123,13 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
|
|||
else
|
||||
return -ENODEV;
|
||||
|
||||
chip->ldac_pin = adt7316_platform_data[1];
|
||||
chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(chip->ldac_pin)) {
|
||||
ret = PTR_ERR(chip->ldac_pin);
|
||||
dev_err(dev, "Failed to request ldac GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (chip->ldac_pin) {
|
||||
chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA;
|
||||
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
|
||||
|
@ -2142,19 +2149,18 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
|
|||
|
||||
if (chip->bus.irq > 0) {
|
||||
if (adt7316_platform_data[0])
|
||||
chip->bus.irq_flags = adt7316_platform_data[0];
|
||||
irq_type = adt7316_platform_data[0];
|
||||
|
||||
ret = devm_request_threaded_irq(dev, chip->bus.irq,
|
||||
NULL,
|
||||
adt7316_event_handler,
|
||||
chip->bus.irq_flags |
|
||||
IRQF_ONESHOT,
|
||||
irq_type | IRQF_ONESHOT,
|
||||
indio_dev->name,
|
||||
indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH)
|
||||
if (irq_type & IRQF_TRIGGER_HIGH)
|
||||
chip->config1 |= ADT7316_INT_POLARITY;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
struct adt7316_bus {
|
||||
void *client;
|
||||
int irq;
|
||||
int irq_flags;
|
||||
int (*read)(void *client, u8 reg, u8 *data);
|
||||
int (*write)(void *client, u8 reg, u8 val);
|
||||
int (*multi_read)(void *client, u8 first_reg, u8 count, u8 *data);
|
||||
|
|
|
@ -786,9 +786,18 @@ static const struct i2c_device_id ad5933_id[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(i2c, ad5933_id);
|
||||
|
||||
static const struct of_device_id ad5933_of_match[] = {
|
||||
{ .compatible = "adi,ad5933" },
|
||||
{ .compatible = "adi,ad5934" },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, ad5933_of_match);
|
||||
|
||||
static struct i2c_driver ad5933_driver = {
|
||||
.driver = {
|
||||
.name = "ad5933",
|
||||
.of_match_table = ad5933_of_match,
|
||||
},
|
||||
.probe = ad5933_probe,
|
||||
.remove = ad5933_remove,
|
||||
|
|
|
@ -3,16 +3,6 @@
|
|||
#
|
||||
menu "Resolver to digital converters"
|
||||
|
||||
config AD2S90
|
||||
tristate "Analog Devices ad2s90 driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for Analog Devices spi resolver
|
||||
to digital converters, ad2s90, provides direct access via sysfs.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad2s90.
|
||||
|
||||
config AD2S1210
|
||||
tristate "Analog Devices ad2s1210 driver"
|
||||
depends on SPI
|
||||
|
|
|
@ -2,5 +2,4 @@
|
|||
# Makefile for Resolver/Synchro drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AD2S90) += ad2s90.o
|
||||
obj-$(CONFIG_AD2S1210) += ad2s1210.o
|
||||
|
|
Loading…
Reference in New Issue