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.marc...@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 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.marc...@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 #define EXYNOS5420_UART_BASE 0x12C00000 #define EXYNOS5420_I2C_BASE 0x12C60000 #define EXYNOS5420_I2C_8910_BASE 0x12E00000 +#define EXYNOS5420_ADC_BASE 0x12D10000 #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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot