Last edited 6 months ago

ADC OpenSTLinux drivers

Applicable for STM32MP13x lines, STM32MP15x lines, STM32MP25x lines

1. Article purpose[edit | edit source]

This article introduces the Linux®, U-Boot and OP-TEE drivers for the ADC internal peripheral. It answers the following questions:

  • Which ADC features are supported by the driver.
  • How to configure, use and debug the driver.
  • What is the driver structure, and where the source code can be found.

2. Short description[edit | edit source]

The ADC internal peripheral is supported in Linux, U-boot and OP-TEE software components through dedicated drivers. Refer to ADC internal peripheral to know the actual support of an ADC particular instance, depending on STM32 MPU device and execution context (here U-Boot, OP-TEE or Linux context).

2.1. U-Boot driver[edit | edit source]

The U-Boot driver is based on the adc-uclass framework. This framework offers an API [1] which can be used to implement ADC client applications.
The U-Boot driver supports one shot conversions in single and scan modes. It uses poll mechanism to monitor the end of ADC conversions, interrupts, or DMA being not supported.

2.2. OP-TEE driver[edit | edit source]

This chapter is only applicable for STM32MP13x lines More info.png.

The OP-TEE driver is based on the OP-TEE ADC framework. This framework offers an API which can be used to implement ADC client applications.
The OP-TEE driver supports one shot or repetitive conversions in single and scan modes. The ADC watchdogs can be configured and enabled, to trigger tamper signals, in given voltage ranges. It uses a poll mechanism to monitor the end of ADC conversions, interrupts or DMA being not supported.

2.3. Linux kernel driver[edit | edit source]

The ADC Linux® driver (kernel space) is based on the IIO framework.
It supports two modes:

  1. IIO direct mode: single capture on a channel (using interrupts).
  2. IIO triggered buffer mode: capture on one or more channels (preferably using DMA).
    It uses the hardware triggers available in IIO. See TIM Linux driver and LPTIM Linux driver for more details.

2.4. Calibration handover between U-Boot and Linux kernel drivers[edit | edit source]

The U-boot and Linux kernel drivers implement calibration support to improve the ADC accuracy. The recommendations to enhance ADC accuracy can be found in the application note AN2834. The ADC internal peripheral offers two kind of calibration:

  • Offset calibration

This calibration is fast and may vary over time depending on voltage and temperature variations. The offset single-ended and differential calibration is performed on each boot in U-boot driver, and each time, new conversions are launched in the Linux kernel driver.

  • Linear calibration (STM32MP15x lines More info.png only)

The linear calibration is SoC dependent. This calibration is time consuming and does not change over time because it is not voltage or temperature dependent. It can be then done only once, on first boot.

Info white.png Information
To minimize clock and voltage disturbances, the linear calibration is performed in U-Boot, when there is a minimal CPU activity. The ADC is kept active during the handover between U-Boot and Linux kernel, which allows the ADC Linux driver to retrieve the linear calibration factors from the ADC registers.

ADC calibration in U-Boot

ADC calibration in Linux kernel

3. Configuration[edit | edit source]

3.1. U-Boot configuration[edit | edit source]

The ADC U-Boot driver can be activated in the U-Boot configuration using the U-Boot Menuconfig tool (enable CONFIG_STM32_ADC).

Device Drivers  --->
	[*] Enable STMicroelectronics STM32 ADC driver

The ADC command line interface can be activated by enabling CMD_ADC flag.

Command line interface  --->
	Device access commands --->
		[*] adc - Access Analog to Digital Converters info and data

3.2. OP-TEE configuration[edit | edit source]

This chapter is only applicable for STM32MP13x lines More info.png.

The ADC OP-TEE driver can be activated by enabling the build directives CFG_DRIVERS_ADC (ADC framework) and CFG_STM32_ADC (STM32 ADC driver).

Refer to How to configure OP-TEE article for details on OP-TEE configuration.

3.3. Linux kernel configuration[edit | edit source]

The ADC Linux driver can be activated in the kernel configuration using the Linux Menuconfig tool (enable both CONFIG_STM32_ADC_CORE and CONFIG_STM32_ADC).

Device Drivers  --->
   <*> Industrial I/O support  --->
      Analog to digital converters  --->
         <*> STMicroelectronics STM32 adc core
         <*> STMicroelectronics STM32 adc

3.4. Device tree[edit | edit source]

Refer to the ADC device tree configuration article where the configuration of ADC Linux kernel, OP-TEE and U-boot drivers is explained.

4. How to use[edit | edit source]

4.1. U-Boot driver[edit | edit source]

The analog-to-digital converters information and data can be accessed through the ADC command line tool. For that, the command line interface must be enabled in U-Boot configuration. This interface makes use of U-Boot ADC API [1].

 adc
Usage:
adc list - list ADC devices
adc info <name> - Get ADC device info
adc single <name> <channel> - Get Single data of ADC device channel
adc scan <name> [channel mask] - Scan all [or masked] ADC channels

4.2. OP-TEE driver[edit | edit source]

This chapter is only applicable for STM32MP13x lines More info.png.

