
Hello,
On 09/01/2015 02:33 AM, Simon Glass wrote:
Hi Przemyslaw,
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@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@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?
Ok, I can add a simple ADC uclass.
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@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?
Yes, will remove.
#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.
Right
#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
Thanks,