[U-Boot] [PATCH 6/7] Exynos: add internal ADC driver

Simon Glass sjg at chromium.org
Tue Sep 1 02:33:28 CEST 2015


Hi Przemyslaw,

On 28 August 2015 at 07:59, Przemyslaw Marczak <p.marczak at samsung.com> wrote:
> This commit adds driver for Voltage Level Monitor based
> on 12-bit resolution internal ADC with 9-channel multiplexer.
>
> New function:
> - exynos_adc_read_channel(int channel) - returns an 12-bit average
>   value after 8 time conversion, done by the hardware.
>   The default sample rate is: 600kSPS. The channel range: 0-9.
>
> Signed-off-by: Przemyslaw Marczak <p.marczak at samsung.com>
> ---
>  arch/arm/mach-exynos/Makefile           |  1 +
>  arch/arm/mach-exynos/adc.c              | 83 +++++++++++++++++++++++++++++++++
>  arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++++++++
>  arch/arm/mach-exynos/include/mach/cpu.h |  4 +-
>  4 files changed, 131 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/mach-exynos/adc.c

Can we add this to the device tree? Maybe we should even have a driver
model uclass for ADC?

>
> diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
> index 8542f89..4b7f91f 100644
> --- a/arch/arm/mach-exynos/Makefile
> +++ b/arch/arm/mach-exynos/Makefile
> @@ -7,6 +7,7 @@
>
>  obj-y  += clock.o power.o soc.o system.o pinmux.o tzpc.o
>
> +obj-$(CONFIG_EXYNOS5420)       += adc.o
>  obj-$(CONFIG_EXYNOS5420)       += sec_boot.o
>
>  ifdef CONFIG_SPL_BUILD
> diff --git a/arch/arm/mach-exynos/adc.c b/arch/arm/mach-exynos/adc.c
> new file mode 100644
> index 0000000..e8dd619
> --- /dev/null
> +++ b/arch/arm/mach-exynos/adc.c
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (C) 2015 Samsung Electronics
> + * Przemyslaw Marczak <p.marczak at samsung.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +#include <common.h>
> +#include <errno.h>
> +#include <asm/arch/adc.h>
> +#include <asm/arch/power.h>
> +
> +extern void sdelay(unsigned long loops);
> +
> +struct exynos_adc_v2 *exynos_adc_probe(void)
> +{
> +       struct exynos_adc_v2 *adc;
> +
> +       adc = (struct exynos_adc_v2 *)samsung_get_base_adc();
> +       if (!adc) {
> +               error("Invalid ADC base address!");
> +               return NULL;
> +       }
> +
> +       /* Check HW version */
> +       if (readl(&adc->version) != ADC_V2_VERSION) {
> +               error("This driver supports only ADC v2!");
> +               return NULL;
> +       }
> +
> +       /* ADC Reset */
> +       writel(ADC_V2_CON1_SOFT_RESET, &adc->con1);
> +
> +       return adc;
> +}
> +
> +static void exynos_adc_start_conversion(struct exynos_adc_v2 *adc, int channel)
> +{
> +       unsigned int cfg;
> +
> +       /* Disable INT - will read status only */
> +       writel(0x0, &adc->int_en);
> +
> +       /* CON2 - set conversion parameters */
> +       cfg = ADC_V2_CON2_C_TIME(3); /* Conversion times: (1 << 3) = 8 */
> +       cfg |= ADC_V2_CON2_OSEL(OSEL_BINARY);
> +       cfg |= ADC_V2_CON2_CHAN_SEL(channel);
> +       cfg |= ADC_V2_CON2_ESEL(ESEL_ADC_EVAL_TIME_20CLK);
> +       cfg |= ADC_V2_CON2_HIGHF(HIGHF_CONV_RATE_600KSPS);
> +       writel(cfg, &adc->con2);
> +
> +       /* Start conversion */
> +       cfg = readl(&adc->con1);
> +       writel(cfg | ADC_V2_CON1_STC_EN, &adc->con1);
> +}
> +
> +int exynos_adc_read_channel(int channel)
> +{
> +       struct exynos_adc_v2 *adc;
> +       int timeout_us = ADC_V2_CONV_TIMEOUT_US;
> +
> +       adc = exynos_adc_probe();
> +       if (!adc) {
> +               error("Can't init ADC!");
> +               return -ENODEV;
> +       }
> +
> +       if (channel > ADC_V2_MAX_CHANNEL) {
> +               error("ADC: max channel is: %d.", ADC_V2_MAX_CHANNEL);
> +               return -ENODEV;
> +       }
> +
> +       exynos_adc_start_conversion(adc, channel);
> +
> +       while (ADC_V2_GET_STATUS_FLAG(readl(&adc->status)) != FLAG_CONV_END) {
> +               sdelay(4);
> +               if (!timeout_us--) {
> +                       error("ADC conversion timeout!");
> +                       return -ETIME;
> +               }
> +       }
> +
> +       return readl(&adc->dat) & ADC_V2_DAT_MASK;
> +}
> diff --git a/arch/arm/mach-exynos/include/mach/adc.h b/arch/arm/mach-exynos/include/mach/adc.h
> index a0e26d7..228acf4 100644
> --- a/arch/arm/mach-exynos/include/mach/adc.h
> +++ b/arch/arm/mach-exynos/include/mach/adc.h
> @@ -9,6 +9,38 @@
>  #ifndef __ASM_ARM_ARCH_ADC_H_
>  #define __ASM_ARM_ARCH_ADC_H_
>
> +#define ADC_V2_CON1_SOFT_RESET         (0x2 << 1)
> +#define ADC_V2_CON1_STC_EN             (0x1)
> +
> +#define ADC_V2_CON2_OSEL(x)            (((x) & 0x1) << 10)
> +#define OSEL_2S                                (0x0)
> +#define OSEL_BINARY                    (0x1)
> +#define ADC_V2_CON2_ESEL(x)            (((x) & 0x1) << 9)
> +#define ESEL_ADC_EVAL_TIME_40CLK       (0x0)
> +#define ESEL_ADC_EVAL_TIME_20CLK       (0x1)
> +#define ADC_V2_CON2_HIGHF(x)           (((x) & 0x1) << 8)
> +#define HIGHF_CONV_RATE_30KSPS         (0x0)
> +#define HIGHF_CONV_RATE_600KSPS                (0x1)
> +#define ADC_V2_CON2_C_TIME(x)          (((x) & 0x7) << 4)
> +#define ADC_V2_CON2_CHAN_SEL(x)                ((x) & 0xf)
> +
> +#define ADC_V2_GET_STATUS_FLAG(x)      (((x) >> 2) & 0x1)
> +#define FLAG_CONV_END                  (0x1)
> +
> +#define ADC_V2_INT_DISABLE             (0x0)
> +#define ADC_V2_INT_ENABLE              (0x1)
> +#define INT_NOT_GENERATED              (0x0)
> +#define INT_GENERATED                  (0x1)
> +
> +#define ADC_V2_VERSION                 (0x80000008)
> +
> +#define ADC_V2_MAX_CHANNEL             (9)
> +
> +/* For default 8 time convertion with sample rate 600 kSPS - 15us timeout */
> +#define ADC_V2_CONV_TIMEOUT_US         (15)
> +
> +#define ADC_V2_DAT_MASK                        (0xfff)
> +
>  #ifndef __ASSEMBLY__
>  struct s5p_adc {
>         unsigned int adccon;
> @@ -21,6 +53,19 @@ struct s5p_adc {
>         unsigned int adcmux;
>         unsigned int adcclrintpndnup;
>  };
> +
> +struct exynos_adc_v2 {
> +       unsigned int con1;
> +       unsigned int con2;
> +       unsigned int status;
> +       unsigned int dat;
> +       unsigned int int_en;
> +       unsigned int int_status;
> +       unsigned int reserved[2];
> +       unsigned int version;
> +};
> +
> +int exynos_adc_read_channel(int channel);
>  #endif
>
>  #endif /* __ASM_ARM_ARCH_ADC_H_ */
> diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h
> index 14a1692..75933e7 100644
> --- a/arch/arm/mach-exynos/include/mach/cpu.h
> +++ b/arch/arm/mach-exynos/include/mach/cpu.h
> @@ -167,10 +167,11 @@
>  #define EXYNOS5420_USB_HOST_EHCI_BASE  0x12110000
>  #define EXYNOS5420_MMC_BASE            0x12200000
>  #define EXYNOS5420_SROMC_BASE          0x12250000
> -#define EXYNOS5420_USB3PHY_BASE        0x12500000
> +#define EXYNOS5420_USB3PHY_BASE                0x12500000

unrelated change?

>  #define EXYNOS5420_UART_BASE           0x12C00000
>  #define EXYNOS5420_I2C_BASE            0x12C60000
>  #define EXYNOS5420_I2C_8910_BASE       0x12E00000
> +#define EXYNOS5420_ADC_BASE            0x12D10000

Then we can drop this.

>  #define EXYNOS5420_SPI_BASE            0x12D20000
>  #define EXYNOS5420_I2S_BASE            0x12D60000
>  #define EXYNOS5420_PWMTIMER_BASE       0x12DD0000
> @@ -186,7 +187,6 @@
>  #define EXYNOS5420_USBPHY_BASE         DEVICE_NOT_AVAILABLE
>  #define EXYNOS5420_USBOTG_BASE         DEVICE_NOT_AVAILABLE
>  #define EXYNOS5420_FIMD_BASE           DEVICE_NOT_AVAILABLE
> -#define EXYNOS5420_ADC_BASE            DEVICE_NOT_AVAILABLE
>  #define EXYNOS5420_MODEM_BASE          DEVICE_NOT_AVAILABLE
>  #define EXYNOS5420_USB_HOST_XHCI_BASE  DEVICE_NOT_AVAILABLE
>
> --
> 1.9.1
>

Regards,
Simon


More information about the U-Boot mailing list