An application using ADC services, needs to register itself as a consumer of ADC channels, as shown in example Device Tree below.

adc_consumer {
	compatible = "adc-consumer";
	io-channels = <&adc2 14>, <&adc2 16>;   /* Consumer of adc2 channels 14 & 16 */
};

The corresponding consumer device can use the OP-TEE ADC framework API [2], to configure the ADC and launch conversions, as shown in code sample below.

static TEE_Result adc_consumer_probe(const void *fdt, int node, const void *compat_data __unused)
{
	struct adc_consumer **cons = NULL;
	...
	adc_consumer_get_all(fdt, node, &nb_cons, &cons);
	for (i = 0; i < nb_cons; i++)
		adc_consumer_read_processed(cons[i], &mv);
	...
}

static const struct dt_device_match adc_consumer_match_table[] = {
	{ .compatible = "adc-consumer" },
};

4.3. Linux kernel driver[edit | edit source]

In "IIO direct mode", the conversion result can be read directly from sysfs (refer to How to do a simple ADC conversion using the sysfs interface).

In "IIO triggered buffer mode", the configuration must be performed using sysfs first. Then, character device (/dev/iio:deviceX) is used to read data (refer to Convert one or more channels using triggered buffer mode).

5. How to trace and debug[edit | edit source]

5.1. In U-Boot[edit | edit source]

Refer to U-Boot - How to debug for details about debug means in U-Boots.

  • Linear calibration factors

The ADC linear calibration factors are saved as persistent environment variables named "adc<addr>_lincalfact<index>". These variables can be displayed through the printenv command (STM32MP15x lines More info.png only):

 printenv
adc48003000_lincalfact1=1fe80602
adc48003000_lincalfact2=1da7c9ff
adc48003000_lincalfact3=1ff7e9b8
...

5.2. In OP-TEE[edit | edit source]

Refer to How to debug OP-TEE for details about debug means in OP-TEE.

5.3. In Linux kernel[edit | edit source]

Refer to How to trace with dynamic debug for how to enable the debug logs in the driver and in the framework.

Refer to How to debug with debugfs for how to access information on ADC driver.

The ADC has system wide dependencies towards other key resources:

  • runtime power management can be disabled, for example it may be forced on via power/control sysfs entry:
 cd /sys/devices/platform/soc/48003000.adc/48003000.adc:adc@0
 cat power/autosuspend_delay_ms
2000
 cat power/control
auto                                     # kernel is allowed to automatically suspend the ADC device after autosuspend_delay_ms
 echo on > power/control         # force the kernel to resume the ADC device (e.g. keep clocks and regulators enabled)
Info white.png Information
It might be useful to disable runtime power management in order to dump registers by any means or to check clock and regulator usage (see example below).
  • clock[3] usage can be verified by reading clk_summary:
 cat /sys/kernel/debug/clk/clk_summary | grep adc
         adc12_k                     1        1        0    24000000          0 0
                  adc12              1        1        0   196607910          0 0
  • regulator[4] tree and usage can be verified (for example, use count, open count or regulator reference voltage) as follows:
 cat /sys/kernel/debug/regulator/regulator_summary
 regulator                      use open bypass voltage current     min     max
-------------------------------------------------------------------------------
    v3v3                          4    5      0  3300mV     0mA  3300mV  3300mV
       vdda                       1    2      0  2900mV     0mA  2900mV  2900mV 
          40017000.dac                                              0mV     0mV
          48003000.adc                                              0mV     0mV
  • pinctrl[5] usage can be verified by reading pinmux-pins:
 cd /sys/kernel/debug/pinctrl/soc\:pin*@50002000/
 cat pinmux-pins | grep adc
pin 92 (PF12): device 48003000.adc function analog group PF12   # check pin is assigned to ADC and is configured as "analog"
  • interrupts can be verified by reading "interrupts":
 cat /proc/interrupts
           CPU0       CPU1
 56:          2          0     dummy   0 Edge      48003000.adc:adc@0
  • Linear calibration factors

The Linear calibration factors can be checked through debugfs (STM32MP15x lines More info.png only):

 cat /sys/kernel/debug/iio/iio:device*/lincalfact*
527955453
521648626
...

6. Source code location[edit | edit source]

6.1. U-Boot[edit | edit source]

The ADC source code is composed of:

  • stm32-adc-core driver to handle common resources such as clock (selection, prescaler), regulator used as reference voltage, interrupt and common registers.
  • stm32-adc driver to handle the resources available for each ADC such as channel configuration.

6.2. OP-TEE driver[edit | edit source]

This chapter is only applicable for STM32MP13x lines More info.png.

The ADC source code is composed of:

  • stm32_adc_core driver to handle common resources such as clock (selection, prescaler), regulator used as reference voltage and common registers.
  • stm32_adc driver to handle the resources available for each ADC such as calibration and channel configuration.

6.3. Linux kernel[edit | edit source]

The ADC source code is composed of:

  • stm32-adc-core driver to handle common resources such as clock (selection, prescaler), regulator used as reference voltage, interrupt, and common registers.
  • stm32-adc driver to handle the resources available for each ADC such as channel configuration and buffer handling.

7. References[edit | edit source]