[U-Boot] [PATCH 0/7] Add board detection for Odroid XU3 / XU3Lite / XU4

This patchset adds: - define the CPU name for Chromebook Peach Pi as Exynos5800 - set the cpu id of Exynos5422 to 0x5422 - S2MPS11 PMIC I/O driver - Exynos5420-compatible (9-channel, 12-bit) ADC driver - board detection for Odroid XU3 / XU3lite / XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-patchset-test
Przemyslaw Marczak (7): s5p: cpu_info: use defined CPU name if available peach-pi: define CPU name for SoC Exynos5800 Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver odroid-xu3: enable s2mps11 PMIC support Exynos: add internal ADC driver exynos5-dt: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 5 ++ arch/arm/dts/exynos5422-odroidxu3.dts | 7 ++ arch/arm/mach-exynos/Makefile | 1 + arch/arm/mach-exynos/adc.c | 83 ++++++++++++++++++++++ arch/arm/mach-exynos/clock.c | 16 ++--- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++ arch/arm/mach-exynos/include/mach/cpu.h | 10 +-- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/exynos5-dt.c | 114 ++++++++++++++++++++++++++++++ configs/odroid-xu3_defconfig | 3 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/configs/odroid_xu3.h | 12 ++++ include/configs/peach-pi.h | 2 + include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++ 21 files changed, 493 insertions(+), 20 deletions(-) create mode 100644 arch/arm/mach-exynos/adc.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h

The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined by the config file.
This commit introduces new config: - CONFIG_CPU_NAME - with cpu name string
If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- arch/arm/cpu/armv7/s5p-common/cpu_info.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..9b125a3 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -30,7 +30,12 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { +/* For SoC with no real CPU ID in naming convention. */ +#ifdef CONFIG_CPU_NAME + printf("CPU: %s @ ", CONFIG_CPU_NAME); +#else printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id); +#endif print_freq(get_arm_clk(), "\n");
return 0;

Hi Przemyslaw,
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined by the config file.
This commit introduces new config:
- CONFIG_CPU_NAME - with cpu name string
If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..9b125a3 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -30,7 +30,12 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { +/* For SoC with no real CPU ID in naming convention. */ +#ifdef CONFIG_CPU_NAME
printf("CPU: %s @ ", CONFIG_CPU_NAME);
+#else printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id); +#endif
This adds a new CONFIG option - we should be trying to keep the code common. Does it print 5422 instead of 5800?
I'd suggest, either:
a) we don't care, 5422 is fine b) we grab it from the device tree model or compatible string
print_freq(get_arm_clk(), "\n"); return 0;
-- 1.9.1
Regards, Simon

Hello Simon,
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:
The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined by the config file.
This commit introduces new config:
- CONFIG_CPU_NAME - with cpu name string
If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..9b125a3 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -30,7 +30,12 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { +/* For SoC with no real CPU ID in naming convention. */ +#ifdef CONFIG_CPU_NAME
printf("CPU: %s @ ", CONFIG_CPU_NAME);
+#else printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id); +#endif
This adds a new CONFIG option - we should be trying to keep the code common. Does it print 5422 instead of 5800?
Yes, it does.
I'd suggest, either:
a) we don't care, 5422 is fine b) we grab it from the device tree model or compatible string
Ok, the second one seem to be good.
print_freq(get_arm_clk(), "\n"); return 0;
-- 1.9.1
Regards, Simon
Best regards,

This platform is based on Exynos5800 but the cpu id is 0x5422. This doesn't fit the common Exynos SoC name convention, so now, the CPU name is defined in config, to be printed properly.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- include/configs/peach-pi.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/configs/peach-pi.h b/include/configs/peach-pi.h index 6c42aaa..0d7bc96 100644 --- a/include/configs/peach-pi.h +++ b/include/configs/peach-pi.h @@ -9,6 +9,8 @@ #ifndef __CONFIG_PEACH_PI_H #define __CONFIG_PEACH_PI_H
+#define CONFIG_CPU_NAME "Exynos5800" + #define MEM_LAYOUT_ENV_SETTINGS \ "bootm_size=0x10000000\0" \ "kernel_addr_r=0x22000000\0" \

The proper CPU ID for those Exynos variants is 0x5422, but before the 0x5800 was set. This commit fix this back.
Changes: - set cpu id to 0x5422 instead of 0x5800 - remove macro proid_is_exynos5800() - add macro proid_is_exynos5422() - change the calls to proid_is_exynos5800() with new macro
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- arch/arm/mach-exynos/clock.c | 16 ++++++++-------- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 ++-- arch/arm/mach-exynos/include/mach/cpu.h | 6 +++--- arch/arm/mach-exynos/include/mach/gpio.h | 4 ++-- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c index 1c6baa1..2d94851 100644 --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -159,8 +159,8 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) div = PLL_DIV_1024; else if (proid_is_exynos4412()) div = PLL_DIV_65535; - else if (proid_is_exynos5250() || proid_is_exynos5420() - || proid_is_exynos5800()) + else if (proid_is_exynos5250() || proid_is_exynos5420() || + proid_is_exynos5422()) div = PLL_DIV_65536; else return 0; @@ -346,7 +346,7 @@ static struct clk_bit_info *get_clk_bit_info(int peripheral) int i; struct clk_bit_info *info;
- if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) info = exynos542x_bit_info; else info = exynos5_bit_info; @@ -558,7 +558,7 @@ static unsigned long exynos542x_get_periph_rate(int peripheral) unsigned long clock_get_periph_rate(int peripheral) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_periph_rate(peripheral); return exynos5_get_periph_rate(peripheral); } else { @@ -1576,7 +1576,7 @@ static unsigned long exynos4_get_i2c_clk(void) unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_pll_clk(pllreg); return exynos5_get_pll_clk(pllreg); } else if (cpu_is_exynos4()) { @@ -1694,7 +1694,7 @@ void set_mmc_clk(int dev_index, unsigned int div) div -= 1;
if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_mmc_clk(dev_index, div); else exynos5_set_mmc_clk(dev_index, div); @@ -1710,7 +1710,7 @@ unsigned long get_lcd_clk(void) } else if (cpu_is_exynos5()) { if (proid_is_exynos5420()) return exynos5420_get_lcd_clk(); - else if (proid_is_exynos5800()) + else if (proid_is_exynos5422()) return exynos5800_get_lcd_clk(); else return exynos5_get_lcd_clk(); @@ -1742,7 +1742,7 @@ void set_mipi_clk(void) int set_spi_clk(int periph_id, unsigned int rate) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_set_spi_clk(periph_id, rate); return exynos5_set_spi_clk(periph_id, rate); } diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c index 0200fd1..1b7498d 100644 --- a/arch/arm/mach-exynos/clock_init_exynos5.c +++ b/arch/arm/mach-exynos/clock_init_exynos5.c @@ -971,7 +971,7 @@ static void exynos5420_system_clock_init(void)
void system_clock_init(void) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_system_clock_init(); else exynos5250_system_clock_init(); diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h index 67aac2d..2829fb2 100644 --- a/arch/arm/mach-exynos/common_setup.h +++ b/arch/arm/mach-exynos/common_setup.h @@ -78,7 +78,7 @@ static inline void configure_l2_ctlr(void) CACHE_TAG_RAM_LATENCY_2_CYCLES | CACHE_DATA_RAM_LATENCY_2_CYCLES;
- if (proid_is_exynos5420() || proid_is_exynos5800()) { + if (proid_is_exynos5420() || proid_is_exynos5422()) { val |= CACHE_ECC_AND_PARITY | CACHE_TAG_RAM_LATENCY_3_CYCLES | CACHE_DATA_RAM_LATENCY_3_CYCLES; @@ -97,7 +97,7 @@ static inline void configure_l2_actlr(void) { uint32_t val;
- if (proid_is_exynos5420() || proid_is_exynos5800()) { + if (proid_is_exynos5420() || proid_is_exynos5422()) { mrc_l2_aux_ctlr(val); val |= CACHE_ENABLE_FORCE_L2_LOGIC | CACHE_DISABLE_CLEAN_EVICT; diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index cb3d2cc..14a1692 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -237,7 +237,7 @@ static inline void s5p_set_cpu_id(void) * Exynos5800 is a variant of Exynos5420 * and has product id 0x5422 */ - s5p_cpu_id = 0x5800; + s5p_cpu_id = 0x5422; break; } } @@ -267,7 +267,7 @@ IS_EXYNOS_TYPE(exynos4210, 0x4210) IS_EXYNOS_TYPE(exynos4412, 0x4412) IS_EXYNOS_TYPE(exynos5250, 0x5250) IS_EXYNOS_TYPE(exynos5420, 0x5420) -IS_EXYNOS_TYPE(exynos5800, 0x5800) +IS_EXYNOS_TYPE(exynos5422, 0x5422)
#define SAMSUNG_BASE(device, base) \ static inline unsigned int __attribute__((no_instrument_function)) \ @@ -278,7 +278,7 @@ static inline unsigned int __attribute__((no_instrument_function)) \ return EXYNOS4X12_##base; \ return EXYNOS4_##base; \ } else if (cpu_is_exynos5()) { \ - if (proid_is_exynos5420() || proid_is_exynos5800()) \ + if (proid_is_exynos5420() || proid_is_exynos5422()) \ return EXYNOS5420_##base; \ return EXYNOS5_##base; \ } \ diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h index 9699954..7fc8e61 100644 --- a/arch/arm/mach-exynos/include/mach/gpio.h +++ b/arch/arm/mach-exynos/include/mach/gpio.h @@ -1398,7 +1398,7 @@ static struct gpio_info exynos5420_gpio_data[EXYNOS5420_GPIO_NUM_PARTS] = { static inline struct gpio_info *get_gpio_data(void) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_gpio_data; else return exynos5_gpio_data; @@ -1415,7 +1415,7 @@ static inline struct gpio_info *get_gpio_data(void) static inline unsigned int get_bank_num(void) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return EXYNOS5420_GPIO_NUM_PARTS; else return EXYNOS5_GPIO_NUM_PARTS; diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c index 179b294..a556e4a 100644 --- a/arch/arm/mach-exynos/pinmux.c +++ b/arch/arm/mach-exynos/pinmux.c @@ -858,7 +858,7 @@ static int exynos4x12_pinmux_config(int peripheral, int flags) int exynos_pinmux_config(int peripheral, int flags) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_pinmux_config(peripheral, flags); else if (proid_is_exynos5250()) return exynos5_pinmux_config(peripheral, flags); diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c index 1b12051..cd2d661 100644 --- a/arch/arm/mach-exynos/power.c +++ b/arch/arm/mach-exynos/power.c @@ -125,7 +125,7 @@ static void exynos5420_set_usbdev_phy_ctrl(unsigned int enable) void set_usbdrd_phy_ctrl(unsigned int enable) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_usbdev_phy_ctrl(enable); else exynos5_set_usbdrd_phy_ctrl(enable);

On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
The proper CPU ID for those Exynos variants is 0x5422, but before the 0x5800 was set. This commit fix this back.
Changes:
- set cpu id to 0x5422 instead of 0x5800
- remove macro proid_is_exynos5800()
- add macro proid_is_exynos5422()
- change the calls to proid_is_exynos5800() with new macro
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
arch/arm/mach-exynos/clock.c | 16 ++++++++-------- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 ++-- arch/arm/mach-exynos/include/mach/cpu.h | 6 +++--- arch/arm/mach-exynos/include/mach/gpio.h | 4 ++-- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with: - CONFIG_DM_PMIC_S2MPS11 and additional, if were not defined: - CONFIG_CMD_PMIC - CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..db8d624 --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUBNG, S2MPS11 PMIC + +This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c + +Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66 + +With those two properties, the pmic device can be used for read/write only. + +Example: + +s2mps11@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; +}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fc6a374..c66b352 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -24,6 +24,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config DM_PMIC_S2MPS11 + bool "Enable Driver Model for PMIC Samsung S2MPS11" + depends on DM_PMIC + ---help--- + The Samsung S2MPS11 PMIC provides: + - 38 adjustable LDO regulators + - 9 High-Efficiency Buck Converters + - 1 BuckBoost Converter + - RTC with two alarms + - Backup battery charger + - I2C Configuration Interface + This driver provides access to I/O interface only. + Binding info: doc/device-tree-bindings/pmic/s2mps11.txt + config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 99c5778..1b58d98 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_DM_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int s2mps11_reg_count(struct udevice *dev) +{ + return S2MPS11_REG_COUNT; +} + +static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + error("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + error("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static struct dm_pmic_ops s2mps11_ops = { + .reg_count = s2mps11_reg_count, + .read = s2mps11_read, + .write = s2mps11_write, +}; + +static const struct udevice_id s2mps11_ids[] = { + { .compatible = "samsung,s2mps11-pmic" }, + { } +}; + +U_BOOT_DRIVER(pmic_s2mps11) = { + .name = "s2mps11_pmic", + .id = UCLASS_PMIC, + .of_match = s2mps11_ids, + .ops = &s2mps11_ops, +}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..885a816 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __INCLUDE__S2MPS11__H__ +#define __INCLUDE__S2MPS11__H__ + +enum s2mps11_reg { + S2MPS11_REG_ID = 0, + S2MPS11_REG_INT1, + S2MPS11_REG_INT2, + S2MPS11_REG_INT3, + S2MPS11_REG_INT1M, + S2MPS11_REG_INT2M, + S2MPS11_REG_INT3M, + S2MPS11_REG_STATUS1, + S2MPS11_REG_STATUS2, + S2MPS11_REG_OFFSRC, + S2MPS11_REG_PWRONSRC, + S2MPS11_REG_RTC_CTRL, + S2MPS11_REG_CTRL1, + S2MPS11_REG_ETC_TEST, + S2MPS11_REG_RSVD3, + S2MPS11_REG_BU_CHG, + S2MPS11_REG_RAMP, + S2MPS11_REG_RAMP_BUCK, + S2MPS11_REG_LDO1_8, + S2MPS11_REG_LDO9_16, + S2MPS11_REG_LDO17_24, + S2MPS11_REG_LDO25_32, + S2MPS11_REG_LDO33_38, + S2MPS11_REG_LDO1_8_OVC, + S2MPS11_REG_LDO9_16_OVC, + S2MPS11_REG_LDO17_24_OVC, + S2MPS11_REG_LDO25_32_OVC, + S2MPS11_REG_LDO33_38_OVC, + S2MPS11_REG_RESERVED1, + S2MPS11_REG_RESERVED2, + S2MPS11_REG_RESERVED3, + S2MPS11_REG_RESERVED4, + S2MPS11_REG_RESERVED5, + S2MPS11_REG_RESERVED6, + S2MPS11_REG_RESERVED7, + S2MPS11_REG_RESERVED8, + S2MPS11_REG_WDRSTEN_CTRL, + S2MPS11_REG_B1CTRL1, + S2MPS11_REG_B1CTRL2, + S2MPS11_REG_B2CTRL1, + S2MPS11_REG_B2CTRL2, + S2MPS11_REG_B3CTRL1, + S2MPS11_REG_B3CTRL2, + S2MPS11_REG_B4CTRL1, + S2MPS11_REG_B4CTRL2, + S2MPS11_REG_B5CTRL1, + S2MPS11_REG_BUCK5_SW, + S2MPS11_REG_B5CTRL2, + S2MPS11_REG_B5CTRL3, + S2MPS11_REG_B5CTRL4, + S2MPS11_REG_B5CTRL5, + S2MPS11_REG_B6CTRL1, + S2MPS11_REG_B6CTRL2, + S2MPS11_REG_B7CTRL1, + S2MPS11_REG_B7CTRL2, + S2MPS11_REG_B8CTRL1, + S2MPS11_REG_B8CTRL2, + S2MPS11_REG_B9CTRL1, + S2MPS11_REG_B9CTRL2, + S2MPS11_REG_B10CTRL1, + S2MPS11_REG_B10CTRL2, + S2MPS11_REG_L1CTRL, + S2MPS11_REG_L2CTRL, + S2MPS11_REG_L3CTRL, + S2MPS11_REG_L4CTRL, + S2MPS11_REG_L5CTRL, + S2MPS11_REG_L6CTRL, + S2MPS11_REG_L7CTRL, + S2MPS11_REG_L8CTRL, + S2MPS11_REG_L9CTRL, + S2MPS11_REG_L10CTRL, + S2MPS11_REG_L11CTRL, + S2MPS11_REG_L12CTRL, + S2MPS11_REG_L13CTRL, + S2MPS11_REG_L14CTRL, + S2MPS11_REG_L15CTRL, + S2MPS11_REG_L16CTRL, + S2MPS11_REG_L17CTRL, + S2MPS11_REG_L18CTRL, + S2MPS11_REG_L19CTRL, + S2MPS11_REG_L20CTRL, + S2MPS11_REG_L21CTRL, + S2MPS11_REG_L22CTRL, + S2MPS11_REG_L23CTRL, + S2MPS11_REG_L24CTRL, + S2MPS11_REG_L25CTRL, + S2MPS11_REG_L26CTRL, + S2MPS11_REG_L27CTRL, + S2MPS11_REG_L28CTRL, + S2MPS11_REG_L29CTRL, + S2MPS11_REG_L30CTRL, + S2MPS11_REG_L31CTRL, + S2MPS11_REG_L32CTRL, + S2MPS11_REG_L33CTRL, + S2MPS11_REG_L34CTRL, + S2MPS11_REG_L35CTRL, + S2MPS11_REG_L36CTRL, + S2MPS11_REG_L37CTRL, + S2MPS11_REG_L38CTRL, + S2MPS11_REG_COUNT, +}; + +#define S2MPS11_LDO26_ENABLE 0xec + +#endif

On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_DM_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
Reviewed-by: Simon Glass sjg@chromium.org
(2 nits below)
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..db8d624 --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUBNG, S2MPS11 PMIC
+This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c
+Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66
+With those two properties, the pmic device can be used for read/write only.
+Example:
+s2mps11@66 {
compatible = "samsung,s2mps11-pmic";
reg = <0x66>;
+}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fc6a374..c66b352 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -24,6 +24,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config DM_PMIC_S2MPS11
nit: I don't think this should have a DM_ prefix. Remember that all the CONFIG_DM_... options are going to be removed one day. It is intended to select the DM version of a subsystem. In your case you only have a DM version of the driver, so just CONFIG_PMIC_S2MPS11 seems fine.
bool "Enable Driver Model for PMIC Samsung S2MPS11"
depends on DM_PMIC
---help---
The Samsung S2MPS11 PMIC provides:
- 38 adjustable LDO regulators
- 9 High-Efficiency Buck Converters
- 1 BuckBoost Converter
- RTC with two alarms
- Backup battery charger
- I2C Configuration Interface
This driver provides access to I/O interface only.
Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 99c5778..1b58d98 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_DM_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int s2mps11_reg_count(struct udevice *dev) +{
return S2MPS11_REG_COUNT;
+}
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
+{
if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
+}
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{
if (dm_i2c_read(dev, reg, buff, len)) {
error("read error from device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
+}
+static struct dm_pmic_ops s2mps11_ops = {
.reg_count = s2mps11_reg_count,
.read = s2mps11_read,
.write = s2mps11_write,
+};
+static const struct udevice_id s2mps11_ids[] = {
{ .compatible = "samsung,s2mps11-pmic" },
{ }
+};
+U_BOOT_DRIVER(pmic_s2mps11) = {
.name = "s2mps11_pmic",
.id = UCLASS_PMIC,
.of_match = s2mps11_ids,
.ops = &s2mps11_ops,
+}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..885a816 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __INCLUDE__S2MPS11__H__
nit: I don't think you need __INCLUDE__ here
+#define __INCLUDE__S2MPS11__H__
+enum s2mps11_reg {
S2MPS11_REG_ID = 0,
S2MPS11_REG_INT1,
S2MPS11_REG_INT2,
S2MPS11_REG_INT3,
S2MPS11_REG_INT1M,
S2MPS11_REG_INT2M,
S2MPS11_REG_INT3M,
S2MPS11_REG_STATUS1,
S2MPS11_REG_STATUS2,
S2MPS11_REG_OFFSRC,
S2MPS11_REG_PWRONSRC,
S2MPS11_REG_RTC_CTRL,
S2MPS11_REG_CTRL1,
S2MPS11_REG_ETC_TEST,
S2MPS11_REG_RSVD3,
S2MPS11_REG_BU_CHG,
S2MPS11_REG_RAMP,
S2MPS11_REG_RAMP_BUCK,
S2MPS11_REG_LDO1_8,
S2MPS11_REG_LDO9_16,
S2MPS11_REG_LDO17_24,
S2MPS11_REG_LDO25_32,
S2MPS11_REG_LDO33_38,
S2MPS11_REG_LDO1_8_OVC,
S2MPS11_REG_LDO9_16_OVC,
S2MPS11_REG_LDO17_24_OVC,
S2MPS11_REG_LDO25_32_OVC,
S2MPS11_REG_LDO33_38_OVC,
S2MPS11_REG_RESERVED1,
S2MPS11_REG_RESERVED2,
S2MPS11_REG_RESERVED3,
S2MPS11_REG_RESERVED4,
S2MPS11_REG_RESERVED5,
S2MPS11_REG_RESERVED6,
S2MPS11_REG_RESERVED7,
S2MPS11_REG_RESERVED8,
S2MPS11_REG_WDRSTEN_CTRL,
S2MPS11_REG_B1CTRL1,
S2MPS11_REG_B1CTRL2,
S2MPS11_REG_B2CTRL1,
S2MPS11_REG_B2CTRL2,
S2MPS11_REG_B3CTRL1,
S2MPS11_REG_B3CTRL2,
S2MPS11_REG_B4CTRL1,
S2MPS11_REG_B4CTRL2,
S2MPS11_REG_B5CTRL1,
S2MPS11_REG_BUCK5_SW,
S2MPS11_REG_B5CTRL2,
S2MPS11_REG_B5CTRL3,
S2MPS11_REG_B5CTRL4,
S2MPS11_REG_B5CTRL5,
S2MPS11_REG_B6CTRL1,
S2MPS11_REG_B6CTRL2,
S2MPS11_REG_B7CTRL1,
S2MPS11_REG_B7CTRL2,
S2MPS11_REG_B8CTRL1,
S2MPS11_REG_B8CTRL2,
S2MPS11_REG_B9CTRL1,
S2MPS11_REG_B9CTRL2,
S2MPS11_REG_B10CTRL1,
S2MPS11_REG_B10CTRL2,
S2MPS11_REG_L1CTRL,
S2MPS11_REG_L2CTRL,
S2MPS11_REG_L3CTRL,
S2MPS11_REG_L4CTRL,
S2MPS11_REG_L5CTRL,
S2MPS11_REG_L6CTRL,
S2MPS11_REG_L7CTRL,
S2MPS11_REG_L8CTRL,
S2MPS11_REG_L9CTRL,
S2MPS11_REG_L10CTRL,
S2MPS11_REG_L11CTRL,
S2MPS11_REG_L12CTRL,
S2MPS11_REG_L13CTRL,
S2MPS11_REG_L14CTRL,
S2MPS11_REG_L15CTRL,
S2MPS11_REG_L16CTRL,
S2MPS11_REG_L17CTRL,
S2MPS11_REG_L18CTRL,
S2MPS11_REG_L19CTRL,
S2MPS11_REG_L20CTRL,
S2MPS11_REG_L21CTRL,
S2MPS11_REG_L22CTRL,
S2MPS11_REG_L23CTRL,
S2MPS11_REG_L24CTRL,
S2MPS11_REG_L25CTRL,
S2MPS11_REG_L26CTRL,
S2MPS11_REG_L27CTRL,
S2MPS11_REG_L28CTRL,
S2MPS11_REG_L29CTRL,
S2MPS11_REG_L30CTRL,
S2MPS11_REG_L31CTRL,
S2MPS11_REG_L32CTRL,
S2MPS11_REG_L33CTRL,
S2MPS11_REG_L34CTRL,
S2MPS11_REG_L35CTRL,
S2MPS11_REG_L36CTRL,
S2MPS11_REG_L37CTRL,
S2MPS11_REG_L38CTRL,
S2MPS11_REG_COUNT,
+};
+#define S2MPS11_LDO26_ENABLE 0xec
+#endif
1.9.1
Regards, Simon

Hello,
On 09/01/2015 02:33 AM, Simon Glass wrote:
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_DM_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
Reviewed-by: Simon Glass sjg@chromium.org
(2 nits below)
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..db8d624 --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUBNG, S2MPS11 PMIC
+This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c
+Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66
+With those two properties, the pmic device can be used for read/write only.
+Example:
+s2mps11@66 {
compatible = "samsung,s2mps11-pmic";
reg = <0x66>;
+}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fc6a374..c66b352 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -24,6 +24,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config DM_PMIC_S2MPS11
nit: I don't think this should have a DM_ prefix. Remember that all the CONFIG_DM_... options are going to be removed one day. It is intended to select the DM version of a subsystem. In your case you only have a DM version of the driver, so just CONFIG_PMIC_S2MPS11 seems fine.
Ah, ok. I will update this.
bool "Enable Driver Model for PMIC Samsung S2MPS11"
depends on DM_PMIC
---help---
The Samsung S2MPS11 PMIC provides:
- 38 adjustable LDO regulators
- 9 High-Efficiency Buck Converters
- 1 BuckBoost Converter
- RTC with two alarms
- Backup battery charger
- I2C Configuration Interface
This driver provides access to I/O interface only.
Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
- config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 99c5778..1b58d98 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_DM_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int s2mps11_reg_count(struct udevice *dev) +{
return S2MPS11_REG_COUNT;
+}
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
+{
if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
+}
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{
if (dm_i2c_read(dev, reg, buff, len)) {
error("read error from device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
+}
+static struct dm_pmic_ops s2mps11_ops = {
.reg_count = s2mps11_reg_count,
.read = s2mps11_read,
.write = s2mps11_write,
+};
+static const struct udevice_id s2mps11_ids[] = {
{ .compatible = "samsung,s2mps11-pmic" },
{ }
+};
+U_BOOT_DRIVER(pmic_s2mps11) = {
.name = "s2mps11_pmic",
.id = UCLASS_PMIC,
.of_match = s2mps11_ids,
.ops = &s2mps11_ops,
+}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..885a816 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __INCLUDE__S2MPS11__H__
nit: I don't think you need __INCLUDE__ here
ok, will remove.
+#define __INCLUDE__S2MPS11__H__
+enum s2mps11_reg {
S2MPS11_REG_ID = 0,
S2MPS11_REG_INT1,
S2MPS11_REG_INT2,
S2MPS11_REG_INT3,
S2MPS11_REG_INT1M,
S2MPS11_REG_INT2M,
S2MPS11_REG_INT3M,
S2MPS11_REG_STATUS1,
S2MPS11_REG_STATUS2,
S2MPS11_REG_OFFSRC,
S2MPS11_REG_PWRONSRC,
S2MPS11_REG_RTC_CTRL,
S2MPS11_REG_CTRL1,
S2MPS11_REG_ETC_TEST,
S2MPS11_REG_RSVD3,
S2MPS11_REG_BU_CHG,
S2MPS11_REG_RAMP,
S2MPS11_REG_RAMP_BUCK,
S2MPS11_REG_LDO1_8,
S2MPS11_REG_LDO9_16,
S2MPS11_REG_LDO17_24,
S2MPS11_REG_LDO25_32,
S2MPS11_REG_LDO33_38,
S2MPS11_REG_LDO1_8_OVC,
S2MPS11_REG_LDO9_16_OVC,
S2MPS11_REG_LDO17_24_OVC,
S2MPS11_REG_LDO25_32_OVC,
S2MPS11_REG_LDO33_38_OVC,
S2MPS11_REG_RESERVED1,
S2MPS11_REG_RESERVED2,
S2MPS11_REG_RESERVED3,
S2MPS11_REG_RESERVED4,
S2MPS11_REG_RESERVED5,
S2MPS11_REG_RESERVED6,
S2MPS11_REG_RESERVED7,
S2MPS11_REG_RESERVED8,
S2MPS11_REG_WDRSTEN_CTRL,
S2MPS11_REG_B1CTRL1,
S2MPS11_REG_B1CTRL2,
S2MPS11_REG_B2CTRL1,
S2MPS11_REG_B2CTRL2,
S2MPS11_REG_B3CTRL1,
S2MPS11_REG_B3CTRL2,
S2MPS11_REG_B4CTRL1,
S2MPS11_REG_B4CTRL2,
S2MPS11_REG_B5CTRL1,
S2MPS11_REG_BUCK5_SW,
S2MPS11_REG_B5CTRL2,
S2MPS11_REG_B5CTRL3,
S2MPS11_REG_B5CTRL4,
S2MPS11_REG_B5CTRL5,
S2MPS11_REG_B6CTRL1,
S2MPS11_REG_B6CTRL2,
S2MPS11_REG_B7CTRL1,
S2MPS11_REG_B7CTRL2,
S2MPS11_REG_B8CTRL1,
S2MPS11_REG_B8CTRL2,
S2MPS11_REG_B9CTRL1,
S2MPS11_REG_B9CTRL2,
S2MPS11_REG_B10CTRL1,
S2MPS11_REG_B10CTRL2,
S2MPS11_REG_L1CTRL,
S2MPS11_REG_L2CTRL,
S2MPS11_REG_L3CTRL,
S2MPS11_REG_L4CTRL,
S2MPS11_REG_L5CTRL,
S2MPS11_REG_L6CTRL,
S2MPS11_REG_L7CTRL,
S2MPS11_REG_L8CTRL,
S2MPS11_REG_L9CTRL,
S2MPS11_REG_L10CTRL,
S2MPS11_REG_L11CTRL,
S2MPS11_REG_L12CTRL,
S2MPS11_REG_L13CTRL,
S2MPS11_REG_L14CTRL,
S2MPS11_REG_L15CTRL,
S2MPS11_REG_L16CTRL,
S2MPS11_REG_L17CTRL,
S2MPS11_REG_L18CTRL,
S2MPS11_REG_L19CTRL,
S2MPS11_REG_L20CTRL,
S2MPS11_REG_L21CTRL,
S2MPS11_REG_L22CTRL,
S2MPS11_REG_L23CTRL,
S2MPS11_REG_L24CTRL,
S2MPS11_REG_L25CTRL,
S2MPS11_REG_L26CTRL,
S2MPS11_REG_L27CTRL,
S2MPS11_REG_L28CTRL,
S2MPS11_REG_L29CTRL,
S2MPS11_REG_L30CTRL,
S2MPS11_REG_L31CTRL,
S2MPS11_REG_L32CTRL,
S2MPS11_REG_L33CTRL,
S2MPS11_REG_L34CTRL,
S2MPS11_REG_L35CTRL,
S2MPS11_REG_L36CTRL,
S2MPS11_REG_L37CTRL,
S2MPS11_REG_L38CTRL,
S2MPS11_REG_COUNT,
+};
+#define S2MPS11_LDO26_ENABLE 0xec
+#endif
1.9.1
Regards, Simon
Thanks,

Dear Przemyslaw Marczak,
Just some minor comment,
On 28/08/15 22:59, Przemyslaw Marczak wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_DM_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..db8d624 --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUBNG, S2MPS11 PMIC
SAMSUNG?
+This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c
+Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66
+With those two properties, the pmic device can be used for read/write only.
+Example:
+s2mps11@66 {
- compatible = "samsung,s2mps11-pmic";
- reg = <0x66>;
+}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fc6a374..c66b352 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -24,6 +24,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config DM_PMIC_S2MPS11
- bool "Enable Driver Model for PMIC Samsung S2MPS11"
- depends on DM_PMIC
- ---help---
- The Samsung S2MPS11 PMIC provides:
- 38 adjustable LDO regulators
- 9 High-Efficiency Buck Converters
- 1 BuckBoost Converter
- RTC with two alarms
- Backup battery charger
- I2C Configuration Interface
- This driver provides access to I/O interface only.
- Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 99c5778..1b58d98 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_DM_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int s2mps11_reg_count(struct udevice *dev) +{
- return S2MPS11_REG_COUNT;
+}
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
+{
- if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
- }
- return 0;
+}
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{
- if (dm_i2c_read(dev, reg, buff, len)) {
error("read error from device: %p register: %#x!", dev, reg);
return -EIO;
- }
- return 0;
+}
+static struct dm_pmic_ops s2mps11_ops = {
- .reg_count = s2mps11_reg_count,
- .read = s2mps11_read,
- .write = s2mps11_write,
+};
+static const struct udevice_id s2mps11_ids[] = {
- { .compatible = "samsung,s2mps11-pmic" },
- { }
+};
+U_BOOT_DRIVER(pmic_s2mps11) = {
- .name = "s2mps11_pmic",
- .id = UCLASS_PMIC,
- .of_match = s2mps11_ids,
- .ops = &s2mps11_ops,
+}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..885a816 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __INCLUDE__S2MPS11__H__ +#define __INCLUDE__S2MPS11__H__
+enum s2mps11_reg {
- S2MPS11_REG_ID = 0,
- S2MPS11_REG_INT1,
- S2MPS11_REG_INT2,
- S2MPS11_REG_INT3,
- S2MPS11_REG_INT1M,
- S2MPS11_REG_INT2M,
- S2MPS11_REG_INT3M,
- S2MPS11_REG_STATUS1,
- S2MPS11_REG_STATUS2,
- S2MPS11_REG_OFFSRC,
- S2MPS11_REG_PWRONSRC,
- S2MPS11_REG_RTC_CTRL,
- S2MPS11_REG_CTRL1,
- S2MPS11_REG_ETC_TEST,
- S2MPS11_REG_RSVD3,
- S2MPS11_REG_BU_CHG,
- S2MPS11_REG_RAMP,
- S2MPS11_REG_RAMP_BUCK,
- S2MPS11_REG_LDO1_8,
- S2MPS11_REG_LDO9_16,
- S2MPS11_REG_LDO17_24,
- S2MPS11_REG_LDO25_32,
- S2MPS11_REG_LDO33_38,
- S2MPS11_REG_LDO1_8_OVC,
- S2MPS11_REG_LDO9_16_OVC,
- S2MPS11_REG_LDO17_24_OVC,
- S2MPS11_REG_LDO25_32_OVC,
- S2MPS11_REG_LDO33_38_OVC,
- S2MPS11_REG_RESERVED1,
- S2MPS11_REG_RESERVED2,
- S2MPS11_REG_RESERVED3,
- S2MPS11_REG_RESERVED4,
- S2MPS11_REG_RESERVED5,
- S2MPS11_REG_RESERVED6,
- S2MPS11_REG_RESERVED7,
- S2MPS11_REG_RESERVED8,
- S2MPS11_REG_WDRSTEN_CTRL,
- S2MPS11_REG_B1CTRL1,
- S2MPS11_REG_B1CTRL2,
- S2MPS11_REG_B2CTRL1,
- S2MPS11_REG_B2CTRL2,
- S2MPS11_REG_B3CTRL1,
- S2MPS11_REG_B3CTRL2,
- S2MPS11_REG_B4CTRL1,
- S2MPS11_REG_B4CTRL2,
- S2MPS11_REG_B5CTRL1,
- S2MPS11_REG_BUCK5_SW,
- S2MPS11_REG_B5CTRL2,
- S2MPS11_REG_B5CTRL3,
- S2MPS11_REG_B5CTRL4,
- S2MPS11_REG_B5CTRL5,
- S2MPS11_REG_B6CTRL1,
- S2MPS11_REG_B6CTRL2,
- S2MPS11_REG_B7CTRL1,
- S2MPS11_REG_B7CTRL2,
- S2MPS11_REG_B8CTRL1,
- S2MPS11_REG_B8CTRL2,
- S2MPS11_REG_B9CTRL1,
- S2MPS11_REG_B9CTRL2,
- S2MPS11_REG_B10CTRL1,
- S2MPS11_REG_B10CTRL2,
- S2MPS11_REG_L1CTRL,
- S2MPS11_REG_L2CTRL,
- S2MPS11_REG_L3CTRL,
- S2MPS11_REG_L4CTRL,
- S2MPS11_REG_L5CTRL,
- S2MPS11_REG_L6CTRL,
- S2MPS11_REG_L7CTRL,
- S2MPS11_REG_L8CTRL,
- S2MPS11_REG_L9CTRL,
- S2MPS11_REG_L10CTRL,
- S2MPS11_REG_L11CTRL,
- S2MPS11_REG_L12CTRL,
- S2MPS11_REG_L13CTRL,
- S2MPS11_REG_L14CTRL,
- S2MPS11_REG_L15CTRL,
- S2MPS11_REG_L16CTRL,
- S2MPS11_REG_L17CTRL,
- S2MPS11_REG_L18CTRL,
- S2MPS11_REG_L19CTRL,
- S2MPS11_REG_L20CTRL,
- S2MPS11_REG_L21CTRL,
- S2MPS11_REG_L22CTRL,
- S2MPS11_REG_L23CTRL,
- S2MPS11_REG_L24CTRL,
- S2MPS11_REG_L25CTRL,
- S2MPS11_REG_L26CTRL,
- S2MPS11_REG_L27CTRL,
- S2MPS11_REG_L28CTRL,
- S2MPS11_REG_L29CTRL,
- S2MPS11_REG_L30CTRL,
- S2MPS11_REG_L31CTRL,
- S2MPS11_REG_L32CTRL,
- S2MPS11_REG_L33CTRL,
- S2MPS11_REG_L34CTRL,
- S2MPS11_REG_L35CTRL,
- S2MPS11_REG_L36CTRL,
- S2MPS11_REG_L37CTRL,
- S2MPS11_REG_L38CTRL,
- S2MPS11_REG_COUNT,
+};
+#define S2MPS11_LDO26_ENABLE 0xec
+#endif
Thanks, Minkyu Kang.

Hello Minkyu,
On 09/07/2015 02:11 AM, Minkyu Kang wrote:
Dear Przemyslaw Marczak,
Just some minor comment,
On 28/08/15 22:59, Przemyslaw Marczak wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_DM_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..db8d624 --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUBNG, S2MPS11 PMIC
SAMSUNG?
Right, will fix.
+This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c
+Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66
+With those two properties, the pmic device can be used for read/write only.
+Example:
+s2mps11@66 {
- compatible = "samsung,s2mps11-pmic";
- reg = <0x66>;
+}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fc6a374..c66b352 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -24,6 +24,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config DM_PMIC_S2MPS11
- bool "Enable Driver Model for PMIC Samsung S2MPS11"
- depends on DM_PMIC
- ---help---
- The Samsung S2MPS11 PMIC provides:
- 38 adjustable LDO regulators
- 9 High-Efficiency Buck Converters
- 1 BuckBoost Converter
- RTC with two alarms
- Backup battery charger
- I2C Configuration Interface
- This driver provides access to I/O interface only.
- Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
- config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 99c5778..1b58d98 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_DM_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int s2mps11_reg_count(struct udevice *dev) +{
- return S2MPS11_REG_COUNT;
+}
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
+{
- if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
- }
- return 0;
+}
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{
- if (dm_i2c_read(dev, reg, buff, len)) {
error("read error from device: %p register: %#x!", dev, reg);
return -EIO;
- }
- return 0;
+}
+static struct dm_pmic_ops s2mps11_ops = {
- .reg_count = s2mps11_reg_count,
- .read = s2mps11_read,
- .write = s2mps11_write,
+};
+static const struct udevice_id s2mps11_ids[] = {
- { .compatible = "samsung,s2mps11-pmic" },
- { }
+};
+U_BOOT_DRIVER(pmic_s2mps11) = {
- .name = "s2mps11_pmic",
- .id = UCLASS_PMIC,
- .of_match = s2mps11_ids,
- .ops = &s2mps11_ops,
+}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..885a816 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __INCLUDE__S2MPS11__H__ +#define __INCLUDE__S2MPS11__H__
+enum s2mps11_reg {
- S2MPS11_REG_ID = 0,
- S2MPS11_REG_INT1,
- S2MPS11_REG_INT2,
- S2MPS11_REG_INT3,
- S2MPS11_REG_INT1M,
- S2MPS11_REG_INT2M,
- S2MPS11_REG_INT3M,
- S2MPS11_REG_STATUS1,
- S2MPS11_REG_STATUS2,
- S2MPS11_REG_OFFSRC,
- S2MPS11_REG_PWRONSRC,
- S2MPS11_REG_RTC_CTRL,
- S2MPS11_REG_CTRL1,
- S2MPS11_REG_ETC_TEST,
- S2MPS11_REG_RSVD3,
- S2MPS11_REG_BU_CHG,
- S2MPS11_REG_RAMP,
- S2MPS11_REG_RAMP_BUCK,
- S2MPS11_REG_LDO1_8,
- S2MPS11_REG_LDO9_16,
- S2MPS11_REG_LDO17_24,
- S2MPS11_REG_LDO25_32,
- S2MPS11_REG_LDO33_38,
- S2MPS11_REG_LDO1_8_OVC,
- S2MPS11_REG_LDO9_16_OVC,
- S2MPS11_REG_LDO17_24_OVC,
- S2MPS11_REG_LDO25_32_OVC,
- S2MPS11_REG_LDO33_38_OVC,
- S2MPS11_REG_RESERVED1,
- S2MPS11_REG_RESERVED2,
- S2MPS11_REG_RESERVED3,
- S2MPS11_REG_RESERVED4,
- S2MPS11_REG_RESERVED5,
- S2MPS11_REG_RESERVED6,
- S2MPS11_REG_RESERVED7,
- S2MPS11_REG_RESERVED8,
- S2MPS11_REG_WDRSTEN_CTRL,
- S2MPS11_REG_B1CTRL1,
- S2MPS11_REG_B1CTRL2,
- S2MPS11_REG_B2CTRL1,
- S2MPS11_REG_B2CTRL2,
- S2MPS11_REG_B3CTRL1,
- S2MPS11_REG_B3CTRL2,
- S2MPS11_REG_B4CTRL1,
- S2MPS11_REG_B4CTRL2,
- S2MPS11_REG_B5CTRL1,
- S2MPS11_REG_BUCK5_SW,
- S2MPS11_REG_B5CTRL2,
- S2MPS11_REG_B5CTRL3,
- S2MPS11_REG_B5CTRL4,
- S2MPS11_REG_B5CTRL5,
- S2MPS11_REG_B6CTRL1,
- S2MPS11_REG_B6CTRL2,
- S2MPS11_REG_B7CTRL1,
- S2MPS11_REG_B7CTRL2,
- S2MPS11_REG_B8CTRL1,
- S2MPS11_REG_B8CTRL2,
- S2MPS11_REG_B9CTRL1,
- S2MPS11_REG_B9CTRL2,
- S2MPS11_REG_B10CTRL1,
- S2MPS11_REG_B10CTRL2,
- S2MPS11_REG_L1CTRL,
- S2MPS11_REG_L2CTRL,
- S2MPS11_REG_L3CTRL,
- S2MPS11_REG_L4CTRL,
- S2MPS11_REG_L5CTRL,
- S2MPS11_REG_L6CTRL,
- S2MPS11_REG_L7CTRL,
- S2MPS11_REG_L8CTRL,
- S2MPS11_REG_L9CTRL,
- S2MPS11_REG_L10CTRL,
- S2MPS11_REG_L11CTRL,
- S2MPS11_REG_L12CTRL,
- S2MPS11_REG_L13CTRL,
- S2MPS11_REG_L14CTRL,
- S2MPS11_REG_L15CTRL,
- S2MPS11_REG_L16CTRL,
- S2MPS11_REG_L17CTRL,
- S2MPS11_REG_L18CTRL,
- S2MPS11_REG_L19CTRL,
- S2MPS11_REG_L20CTRL,
- S2MPS11_REG_L21CTRL,
- S2MPS11_REG_L22CTRL,
- S2MPS11_REG_L23CTRL,
- S2MPS11_REG_L24CTRL,
- S2MPS11_REG_L25CTRL,
- S2MPS11_REG_L26CTRL,
- S2MPS11_REG_L27CTRL,
- S2MPS11_REG_L28CTRL,
- S2MPS11_REG_L29CTRL,
- S2MPS11_REG_L30CTRL,
- S2MPS11_REG_L31CTRL,
- S2MPS11_REG_L32CTRL,
- S2MPS11_REG_L33CTRL,
- S2MPS11_REG_L34CTRL,
- S2MPS11_REG_L35CTRL,
- S2MPS11_REG_L36CTRL,
- S2MPS11_REG_L37CTRL,
- S2MPS11_REG_L38CTRL,
- S2MPS11_REG_COUNT,
+};
+#define S2MPS11_LDO26_ENABLE 0xec
+#endif
Thanks, Minkyu Kang.
Best regards,

Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- arch/arm/dts/exynos5422-odroidxu3.dts | 7 +++++++ configs/odroid-xu3_defconfig | 3 +++ 2 files changed, 10 insertions(+)
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts index d0a8621..9dec679 100644 --- a/arch/arm/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/dts/exynos5422-odroidxu3.dts @@ -31,6 +31,13 @@ 0xb0000000 0xea00000>; };
+ i2c@12CA0000 { + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + }; + }; + ehci@12110000 { samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>; }; diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 9c3b6d6..ae6270b 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -8,7 +8,10 @@ CONFIG_DEFAULT_DEVICE_TREE="exynos5422-odroidxu3" CONFIG_DM_I2C=y CONFIG_DM_I2C_COMPAT=y CONFIG_DM_PMIC=y +CONFIG_CMD_PMIC=y +CONFIG_ERRNO_STR=y CONFIG_DM_REGULATOR=y +CONFIG_DM_PMIC_S2MPS11=y CONFIG_VIDEO_BRIDGE=y CONFIG_SYS_PROMPT="ODROID-XU3 # " CONFIG_USB=y

On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
arch/arm/dts/exynos5422-odroidxu3.dts | 7 +++++++ configs/odroid-xu3_defconfig | 3 +++ 2 files changed, 10 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

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
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 #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

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?
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?
#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

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,

There are few revisions of Odroid XU3/XU4: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 739 XU4 0.1
This commit adds implementation of functions: - set_board_type() - read ADC and set type - get_board_rev() - returns board revision: 1..3 - board_is_odroidxu3() - returns bool - board_is_odroidxu4() - returns bool - get_board_type() - returns board type string
After I2C controller init, the last function can check if the board is "Lite" variant for XU3, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
The enabled configs: - CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG - CONFIG_ODROID_REV_AIN - CONFIG_REVISION_TAG - CONFIG_MISC_INIT_R - CONFIG_BOARD_TYPES
This also redefines CONFIG_SYS_BOARD to "odroid".
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- board/samsung/common/exynos5-dt.c | 114 ++++++++++++++++++++++++++++++++++++++ include/configs/odroid_xu3.h | 12 ++++ 2 files changed, 126 insertions(+)
diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 7d1b88a..41141df 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -18,6 +18,7 @@ #include <usb.h> #include <video_bridge.h> #include <asm/gpio.h> +#include <asm/arch/adc.h> #include <asm/arch/cpu.h> #include <asm/arch/dwmmc.h> #include <asm/arch/mmc.h> @@ -28,6 +29,7 @@ #include <power/max77686_pmic.h> #include <power/regulator.h> #include <power/s5m8767.h> +#include <power/s2mps11.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -360,3 +362,115 @@ char *get_dfu_alt_boot(char *interface, char *devstr) return alt_boot; } #endif + +#ifdef CONFIG_REVISION_TAG +/** + * Odroix XU3/4 board revisions: + * Rev ADC Board + * 0.1 0 XU3 0.1 + * 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231) + * 0.3 739 XU4 0.1 + * Use +/-20 for ADC value tolerance. + */ +enum { + ODROID_XU3_REV01, + ODROID_XU3_REV02, + ODROID_XU4_REV01, + ODROID_UNKNOWN_REV, + ODROID_REV_COUNT, +}; + +struct odroid_type { + int board_type; + int rev; + int adc_val; + const char *name; +}; + +struct odroid_type odroid_type[] = { + { ODROID_XU3_REV01, 1, 0, "xu3" }, + { ODROID_XU3_REV02, 2, 372, "xu3" }, + { ODROID_XU4_REV01, 1, 739, "xu4" }, + { ODROID_UNKNOWN_REV, 0, 4095, "unknown" }, +}; + +bool board_is_odroidxu3(void) +{ + if (gd->board_type < ODROID_XU4_REV01) + return true; + + return false; +} + +bool board_is_odroidxu4(void) +{ + if (gd->board_type > ODROID_XU3_REV02) + return true; + + return false; +} + +int set_board_type(void) +{ + int adcval, i; + + adcval = exynos_adc_read_channel(CONFIG_ODROID_REV_AIN); + if (adcval < 0) + return adcval; + + for (i = 0; i < ODROID_REV_COUNT; i++) { + /* ADC tolerance: +20 */ + if (adcval < odroid_type[i].adc_val + 20) { + gd->board_type = i; + return i; + } + } + + return ODROID_UNKNOWN_REV; +} + +int get_board_rev(void) +{ + return odroid_type[gd->board_type].rev; +} + +/** + * get_board_type - returns pointer to one of the board type string. + * Board types: "xu3", "xu3-lite", "xu4". However the "xu3itel" can be + * detected only when the i2c controller is ready to use. Fortunately, + * XU3 and XU3L are compatible, and the information about board lite + * revision is needed before boot linux, to set proper environment + * variable: $fdtfile. + */ +const char *get_board_type(void) +{ + const char *type_xu3l = "xu3-lite"; + struct udevice *dev, *chip; + int ret; + + if (gd->board_type != ODROID_XU3_REV02) + goto exit; + + ret = pmic_get("s2mps11", &dev); + if (ret) + goto exit; + + /* Enable LDO26: 3.0V */ + ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL, + S2MPS11_LDO26_ENABLE); + if (ret) + goto exit; + + /* Check XU3Lite by probe INA231 I2C0:0x40 */ + ret = uclass_get_device(UCLASS_I2C, 0, &dev); + if (ret) + goto exit; + + ret = dm_i2c_probe(dev, 0x40, 0x0, &chip); + if (ret) + return type_xu3l; + +exit: + return odroid_type[gd->board_type].name; +} +#endif diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \ + "exynos5422-odroidxu3-lite.dtb fat 0 1;" \ + "exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES + +#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid" + /* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \

Hi Przemyslaw,
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
There are few revisions of Odroid XU3/XU4: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 739 XU4 0.1
This commit adds implementation of functions:
- set_board_type() - read ADC and set type
- get_board_rev() - returns board revision: 1..3
- board_is_odroidxu3() - returns bool
- board_is_odroidxu4() - returns bool
- get_board_type() - returns board type string
After I2C controller init, the last function can check if the board is "Lite" variant for XU3, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
The enabled configs:
- CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
- CONFIG_ODROID_REV_AIN
- CONFIG_REVISION_TAG
- CONFIG_MISC_INIT_R
- CONFIG_BOARD_TYPES
This also redefines CONFIG_SYS_BOARD to "odroid".
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
board/samsung/common/exynos5-dt.c | 114 ++++++++++++++++++++++++++++++++++++++ include/configs/odroid_xu3.h | 12 ++++ 2 files changed, 126 insertions(+)
diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 7d1b88a..41141df 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -18,6 +18,7 @@ #include <usb.h> #include <video_bridge.h> #include <asm/gpio.h> +#include <asm/arch/adc.h> #include <asm/arch/cpu.h> #include <asm/arch/dwmmc.h> #include <asm/arch/mmc.h> @@ -28,6 +29,7 @@ #include <power/max77686_pmic.h> #include <power/regulator.h> #include <power/s5m8767.h> +#include <power/s2mps11.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -360,3 +362,115 @@ char *get_dfu_alt_boot(char *interface, char *devstr) return alt_boot; } #endif
+#ifdef CONFIG_REVISION_TAG
Can we check the compatible string instead? It would be good to avoid #ifdef in common code.
+/**
- Odroix XU3/4 board revisions:
- Rev ADC Board
- 0.1 0 XU3 0.1
- 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231)
- 0.3 739 XU4 0.1
- Use +/-20 for ADC value tolerance.
- */
+enum {
ODROID_XU3_REV01,
ODROID_XU3_REV02,
ODROID_XU4_REV01,
ODROID_UNKNOWN_REV,
ODROID_REV_COUNT,
+};
+struct odroid_type {
int board_type;
int rev;
int adc_val;
const char *name;
+};
+struct odroid_type odroid_type[] = {
{ ODROID_XU3_REV01, 1, 0, "xu3" },
{ ODROID_XU3_REV02, 2, 372, "xu3" },
{ ODROID_XU4_REV01, 1, 739, "xu4" },
{ ODROID_UNKNOWN_REV, 0, 4095, "unknown" },
+};
+bool board_is_odroidxu3(void) +{
if (gd->board_type < ODROID_XU4_REV01)
return true;
return false;
+}
+bool board_is_odroidxu4(void) +{
if (gd->board_type > ODROID_XU3_REV02)
return true;
return false;
+}
+int set_board_type(void) +{
int adcval, i;
adcval = exynos_adc_read_channel(CONFIG_ODROID_REV_AIN);
if (adcval < 0)
return adcval;
for (i = 0; i < ODROID_REV_COUNT; i++) {
/* ADC tolerance: +20 */
if (adcval < odroid_type[i].adc_val + 20) {
gd->board_type = i;
return i;
}
}
return ODROID_UNKNOWN_REV;
+}
+int get_board_rev(void) +{
return odroid_type[gd->board_type].rev;
+}
+/**
- get_board_type - returns pointer to one of the board type string.
- Board types: "xu3", "xu3-lite", "xu4". However the "xu3itel" can be
- detected only when the i2c controller is ready to use. Fortunately,
- XU3 and XU3L are compatible, and the information about board lite
- revision is needed before boot linux, to set proper environment
- variable: $fdtfile.
- */
+const char *get_board_type(void) +{
const char *type_xu3l = "xu3-lite";
struct udevice *dev, *chip;
int ret;
if (gd->board_type != ODROID_XU3_REV02)
goto exit;
ret = pmic_get("s2mps11", &dev);
if (ret)
goto exit;
/* Enable LDO26: 3.0V */
ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL,
S2MPS11_LDO26_ENABLE);
if (ret)
goto exit;
/* Check XU3Lite by probe INA231 I2C0:0x40 */
ret = uclass_get_device(UCLASS_I2C, 0, &dev);
if (ret)
goto exit;
ret = dm_i2c_probe(dev, 0x40, 0x0, &chip);
if (ret)
return type_xu3l;
+exit:
return odroid_type[gd->board_type].name;
+} +#endif diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \
"exynos5422-odroidxu3-lite.dtb fat 0 1;" \
"exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES
+#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid"
/* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS
#define CONFIG_EXTRA_ENV_SETTINGS \
1.9.1
Regards, Simon

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:
There are few revisions of Odroid XU3/XU4: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 739 XU4 0.1
This commit adds implementation of functions:
- set_board_type() - read ADC and set type
- get_board_rev() - returns board revision: 1..3
- board_is_odroidxu3() - returns bool
- board_is_odroidxu4() - returns bool
- get_board_type() - returns board type string
After I2C controller init, the last function can check if the board is "Lite" variant for XU3, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
The enabled configs:
- CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
- CONFIG_ODROID_REV_AIN
- CONFIG_REVISION_TAG
- CONFIG_MISC_INIT_R
- CONFIG_BOARD_TYPES
This also redefines CONFIG_SYS_BOARD to "odroid".
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
board/samsung/common/exynos5-dt.c | 114 ++++++++++++++++++++++++++++++++++++++ include/configs/odroid_xu3.h | 12 ++++ 2 files changed, 126 insertions(+)
diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 7d1b88a..41141df 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -18,6 +18,7 @@ #include <usb.h> #include <video_bridge.h> #include <asm/gpio.h> +#include <asm/arch/adc.h> #include <asm/arch/cpu.h> #include <asm/arch/dwmmc.h> #include <asm/arch/mmc.h> @@ -28,6 +29,7 @@ #include <power/max77686_pmic.h> #include <power/regulator.h> #include <power/s5m8767.h> +#include <power/s2mps11.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -360,3 +362,115 @@ char *get_dfu_alt_boot(char *interface, char *devstr) return alt_boot; } #endif
+#ifdef CONFIG_REVISION_TAG
Can we check the compatible string instead? It would be good to avoid #ifdef in common code.
Ok, I will add some lines to check it.
+/**
- Odroix XU3/4 board revisions:
- Rev ADC Board
- 0.1 0 XU3 0.1
- 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231)
- 0.3 739 XU4 0.1
- Use +/-20 for ADC value tolerance.
- */
+enum {
ODROID_XU3_REV01,
ODROID_XU3_REV02,
ODROID_XU4_REV01,
ODROID_UNKNOWN_REV,
ODROID_REV_COUNT,
+};
+struct odroid_type {
int board_type;
int rev;
int adc_val;
const char *name;
+};
+struct odroid_type odroid_type[] = {
{ ODROID_XU3_REV01, 1, 0, "xu3" },
{ ODROID_XU3_REV02, 2, 372, "xu3" },
{ ODROID_XU4_REV01, 1, 739, "xu4" },
{ ODROID_UNKNOWN_REV, 0, 4095, "unknown" },
+};
+bool board_is_odroidxu3(void) +{
if (gd->board_type < ODROID_XU4_REV01)
return true;
return false;
+}
+bool board_is_odroidxu4(void) +{
if (gd->board_type > ODROID_XU3_REV02)
return true;
return false;
+}
+int set_board_type(void) +{
int adcval, i;
adcval = exynos_adc_read_channel(CONFIG_ODROID_REV_AIN);
if (adcval < 0)
return adcval;
for (i = 0; i < ODROID_REV_COUNT; i++) {
/* ADC tolerance: +20 */
if (adcval < odroid_type[i].adc_val + 20) {
gd->board_type = i;
return i;
}
}
return ODROID_UNKNOWN_REV;
+}
+int get_board_rev(void) +{
return odroid_type[gd->board_type].rev;
+}
+/**
- get_board_type - returns pointer to one of the board type string.
- Board types: "xu3", "xu3-lite", "xu4". However the "xu3itel" can be
- detected only when the i2c controller is ready to use. Fortunately,
- XU3 and XU3L are compatible, and the information about board lite
- revision is needed before boot linux, to set proper environment
- variable: $fdtfile.
- */
+const char *get_board_type(void) +{
const char *type_xu3l = "xu3-lite";
struct udevice *dev, *chip;
int ret;
if (gd->board_type != ODROID_XU3_REV02)
goto exit;
ret = pmic_get("s2mps11", &dev);
if (ret)
goto exit;
/* Enable LDO26: 3.0V */
ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL,
S2MPS11_LDO26_ENABLE);
if (ret)
goto exit;
/* Check XU3Lite by probe INA231 I2C0:0x40 */
ret = uclass_get_device(UCLASS_I2C, 0, &dev);
if (ret)
goto exit;
ret = dm_i2c_probe(dev, 0x40, 0x0, &chip);
if (ret)
return type_xu3l;
+exit:
return odroid_type[gd->board_type].name;
+} +#endif diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \
"exynos5422-odroidxu3-lite.dtb fat 0 1;" \
"exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES
+#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid"
- /* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \
-- 1.9.1
Regards, Simon
Thanks,

hi Przemyslaw,
On 28 August 2015 at 19:29, Przemyslaw Marczak p.marczak@samsung.com wrote:
This patchset adds:
- define the CPU name for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- board detection for Odroid XU3 / XU3lite / XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-patchset-test
Przemyslaw Marczak (7): s5p: cpu_info: use defined CPU name if available peach-pi: define CPU name for SoC Exynos5800 Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver odroid-xu3: enable s2mps11 PMIC support Exynos: add internal ADC driver exynos5-dt: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 5 ++ arch/arm/dts/exynos5422-odroidxu3.dts | 7 ++ arch/arm/mach-exynos/Makefile | 1 + arch/arm/mach-exynos/adc.c | 83 ++++++++++++++++++++++ arch/arm/mach-exynos/clock.c | 16 ++--- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++ arch/arm/mach-exynos/include/mach/cpu.h | 10 +-- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/exynos5-dt.c | 114
++++++++++++++++++++++++++++++
configs/odroid-xu3_defconfig | 3 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/configs/odroid_xu3.h | 12 ++++ include/configs/peach-pi.h | 2 + include/power/s2mps11.h | 109
++++++++++++++++++++++++++++
21 files changed, 493 insertions(+), 20 deletions(-) create mode 100644 arch/arm/mach-exynos/adc.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
Thanks for these patches. 👍
At the last moment I got this to work on my odroidxu3 board.
One problem I would like to address out is usb smsc95xx ethernet is not getting started at the boot.
# usb start /* command failed at the start */ ------------------------------------------------------------------------------------------------------ U-Boot 2015.10-rc2-00226-g7dbe336 (Aug 30 2015 - 23:41:27 +0530) for ODROID-XU3
CPU: Exynos5422 @ 800 MHz Model: Odroid XU3 based on EXYNOS5422 Board: Odroid XU3 based on EXYNOS5422 Model: xu3 DRAM: 2 GiB MMC: EXYNOS DWMMC: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: No ethernet found. Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc0 is current device Scanning mmc 0:1... starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found No ethernet found. missing environment variable: pxeuuid missing environment variable: bootfile -----------------------------------------------------------------------------------------
I will give it a try with latest kernel and let you know how it worked on Odroid-XU4 / XU4.
-Anand Moon
-- 1.9.1

Hello Anand,
On 08/30/2015 09:03 PM, Anand Moon wrote:
hi Przemyslaw,
On 28 August 2015 at 19:29, Przemyslaw Marczak <p.marczak@samsung.com mailto:p.marczak@samsung.com> wrote:
This patchset adds:
- define the CPU name for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- board detection for Odroid XU3 / XU3lite / XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-patchset-test
Przemyslaw Marczak (7): s5p: cpu_info: use defined CPU name if available peach-pi: define CPU name for SoC Exynos5800 Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver odroid-xu3: enable s2mps11 PMIC support Exynos: add internal ADC driver exynos5-dt: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 5 ++ arch/arm/dts/exynos5422-odroidxu3.dts | 7 ++ arch/arm/mach-exynos/Makefile | 1 + arch/arm/mach-exynos/adc.c | 83 ++++++++++++++++++++++ arch/arm/mach-exynos/clock.c | 16 ++--- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++ arch/arm/mach-exynos/include/mach/cpu.h | 10 +-- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/exynos5-dt.c | 114
++++++++++++++++++++++++++++++
configs/odroid-xu3_defconfig | 3 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/configs/odroid_xu3.h | 12 ++++ include/configs/peach-pi.h | 2 + include/power/s2mps11.h | 109
++++++++++++++++++++++++++++
21 files changed, 493 insertions(+), 20 deletions(-) create mode 100644 arch/arm/mach-exynos/adc.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
Thanks for these patches. 👍
At the last moment I got this to work on my odroidxu3 board.
One problem I would like to address out is usb smsc95xx ethernet is not getting started at the boot.
# usb start /* command failed at the start */
U-Boot 2015.10-rc2-00226-g7dbe336 (Aug 30 2015 - 23:41:27 +0530) for ODROID-XU3
CPU: Exynos5422 @ 800 MHz Model: Odroid XU3 based on EXYNOS5422 Board: Odroid XU3 based on EXYNOS5422 Model: xu3 DRAM: 2 GiB MMC: EXYNOS DWMMC: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: No ethernet found. Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc0 is current device Scanning mmc 0:1... starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found No ethernet found. missing environment variable: pxeuuid missing environment variable: bootfile
I will give it a try with latest kernel and let you know how it worked on Odroid-XU4 / XU4.
-Anand Moon
-- 1.9.1
Thank you for pointing this, but at present I'm busy with some other work and I don't have too much time for it. Maybe in the next week.
Best regards,

On Mon, 31 Aug 2015 00:33:16 +0530 Anand Moon linux.amoon@gmail.com wrote:
At the last moment I got this to work on my odroidxu3 board.
One problem I would like to address out is usb smsc95xx ethernet is not getting started at the boot.
# usb start /* command failed at the start */
U-Boot 2015.10-rc2-00226-g7dbe336 (Aug 30 2015 - 23:41:27 +0530) for ODROID-XU3
CPU: Exynos5422 @ 800 MHz Model: Odroid XU3 based on EXYNOS5422 Board: Odroid XU3 based on EXYNOS5422 Model: xu3 DRAM: 2 GiB MMC: EXYNOS DWMMC: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: No ethernet found. Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc0 is current device Scanning mmc 0:1... starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found No ethernet found. missing environment variable: pxeuuid missing environment variable: bootfile
Hi Anand,
This looks like it might be the same problem as http://lists.denx.de/pipermail/u-boot/2015-October/230827.html
Simon Glass asked if this also happens on XU3, so maybe you could test the same workaround on your board and provide feedback?

Hi Siarhei
On 21 October 2015 at 07:28, Siarhei Siamashka siarhei.siamashka@gmail.com wrote:
On Mon, 31 Aug 2015 00:33:16 +0530 Anand Moon linux.amoon@gmail.com wrote:
At the last moment I got this to work on my odroidxu3 board.
One problem I would like to address out is usb smsc95xx ethernet is not getting started at the boot.
# usb start /* command failed at the start */
U-Boot 2015.10-rc2-00226-g7dbe336 (Aug 30 2015 - 23:41:27 +0530) for ODROID-XU3
CPU: Exynos5422 @ 800 MHz Model: Odroid XU3 based on EXYNOS5422 Board: Odroid XU3 based on EXYNOS5422 Model: xu3 DRAM: 2 GiB MMC: EXYNOS DWMMC: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: No ethernet found. Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc0 is current device Scanning mmc 0:1... starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found No ethernet found. missing environment variable: pxeuuid missing environment variable: bootfile
Hi Anand,
This looks like it might be the same problem as http://lists.denx.de/pipermail/u-boot/2015-October/230827.html
Simon Glass asked if this also happens on XU3, so maybe you could test the same workaround on your board and provide feedback?
Yes I see the same problem. ---------------------------------------------------------------------------------------------------- U-Boot 2015.10-rc3-00227-g94fa041-dirty (Sep 27 2015 - 15:37:17 +0930) for ODROI
CPU: Exynos5422 @ 800 MHz Model: Odroid XU3 based on EXYNOS5422 Board: Odroid XU3 based on EXYNOS5422 Type: xu3 DRAM: 2 GiB MMC: EXYNOS DWMMC: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: No ethernet found. Hit any key to stop autoboot: 0 ODROID-XU3 # ODROID-XU3 # ODROID-XU3 # ODROID-XU3 # setenv usbethaddr 02:DE:AD:BE:EF:FF ODROID-XU3 # usb start starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found ODROID-XU3 # ----------------------------------------------------------------------------------------------------
-Anand Moon
-- Best regards, Siarhei Siamashka

Hi Siarhei ,
On 21 October 2015 at 07:28, Siarhei Siamashka siarhei.siamashka@gmail.com wrote:
On Mon, 31 Aug 2015 00:33:16 +0530 Anand Moon linux.amoon@gmail.com wrote:
At the last moment I got this to work on my odroidxu3 board.
One problem I would like to address out is usb smsc95xx ethernet is not getting started at the boot.
# usb start /* command failed at the start */
U-Boot 2015.10-rc2-00226-g7dbe336 (Aug 30 2015 - 23:41:27 +0530) for ODROID-XU3
CPU: Exynos5422 @ 800 MHz Model: Odroid XU3 based on EXYNOS5422 Board: Odroid XU3 based on EXYNOS5422 Model: xu3 DRAM: 2 GiB MMC: EXYNOS DWMMC: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: No ethernet found. Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc0 is current device Scanning mmc 0:1... starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found No ethernet found. missing environment variable: pxeuuid missing environment variable: bootfile
Hi Anand,
This looks like it might be the same problem as http://lists.denx.de/pipermail/u-boot/2015-October/230827.html
Simon Glass asked if this also happens on XU3, so maybe you could test the same workaround on your board and provide feedback?
--
Odroid u3 also has the same problem --------------------------------------------------------- U-Boot 2015.10-rc5-00030-gac6a532-dirty (Oct 20 2015 - 01:37:27 +1030)
CPU: Exynos4412 @ 1 GHz Model: Odroid based on Exynos4412 Board: Odroid based on Exynos4412 Model: u3 DRAM: 2 GiB LDO20@VDDQ_EMMC_1.8V: set 1800000 uV; enabling LDO22@VDDQ_EMMC_2.8V: set 2800000 uV; enabling LDO21@TFLASH_2.8V: set 2800000 uV; enabling MMC: SAMSUNG SDHCI: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
Net: No ethernet found. Hit any key to stop autoboot: 0 Odroid # setenv usbethaddr 02:DE:AD:BE:EF:FF Odroid # usb start starting USB... USB0: USB EHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found Odroid # ---------------------------------------------------------
-Anand Moon
Best regards, Siarhei Siamashka

Hello Siarhei, Anand,
On 10/21/2015 11:57 AM, Anand Moon wrote:
Hi Siarhei ,
On 21 October 2015 at 07:28, Siarhei Siamashka siarhei.siamashka@gmail.com wrote:
On Mon, 31 Aug 2015 00:33:16 +0530 Anand Moon linux.amoon@gmail.com wrote:
At the last moment I got this to work on my odroidxu3 board.
One problem I would like to address out is usb smsc95xx ethernet is not getting started at the boot.
# usb start /* command failed at the start */
U-Boot 2015.10-rc2-00226-g7dbe336 (Aug 30 2015 - 23:41:27 +0530) for ODROID-XU3
CPU: Exynos5422 @ 800 MHz Model: Odroid XU3 based on EXYNOS5422 Board: Odroid XU3 based on EXYNOS5422 Model: xu3 DRAM: 2 GiB MMC: EXYNOS DWMMC: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: No ethernet found. Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc0 is current device Scanning mmc 0:1... starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found No ethernet found. missing environment variable: pxeuuid missing environment variable: bootfile
Hi Anand,
This looks like it might be the same problem as http://lists.denx.de/pipermail/u-boot/2015-October/230827.html
Simon Glass asked if this also happens on XU3, so maybe you could test the same workaround on your board and provide feedback?
--
Odroid u3 also has the same problem
U-Boot 2015.10-rc5-00030-gac6a532-dirty (Oct 20 2015 - 01:37:27 +1030)
CPU: Exynos4412 @ 1 GHz Model: Odroid based on Exynos4412 Board: Odroid based on Exynos4412 Model: u3 DRAM: 2 GiB LDO20@VDDQ_EMMC_1.8V: set 1800000 uV; enabling LDO22@VDDQ_EMMC_2.8V: set 2800000 uV; enabling LDO21@TFLASH_2.8V: set 2800000 uV; enabling MMC: SAMSUNG SDHCI: 0, EXYNOS DWMMC: 1 *** Warning - bad CRC, using default environment
Net: No ethernet found. Hit any key to stop autoboot: 0 Odroid # setenv usbethaddr 02:DE:AD:BE:EF:FF Odroid # usb start starting USB... USB0: USB EHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found Odroid #
-Anand Moon
Best regards, Siarhei Siamashka
Lukasz is working on that issue, and he discovered that the sequence of usb start/reset works for this and the Ethernet is detected then.
----------------------------------------------------------------------- ODROID-XU3 # usb start starting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... 0 Ethernet Device(s) found ODROID-XU3 # usb reset resetting USB... USB0: USB EHCI 1.00 USB1: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 USB2: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.00 scanning bus 0 for devices... 3 USB Device(s) found scanning bus 1 for devices... 1 USB Device(s) found scanning bus 2 for devices... 1 USB Device(s) found scanning usb for ethernet devices... Error: sms0 address not set. Warning: failed to set MAC address 1 Ethernet Device(s) found ODROID-XU3 # -----------------------------------------------------------------------
Best regards,

Hi Przemyslaw,
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
This patchset adds:
- define the CPU name for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- board detection for Odroid XU3 / XU3lite / XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-patchset-test
Przemyslaw Marczak (7): s5p: cpu_info: use defined CPU name if available peach-pi: define CPU name for SoC Exynos5800 Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver odroid-xu3: enable s2mps11 PMIC support Exynos: add internal ADC driver exynos5-dt: add board detection for Odroid XU3/XU3L/XU4.
It's nice to have things automatic. Is this easier than having a separate device tree for each board?
Regards Simon

Hello Simon,
On 08/31/2015 03:22 PM, Simon Glass wrote:
Hi Przemyslaw,
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
This patchset adds:
- define the CPU name for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- board detection for Odroid XU3 / XU3lite / XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-patchset-test
Przemyslaw Marczak (7): s5p: cpu_info: use defined CPU name if available peach-pi: define CPU name for SoC Exynos5800 Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver odroid-xu3: enable s2mps11 PMIC support Exynos: add internal ADC driver exynos5-dt: add board detection for Odroid XU3/XU3L/XU4.
It's nice to have things automatic. Is this easier than having a separate device tree for each board?
Regards Simon
In my intention was using a single U-Boot binary (u-boot-dtb.bin) with the three almost full compatible boards. This is also easier for other developers, who don't need care about few configs and few dtb's.
And finally this code can load proper dtb for Linux Kernel for each supported board. So in the next part (Linux boot), things are done clean.
The common board file is quite messy because of this code, so if you don't like it, then I can move it to independent file.
Best regards,

Hi Przemyslaw,
On 31 August 2015 at 12:29, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hello Simon,
On 08/31/2015 03:22 PM, Simon Glass wrote:
Hi Przemyslaw,
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
This patchset adds:
- define the CPU name for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- board detection for Odroid XU3 / XU3lite / XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-patchset-test
Przemyslaw Marczak (7): s5p: cpu_info: use defined CPU name if available peach-pi: define CPU name for SoC Exynos5800 Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver odroid-xu3: enable s2mps11 PMIC support Exynos: add internal ADC driver exynos5-dt: add board detection for Odroid XU3/XU3L/XU4.
It's nice to have things automatic. Is this easier than having a separate device tree for each board?
Regards Simon
In my intention was using a single U-Boot binary (u-boot-dtb.bin) with the three almost full compatible boards. This is also easier for other developers, who don't need care about few configs and few dtb's.
And finally this code can load proper dtb for Linux Kernel for each supported board. So in the next part (Linux boot), things are done clean.
The common board file is quite messy because of this code, so if you don't like it, then I can move it to independent file.
I don't think it matters that much. I'm not keen on the #ifdef CONFIG_REVISION_TAG - can you instead check the board compatible string? The code should be generic to exynos5.
Regards, Simon

Hello,
On 09/01/2015 01:13 AM, Simon Glass wrote:
Hi Przemyslaw,
On 31 August 2015 at 12:29, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hello Simon,
On 08/31/2015 03:22 PM, Simon Glass wrote:
Hi Przemyslaw,
On 28 August 2015 at 07:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
This patchset adds:
- define the CPU name for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- board detection for Odroid XU3 / XU3lite / XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-patchset-test
Przemyslaw Marczak (7): s5p: cpu_info: use defined CPU name if available peach-pi: define CPU name for SoC Exynos5800 Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver odroid-xu3: enable s2mps11 PMIC support Exynos: add internal ADC driver exynos5-dt: add board detection for Odroid XU3/XU3L/XU4.
It's nice to have things automatic. Is this easier than having a separate device tree for each board?
Regards Simon
In my intention was using a single U-Boot binary (u-boot-dtb.bin) with the three almost full compatible boards. This is also easier for other developers, who don't need care about few configs and few dtb's.
And finally this code can load proper dtb for Linux Kernel for each supported board. So in the next part (Linux boot), things are done clean.
The common board file is quite messy because of this code, so if you don't like it, then I can move it to independent file.
I don't think it matters that much. I'm not keen on the #ifdef CONFIG_REVISION_TAG - can you instead check the board compatible string? The code should be generic to exynos5.
Regards, Simon
Thanks for review, I will send the next version in the next week. And will try to keep things common.
Best regards

This patchset adds: - CPU model in dts for Chromebook Peach Pi as Exynos5800 - set the cpu id of Exynos5422 to 0x5422 - S2MPS11 PMIC I/O driver - Exynos5420-compatible (9-channel, 12-bit) ADC driver - new file for Exynos5: exynos5-dt-types.c - board detection for Odroid XU3 / XU3lite / XU4 - fixed ADC val for XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2
Przemyslaw Marczak (11): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 ++- arch/arm/dts/exynos5422-odroidxu3.dts | 12 ++ arch/arm/dts/exynos54xx.dtsi | 7 ++ arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +-- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 +++++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 17 +++ drivers/adc/Makefile | 9 ++ drivers/adc/adc-uclass.c | 76 ++++++++++++ drivers/adc/exynos-adc.c | 102 ++++++++++++++++ drivers/power/pmic/Kconfig | 14 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 +++++++++ include/adc.h | 88 ++++++++++++++ include/configs/odroid_xu3.h | 12 ++ include/dm/uclass-id.h | 1 + include/power/s2mps11.h | 109 +++++++++++++++++ include/samsung/exynos5-dt-types.h | 27 ++++ 33 files changed, 854 insertions(+), 22 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h

The function get_board_type() is called in two places by common code, but the returned pointer was never check.
This commit adds checking the returned pointer, before use it.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - new commit --- board/samsung/common/board.c | 4 ++-- board/samsung/common/misc.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c index d32c75d..1334c22 100644 --- a/board/samsung/common/board.c +++ b/board/samsung/common/board.c @@ -304,8 +304,8 @@ int checkboard(void) printf("Board: %s\n", board_info ? board_info : "unknown"); #ifdef CONFIG_BOARD_TYPES board_info = get_board_type(); - - printf("Model: %s\n", board_info ? board_info : "unknown"); + if (board_info) + printf("Type: %s\n", board_info); #endif return 0; } diff --git a/board/samsung/common/misc.c b/board/samsung/common/misc.c index e0e2c48..c8316d8 100644 --- a/board/samsung/common/misc.c +++ b/board/samsung/common/misc.c @@ -85,6 +85,9 @@ void set_board_info(void)
#ifdef CONFIG_BOARD_TYPES bdtype = get_board_type(); + if (!bdtype) + bdtype = ""; + sprintf(info, "%s%s", bdname, bdtype); setenv("boardname", info); #endif

On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
The function get_board_type() is called in two places by common code, but the returned pointer was never check.
This commit adds checking the returned pointer, before use it.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit
board/samsung/common/board.c | 4 ++-- board/samsung/common/misc.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined in device tree.
This commit introduces new device-tree property for Exynos: - "cpu-model" - with cpu name string If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - new commit --- arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..97d611f 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -5,9 +5,12 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <fdtdec.h> #include <asm/io.h> #include <asm/arch/clk.h>
+DECLARE_GLOBAL_DATA_PTR; + /* Default is s5pc100 */ unsigned int s5p_cpu_id = 0xC100; /* Default is EVT1 */ @@ -30,7 +33,16 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { - printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id); + const char *cpu_model = NULL; + int len = 0; + + /* For SoC with no real CPU ID in naming convention. */ + cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len); + if (cpu_model) + printf("CPU: %.*s @ ", len, cpu_model); + else + printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id); + print_freq(get_arm_clk(), "\n");
return 0;

On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined in device tree.
This commit introduces new device-tree property for Exynos:
- "cpu-model" - with cpu name string
If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
Please see nit below.
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..97d611f 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -5,9 +5,12 @@
- SPDX-License-Identifier: GPL-2.0+
*/ #include <common.h> +#include <fdtdec.h> #include <asm/io.h> #include <asm/arch/clk.h>
+DECLARE_GLOBAL_DATA_PTR;
/* Default is s5pc100 */ unsigned int s5p_cpu_id = 0xC100; /* Default is EVT1 */ @@ -30,7 +33,16 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) {
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
const char *cpu_model = NULL;
int len = 0;
No need to init these two variables.
/* For SoC with no real CPU ID in naming convention. */
cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
if (cpu_model)
printf("CPU: %.*s @ ", len, cpu_model);
else
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
print_freq(get_arm_clk(), "\n"); return 0;
-- 1.9.1

Hello Simon,
On 10/03/2015 04:27 PM, Simon Glass wrote:
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined in device tree.
This commit introduces new device-tree property for Exynos:
- "cpu-model" - with cpu name string
If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
Please see nit below.
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..97d611f 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -5,9 +5,12 @@
- SPDX-License-Identifier: GPL-2.0+
*/ #include <common.h> +#include <fdtdec.h> #include <asm/io.h> #include <asm/arch/clk.h>
+DECLARE_GLOBAL_DATA_PTR;
- /* Default is s5pc100 */ unsigned int s5p_cpu_id = 0xC100; /* Default is EVT1 */
@@ -30,7 +33,16 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) {
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
const char *cpu_model = NULL;
int len = 0;
No need to init these two variables.
Ok, will correct this.
/* For SoC with no real CPU ID in naming convention. */
cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
if (cpu_model)
printf("CPU: %.*s @ ", len, cpu_model);
else
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
print_freq(get_arm_clk(), "\n"); return 0;
-- 1.9.1
Best regards,

This platform is based on Exynos5800 but the cpu id is 0x5422. This doesn't fit the common Exynos SoC name convention, so now, the CPU name is defined by device tree string, to be printed properly.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - move cpu name from config to dts --- arch/arm/dts/exynos5800-peach-pi.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts index 1d7ff23..76826dc 100644 --- a/arch/arm/dts/exynos5800-peach-pi.dts +++ b/arch/arm/dts/exynos5800-peach-pi.dts @@ -12,6 +12,7 @@
/ { model = "Samsung/Google Peach Pi board based on Exynos5800"; + cpu-model = "Exynos5800";
compatible = "google,pit-rev#", "google,pit", "google,peach", "samsung,exynos5800", "samsung,exynos5";

Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This platform is based on Exynos5800 but the cpu id is 0x5422. This doesn't fit the common Exynos SoC name convention, so now, the CPU name is defined by device tree string, to be printed properly.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- move cpu name from config to dts
arch/arm/dts/exynos5800-peach-pi.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts index 1d7ff23..76826dc 100644 --- a/arch/arm/dts/exynos5800-peach-pi.dts +++ b/arch/arm/dts/exynos5800-peach-pi.dts @@ -12,6 +12,7 @@
/ { model = "Samsung/Google Peach Pi board based on Exynos5800";
cpu-model = "Exynos5800"; compatible = "google,pit-rev#", "google,pit", "google,peach", "samsung,exynos5800", "samsung,exynos5";
-- 1.9.1
Is this defined by the standard binding? If not, can you add or change the binding file?
Regards, Simon

Hello Simon,
On 10/03/2015 04:28 PM, Simon Glass wrote:
Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This platform is based on Exynos5800 but the cpu id is 0x5422. This doesn't fit the common Exynos SoC name convention, so now, the CPU name is defined by device tree string, to be printed properly.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- move cpu name from config to dts
arch/arm/dts/exynos5800-peach-pi.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts index 1d7ff23..76826dc 100644 --- a/arch/arm/dts/exynos5800-peach-pi.dts +++ b/arch/arm/dts/exynos5800-peach-pi.dts @@ -12,6 +12,7 @@
/ { model = "Samsung/Google Peach Pi board based on Exynos5800";
cpu-model = "Exynos5800"; compatible = "google,pit-rev#", "google,pit", "google,peach", "samsung,exynos5800", "samsung,exynos5";
-- 1.9.1
Is this defined by the standard binding? If not, can you add or change the binding file?
Regards, Simon
No, it's not standard. I will add binding info.
Best regards

The proper CPU ID for those Exynos variants is 0x5422, but before the 0x5800 was set. This commit fix this back.
Changes: - set cpu id to 0x5422 instead of 0x5800 - remove macro proid_is_exynos5800() - add macro proid_is_exynos5422() - change the calls to proid_is_exynos5800() with new macro
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - none --- arch/arm/mach-exynos/clock.c | 16 ++++++++-------- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 ++-- arch/arm/mach-exynos/include/mach/cpu.h | 6 +++--- arch/arm/mach-exynos/include/mach/gpio.h | 4 ++-- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c index 1c6baa1..2d94851 100644 --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -159,8 +159,8 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) div = PLL_DIV_1024; else if (proid_is_exynos4412()) div = PLL_DIV_65535; - else if (proid_is_exynos5250() || proid_is_exynos5420() - || proid_is_exynos5800()) + else if (proid_is_exynos5250() || proid_is_exynos5420() || + proid_is_exynos5422()) div = PLL_DIV_65536; else return 0; @@ -346,7 +346,7 @@ static struct clk_bit_info *get_clk_bit_info(int peripheral) int i; struct clk_bit_info *info;
- if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) info = exynos542x_bit_info; else info = exynos5_bit_info; @@ -558,7 +558,7 @@ static unsigned long exynos542x_get_periph_rate(int peripheral) unsigned long clock_get_periph_rate(int peripheral) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_periph_rate(peripheral); return exynos5_get_periph_rate(peripheral); } else { @@ -1576,7 +1576,7 @@ static unsigned long exynos4_get_i2c_clk(void) unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_pll_clk(pllreg); return exynos5_get_pll_clk(pllreg); } else if (cpu_is_exynos4()) { @@ -1694,7 +1694,7 @@ void set_mmc_clk(int dev_index, unsigned int div) div -= 1;
if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_mmc_clk(dev_index, div); else exynos5_set_mmc_clk(dev_index, div); @@ -1710,7 +1710,7 @@ unsigned long get_lcd_clk(void) } else if (cpu_is_exynos5()) { if (proid_is_exynos5420()) return exynos5420_get_lcd_clk(); - else if (proid_is_exynos5800()) + else if (proid_is_exynos5422()) return exynos5800_get_lcd_clk(); else return exynos5_get_lcd_clk(); @@ -1742,7 +1742,7 @@ void set_mipi_clk(void) int set_spi_clk(int periph_id, unsigned int rate) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_set_spi_clk(periph_id, rate); return exynos5_set_spi_clk(periph_id, rate); } diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c index 0200fd1..1b7498d 100644 --- a/arch/arm/mach-exynos/clock_init_exynos5.c +++ b/arch/arm/mach-exynos/clock_init_exynos5.c @@ -971,7 +971,7 @@ static void exynos5420_system_clock_init(void)
void system_clock_init(void) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_system_clock_init(); else exynos5250_system_clock_init(); diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h index 67aac2d..2829fb2 100644 --- a/arch/arm/mach-exynos/common_setup.h +++ b/arch/arm/mach-exynos/common_setup.h @@ -78,7 +78,7 @@ static inline void configure_l2_ctlr(void) CACHE_TAG_RAM_LATENCY_2_CYCLES | CACHE_DATA_RAM_LATENCY_2_CYCLES;
- if (proid_is_exynos5420() || proid_is_exynos5800()) { + if (proid_is_exynos5420() || proid_is_exynos5422()) { val |= CACHE_ECC_AND_PARITY | CACHE_TAG_RAM_LATENCY_3_CYCLES | CACHE_DATA_RAM_LATENCY_3_CYCLES; @@ -97,7 +97,7 @@ static inline void configure_l2_actlr(void) { uint32_t val;
- if (proid_is_exynos5420() || proid_is_exynos5800()) { + if (proid_is_exynos5420() || proid_is_exynos5422()) { mrc_l2_aux_ctlr(val); val |= CACHE_ENABLE_FORCE_L2_LOGIC | CACHE_DISABLE_CLEAN_EVICT; diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index cb3d2cc..14a1692 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -237,7 +237,7 @@ static inline void s5p_set_cpu_id(void) * Exynos5800 is a variant of Exynos5420 * and has product id 0x5422 */ - s5p_cpu_id = 0x5800; + s5p_cpu_id = 0x5422; break; } } @@ -267,7 +267,7 @@ IS_EXYNOS_TYPE(exynos4210, 0x4210) IS_EXYNOS_TYPE(exynos4412, 0x4412) IS_EXYNOS_TYPE(exynos5250, 0x5250) IS_EXYNOS_TYPE(exynos5420, 0x5420) -IS_EXYNOS_TYPE(exynos5800, 0x5800) +IS_EXYNOS_TYPE(exynos5422, 0x5422)
#define SAMSUNG_BASE(device, base) \ static inline unsigned int __attribute__((no_instrument_function)) \ @@ -278,7 +278,7 @@ static inline unsigned int __attribute__((no_instrument_function)) \ return EXYNOS4X12_##base; \ return EXYNOS4_##base; \ } else if (cpu_is_exynos5()) { \ - if (proid_is_exynos5420() || proid_is_exynos5800()) \ + if (proid_is_exynos5420() || proid_is_exynos5422()) \ return EXYNOS5420_##base; \ return EXYNOS5_##base; \ } \ diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h index 9699954..7fc8e61 100644 --- a/arch/arm/mach-exynos/include/mach/gpio.h +++ b/arch/arm/mach-exynos/include/mach/gpio.h @@ -1398,7 +1398,7 @@ static struct gpio_info exynos5420_gpio_data[EXYNOS5420_GPIO_NUM_PARTS] = { static inline struct gpio_info *get_gpio_data(void) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_gpio_data; else return exynos5_gpio_data; @@ -1415,7 +1415,7 @@ static inline struct gpio_info *get_gpio_data(void) static inline unsigned int get_bank_num(void) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return EXYNOS5420_GPIO_NUM_PARTS; else return EXYNOS5_GPIO_NUM_PARTS; diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c index 179b294..a556e4a 100644 --- a/arch/arm/mach-exynos/pinmux.c +++ b/arch/arm/mach-exynos/pinmux.c @@ -858,7 +858,7 @@ static int exynos4x12_pinmux_config(int peripheral, int flags) int exynos_pinmux_config(int peripheral, int flags) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_pinmux_config(peripheral, flags); else if (proid_is_exynos5250()) return exynos5_pinmux_config(peripheral, flags); diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c index 1b12051..cd2d661 100644 --- a/arch/arm/mach-exynos/power.c +++ b/arch/arm/mach-exynos/power.c @@ -125,7 +125,7 @@ static void exynos5420_set_usbdev_phy_ctrl(unsigned int enable) void set_usbdrd_phy_ctrl(unsigned int enable) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_usbdev_phy_ctrl(enable); else exynos5_set_usbdrd_phy_ctrl(enable);

Hi, Przemyslaw.
On 09/21/2015 09:26 PM, Przemyslaw Marczak wrote:
The proper CPU ID for those Exynos variants is 0x5422, but before the 0x5800 was set. This commit fix this back.
Changes:
- set cpu id to 0x5422 instead of 0x5800
- remove macro proid_is_exynos5800()
- add macro proid_is_exynos5422()
- change the calls to proid_is_exynos5800() with new macro
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- none
arch/arm/mach-exynos/clock.c | 16 ++++++++-------- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 ++-- arch/arm/mach-exynos/include/mach/cpu.h | 6 +++--- arch/arm/mach-exynos/include/mach/gpio.h | 4 ++-- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c index 1c6baa1..2d94851 100644 --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -159,8 +159,8 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) div = PLL_DIV_1024; else if (proid_is_exynos4412()) div = PLL_DIV_65535;
else if (proid_is_exynos5250() || proid_is_exynos5420()
|| proid_is_exynos5800())
else if (proid_is_exynos5250() || proid_is_exynos5420() ||
else return 0;proid_is_exynos5422()) div = PLL_DIV_65536;
@@ -346,7 +346,7 @@ static struct clk_bit_info *get_clk_bit_info(int peripheral) int i; struct clk_bit_info *info;
- if (proid_is_exynos5420() || proid_is_exynos5800())
- if (proid_is_exynos5420() || proid_is_exynos5422()) info = exynos542x_bit_info; else info = exynos5_bit_info;
@@ -558,7 +558,7 @@ static unsigned long exynos542x_get_periph_rate(int peripheral) unsigned long clock_get_periph_rate(int peripheral) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
return exynos5_get_periph_rate(peripheral); } else {if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_periph_rate(peripheral);
@@ -1576,7 +1576,7 @@ static unsigned long exynos4_get_i2c_clk(void) unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
return exynos5_get_pll_clk(pllreg); } else if (cpu_is_exynos4()) {if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_pll_clk(pllreg);
@@ -1694,7 +1694,7 @@ void set_mmc_clk(int dev_index, unsigned int div) div -= 1;
if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
else exynos5_set_mmc_clk(dev_index, div);if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_mmc_clk(dev_index, div);
@@ -1710,7 +1710,7 @@ unsigned long get_lcd_clk(void) } else if (cpu_is_exynos5()) { if (proid_is_exynos5420()) return exynos5420_get_lcd_clk();
else if (proid_is_exynos5800())
else return exynos5_get_lcd_clk();else if (proid_is_exynos5422()) return exynos5800_get_lcd_clk();
@@ -1742,7 +1742,7 @@ void set_mipi_clk(void) int set_spi_clk(int periph_id, unsigned int rate) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
return exynos5_set_spi_clk(periph_id, rate); }if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_set_spi_clk(periph_id, rate);
diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c index 0200fd1..1b7498d 100644 --- a/arch/arm/mach-exynos/clock_init_exynos5.c +++ b/arch/arm/mach-exynos/clock_init_exynos5.c @@ -971,7 +971,7 @@ static void exynos5420_system_clock_init(void)
void system_clock_init(void) {
- if (proid_is_exynos5420() || proid_is_exynos5800())
- if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_system_clock_init(); else exynos5250_system_clock_init();
diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h index 67aac2d..2829fb2 100644 --- a/arch/arm/mach-exynos/common_setup.h +++ b/arch/arm/mach-exynos/common_setup.h @@ -78,7 +78,7 @@ static inline void configure_l2_ctlr(void) CACHE_TAG_RAM_LATENCY_2_CYCLES | CACHE_DATA_RAM_LATENCY_2_CYCLES;
- if (proid_is_exynos5420() || proid_is_exynos5800()) {
- if (proid_is_exynos5420() || proid_is_exynos5422()) { val |= CACHE_ECC_AND_PARITY | CACHE_TAG_RAM_LATENCY_3_CYCLES | CACHE_DATA_RAM_LATENCY_3_CYCLES;
@@ -97,7 +97,7 @@ static inline void configure_l2_actlr(void) { uint32_t val;
- if (proid_is_exynos5420() || proid_is_exynos5800()) {
- if (proid_is_exynos5420() || proid_is_exynos5422()) { mrc_l2_aux_ctlr(val); val |= CACHE_ENABLE_FORCE_L2_LOGIC | CACHE_DISABLE_CLEAN_EVICT;
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index cb3d2cc..14a1692 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -237,7 +237,7 @@ static inline void s5p_set_cpu_id(void) * Exynos5800 is a variant of Exynos5420 * and has product id 0x5422 */
Needs to modify the above comment?
Best Regards, Jaehoon Chung
s5p_cpu_id = 0x5800;
break; }s5p_cpu_id = 0x5422;
} @@ -267,7 +267,7 @@ IS_EXYNOS_TYPE(exynos4210, 0x4210) IS_EXYNOS_TYPE(exynos4412, 0x4412) IS_EXYNOS_TYPE(exynos5250, 0x5250) IS_EXYNOS_TYPE(exynos5420, 0x5420) -IS_EXYNOS_TYPE(exynos5800, 0x5800) +IS_EXYNOS_TYPE(exynos5422, 0x5422)
#define SAMSUNG_BASE(device, base) \ static inline unsigned int __attribute__((no_instrument_function)) \ @@ -278,7 +278,7 @@ static inline unsigned int __attribute__((no_instrument_function)) \ return EXYNOS4X12_##base; \ return EXYNOS4_##base; \ } else if (cpu_is_exynos5()) { \
if (proid_is_exynos5420() || proid_is_exynos5800()) \
return EXYNOS5_##base; \ } \if (proid_is_exynos5420() || proid_is_exynos5422()) \ return EXYNOS5420_##base; \
diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h index 9699954..7fc8e61 100644 --- a/arch/arm/mach-exynos/include/mach/gpio.h +++ b/arch/arm/mach-exynos/include/mach/gpio.h @@ -1398,7 +1398,7 @@ static struct gpio_info exynos5420_gpio_data[EXYNOS5420_GPIO_NUM_PARTS] = { static inline struct gpio_info *get_gpio_data(void) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
else return exynos5_gpio_data;if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_gpio_data;
@@ -1415,7 +1415,7 @@ static inline struct gpio_info *get_gpio_data(void) static inline unsigned int get_bank_num(void) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
else return EXYNOS5_GPIO_NUM_PARTS;if (proid_is_exynos5420() || proid_is_exynos5422()) return EXYNOS5420_GPIO_NUM_PARTS;
diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c index 179b294..a556e4a 100644 --- a/arch/arm/mach-exynos/pinmux.c +++ b/arch/arm/mach-exynos/pinmux.c @@ -858,7 +858,7 @@ static int exynos4x12_pinmux_config(int peripheral, int flags) int exynos_pinmux_config(int peripheral, int flags) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
else if (proid_is_exynos5250()) return exynos5_pinmux_config(peripheral, flags);if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_pinmux_config(peripheral, flags);
diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c index 1b12051..cd2d661 100644 --- a/arch/arm/mach-exynos/power.c +++ b/arch/arm/mach-exynos/power.c @@ -125,7 +125,7 @@ static void exynos5420_set_usbdev_phy_ctrl(unsigned int enable) void set_usbdrd_phy_ctrl(unsigned int enable) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
else exynos5_set_usbdrd_phy_ctrl(enable);if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_usbdev_phy_ctrl(enable);

Hello Jaehoon,
On 09/21/2015 02:47 PM, Jaehoon Chung wrote:
Hi, Przemyslaw.
On 09/21/2015 09:26 PM, Przemyslaw Marczak wrote:
The proper CPU ID for those Exynos variants is 0x5422, but before the 0x5800 was set. This commit fix this back.
Changes:
- set cpu id to 0x5422 instead of 0x5800
- remove macro proid_is_exynos5800()
- add macro proid_is_exynos5422()
- change the calls to proid_is_exynos5800() with new macro
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- none
arch/arm/mach-exynos/clock.c | 16 ++++++++-------- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 ++-- arch/arm/mach-exynos/include/mach/cpu.h | 6 +++--- arch/arm/mach-exynos/include/mach/gpio.h | 4 ++-- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c index 1c6baa1..2d94851 100644 --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -159,8 +159,8 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) div = PLL_DIV_1024; else if (proid_is_exynos4412()) div = PLL_DIV_65535;
else if (proid_is_exynos5250() || proid_is_exynos5420()
|| proid_is_exynos5800())
else if (proid_is_exynos5250() || proid_is_exynos5420() ||
else return 0;proid_is_exynos5422()) div = PLL_DIV_65536;
@@ -346,7 +346,7 @@ static struct clk_bit_info *get_clk_bit_info(int peripheral) int i; struct clk_bit_info *info;
- if (proid_is_exynos5420() || proid_is_exynos5800())
- if (proid_is_exynos5420() || proid_is_exynos5422()) info = exynos542x_bit_info; else info = exynos5_bit_info;
@@ -558,7 +558,7 @@ static unsigned long exynos542x_get_periph_rate(int peripheral) unsigned long clock_get_periph_rate(int peripheral) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
return exynos5_get_periph_rate(peripheral); } else {if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_periph_rate(peripheral);
@@ -1576,7 +1576,7 @@ static unsigned long exynos4_get_i2c_clk(void) unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
return exynos5_get_pll_clk(pllreg); } else if (cpu_is_exynos4()) {if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_pll_clk(pllreg);
@@ -1694,7 +1694,7 @@ void set_mmc_clk(int dev_index, unsigned int div) div -= 1;
if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
else exynos5_set_mmc_clk(dev_index, div);if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_mmc_clk(dev_index, div);
@@ -1710,7 +1710,7 @@ unsigned long get_lcd_clk(void) } else if (cpu_is_exynos5()) { if (proid_is_exynos5420()) return exynos5420_get_lcd_clk();
else if (proid_is_exynos5800())
else return exynos5_get_lcd_clk();else if (proid_is_exynos5422()) return exynos5800_get_lcd_clk();
@@ -1742,7 +1742,7 @@ void set_mipi_clk(void) int set_spi_clk(int periph_id, unsigned int rate) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
return exynos5_set_spi_clk(periph_id, rate); }if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_set_spi_clk(periph_id, rate);
diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c index 0200fd1..1b7498d 100644 --- a/arch/arm/mach-exynos/clock_init_exynos5.c +++ b/arch/arm/mach-exynos/clock_init_exynos5.c @@ -971,7 +971,7 @@ static void exynos5420_system_clock_init(void)
void system_clock_init(void) {
- if (proid_is_exynos5420() || proid_is_exynos5800())
- if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_system_clock_init(); else exynos5250_system_clock_init();
diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h index 67aac2d..2829fb2 100644 --- a/arch/arm/mach-exynos/common_setup.h +++ b/arch/arm/mach-exynos/common_setup.h @@ -78,7 +78,7 @@ static inline void configure_l2_ctlr(void) CACHE_TAG_RAM_LATENCY_2_CYCLES | CACHE_DATA_RAM_LATENCY_2_CYCLES;
- if (proid_is_exynos5420() || proid_is_exynos5800()) {
- if (proid_is_exynos5420() || proid_is_exynos5422()) { val |= CACHE_ECC_AND_PARITY | CACHE_TAG_RAM_LATENCY_3_CYCLES | CACHE_DATA_RAM_LATENCY_3_CYCLES;
@@ -97,7 +97,7 @@ static inline void configure_l2_actlr(void) { uint32_t val;
- if (proid_is_exynos5420() || proid_is_exynos5800()) {
- if (proid_is_exynos5420() || proid_is_exynos5422()) { mrc_l2_aux_ctlr(val); val |= CACHE_ENABLE_FORCE_L2_LOGIC | CACHE_DISABLE_CLEAN_EVICT;
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index cb3d2cc..14a1692 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -237,7 +237,7 @@ static inline void s5p_set_cpu_id(void) * Exynos5800 is a variant of Exynos5420 * and has product id 0x5422 */
Needs to modify the above comment?
Best Regards, Jaehoon Chung
Thanks! Will fix in next version.
Best regards,

This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with: - CONFIG_PMIC_S2MPS11 and additional, if were not defined: - CONFIG_CMD_PMIC - CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - remove "DM" prefix from config name - fix word mistake in binding description --- doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..422f14f --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUNG, S2MPS11 PMIC + +This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c + +Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66 + +With those two properties, the pmic device can be used for read/write only. + +Example: + +s2mps11@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; +}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 547fd1a..fb29843 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -33,6 +33,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config PMIC_S2MPS11 + bool "Enable Driver Model for PMIC Samsung S2MPS11" + depends on DM_PMIC + ---help--- + The Samsung S2MPS11 PMIC provides: + - 38 adjustable LDO regulators + - 9 High-Efficiency Buck Converters + - 1 BuckBoost Converter + - RTC with two alarms + - Backup battery charger + - I2C Configuration Interface + This driver provides access to I/O interface only. + Binding info: doc/device-tree-bindings/pmic/s2mps11.txt + config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 00fde71..91e78f8 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int s2mps11_reg_count(struct udevice *dev) +{ + return S2MPS11_REG_COUNT; +} + +static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + error("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + error("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static struct dm_pmic_ops s2mps11_ops = { + .reg_count = s2mps11_reg_count, + .read = s2mps11_read, + .write = s2mps11_write, +}; + +static const struct udevice_id s2mps11_ids[] = { + { .compatible = "samsung,s2mps11-pmic" }, + { } +}; + +U_BOOT_DRIVER(pmic_s2mps11) = { + .name = "s2mps11_pmic", + .id = UCLASS_PMIC, + .of_match = s2mps11_ids, + .ops = &s2mps11_ops, +}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..5da4719 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __S2MPS11__H__ +#define __S2MPS11__H__ + +enum s2mps11_reg { + S2MPS11_REG_ID = 0, + S2MPS11_REG_INT1, + S2MPS11_REG_INT2, + S2MPS11_REG_INT3, + S2MPS11_REG_INT1M, + S2MPS11_REG_INT2M, + S2MPS11_REG_INT3M, + S2MPS11_REG_STATUS1, + S2MPS11_REG_STATUS2, + S2MPS11_REG_OFFSRC, + S2MPS11_REG_PWRONSRC, + S2MPS11_REG_RTC_CTRL, + S2MPS11_REG_CTRL1, + S2MPS11_REG_ETC_TEST, + S2MPS11_REG_RSVD3, + S2MPS11_REG_BU_CHG, + S2MPS11_REG_RAMP, + S2MPS11_REG_RAMP_BUCK, + S2MPS11_REG_LDO1_8, + S2MPS11_REG_LDO9_16, + S2MPS11_REG_LDO17_24, + S2MPS11_REG_LDO25_32, + S2MPS11_REG_LDO33_38, + S2MPS11_REG_LDO1_8_OVC, + S2MPS11_REG_LDO9_16_OVC, + S2MPS11_REG_LDO17_24_OVC, + S2MPS11_REG_LDO25_32_OVC, + S2MPS11_REG_LDO33_38_OVC, + S2MPS11_REG_RESERVED1, + S2MPS11_REG_RESERVED2, + S2MPS11_REG_RESERVED3, + S2MPS11_REG_RESERVED4, + S2MPS11_REG_RESERVED5, + S2MPS11_REG_RESERVED6, + S2MPS11_REG_RESERVED7, + S2MPS11_REG_RESERVED8, + S2MPS11_REG_WDRSTEN_CTRL, + S2MPS11_REG_B1CTRL1, + S2MPS11_REG_B1CTRL2, + S2MPS11_REG_B2CTRL1, + S2MPS11_REG_B2CTRL2, + S2MPS11_REG_B3CTRL1, + S2MPS11_REG_B3CTRL2, + S2MPS11_REG_B4CTRL1, + S2MPS11_REG_B4CTRL2, + S2MPS11_REG_B5CTRL1, + S2MPS11_REG_BUCK5_SW, + S2MPS11_REG_B5CTRL2, + S2MPS11_REG_B5CTRL3, + S2MPS11_REG_B5CTRL4, + S2MPS11_REG_B5CTRL5, + S2MPS11_REG_B6CTRL1, + S2MPS11_REG_B6CTRL2, + S2MPS11_REG_B7CTRL1, + S2MPS11_REG_B7CTRL2, + S2MPS11_REG_B8CTRL1, + S2MPS11_REG_B8CTRL2, + S2MPS11_REG_B9CTRL1, + S2MPS11_REG_B9CTRL2, + S2MPS11_REG_B10CTRL1, + S2MPS11_REG_B10CTRL2, + S2MPS11_REG_L1CTRL, + S2MPS11_REG_L2CTRL, + S2MPS11_REG_L3CTRL, + S2MPS11_REG_L4CTRL, + S2MPS11_REG_L5CTRL, + S2MPS11_REG_L6CTRL, + S2MPS11_REG_L7CTRL, + S2MPS11_REG_L8CTRL, + S2MPS11_REG_L9CTRL, + S2MPS11_REG_L10CTRL, + S2MPS11_REG_L11CTRL, + S2MPS11_REG_L12CTRL, + S2MPS11_REG_L13CTRL, + S2MPS11_REG_L14CTRL, + S2MPS11_REG_L15CTRL, + S2MPS11_REG_L16CTRL, + S2MPS11_REG_L17CTRL, + S2MPS11_REG_L18CTRL, + S2MPS11_REG_L19CTRL, + S2MPS11_REG_L20CTRL, + S2MPS11_REG_L21CTRL, + S2MPS11_REG_L22CTRL, + S2MPS11_REG_L23CTRL, + S2MPS11_REG_L24CTRL, + S2MPS11_REG_L25CTRL, + S2MPS11_REG_L26CTRL, + S2MPS11_REG_L27CTRL, + S2MPS11_REG_L28CTRL, + S2MPS11_REG_L29CTRL, + S2MPS11_REG_L30CTRL, + S2MPS11_REG_L31CTRL, + S2MPS11_REG_L32CTRL, + S2MPS11_REG_L33CTRL, + S2MPS11_REG_L34CTRL, + S2MPS11_REG_L35CTRL, + S2MPS11_REG_L36CTRL, + S2MPS11_REG_L37CTRL, + S2MPS11_REG_L38CTRL, + S2MPS11_REG_COUNT, +}; + +#define S2MPS11_LDO26_ENABLE 0xec + +#endif

Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- remove "DM" prefix from config name
- fix word mistake in binding description
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
Reviewed-by: Simon Glass sjg@chromium.org
But please see nit below.
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..422f14f --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUNG, S2MPS11 PMIC
+This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c
+Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66
+With those two properties, the pmic device can be used for read/write only.
+Example:
+s2mps11@66 {
compatible = "samsung,s2mps11-pmic";
reg = <0x66>;
+}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 547fd1a..fb29843 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -33,6 +33,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config PMIC_S2MPS11
bool "Enable Driver Model for PMIC Samsung S2MPS11"
depends on DM_PMIC
---help---
The Samsung S2MPS11 PMIC provides:
- 38 adjustable LDO regulators
- 9 High-Efficiency Buck Converters
- 1 BuckBoost Converter
- RTC with two alarms
- Backup battery charger
- I2C Configuration Interface
This driver provides access to I/O interface only.
Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 00fde71..91e78f8 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int s2mps11_reg_count(struct udevice *dev) +{
return S2MPS11_REG_COUNT;
+}
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
+{
if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
Should return the value of dm_i2c_write(). Also below.
}
return 0;
+}
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{
if (dm_i2c_read(dev, reg, buff, len)) {
error("read error from device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
+}
+static struct dm_pmic_ops s2mps11_ops = {
.reg_count = s2mps11_reg_count,
.read = s2mps11_read,
.write = s2mps11_write,
+};
+static const struct udevice_id s2mps11_ids[] = {
{ .compatible = "samsung,s2mps11-pmic" },
{ }
+};
+U_BOOT_DRIVER(pmic_s2mps11) = {
.name = "s2mps11_pmic",
.id = UCLASS_PMIC,
.of_match = s2mps11_ids,
.ops = &s2mps11_ops,
+}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..5da4719 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __S2MPS11__H__ +#define __S2MPS11__H__
+enum s2mps11_reg {
S2MPS11_REG_ID = 0,
S2MPS11_REG_INT1,
S2MPS11_REG_INT2,
S2MPS11_REG_INT3,
S2MPS11_REG_INT1M,
S2MPS11_REG_INT2M,
S2MPS11_REG_INT3M,
S2MPS11_REG_STATUS1,
S2MPS11_REG_STATUS2,
S2MPS11_REG_OFFSRC,
S2MPS11_REG_PWRONSRC,
S2MPS11_REG_RTC_CTRL,
S2MPS11_REG_CTRL1,
S2MPS11_REG_ETC_TEST,
S2MPS11_REG_RSVD3,
S2MPS11_REG_BU_CHG,
S2MPS11_REG_RAMP,
S2MPS11_REG_RAMP_BUCK,
S2MPS11_REG_LDO1_8,
S2MPS11_REG_LDO9_16,
S2MPS11_REG_LDO17_24,
S2MPS11_REG_LDO25_32,
S2MPS11_REG_LDO33_38,
S2MPS11_REG_LDO1_8_OVC,
S2MPS11_REG_LDO9_16_OVC,
S2MPS11_REG_LDO17_24_OVC,
S2MPS11_REG_LDO25_32_OVC,
S2MPS11_REG_LDO33_38_OVC,
S2MPS11_REG_RESERVED1,
S2MPS11_REG_RESERVED2,
S2MPS11_REG_RESERVED3,
S2MPS11_REG_RESERVED4,
S2MPS11_REG_RESERVED5,
S2MPS11_REG_RESERVED6,
S2MPS11_REG_RESERVED7,
S2MPS11_REG_RESERVED8,
S2MPS11_REG_WDRSTEN_CTRL,
S2MPS11_REG_B1CTRL1,
S2MPS11_REG_B1CTRL2,
S2MPS11_REG_B2CTRL1,
S2MPS11_REG_B2CTRL2,
S2MPS11_REG_B3CTRL1,
S2MPS11_REG_B3CTRL2,
S2MPS11_REG_B4CTRL1,
S2MPS11_REG_B4CTRL2,
S2MPS11_REG_B5CTRL1,
S2MPS11_REG_BUCK5_SW,
S2MPS11_REG_B5CTRL2,
S2MPS11_REG_B5CTRL3,
S2MPS11_REG_B5CTRL4,
S2MPS11_REG_B5CTRL5,
S2MPS11_REG_B6CTRL1,
S2MPS11_REG_B6CTRL2,
S2MPS11_REG_B7CTRL1,
S2MPS11_REG_B7CTRL2,
S2MPS11_REG_B8CTRL1,
S2MPS11_REG_B8CTRL2,
S2MPS11_REG_B9CTRL1,
S2MPS11_REG_B9CTRL2,
S2MPS11_REG_B10CTRL1,
S2MPS11_REG_B10CTRL2,
S2MPS11_REG_L1CTRL,
S2MPS11_REG_L2CTRL,
S2MPS11_REG_L3CTRL,
S2MPS11_REG_L4CTRL,
S2MPS11_REG_L5CTRL,
S2MPS11_REG_L6CTRL,
S2MPS11_REG_L7CTRL,
S2MPS11_REG_L8CTRL,
S2MPS11_REG_L9CTRL,
S2MPS11_REG_L10CTRL,
S2MPS11_REG_L11CTRL,
S2MPS11_REG_L12CTRL,
S2MPS11_REG_L13CTRL,
S2MPS11_REG_L14CTRL,
S2MPS11_REG_L15CTRL,
S2MPS11_REG_L16CTRL,
S2MPS11_REG_L17CTRL,
S2MPS11_REG_L18CTRL,
S2MPS11_REG_L19CTRL,
S2MPS11_REG_L20CTRL,
S2MPS11_REG_L21CTRL,
S2MPS11_REG_L22CTRL,
S2MPS11_REG_L23CTRL,
S2MPS11_REG_L24CTRL,
S2MPS11_REG_L25CTRL,
S2MPS11_REG_L26CTRL,
S2MPS11_REG_L27CTRL,
S2MPS11_REG_L28CTRL,
S2MPS11_REG_L29CTRL,
S2MPS11_REG_L30CTRL,
S2MPS11_REG_L31CTRL,
S2MPS11_REG_L32CTRL,
S2MPS11_REG_L33CTRL,
S2MPS11_REG_L34CTRL,
S2MPS11_REG_L35CTRL,
S2MPS11_REG_L36CTRL,
S2MPS11_REG_L37CTRL,
S2MPS11_REG_L38CTRL,
S2MPS11_REG_COUNT,
+};
+#define S2MPS11_LDO26_ENABLE 0xec
+#endif
1.9.1
Regards, Simon

Hi Simon,
On 10/03/2015 04:28 PM, Simon Glass wrote:
Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- remove "DM" prefix from config name
- fix word mistake in binding description
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 ++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
Reviewed-by: Simon Glass sjg@chromium.org
But please see nit below.
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..422f14f --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUNG, S2MPS11 PMIC
+This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c
+Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66
+With those two properties, the pmic device can be used for read/write only.
+Example:
+s2mps11@66 {
compatible = "samsung,s2mps11-pmic";
reg = <0x66>;
+}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 547fd1a..fb29843 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -33,6 +33,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config PMIC_S2MPS11
bool "Enable Driver Model for PMIC Samsung S2MPS11"
depends on DM_PMIC
---help---
The Samsung S2MPS11 PMIC provides:
- 38 adjustable LDO regulators
- 9 High-Efficiency Buck Converters
- 1 BuckBoost Converter
- RTC with two alarms
- Backup battery charger
- I2C Configuration Interface
This driver provides access to I/O interface only.
Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
- config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 00fde71..91e78f8 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..7e28402 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,60 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int s2mps11_reg_count(struct udevice *dev) +{
return S2MPS11_REG_COUNT;
+}
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
+{
if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
Should return the value of dm_i2c_write(). Also below.
Right, will fix.
}
return 0;
+}
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{
if (dm_i2c_read(dev, reg, buff, len)) {
error("read error from device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
+}
+static struct dm_pmic_ops s2mps11_ops = {
.reg_count = s2mps11_reg_count,
.read = s2mps11_read,
.write = s2mps11_write,
+};
+static const struct udevice_id s2mps11_ids[] = {
{ .compatible = "samsung,s2mps11-pmic" },
{ }
+};
+U_BOOT_DRIVER(pmic_s2mps11) = {
.name = "s2mps11_pmic",
.id = UCLASS_PMIC,
.of_match = s2mps11_ids,
.ops = &s2mps11_ops,
+}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..5da4719 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __S2MPS11__H__ +#define __S2MPS11__H__
+enum s2mps11_reg {
S2MPS11_REG_ID = 0,
S2MPS11_REG_INT1,
S2MPS11_REG_INT2,
S2MPS11_REG_INT3,
S2MPS11_REG_INT1M,
S2MPS11_REG_INT2M,
S2MPS11_REG_INT3M,
S2MPS11_REG_STATUS1,
S2MPS11_REG_STATUS2,
S2MPS11_REG_OFFSRC,
S2MPS11_REG_PWRONSRC,
S2MPS11_REG_RTC_CTRL,
S2MPS11_REG_CTRL1,
S2MPS11_REG_ETC_TEST,
S2MPS11_REG_RSVD3,
S2MPS11_REG_BU_CHG,
S2MPS11_REG_RAMP,
S2MPS11_REG_RAMP_BUCK,
S2MPS11_REG_LDO1_8,
S2MPS11_REG_LDO9_16,
S2MPS11_REG_LDO17_24,
S2MPS11_REG_LDO25_32,
S2MPS11_REG_LDO33_38,
S2MPS11_REG_LDO1_8_OVC,
S2MPS11_REG_LDO9_16_OVC,
S2MPS11_REG_LDO17_24_OVC,
S2MPS11_REG_LDO25_32_OVC,
S2MPS11_REG_LDO33_38_OVC,
S2MPS11_REG_RESERVED1,
S2MPS11_REG_RESERVED2,
S2MPS11_REG_RESERVED3,
S2MPS11_REG_RESERVED4,
S2MPS11_REG_RESERVED5,
S2MPS11_REG_RESERVED6,
S2MPS11_REG_RESERVED7,
S2MPS11_REG_RESERVED8,
S2MPS11_REG_WDRSTEN_CTRL,
S2MPS11_REG_B1CTRL1,
S2MPS11_REG_B1CTRL2,
S2MPS11_REG_B2CTRL1,
S2MPS11_REG_B2CTRL2,
S2MPS11_REG_B3CTRL1,
S2MPS11_REG_B3CTRL2,
S2MPS11_REG_B4CTRL1,
S2MPS11_REG_B4CTRL2,
S2MPS11_REG_B5CTRL1,
S2MPS11_REG_BUCK5_SW,
S2MPS11_REG_B5CTRL2,
S2MPS11_REG_B5CTRL3,
S2MPS11_REG_B5CTRL4,
S2MPS11_REG_B5CTRL5,
S2MPS11_REG_B6CTRL1,
S2MPS11_REG_B6CTRL2,
S2MPS11_REG_B7CTRL1,
S2MPS11_REG_B7CTRL2,
S2MPS11_REG_B8CTRL1,
S2MPS11_REG_B8CTRL2,
S2MPS11_REG_B9CTRL1,
S2MPS11_REG_B9CTRL2,
S2MPS11_REG_B10CTRL1,
S2MPS11_REG_B10CTRL2,
S2MPS11_REG_L1CTRL,
S2MPS11_REG_L2CTRL,
S2MPS11_REG_L3CTRL,
S2MPS11_REG_L4CTRL,
S2MPS11_REG_L5CTRL,
S2MPS11_REG_L6CTRL,
S2MPS11_REG_L7CTRL,
S2MPS11_REG_L8CTRL,
S2MPS11_REG_L9CTRL,
S2MPS11_REG_L10CTRL,
S2MPS11_REG_L11CTRL,
S2MPS11_REG_L12CTRL,
S2MPS11_REG_L13CTRL,
S2MPS11_REG_L14CTRL,
S2MPS11_REG_L15CTRL,
S2MPS11_REG_L16CTRL,
S2MPS11_REG_L17CTRL,
S2MPS11_REG_L18CTRL,
S2MPS11_REG_L19CTRL,
S2MPS11_REG_L20CTRL,
S2MPS11_REG_L21CTRL,
S2MPS11_REG_L22CTRL,
S2MPS11_REG_L23CTRL,
S2MPS11_REG_L24CTRL,
S2MPS11_REG_L25CTRL,
S2MPS11_REG_L26CTRL,
S2MPS11_REG_L27CTRL,
S2MPS11_REG_L28CTRL,
S2MPS11_REG_L29CTRL,
S2MPS11_REG_L30CTRL,
S2MPS11_REG_L31CTRL,
S2MPS11_REG_L32CTRL,
S2MPS11_REG_L33CTRL,
S2MPS11_REG_L34CTRL,
S2MPS11_REG_L35CTRL,
S2MPS11_REG_L36CTRL,
S2MPS11_REG_L37CTRL,
S2MPS11_REG_L38CTRL,
S2MPS11_REG_COUNT,
+};
+#define S2MPS11_LDO26_ENABLE 0xec
+#endif
1.9.1
Regards, Simon
Best regards,

This commit adds: - new uclass id: UCLASS_ADC - new uclass driver: drivers/adc/adc-uclass.c
The uclass's implementation is as simple as needed and provides functions: - adc_init() - init ADC conversion - adc_data() - convert and return data - adc_data_mask() - return ADC data mask - adc_channel_single_shot() - function for single ADC convertion
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - new commit - introduce ADC uclass driver --- drivers/Kconfig | 2 ++ drivers/Makefile | 1 + drivers/adc/Kconfig | 8 +++++ drivers/adc/Makefile | 8 +++++ drivers/adc/adc-uclass.c | 76 +++++++++++++++++++++++++++++++++++++++++ include/adc.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 7 files changed, 184 insertions(+) create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 include/adc.h
diff --git a/drivers/Kconfig b/drivers/Kconfig index 63c92c5..ad9ae3a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -4,6 +4,8 @@ source "drivers/core/Kconfig"
# types of drivers sorted in alphabetical order
+source "drivers/adc/Kconfig" + source "drivers/block/Kconfig"
source "drivers/clk/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 9d0a595..d7d5e9f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
else
+obj-y += adc/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig new file mode 100644 index 0000000..1cb1a8d --- /dev/null +++ b/drivers/adc/Kconfig @@ -0,0 +1,8 @@ +config ADC + bool "Enable ADC drivers using Driver Model" + help + This allows drivers to be provided for ADCs to drive their features, + trough simple ADC uclass driver interface, with operations: + - device enable + - conversion init + - conversion start and return data with data mask diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile new file mode 100644 index 0000000..c4d9618 --- /dev/null +++ b/drivers/adc/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2015 Samsung Electronics +# Przemyslaw Marczak p.marczak@samsung.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_ADC) += adc-uclass.o diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c new file mode 100644 index 0000000..bb71b6e --- /dev/null +++ b/drivers/adc/adc-uclass.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <adc.h> + +#define ADC_UCLASS_PLATDATA_SIZE sizeof(struct adc_uclass_platdata) + +int adc_init(struct udevice *dev, int channel) +{ + const struct adc_ops *ops = dev_get_driver_ops(dev); + + if (ops->adc_init) + return ops->adc_init(dev, channel); + + return -ENOSYS; +} + +int adc_data(struct udevice *dev, unsigned int *data) +{ + const struct adc_ops *ops = dev_get_driver_ops(dev); + + *data = 0; + + if (ops->adc_data) + return ops->adc_data(dev, data); + + return -ENOSYS; +} + +int adc_data_mask(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + + if (uc_pdata) + return uc_pdata->data_mask; + + return -ENOSYS; +} + +int adc_channel_single_shot(const char *name, int channel, unsigned int *data) +{ + struct udevice *dev; + int ret; + + *data = 0; + + ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev); + if (ret) + return ret; + + ret = adc_init(dev, channel); + if (ret) + return ret; + + ret = adc_data(dev, data); + if (ret) + return ret; + + return 0; +} + +UCLASS_DRIVER(adc) = { + .id = UCLASS_ADC, + .name = "adc", + .per_device_platdata_auto_alloc_size = ADC_UCLASS_PLATDATA_SIZE, +}; diff --git a/include/adc.h b/include/adc.h new file mode 100644 index 0000000..57b9281 --- /dev/null +++ b/include/adc.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ADC_H_ +#define _ADC_H_ + +/** + * struct adc_uclass_platdata - ADC power supply and reference Voltage info + * + * @data_mask - conversion output data mask + * @channels_num - number of analog channels input + * @vdd_supply - positive reference voltage supply + * @vss_supply - negative reference voltage supply + */ +struct adc_uclass_platdata { + unsigned int data_mask; + unsigned int channels_num; + struct udevice *vdd_supply; + struct udevice *vss_supply; +}; + +/** + * struct adc_ops - ADC device operations + */ +struct adc_ops { + /** + * conversion_init() - init device's default conversion parameters + * + * @dev: ADC device to init + * @channel: analog channel number + * @return: 0 if OK, -ve on error + */ + int (*adc_init)(struct udevice *dev, int channel); + + /** + * conversion_data() - get output data of given channel conversion + * + * @dev: ADC device to trigger + * @channel_data: pointer to returned channel's data + * @return: 0 if OK, -ve on error + */ + int (*adc_data)(struct udevice *dev, unsigned int *channel_data); +}; + +/** + * adc_init() - init device's default conversion parameters for the given + * analog input channel. + * + * @dev: ADC device to init + * @channel: analog channel number + * @return: 0 if OK, -ve on error + */ +int adc_init(struct udevice *dev, int channel); + +/** + * adc_data() - get conversion data for the channel inited by adc_init(). + * + * @dev: ADC device to trigger + * @data: pointer to returned channel's data + * @return: 0 if OK, -ve on error + */ +int adc_data(struct udevice *dev, unsigned int *data); + +/** + * adc_data_mask() - get data mask (ADC resolution mask) for given ADC device. + * This can be used if adc uclass platform data is filled. + * + * @dev: ADC device to check + * @return: 0 if OK, -ve on error + */ +int adc_data_mask(struct udevice *dev); + +/** + * adc_channel_single_shot() - get output data of convertion for the ADC + * device's channel. This function search for the device with the given name, + * init the given channel and returns the convertion data. + * + * @name: device's name to search + * @channel: device's input channel to init + * @data: pointer to convertion output data + */ +int adc_channel_single_shot(const char *name, int channel, unsigned int *data); + +#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1eeec74..0f7e7da 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -25,6 +25,7 @@ enum uclass_id { UCLASS_SIMPLE_BUS, /* bus with child devices */
/* U-Boot uclasses start here - in alphabetical order */ + UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_CLK, /* Clock source, e.g. used by peripherals */ UCLASS_CPU, /* CPU, typically part of an SoC */ UCLASS_CROS_EC, /* Chrome OS EC */

Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds:
- new uclass id: UCLASS_ADC
- new uclass driver: drivers/adc/adc-uclass.c
The uclass's implementation is as simple as needed and provides functions:
- adc_init() - init ADC conversion
- adc_data() - convert and return data
- adc_data_mask() - return ADC data mask
- adc_channel_single_shot() - function for single ADC convertion
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit - introduce ADC uclass driver
drivers/Kconfig | 2 ++ drivers/Makefile | 1 + drivers/adc/Kconfig | 8 +++++ drivers/adc/Makefile | 8 +++++ drivers/adc/adc-uclass.c | 76 +++++++++++++++++++++++++++++++++++++++++ include/adc.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 7 files changed, 184 insertions(+) create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 include/adc.h
Sorry I have quite a lot of questions and comments on this.
diff --git a/drivers/Kconfig b/drivers/Kconfig index 63c92c5..ad9ae3a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -4,6 +4,8 @@ source "drivers/core/Kconfig"
# types of drivers sorted in alphabetical order
+source "drivers/adc/Kconfig"
source "drivers/block/Kconfig"
source "drivers/clk/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 9d0a595..d7d5e9f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
else
+obj-y += adc/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig new file mode 100644 index 0000000..1cb1a8d --- /dev/null +++ b/drivers/adc/Kconfig @@ -0,0 +1,8 @@ +config ADC
bool "Enable ADC drivers using Driver Model"
help
This allows drivers to be provided for ADCs to drive their features,
trough simple ADC uclass driver interface, with operations:
through a simple
- device enable
- conversion init
- conversion start and return data with data mask
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile new file mode 100644 index 0000000..c4d9618 --- /dev/null +++ b/drivers/adc/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2015 Samsung Electronics +# Przemyslaw Marczak p.marczak@samsung.com +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_ADC) += adc-uclass.o diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c new file mode 100644 index 0000000..bb71b6e --- /dev/null +++ b/drivers/adc/adc-uclass.c @@ -0,0 +1,76 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <adc.h>
+#define ADC_UCLASS_PLATDATA_SIZE sizeof(struct adc_uclass_platdata)
Can we drop #define?
+int adc_init(struct udevice *dev, int channel) +{
const struct adc_ops *ops = dev_get_driver_ops(dev);
if (ops->adc_init)
return ops->adc_init(dev, channel);
return -ENOSYS;
Let's turn each of these around so that errors are the exception, not the normal path.
if (!ops->adc_init) return -ENOSYS;
return ops->...
+}
+int adc_data(struct udevice *dev, unsigned int *data) +{
const struct adc_ops *ops = dev_get_driver_ops(dev);
*data = 0;
if (ops->adc_data)
return ops->adc_data(dev, data);
return -ENOSYS;
+}
+int adc_data_mask(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
if (uc_pdata)
return uc_pdata->data_mask;
return -ENOSYS;
+}
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data) +{
struct udevice *dev;
int ret;
*data = 0;
I don't think we need this assignment. This can be undefined if an error is returned.
ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
if (ret)
return ret;
ret = adc_init(dev, channel);
if (ret)
return ret;
ret = adc_data(dev, data);
if (ret)
return ret;
return 0;
+}
+UCLASS_DRIVER(adc) = {
.id = UCLASS_ADC,
.name = "adc",
.per_device_platdata_auto_alloc_size = ADC_UCLASS_PLATDATA_SIZE,
+}; diff --git a/include/adc.h b/include/adc.h new file mode 100644 index 0000000..57b9281 --- /dev/null +++ b/include/adc.h @@ -0,0 +1,88 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _ADC_H_ +#define _ADC_H_
+/**
- struct adc_uclass_platdata - ADC power supply and reference Voltage info
- @data_mask - conversion output data mask
- @channels_num - number of analog channels input
- @vdd_supply - positive reference voltage supply
- @vss_supply - negative reference voltage supply
- */
+struct adc_uclass_platdata {
unsigned int data_mask;
unsigned int channels_num;
struct udevice *vdd_supply;
struct udevice *vss_supply;
+};
+/**
- struct adc_ops - ADC device operations
- */
+struct adc_ops {
/**
* conversion_init() - init device's default conversion parameters
*
* @dev: ADC device to init
* @channel: analog channel number
* @return: 0 if OK, -ve on error
*/
int (*adc_init)(struct udevice *dev, int channel);
s/adc_init/init/
Same below. Also it seems like this starts the conversion, so how about using the name start().
/**
* conversion_data() - get output data of given channel conversion
*
* @dev: ADC device to trigger
* @channel_data: pointer to returned channel's data
* @return: 0 if OK, -ve on error
*/
int (*adc_data)(struct udevice *dev, unsigned int *channel_data);
+};
+/**
- adc_init() - init device's default conversion parameters for the given
- analog input channel.
- @dev: ADC device to init
- @channel: analog channel number
- @return: 0 if OK, -ve on error
- */
+int adc_init(struct udevice *dev, int channel);
adc_start()?
+/**
- adc_data() - get conversion data for the channel inited by adc_init().
- @dev: ADC device to trigger
- @data: pointer to returned channel's data
- @return: 0 if OK, -ve on error
- */
+int adc_data(struct udevice *dev, unsigned int *data);
This seems a bit wonky. Why not pass in the channel with this call? What if I want to start conversions on multiple channels at the same time?
+/**
- adc_data_mask() - get data mask (ADC resolution mask) for given ADC device.
- This can be used if adc uclass platform data is filled.
- @dev: ADC device to check
- @return: 0 if OK, -ve on error
If it always returns 0 unless there is an error, what is the point? Or is this comment incorrect?
- */
+int adc_data_mask(struct udevice *dev);
+/**
- adc_channel_single_shot() - get output data of convertion for the ADC
- device's channel. This function search for the device with the given name,
- init the given channel and returns the convertion data.
It also inits the device.
I would prefer a function that finds a device by name and inits it.
- @name: device's name to search
- @channel: device's input channel to init
- @data: pointer to convertion output data
conversion
- */
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data);
+#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1eeec74..0f7e7da 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -25,6 +25,7 @@ enum uclass_id { UCLASS_SIMPLE_BUS, /* bus with child devices */
/* U-Boot uclasses start here - in alphabetical order */
UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_CLK, /* Clock source, e.g. used by peripherals */ UCLASS_CPU, /* CPU, typically part of an SoC */ UCLASS_CROS_EC, /* Chrome OS EC */
-- 1.9.1
Regards, Simon

Hello Simon,
On 10/03/2015 04:28 PM, Simon Glass wrote:
Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds:
- new uclass id: UCLASS_ADC
- new uclass driver: drivers/adc/adc-uclass.c
The uclass's implementation is as simple as needed and provides functions:
- adc_init() - init ADC conversion
- adc_data() - convert and return data
- adc_data_mask() - return ADC data mask
- adc_channel_single_shot() - function for single ADC convertion
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit - introduce ADC uclass driver
drivers/Kconfig | 2 ++ drivers/Makefile | 1 + drivers/adc/Kconfig | 8 +++++ drivers/adc/Makefile | 8 +++++ drivers/adc/adc-uclass.c | 76 +++++++++++++++++++++++++++++++++++++++++ include/adc.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 7 files changed, 184 insertions(+) create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 include/adc.h
Sorry I have quite a lot of questions and comments on this.
Yes, ok.
diff --git a/drivers/Kconfig b/drivers/Kconfig index 63c92c5..ad9ae3a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -4,6 +4,8 @@ source "drivers/core/Kconfig"
# types of drivers sorted in alphabetical order
+source "drivers/adc/Kconfig"
source "drivers/block/Kconfig"
source "drivers/clk/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile index 9d0a595..d7d5e9f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
else
+obj-y += adc/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig new file mode 100644 index 0000000..1cb1a8d --- /dev/null +++ b/drivers/adc/Kconfig @@ -0,0 +1,8 @@ +config ADC
bool "Enable ADC drivers using Driver Model"
help
This allows drivers to be provided for ADCs to drive their features,
trough simple ADC uclass driver interface, with operations:
through a simple
Ok.
- device enable
- conversion init
- conversion start and return data with data mask
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile new file mode 100644 index 0000000..c4d9618 --- /dev/null +++ b/drivers/adc/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2015 Samsung Electronics +# Przemyslaw Marczak p.marczak@samsung.com +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_ADC) += adc-uclass.o diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c new file mode 100644 index 0000000..bb71b6e --- /dev/null +++ b/drivers/adc/adc-uclass.c @@ -0,0 +1,76 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <adc.h>
+#define ADC_UCLASS_PLATDATA_SIZE sizeof(struct adc_uclass_platdata)
Can we drop #define?
Don't you think, that single line initialization looks better than those with line breaks? This is the purpose of that define.
+int adc_init(struct udevice *dev, int channel) +{
const struct adc_ops *ops = dev_get_driver_ops(dev);
if (ops->adc_init)
return ops->adc_init(dev, channel);
return -ENOSYS;
Let's turn each of these around so that errors are the exception, not the normal path.
if (!ops->adc_init) return -ENOSYS;
return ops->...
Ok, I will turn it.
+}
+int adc_data(struct udevice *dev, unsigned int *data) +{
const struct adc_ops *ops = dev_get_driver_ops(dev);
*data = 0;
if (ops->adc_data)
return ops->adc_data(dev, data);
return -ENOSYS;
+}
+int adc_data_mask(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
if (uc_pdata)
return uc_pdata->data_mask;
return -ENOSYS;
+}
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data) +{
struct udevice *dev;
int ret;
*data = 0;
I don't think we need this assignment. This can be undefined if an error is returned.
Ok.
ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
if (ret)
return ret;
ret = adc_init(dev, channel);
if (ret)
return ret;
ret = adc_data(dev, data);
if (ret)
return ret;
return 0;
+}
+UCLASS_DRIVER(adc) = {
.id = UCLASS_ADC,
.name = "adc",
.per_device_platdata_auto_alloc_size = ADC_UCLASS_PLATDATA_SIZE,
+}; diff --git a/include/adc.h b/include/adc.h new file mode 100644 index 0000000..57b9281 --- /dev/null +++ b/include/adc.h @@ -0,0 +1,88 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _ADC_H_ +#define _ADC_H_
+/**
- struct adc_uclass_platdata - ADC power supply and reference Voltage info
- @data_mask - conversion output data mask
- @channels_num - number of analog channels input
- @vdd_supply - positive reference voltage supply
- @vss_supply - negative reference voltage supply
- */
+struct adc_uclass_platdata {
unsigned int data_mask;
unsigned int channels_num;
struct udevice *vdd_supply;
struct udevice *vss_supply;
+};
+/**
- struct adc_ops - ADC device operations
- */
+struct adc_ops {
/**
* conversion_init() - init device's default conversion parameters
*
* @dev: ADC device to init
* @channel: analog channel number
* @return: 0 if OK, -ve on error
*/
int (*adc_init)(struct udevice *dev, int channel);
s/adc_init/init/
Same below. Also it seems like this starts the conversion, so how about using the name start().
Ok, I will modify the API.
/**
* conversion_data() - get output data of given channel conversion
*
* @dev: ADC device to trigger
* @channel_data: pointer to returned channel's data
* @return: 0 if OK, -ve on error
*/
int (*adc_data)(struct udevice *dev, unsigned int *channel_data);
+};
+/**
- adc_init() - init device's default conversion parameters for the given
- analog input channel.
- @dev: ADC device to init
- @channel: analog channel number
- @return: 0 if OK, -ve on error
- */
+int adc_init(struct udevice *dev, int channel);
adc_start()?
+/**
- adc_data() - get conversion data for the channel inited by adc_init().
- @dev: ADC device to trigger
- @data: pointer to returned channel's data
- @return: 0 if OK, -ve on error
- */
+int adc_data(struct udevice *dev, unsigned int *data);
This seems a bit wonky. Why not pass in the channel with this call? What if I want to start conversions on multiple channels at the same time?
Right, this could be more flexible. I will modify it.
+/**
- adc_data_mask() - get data mask (ADC resolution mask) for given ADC device.
- This can be used if adc uclass platform data is filled.
- @dev: ADC device to check
- @return: 0 if OK, -ve on error
If it always returns 0 unless there is an error, what is the point? Or is this comment incorrect?
Yes, that is a mistake.
- */
+int adc_data_mask(struct udevice *dev);
+/**
- adc_channel_single_shot() - get output data of convertion for the ADC
- device's channel. This function search for the device with the given name,
- init the given channel and returns the convertion data.
It also inits the device.
I would prefer a function that finds a device by name and inits it.
Ah, ok.
- @name: device's name to search
- @channel: device's input channel to init
- @data: pointer to convertion output data
conversion
Okay.
- */
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data);
+#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1eeec74..0f7e7da 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -25,6 +25,7 @@ enum uclass_id { UCLASS_SIMPLE_BUS, /* bus with child devices */
/* U-Boot uclasses start here - in alphabetical order */
UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_CLK, /* Clock source, e.g. used by peripherals */ UCLASS_CPU, /* CPU, typically part of an SoC */ UCLASS_CROS_EC, /* Chrome OS EC */
-- 1.9.1
Regards, Simon
Thanks for comments. The ADC API is not ideal, however it fits my needs. Also it looks like nobody was using ADC before in U-Boot, so I can suppose it can be as simple as possible. I will clean this :)
Best regards

This commit adds driver for Exynos54xx ADC subsystem.
The driver is implemented using driver model, amd provides ADC uclass's operations: - adc_init() - adc_data()
This driver uses sdelay() function on pooling, so it can be used before the delay timer is inited. The basic parameters of ADC conversion, are: - sample rate: 600KSPS - output the data as average of 8 time conversion
ADC features: - sample rate: 600KSPS - resolution: 12-bit - channels: 10 (analog multiplexer)
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - new commit - move previous adc driver from SoC directory to drivers/adc --- arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++++ drivers/adc/Kconfig | 9 +++ drivers/adc/Makefile | 1 + drivers/adc/exynos-adc.c | 102 ++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/adc/exynos-adc.c
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/drivers/adc/Kconfig b/drivers/adc/Kconfig index 1cb1a8d..8ee6531 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -6,3 +6,12 @@ config ADC - device enable - conversion init - conversion start and return data with data mask + +config ADC_EXYNOS + bool "Enable Exynos 54xx ADC driver" + help + This enables basic driver for Exynos ADC compatible with Exynos54xx. + It provides: + - 10 analog input channels + - 12-bit resolution + - 600 KSPS of sample rate diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index c4d9618..eb85b8b 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -6,3 +6,4 @@ #
obj-$(CONFIG_ADC) += adc-uclass.o +obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c new file mode 100644 index 0000000..fdffea0 --- /dev/null +++ b/drivers/adc/exynos-adc.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <adc.h> +#include <asm/arch/adc.h> + +struct exynos_adc_priv { + struct exynos_adc_v2 *regs; +}; + +extern void sdelay(unsigned long loops); + +int exynos_adc_data(struct udevice *dev, unsigned int *data) +{ + struct exynos_adc_priv *priv = dev_get_priv(dev); + struct exynos_adc_v2 *regs = priv->regs; + unsigned int cfg, timeout_us = ADC_V2_CONV_TIMEOUT_US; + + /* Start conversion */ + cfg = readl(®s->con1); + writel(cfg | ADC_V2_CON1_STC_EN, ®s->con1); + + while (ADC_V2_GET_STATUS_FLAG(readl(®s->status)) != FLAG_CONV_END) { + sdelay(4); + if (!timeout_us--) { + error("ADC conversion timeout!"); + return -ETIME; + } + } + + *data = readl(®s->dat) & ADC_V2_DAT_MASK; + + return 0; +} + +int exynos_adc_init(struct udevice *dev, int channel) +{ + struct exynos_adc_priv *priv = dev_get_priv(dev); + struct exynos_adc_v2 *regs = priv->regs; + unsigned int cfg; + + /* Check HW version */ + if (readl(®s->version) != ADC_V2_VERSION) { + error("This driver supports only ADC v2!"); + return -ENXIO; + } + + /* ADC Reset */ + writel(ADC_V2_CON1_SOFT_RESET, ®s->con1); + + /* Disable INT - will read status only */ + writel(0x0, ®s->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, ®s->con2); + + return 0; +} + +int exynos_adc_ofdata_to_platdata(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + struct exynos_adc_priv *priv = dev_get_priv(dev); + + priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev); + + uc_pdata->data_mask = ADC_V2_DAT_MASK; + /* Channel count starts from 0 */ + uc_pdata->channels_num = ADC_V2_MAX_CHANNEL + 1; + + return 0; +} + +static const struct adc_ops exynos_adc_ops = { + .adc_init = exynos_adc_init, + .adc_data = exynos_adc_data, +}; + +static const struct udevice_id exynos_adc_ids[] = { + { .compatible = "samsung,exynos-adc-v2" }, + { } +}; + +U_BOOT_DRIVER(exynos_adc) = { + .name = "exynos-adc", + .id = UCLASS_ADC, + .of_match = exynos_adc_ids, + .ops = &exynos_adc_ops, + .ofdata_to_platdata = exynos_adc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct exynos_adc_priv), +};

Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds driver for Exynos54xx ADC subsystem.
The driver is implemented using driver model, amd provides ADC uclass's operations:
- adc_init()
- adc_data()
This driver uses sdelay() function on pooling, so it can be used before the delay timer is inited. The basic parameters of ADC conversion, are:
- sample rate: 600KSPS
- output the data as average of 8 time conversion
ADC features:
- sample rate: 600KSPS
- resolution: 12-bit
- channels: 10 (analog multiplexer)
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit - move previous adc driver from SoC directory to drivers/adc
arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++++ drivers/adc/Kconfig | 9 +++ drivers/adc/Makefile | 1 + drivers/adc/exynos-adc.c | 102 ++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/adc/exynos-adc.c
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)
No need for brackets on these simple ones
+#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/drivers/adc/Kconfig b/drivers/adc/Kconfig index 1cb1a8d..8ee6531 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -6,3 +6,12 @@ config ADC - device enable - conversion init - conversion start and return data with data mask
+config ADC_EXYNOS
bool "Enable Exynos 54xx ADC driver"
help
This enables basic driver for Exynos ADC compatible with Exynos54xx.
It provides:
- 10 analog input channels
- 12-bit resolution
- 600 KSPS of sample rate
Great help!
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index c4d9618..eb85b8b 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -6,3 +6,4 @@ #
obj-$(CONFIG_ADC) += adc-uclass.o +obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c new file mode 100644 index 0000000..fdffea0 --- /dev/null +++ b/drivers/adc/exynos-adc.c @@ -0,0 +1,102 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <adc.h> +#include <asm/arch/adc.h>
+struct exynos_adc_priv {
struct exynos_adc_v2 *regs;
+};
+extern void sdelay(unsigned long loops);
Can you put this include system.h for exynos, or similar? Also, I think the problem is that timer_init() is called after initf_dm(). There is a patch to add timer support to driver model so perhaps that will help?
+int exynos_adc_data(struct udevice *dev, unsigned int *data) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg, timeout_us = ADC_V2_CONV_TIMEOUT_US;
/* Start conversion */
cfg = readl(®s->con1);
writel(cfg | ADC_V2_CON1_STC_EN, ®s->con1);
while (ADC_V2_GET_STATUS_FLAG(readl(®s->status)) != FLAG_CONV_END) {
sdelay(4);
if (!timeout_us--) {
error("ADC conversion timeout!");
return -ETIME;
}
}
Hmm, we don't want to put delays in drivers. I though that the init() method was used to start the conversion, but now I see that it is not. I think the uclass is going to have to know how long to wait for the conversion to be ready.
How about this for an interface:
adc_start(dev, channel) adc_read(dev, channel)
which waits until the conversion is ready on that channel. The driver can set up the time that the conversion will be ready (and store it in the uclass) when the conversion starts.
Can we support conversions on several channels at once?
*data = readl(®s->dat) & ADC_V2_DAT_MASK;
return 0;
+}
+int exynos_adc_init(struct udevice *dev, int channel) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg;
/* Check HW version */
if (readl(®s->version) != ADC_V2_VERSION) {
error("This driver supports only ADC v2!");
return -ENXIO;
}
/* ADC Reset */
writel(ADC_V2_CON1_SOFT_RESET, ®s->con1);
/* Disable INT - will read status only */
writel(0x0, ®s->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, ®s->con2);
Can this function go in probe() instead? The only thing that can't is 'channel'. Is that setting which channel does the conversion? If so, perhaps that particular setting could move to the start function?
return 0;
+}
+int exynos_adc_ofdata_to_platdata(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
struct exynos_adc_priv *priv = dev_get_priv(dev);
priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev);
uc_pdata->data_mask = ADC_V2_DAT_MASK;
/* Channel count starts from 0 */
uc_pdata->channels_num = ADC_V2_MAX_CHANNEL + 1;
return 0;
+}
+static const struct adc_ops exynos_adc_ops = {
.adc_init = exynos_adc_init,
.adc_data = exynos_adc_data,
+};
+static const struct udevice_id exynos_adc_ids[] = {
{ .compatible = "samsung,exynos-adc-v2" },
{ }
+};
+U_BOOT_DRIVER(exynos_adc) = {
.name = "exynos-adc",
.id = UCLASS_ADC,
.of_match = exynos_adc_ids,
.ops = &exynos_adc_ops,
.ofdata_to_platdata = exynos_adc_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct exynos_adc_priv),
+};
1.9.1
Regards, Simon

Hello Simon,
On 10/03/2015 04:28 PM, Simon Glass wrote:
Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds driver for Exynos54xx ADC subsystem.
The driver is implemented using driver model, amd provides ADC uclass's operations:
- adc_init()
- adc_data()
This driver uses sdelay() function on pooling, so it can be used before the delay timer is inited. The basic parameters of ADC conversion, are:
- sample rate: 600KSPS
- output the data as average of 8 time conversion
ADC features:
- sample rate: 600KSPS
- resolution: 12-bit
- channels: 10 (analog multiplexer)
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit - move previous adc driver from SoC directory to drivers/adc
arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++++ drivers/adc/Kconfig | 9 +++ drivers/adc/Makefile | 1 + drivers/adc/exynos-adc.c | 102 ++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/adc/exynos-adc.c
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)
No need for brackets on these simple ones
Okay, I will remove them.
+#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/drivers/adc/Kconfig b/drivers/adc/Kconfig index 1cb1a8d..8ee6531 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -6,3 +6,12 @@ config ADC - device enable - conversion init - conversion start and return data with data mask
+config ADC_EXYNOS
bool "Enable Exynos 54xx ADC driver"
help
This enables basic driver for Exynos ADC compatible with Exynos54xx.
It provides:
- 10 analog input channels
- 12-bit resolution
- 600 KSPS of sample rate
Great help!
Thanks:)
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index c4d9618..eb85b8b 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -6,3 +6,4 @@ #
obj-$(CONFIG_ADC) += adc-uclass.o +obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c new file mode 100644 index 0000000..fdffea0 --- /dev/null +++ b/drivers/adc/exynos-adc.c @@ -0,0 +1,102 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <adc.h> +#include <asm/arch/adc.h>
+struct exynos_adc_priv {
struct exynos_adc_v2 *regs;
+};
+extern void sdelay(unsigned long loops);
Can you put this include system.h for exynos, or similar? Also, I think the problem is that timer_init() is called after initf_dm(). There is a patch to add timer support to driver model so perhaps that will help?
Ok, will move this. And yes, the problem is with too late timer init. I saw the work for timer uclass, however I would prefer just use this function. It can be moved in the future.
I'm trying add simple functionality, move everything to driver model is not related to this patch set.
We can add the timer driver later, and then fix each timer call.
+int exynos_adc_data(struct udevice *dev, unsigned int *data) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg, timeout_us = ADC_V2_CONV_TIMEOUT_US;
/* Start conversion */
cfg = readl(®s->con1);
writel(cfg | ADC_V2_CON1_STC_EN, ®s->con1);
while (ADC_V2_GET_STATUS_FLAG(readl(®s->status)) != FLAG_CONV_END) {
sdelay(4);
if (!timeout_us--) {
error("ADC conversion timeout!");
return -ETIME;
}
}
Hmm, we don't want to put delays in drivers. I though that the init() method was used to start the conversion, but now I see that it is not. I think the uclass is going to have to know how long to wait for the conversion to be ready.
Good point, I will move the delay to uclass driver.
How about this for an interface:
adc_start(dev, channel) adc_read(dev, channel)
which waits until the conversion is ready on that channel. The driver can set up the time that the conversion will be ready (and store it in the uclass) when the conversion starts.
Ok, that sounds good.
Can we support conversions on several channels at once?
Some hardware can do this, but the Exynos internal ADC is simple and allows only for a single channel conversion at a time.
I can add an uclass operation function call, e.g. adc_channels_data(), and if it's not implemented by the device driver, then it can get the data for each channel in a loop.
Is that good to you?
*data = readl(®s->dat) & ADC_V2_DAT_MASK;
return 0;
+}
+int exynos_adc_init(struct udevice *dev, int channel) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg;
/* Check HW version */
if (readl(®s->version) != ADC_V2_VERSION) {
error("This driver supports only ADC v2!");
return -ENXIO;
}
/* ADC Reset */
writel(ADC_V2_CON1_SOFT_RESET, ®s->con1);
/* Disable INT - will read status only */
writel(0x0, ®s->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, ®s->con2);
Can this function go in probe() instead? The only thing that can't is 'channel'. Is that setting which channel does the conversion? If so, perhaps that particular setting could move to the start function?
Yes, those settings should be done before each conversion.
return 0;
+}
+int exynos_adc_ofdata_to_platdata(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
struct exynos_adc_priv *priv = dev_get_priv(dev);
priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev);
uc_pdata->data_mask = ADC_V2_DAT_MASK;
/* Channel count starts from 0 */
uc_pdata->channels_num = ADC_V2_MAX_CHANNEL + 1;
return 0;
+}
+static const struct adc_ops exynos_adc_ops = {
.adc_init = exynos_adc_init,
.adc_data = exynos_adc_data,
+};
+static const struct udevice_id exynos_adc_ids[] = {
{ .compatible = "samsung,exynos-adc-v2" },
{ }
+};
+U_BOOT_DRIVER(exynos_adc) = {
.name = "exynos-adc",
.id = UCLASS_ADC,
.of_match = exynos_adc_ids,
.ops = &exynos_adc_ops,
.ofdata_to_platdata = exynos_adc_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct exynos_adc_priv),
+};
1.9.1
Regards, Simon
Best regards

Hi Przemyslaw,
On 13 October 2015 at 05:58, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hello Simon,
On 10/03/2015 04:28 PM, Simon Glass wrote:
Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds driver for Exynos54xx ADC subsystem.
The driver is implemented using driver model, amd provides ADC uclass's operations:
- adc_init()
- adc_data()
This driver uses sdelay() function on pooling, so it can be used before the delay timer is inited. The basic parameters of ADC conversion, are:
- sample rate: 600KSPS
- output the data as average of 8 time conversion
ADC features:
- sample rate: 600KSPS
- resolution: 12-bit
- channels: 10 (analog multiplexer)
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit - move previous adc driver from SoC directory to drivers/adc
arch/arm/mach-exynos/include/mach/adc.h | 45 ++++++++++++++ drivers/adc/Kconfig | 9 +++ drivers/adc/Makefile | 1 + drivers/adc/exynos-adc.c | 102 ++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/adc/exynos-adc.c
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)
No need for brackets on these simple ones
Okay, I will remove them.
+#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/drivers/adc/Kconfig b/drivers/adc/Kconfig index 1cb1a8d..8ee6531 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -6,3 +6,12 @@ config ADC - device enable - conversion init - conversion start and return data with data mask
+config ADC_EXYNOS
bool "Enable Exynos 54xx ADC driver"
help
This enables basic driver for Exynos ADC compatible with
Exynos54xx.
It provides:
- 10 analog input channels
- 12-bit resolution
- 600 KSPS of sample rate
Great help!
Thanks:)
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index c4d9618..eb85b8b 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -6,3 +6,4 @@ #
obj-$(CONFIG_ADC) += adc-uclass.o +obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c new file mode 100644 index 0000000..fdffea0 --- /dev/null +++ b/drivers/adc/exynos-adc.c @@ -0,0 +1,102 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <adc.h> +#include <asm/arch/adc.h>
+struct exynos_adc_priv {
struct exynos_adc_v2 *regs;
+};
+extern void sdelay(unsigned long loops);
Can you put this include system.h for exynos, or similar? Also, I think the problem is that timer_init() is called after initf_dm(). There is a patch to add timer support to driver model so perhaps that will help?
Ok, will move this. And yes, the problem is with too late timer init. I saw the work for timer uclass, however I would prefer just use this function. It can be moved in the future.
I'm trying add simple functionality, move everything to driver model is not related to this patch set.
We can add the timer driver later, and then fix each timer call.
+int exynos_adc_data(struct udevice *dev, unsigned int *data) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg, timeout_us = ADC_V2_CONV_TIMEOUT_US;
/* Start conversion */
cfg = readl(®s->con1);
writel(cfg | ADC_V2_CON1_STC_EN, ®s->con1);
while (ADC_V2_GET_STATUS_FLAG(readl(®s->status)) !=
FLAG_CONV_END) {
sdelay(4);
if (!timeout_us--) {
error("ADC conversion timeout!");
return -ETIME;
}
}
Hmm, we don't want to put delays in drivers. I though that the init() method was used to start the conversion, but now I see that it is not. I think the uclass is going to have to know how long to wait for the conversion to be ready.
Good point, I will move the delay to uclass driver.
How about this for an interface:
adc_start(dev, channel) adc_read(dev, channel)
which waits until the conversion is ready on that channel. The driver can set up the time that the conversion will be ready (and store it in the uclass) when the conversion starts.
Ok, that sounds good.
Can we support conversions on several channels at once?
Some hardware can do this, but the Exynos internal ADC is simple and allows only for a single channel conversion at a time.
I can add an uclass operation function call, e.g. adc_channels_data(), and if it's not implemented by the device driver, then it can get the data for each channel in a loop.
Is that good to you?
Yes - so long as the loop is not in the driver it is good.
*data = readl(®s->dat) & ADC_V2_DAT_MASK;
return 0;
+}
+int exynos_adc_init(struct udevice *dev, int channel) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg;
/* Check HW version */
if (readl(®s->version) != ADC_V2_VERSION) {
error("This driver supports only ADC v2!");
return -ENXIO;
}
/* ADC Reset */
writel(ADC_V2_CON1_SOFT_RESET, ®s->con1);
/* Disable INT - will read status only */
writel(0x0, ®s->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, ®s->con2);
Can this function go in probe() instead? The only thing that can't is 'channel'. Is that setting which channel does the conversion? If so, perhaps that particular setting could move to the start function?
Yes, those settings should be done before each conversion.
return 0;
+}
+int exynos_adc_ofdata_to_platdata(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata =
dev_get_uclass_platdata(dev);
struct exynos_adc_priv *priv = dev_get_priv(dev);
priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev);
uc_pdata->data_mask = ADC_V2_DAT_MASK;
/* Channel count starts from 0 */
uc_pdata->channels_num = ADC_V2_MAX_CHANNEL + 1;
return 0;
+}
+static const struct adc_ops exynos_adc_ops = {
.adc_init = exynos_adc_init,
.adc_data = exynos_adc_data,
+};
+static const struct udevice_id exynos_adc_ids[] = {
{ .compatible = "samsung,exynos-adc-v2" },
{ }
+};
+U_BOOT_DRIVER(exynos_adc) = {
.name = "exynos-adc",
.id = UCLASS_ADC,
.of_match = exynos_adc_ids,
.ops = &exynos_adc_ops,
.ofdata_to_platdata = exynos_adc_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct exynos_adc_priv),
+};
1.9.1
Regards, Simon
Best regards
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak@samsung.com
Regards, Simon

Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - none --- arch/arm/dts/exynos5422-odroidxu3.dts | 7 +++++++ configs/odroid-xu3_defconfig | 3 +++ 2 files changed, 10 insertions(+)
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts index d0a8621..9dec679 100644 --- a/arch/arm/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/dts/exynos5422-odroidxu3.dts @@ -31,6 +31,13 @@ 0xb0000000 0xea00000>; };
+ i2c@12CA0000 { + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + }; + }; + ehci@12110000 { samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>; }; diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 9c3b6d6..f38c37b 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -8,7 +8,10 @@ CONFIG_DEFAULT_DEVICE_TREE="exynos5422-odroidxu3" CONFIG_DM_I2C=y CONFIG_DM_I2C_COMPAT=y CONFIG_DM_PMIC=y +CONFIG_CMD_PMIC=y +CONFIG_ERRNO_STR=y CONFIG_DM_REGULATOR=y +CONFIG_PMIC_S2MPS11=y CONFIG_VIDEO_BRIDGE=y CONFIG_SYS_PROMPT="ODROID-XU3 # " CONFIG_USB=y

On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- none
arch/arm/dts/exynos5422-odroidxu3.dts | 7 +++++++ configs/odroid-xu3_defconfig | 3 +++ 2 files changed, 10 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

This commit adds common ADC node, which is disabled as default.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - new commit --- arch/arm/dts/exynos54xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index bd3619d..daa6a33 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -42,6 +42,13 @@ xhci1 = "/xhci@12400000"; };
+ adc@12D10000 { + compatible = "samsung,exynos-adc-v2"; + reg = <0x12D10000 0x100>; + interrupts = <0 106 0>; + status = "disabled"; + }; + i2c@12CA0000 { #address-cells = <1>; #size-cells = <0>;

On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds common ADC node, which is disabled as default.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit
arch/arm/dts/exynos54xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index bd3619d..daa6a33 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -42,6 +42,13 @@ xhci1 = "/xhci@12400000"; };
Reviewed-by: Simon Glass sjg@chromium.org

This ADC is required for Odroid's board revision detection. The pre-reloc request is enabled, since board detection will be done in one of early function call.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - new commit --- arch/arm/dts/exynos5422-odroidxu3.dts | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts index 9dec679..690c747 100644 --- a/arch/arm/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/dts/exynos5422-odroidxu3.dts @@ -31,6 +31,11 @@ 0xb0000000 0xea00000>; };
+ adc@12D10000 { + u-boot,dm-pre-reloc; + status = "okay"; + }; + i2c@12CA0000 { s2mps11_pmic@66 { compatible = "samsung,s2mps11-pmic";

On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This ADC is required for Odroid's board revision detection. The pre-reloc request is enabled, since board detection will be done in one of early function call.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- new commit
arch/arm/dts/exynos5422-odroidxu3.dts | 5 +++++ 1 file changed, 5 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

This commit adds additional file with implementation of board detection code for Odroid-XU3/XU4.
The detection depends on compatible found in fdt: - "samsung,exynos5" - uses Exynos5 generic code - "samsung,odroidxu3" - try detect XU3 revision
There are few revisions of Odroid XU3/XU4, each can be detected by checking the value of channel 9 of built-in ADC: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 1280 XU4 0.1
The detection code depends on the ADC+10% value.
Implementation of functions: - set_board_type() - read ADC and set type - get_board_rev() - returns board revision: 1..3 - get_board_type() - returns board type string
Additional functions with return values of bool: - board_is_generic() - true if found compatible "samsung,exynos5" but not "samsung,odroidxu3" - board_is_odroidxu3() - true if found compatible "samsung,odroidxu3" and one of XU3 revision. - board_is_odroidxu4() - true if found compatible "samsung,odroidxu3" and XU4 revision.
After I2C controller init, the get_board_type() can check if the XU3 board is a "Lite" variant, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
Enabled configs: - CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG - CONFIG_ODROID_REV_AIN - CONFIG_REVISION_TAG - CONFIG_BOARD_TYPES
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - move detection code from exynos5-dt.c to exynos5-dt-types.c - add header with board type function declarations - check for compatible before do the detection - update the ADC max values with 20% tolerance - fix XU4 adc value, related to mistake from table in XU4 schematic - return "Not supported" for XU4 when calls one of: --dfu_get_alt_boot() --dfu_get_alt_system() - extend ${dfu_alt_system} by strings: -- 'exynos5422-odroidxu3-lite.dtb' -- 'exynos5422-odroidxu4.dtb' - allows prepare card on XU3 --- board/samsung/common/Makefile | 5 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ configs/odroid-xu3_defconfig | 2 + include/configs/odroid_xu3.h | 12 ++ include/samsung/exynos5-dt-types.h | 27 +++++ 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 include/samsung/exynos5-dt-types.h
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile index 6cbd906..ef1a8f3 100644 --- a/board/samsung/common/Makefile +++ b/board/samsung/common/Makefile @@ -11,5 +11,8 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_BOARD_COMMON) += board.o -obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o +ifdef CONFIG_EXYNOS5_DT +obj-y += exynos5-dt.o +obj-$(CONFIG_BOARD_TYPES) += exynos5-dt-types.o +endif endif diff --git a/board/samsung/common/exynos5-dt-types.c b/board/samsung/common/exynos5-dt-types.c new file mode 100644 index 0000000..1364e98 --- /dev/null +++ b/board/samsung/common/exynos5-dt-types.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <adc.h> +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/s2mps11.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct udevice_id board_ids[] = { + { .compatible = "samsung,odroidxu3", .data = EXYNOS5_BOARD_ODROID_XU3 }, + { .compatible = "samsung,exynos5", .data = EXYNOS5_BOARD_GENERIC }, + { }, +}; + +/** + * Odroix XU3/4 board revisions: + * Rev ADCmax Board + * 0.1 0 XU3 0.1 + * 0.2 410 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231) + * 0.3 1408 XU4 0.1 + * Use +10 % for ADC value tolerance. + */ +struct odroid_rev_info odroid_info[] = { + { EXYNOS5_BOARD_ODROID_XU3_REV01, 1, 10, "xu3" }, + { EXYNOS5_BOARD_ODROID_XU3_REV02, 2, 410, "xu3" }, + { EXYNOS5_BOARD_ODROID_XU4_REV01, 1, 1408, "xu4" }, + { EXYNOS5_BOARD_ODROID_UNKNOWN, 0, 4095, "unknown" }, +}; + +static unsigned int odroid_get_rev(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(odroid_info); i++) { + if (odroid_info[i].board_type == gd->board_type) + return odroid_info[i].board_rev; + } + + return 0; +} + +static int odroid_get_board_type(void) +{ + unsigned int adcval; + int ret, i; + + ret = adc_channel_single_shot("adc", CONFIG_ODROID_REV_AIN, &adcval); + if (ret) + goto rev_default; + + for (i = 0; i < ARRAY_SIZE(odroid_info); i++) { + /* ADC tolerance: +20 % */ + if (adcval < odroid_info[i].adc_val) + return odroid_info[i].board_type; + } + +rev_default: + return EXYNOS5_BOARD_ODROID_XU3; +} + +/** + * odroid_get_type_str - returns pointer to one of the board type string. + * Board types: "xu3", "xu3-lite", "xu4". However the "xu3lite" can be + * detected only when the i2c controller is ready to use. Fortunately, + * XU3 and XU3L are compatible, and the information about board lite + * revision is needed before booting the linux, to set proper environment + * variable: $fdtfile. + */ +static const char *odroid_get_type_str(void) +{ + const char *type_xu3l = "xu3-lite"; + struct udevice *dev, *chip; + int i, ret; + + if (gd->board_type != EXYNOS5_BOARD_ODROID_XU3_REV02) + goto exit; + + ret = pmic_get("s2mps11", &dev); + if (ret) + goto exit; + + /* Enable LDO26: 3.0V */ + ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL, + S2MPS11_LDO26_ENABLE); + if (ret) + goto exit; + + /* Check XU3Lite by probe INA231 I2C0:0x40 */ + ret = uclass_get_device(UCLASS_I2C, 0, &dev); + if (ret) + goto exit; + + ret = dm_i2c_probe(dev, 0x40, 0x0, &chip); + if (ret) + return type_xu3l; + +exit: + for (i = 0; i < ARRAY_SIZE(odroid_info); i++) { + if (odroid_info[i].board_type == gd->board_type) + return odroid_info[i].name; + } + + return NULL; +} + +bool board_is_odroidxu3(void) +{ + if (gd->board_type >= EXYNOS5_BOARD_ODROID_XU3 && + gd->board_type <= EXYNOS5_BOARD_ODROID_XU3_REV02) + return true; + + return false; +} + +bool board_is_odroidxu4(void) +{ + if (gd->board_type == EXYNOS5_BOARD_ODROID_XU4_REV01) + return true; + + return false; +} + +bool board_is_generic(void) +{ + if (gd->board_type == EXYNOS5_BOARD_GENERIC) + return true; + + return false; +} + +/** + * get_board_rev() - return detected board revision. + * + * @return: return board revision number for XU3 or 0 for generic + */ +u32 get_board_rev(void) +{ + if (board_is_generic()) + return 0; + + return odroid_get_rev(); +} + +/** + * get_board_type() - returns board type string. + * + * @return: return board type string for XU3 or empty string for generic + */ +const char *get_board_type(void) +{ + const char *generic = ""; + + if (board_is_generic()) + return generic; + + return odroid_get_type_str(); +} + +/** + * set_board_type() - set board type in gd->board_type. + * As default type set EXYNOS5_BOARD_GENERIC, if detect Odroid, + * then set it's proper type. + */ +void set_board_type(void) +{ + const struct udevice_id *of_match = board_ids; + int ret; + + gd->board_type = EXYNOS5_BOARD_GENERIC; + + while (of_match->compatible) { + ret = fdt_node_check_compatible(gd->fdt_blob, 0, + of_match->compatible); + if (ret) + of_match++; + + gd->board_type = of_match->data; + break; + } + + /* If Odroid, then check it's revision */ + if (board_is_odroidxu3()) + gd->board_type = odroid_get_board_type(); +} diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 4250f72..4d9e151 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -27,7 +27,10 @@ #include <power/pmic.h> #include <power/max77686_pmic.h> #include <power/regulator.h> +#include <power/s2mps11.h> #include <power/s5m8767.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -335,15 +338,24 @@ int board_usb_init(int index, enum usb_init_type init) #ifdef CONFIG_SET_DFU_ALT_INFO char *get_dfu_alt_system(char *interface, char *devstr) { + char *info = "Not supported!"; + + if (board_is_odroidxu4()) + return info; + return getenv("dfu_alt_system"); }
char *get_dfu_alt_boot(char *interface, char *devstr) { + char *info = "Not supported!"; struct mmc *mmc; char *alt_boot; int dev_num;
+ if (board_is_odroidxu4()) + return info; + dev_num = simple_strtoul(devstr, NULL, 10);
mmc = find_mmc_device(dev_num); diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index f38c37b..d7e5698 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -16,3 +16,5 @@ CONFIG_VIDEO_BRIDGE=y CONFIG_SYS_PROMPT="ODROID-XU3 # " CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_ADC=y +CONFIG_ADC_EXYNOS=y diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \ + "exynos5422-odroidxu3-lite.dtb fat 0 1;" \ + "exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES + +#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid" + /* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \ diff --git a/include/samsung/exynos5-dt-types.h b/include/samsung/exynos5-dt-types.h new file mode 100644 index 0000000..479e2e7 --- /dev/null +++ b/include/samsung/exynos5-dt-types.h @@ -0,0 +1,27 @@ +#ifndef _EXYNOS5_DT_H_ +#define _EXYNOS5_DT_H_ + +enum { + EXYNOS5_BOARD_GENERIC, + + EXYNOS5_BOARD_ODROID_XU3, + EXYNOS5_BOARD_ODROID_XU3_REV01, + EXYNOS5_BOARD_ODROID_XU3_REV02, + EXYNOS5_BOARD_ODROID_XU4_REV01, + EXYNOS5_BOARD_ODROID_UNKNOWN, + + EXYNOS5_BOARD_COUNT, +}; + +struct odroid_rev_info { + int board_type; + int board_rev; + int adc_val; + const char *name; +}; + +bool board_is_generic(void); +bool board_is_odroidxu3(void); +bool board_is_odroidxu4(void); + +#endif

Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds additional file with implementation of board detection code for Odroid-XU3/XU4.
The detection depends on compatible found in fdt:
- "samsung,exynos5" - uses Exynos5 generic code
- "samsung,odroidxu3" - try detect XU3 revision
There are few revisions of Odroid XU3/XU4, each can be detected by checking the value of channel 9 of built-in ADC: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 1280 XU4 0.1
The detection code depends on the ADC+10% value.
Implementation of functions:
- set_board_type() - read ADC and set type
- get_board_rev() - returns board revision: 1..3
- get_board_type() - returns board type string
Additional functions with return values of bool:
- board_is_generic() - true if found compatible "samsung,exynos5" but not "samsung,odroidxu3"
- board_is_odroidxu3() - true if found compatible "samsung,odroidxu3" and one of XU3 revision.
- board_is_odroidxu4() - true if found compatible "samsung,odroidxu3" and XU4 revision.
After I2C controller init, the get_board_type() can check if the XU3 board is a "Lite" variant, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
Enabled configs:
- CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
- CONFIG_ODROID_REV_AIN
- CONFIG_REVISION_TAG
- CONFIG_BOARD_TYPES
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- move detection code from exynos5-dt.c to exynos5-dt-types.c
- add header with board type function declarations
- check for compatible before do the detection
- update the ADC max values with 20% tolerance
- fix XU4 adc value, related to mistake from table in XU4 schematic
- return "Not supported" for XU4 when calls one of: --dfu_get_alt_boot() --dfu_get_alt_system()
- extend ${dfu_alt_system} by strings: -- 'exynos5422-odroidxu3-lite.dtb' -- 'exynos5422-odroidxu4.dtb' - allows prepare card on XU3
board/samsung/common/Makefile | 5 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ configs/odroid-xu3_defconfig | 2 + include/configs/odroid_xu3.h | 12 ++ include/samsung/exynos5-dt-types.h | 27 +++++ 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 include/samsung/exynos5-dt-types.h
Reviewed-by: Simon Glass sjg@chromium.org
See nits below.
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile index 6cbd906..ef1a8f3 100644 --- a/board/samsung/common/Makefile +++ b/board/samsung/common/Makefile @@ -11,5 +11,8 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_BOARD_COMMON) += board.o -obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o +ifdef CONFIG_EXYNOS5_DT +obj-y += exynos5-dt.o +obj-$(CONFIG_BOARD_TYPES) += exynos5-dt-types.o +endif endif diff --git a/board/samsung/common/exynos5-dt-types.c b/board/samsung/common/exynos5-dt-types.c new file mode 100644 index 0000000..1364e98 --- /dev/null +++ b/board/samsung/common/exynos5-dt-types.c @@ -0,0 +1,196 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <adc.h> +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/s2mps11.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h>
+DECLARE_GLOBAL_DATA_PTR;
+static const struct udevice_id board_ids[] = {
{ .compatible = "samsung,odroidxu3", .data = EXYNOS5_BOARD_ODROID_XU3 },
{ .compatible = "samsung,exynos5", .data = EXYNOS5_BOARD_GENERIC },
{ },
+};
+/**
- Odroix XU3/4 board revisions:
- Rev ADCmax Board
- 0.1 0 XU3 0.1
- 0.2 410 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231)
- 0.3 1408 XU4 0.1
- Use +10 % for ADC value tolerance.
- */
+struct odroid_rev_info odroid_info[] = {
{ EXYNOS5_BOARD_ODROID_XU3_REV01, 1, 10, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU3_REV02, 2, 410, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU4_REV01, 1, 1408, "xu4" },
{ EXYNOS5_BOARD_ODROID_UNKNOWN, 0, 4095, "unknown" },
+};
+static unsigned int odroid_get_rev(void) +{
int i;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].board_rev;
}
return 0;
+}
+static int odroid_get_board_type(void) +{
unsigned int adcval;
int ret, i;
ret = adc_channel_single_shot("adc", CONFIG_ODROID_REV_AIN, &adcval);
if (ret)
goto rev_default;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
/* ADC tolerance: +20 % */
if (adcval < odroid_info[i].adc_val)
return odroid_info[i].board_type;
}
+rev_default:
return EXYNOS5_BOARD_ODROID_XU3;
+}
+/**
- odroid_get_type_str - returns pointer to one of the board type string.
- Board types: "xu3", "xu3-lite", "xu4". However the "xu3lite" can be
- detected only when the i2c controller is ready to use. Fortunately,
- XU3 and XU3L are compatible, and the information about board lite
- revision is needed before booting the linux, to set proper environment
- variable: $fdtfile.
- */
+static const char *odroid_get_type_str(void) +{
const char *type_xu3l = "xu3-lite";
struct udevice *dev, *chip;
int i, ret;
if (gd->board_type != EXYNOS5_BOARD_ODROID_XU3_REV02)
goto exit;
ret = pmic_get("s2mps11", &dev);
if (ret)
goto exit;
/* Enable LDO26: 3.0V */
ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL,
S2MPS11_LDO26_ENABLE);
if (ret)
goto exit;
/* Check XU3Lite by probe INA231 I2C0:0x40 */
ret = uclass_get_device(UCLASS_I2C, 0, &dev);
Yikes! What happens if you want to add a driver for this?
if (ret)
goto exit;
ret = dm_i2c_probe(dev, 0x40, 0x0, &chip);
if (ret)
return type_xu3l;
+exit:
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].name;
}
return NULL;
+}
+bool board_is_odroidxu3(void) +{
if (gd->board_type >= EXYNOS5_BOARD_ODROID_XU3 &&
gd->board_type <= EXYNOS5_BOARD_ODROID_XU3_REV02)
return true;
return false;
+}
+bool board_is_odroidxu4(void) +{
if (gd->board_type == EXYNOS5_BOARD_ODROID_XU4_REV01)
return true;
return false;
+}
+bool board_is_generic(void) +{
if (gd->board_type == EXYNOS5_BOARD_GENERIC)
return true;
return false;
+}
+/**
- get_board_rev() - return detected board revision.
- @return: return board revision number for XU3 or 0 for generic
- */
+u32 get_board_rev(void) +{
if (board_is_generic())
return 0;
return odroid_get_rev();
+}
+/**
- get_board_type() - returns board type string.
- @return: return board type string for XU3 or empty string for generic
- */
+const char *get_board_type(void) +{
const char *generic = "";
if (board_is_generic())
return generic;
return odroid_get_type_str();
+}
+/**
- set_board_type() - set board type in gd->board_type.
- As default type set EXYNOS5_BOARD_GENERIC, if detect Odroid,
- then set it's proper type.
its
- */
+void set_board_type(void) +{
const struct udevice_id *of_match = board_ids;
int ret;
gd->board_type = EXYNOS5_BOARD_GENERIC;
while (of_match->compatible) {
ret = fdt_node_check_compatible(gd->fdt_blob, 0,
of_match->compatible);
if (ret)
of_match++;
gd->board_type = of_match->data;
break;
}
/* If Odroid, then check it's revision */
its
if (board_is_odroidxu3())
gd->board_type = odroid_get_board_type();
+} diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 4250f72..4d9e151 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -27,7 +27,10 @@ #include <power/pmic.h> #include <power/max77686_pmic.h> #include <power/regulator.h> +#include <power/s2mps11.h> #include <power/s5m8767.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -335,15 +338,24 @@ int board_usb_init(int index, enum usb_init_type init) #ifdef CONFIG_SET_DFU_ALT_INFO char *get_dfu_alt_system(char *interface, char *devstr) {
char *info = "Not supported!";
if (board_is_odroidxu4())
return info;
return getenv("dfu_alt_system");
}
char *get_dfu_alt_boot(char *interface, char *devstr) {
char *info = "Not supported!"; struct mmc *mmc; char *alt_boot; int dev_num;
if (board_is_odroidxu4())
return info;
dev_num = simple_strtoul(devstr, NULL, 10); mmc = find_mmc_device(dev_num);
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index f38c37b..d7e5698 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -16,3 +16,5 @@ CONFIG_VIDEO_BRIDGE=y CONFIG_SYS_PROMPT="ODROID-XU3 # " CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_ADC=y +CONFIG_ADC_EXYNOS=y diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \
"exynos5422-odroidxu3-lite.dtb fat 0 1;" \
"exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES
+#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid"
/* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \ diff --git a/include/samsung/exynos5-dt-types.h b/include/samsung/exynos5-dt-types.h new file mode 100644 index 0000000..479e2e7 --- /dev/null +++ b/include/samsung/exynos5-dt-types.h @@ -0,0 +1,27 @@ +#ifndef _EXYNOS5_DT_H_ +#define _EXYNOS5_DT_H_
+enum {
EXYNOS5_BOARD_GENERIC,
EXYNOS5_BOARD_ODROID_XU3,
EXYNOS5_BOARD_ODROID_XU3_REV01,
EXYNOS5_BOARD_ODROID_XU3_REV02,
EXYNOS5_BOARD_ODROID_XU4_REV01,
EXYNOS5_BOARD_ODROID_UNKNOWN,
EXYNOS5_BOARD_COUNT,
+};
+struct odroid_rev_info {
int board_type;
int board_rev;
int adc_val;
const char *name;
+};
+bool board_is_generic(void); +bool board_is_odroidxu3(void); +bool board_is_odroidxu4(void);
+#endif
1.9.1
I can't help wondering why we don't just have separate device trees for these boards. It seems a pain to try to support them all with this auto-detection. Anyway, I think I already asked this and you're pretty sure this is what you want. I do understand the need to make it painless for users.
Regards, Simon

Hello Simon,
On 10/03/2015 04:28 PM, Simon Glass wrote:
Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds additional file with implementation of board detection code for Odroid-XU3/XU4.
The detection depends on compatible found in fdt:
- "samsung,exynos5" - uses Exynos5 generic code
- "samsung,odroidxu3" - try detect XU3 revision
There are few revisions of Odroid XU3/XU4, each can be detected by checking the value of channel 9 of built-in ADC: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 1280 XU4 0.1
The detection code depends on the ADC+10% value.
Implementation of functions:
- set_board_type() - read ADC and set type
- get_board_rev() - returns board revision: 1..3
- get_board_type() - returns board type string
Additional functions with return values of bool:
- board_is_generic() - true if found compatible "samsung,exynos5" but not "samsung,odroidxu3"
- board_is_odroidxu3() - true if found compatible "samsung,odroidxu3" and one of XU3 revision.
- board_is_odroidxu4() - true if found compatible "samsung,odroidxu3" and XU4 revision.
After I2C controller init, the get_board_type() can check if the XU3 board is a "Lite" variant, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
Enabled configs:
- CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
- CONFIG_ODROID_REV_AIN
- CONFIG_REVISION_TAG
- CONFIG_BOARD_TYPES
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- move detection code from exynos5-dt.c to exynos5-dt-types.c
- add header with board type function declarations
- check for compatible before do the detection
- update the ADC max values with 20% tolerance
- fix XU4 adc value, related to mistake from table in XU4 schematic
- return "Not supported" for XU4 when calls one of: --dfu_get_alt_boot() --dfu_get_alt_system()
- extend ${dfu_alt_system} by strings: -- 'exynos5422-odroidxu3-lite.dtb' -- 'exynos5422-odroidxu4.dtb' - allows prepare card on XU3
board/samsung/common/Makefile | 5 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ configs/odroid-xu3_defconfig | 2 + include/configs/odroid_xu3.h | 12 ++ include/samsung/exynos5-dt-types.h | 27 +++++ 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 include/samsung/exynos5-dt-types.h
Reviewed-by: Simon Glass sjg@chromium.org
See nits below.
Ok.
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile index 6cbd906..ef1a8f3 100644 --- a/board/samsung/common/Makefile +++ b/board/samsung/common/Makefile @@ -11,5 +11,8 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_BOARD_COMMON) += board.o -obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o +ifdef CONFIG_EXYNOS5_DT +obj-y += exynos5-dt.o +obj-$(CONFIG_BOARD_TYPES) += exynos5-dt-types.o +endif endif diff --git a/board/samsung/common/exynos5-dt-types.c b/board/samsung/common/exynos5-dt-types.c new file mode 100644 index 0000000..1364e98 --- /dev/null +++ b/board/samsung/common/exynos5-dt-types.c @@ -0,0 +1,196 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <adc.h> +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/s2mps11.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h>
+DECLARE_GLOBAL_DATA_PTR;
+static const struct udevice_id board_ids[] = {
{ .compatible = "samsung,odroidxu3", .data = EXYNOS5_BOARD_ODROID_XU3 },
{ .compatible = "samsung,exynos5", .data = EXYNOS5_BOARD_GENERIC },
{ },
+};
+/**
- Odroix XU3/4 board revisions:
- Rev ADCmax Board
- 0.1 0 XU3 0.1
- 0.2 410 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231)
- 0.3 1408 XU4 0.1
- Use +10 % for ADC value tolerance.
- */
+struct odroid_rev_info odroid_info[] = {
{ EXYNOS5_BOARD_ODROID_XU3_REV01, 1, 10, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU3_REV02, 2, 410, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU4_REV01, 1, 1408, "xu4" },
{ EXYNOS5_BOARD_ODROID_UNKNOWN, 0, 4095, "unknown" },
+};
+static unsigned int odroid_get_rev(void) +{
int i;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].board_rev;
}
return 0;
+}
+static int odroid_get_board_type(void) +{
unsigned int adcval;
int ret, i;
ret = adc_channel_single_shot("adc", CONFIG_ODROID_REV_AIN, &adcval);
if (ret)
goto rev_default;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
/* ADC tolerance: +20 % */
if (adcval < odroid_info[i].adc_val)
return odroid_info[i].board_type;
}
+rev_default:
return EXYNOS5_BOARD_ODROID_XU3;
+}
+/**
- odroid_get_type_str - returns pointer to one of the board type string.
- Board types: "xu3", "xu3-lite", "xu4". However the "xu3lite" can be
- detected only when the i2c controller is ready to use. Fortunately,
- XU3 and XU3L are compatible, and the information about board lite
- revision is needed before booting the linux, to set proper environment
- variable: $fdtfile.
- */
+static const char *odroid_get_type_str(void) +{
const char *type_xu3l = "xu3-lite";
struct udevice *dev, *chip;
int i, ret;
if (gd->board_type != EXYNOS5_BOARD_ODROID_XU3_REV02)
goto exit;
ret = pmic_get("s2mps11", &dev);
if (ret)
goto exit;
/* Enable LDO26: 3.0V */
ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL,
S2MPS11_LDO26_ENABLE);
if (ret)
goto exit;
/* Check XU3Lite by probe INA231 I2C0:0x40 */
ret = uclass_get_device(UCLASS_I2C, 0, &dev);
Yikes! What happens if you want to add a driver for this?
This may look much more pretty, but the INA's driver is not needed at U-Boot and also I don't like implement everything at once, since as you can see it takes some time to review and fixing again and again.
if (ret)
goto exit;
ret = dm_i2c_probe(dev, 0x40, 0x0, &chip);
if (ret)
return type_xu3l;
+exit:
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].name;
}
return NULL;
+}
+bool board_is_odroidxu3(void) +{
if (gd->board_type >= EXYNOS5_BOARD_ODROID_XU3 &&
gd->board_type <= EXYNOS5_BOARD_ODROID_XU3_REV02)
return true;
return false;
+}
+bool board_is_odroidxu4(void) +{
if (gd->board_type == EXYNOS5_BOARD_ODROID_XU4_REV01)
return true;
return false;
+}
+bool board_is_generic(void) +{
if (gd->board_type == EXYNOS5_BOARD_GENERIC)
return true;
return false;
+}
+/**
- get_board_rev() - return detected board revision.
- @return: return board revision number for XU3 or 0 for generic
- */
+u32 get_board_rev(void) +{
if (board_is_generic())
return 0;
return odroid_get_rev();
+}
+/**
- get_board_type() - returns board type string.
- @return: return board type string for XU3 or empty string for generic
- */
+const char *get_board_type(void) +{
const char *generic = "";
if (board_is_generic())
return generic;
return odroid_get_type_str();
+}
+/**
- set_board_type() - set board type in gd->board_type.
- As default type set EXYNOS5_BOARD_GENERIC, if detect Odroid,
- then set it's proper type.
its
Right.
- */
+void set_board_type(void) +{
const struct udevice_id *of_match = board_ids;
int ret;
gd->board_type = EXYNOS5_BOARD_GENERIC;
while (of_match->compatible) {
ret = fdt_node_check_compatible(gd->fdt_blob, 0,
of_match->compatible);
if (ret)
of_match++;
gd->board_type = of_match->data;
break;
}
/* If Odroid, then check it's revision */
its
ok.
if (board_is_odroidxu3())
gd->board_type = odroid_get_board_type();
+} diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 4250f72..4d9e151 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -27,7 +27,10 @@ #include <power/pmic.h> #include <power/max77686_pmic.h> #include <power/regulator.h> +#include <power/s2mps11.h> #include <power/s5m8767.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -335,15 +338,24 @@ int board_usb_init(int index, enum usb_init_type init) #ifdef CONFIG_SET_DFU_ALT_INFO char *get_dfu_alt_system(char *interface, char *devstr) {
char *info = "Not supported!";
if (board_is_odroidxu4())
return info;
return getenv("dfu_alt_system");
}
char *get_dfu_alt_boot(char *interface, char *devstr) {
char *info = "Not supported!"; struct mmc *mmc; char *alt_boot; int dev_num;
if (board_is_odroidxu4())
return info;
dev_num = simple_strtoul(devstr, NULL, 10); mmc = find_mmc_device(dev_num);
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index f38c37b..d7e5698 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -16,3 +16,5 @@ CONFIG_VIDEO_BRIDGE=y CONFIG_SYS_PROMPT="ODROID-XU3 # " CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_ADC=y +CONFIG_ADC_EXYNOS=y diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \
"exynos5422-odroidxu3-lite.dtb fat 0 1;" \
"exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES
+#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid"
- /* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \
diff --git a/include/samsung/exynos5-dt-types.h b/include/samsung/exynos5-dt-types.h new file mode 100644 index 0000000..479e2e7 --- /dev/null +++ b/include/samsung/exynos5-dt-types.h @@ -0,0 +1,27 @@ +#ifndef _EXYNOS5_DT_H_ +#define _EXYNOS5_DT_H_
+enum {
EXYNOS5_BOARD_GENERIC,
EXYNOS5_BOARD_ODROID_XU3,
EXYNOS5_BOARD_ODROID_XU3_REV01,
EXYNOS5_BOARD_ODROID_XU3_REV02,
EXYNOS5_BOARD_ODROID_XU4_REV01,
EXYNOS5_BOARD_ODROID_UNKNOWN,
EXYNOS5_BOARD_COUNT,
+};
+struct odroid_rev_info {
int board_type;
int board_rev;
int adc_val;
const char *name;
+};
+bool board_is_generic(void); +bool board_is_odroidxu3(void); +bool board_is_odroidxu4(void);
+#endif
1.9.1
I can't help wondering why we don't just have separate device trees for these boards. It seems a pain to try to support them all with this auto-detection. Anyway, I think I already asked this and you're pretty sure this is what you want. I do understand the need to make it painless for users.
Regards, Simon
It's much more easy for us, to support several Odroid revisions with the same SoC by the single U-Boot binary. It's also easy for the users, if they have a single binary for actually the same board variants.
And it's one less thing, that can be broken by the mistake :)
Thank you for your helpful comments, I will take them into account in V3.
Best regards,

Hi Premyslaw,
On 13 October 2015 at 05:59, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hello Simon,
On 10/03/2015 04:28 PM, Simon Glass wrote:
Hi Przemyslaw,
On 21 September 2015 at 13:26, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds additional file with implementation of board detection code for Odroid-XU3/XU4.
The detection depends on compatible found in fdt:
- "samsung,exynos5" - uses Exynos5 generic code
- "samsung,odroidxu3" - try detect XU3 revision
There are few revisions of Odroid XU3/XU4, each can be detected by checking the value of channel 9 of built-in ADC: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 1280 XU4 0.1
The detection code depends on the ADC+10% value.
Implementation of functions:
- set_board_type() - read ADC and set type
- get_board_rev() - returns board revision: 1..3
- get_board_type() - returns board type string
Additional functions with return values of bool:
- board_is_generic() - true if found compatible "samsung,exynos5" but not "samsung,odroidxu3"
- board_is_odroidxu3() - true if found compatible "samsung,odroidxu3" and one of XU3 revision.
- board_is_odroidxu4() - true if found compatible "samsung,odroidxu3" and XU4 revision.
After I2C controller init, the get_board_type() can check if the XU3 board is a "Lite" variant, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
Enabled configs:
- CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
- CONFIG_ODROID_REV_AIN
- CONFIG_REVISION_TAG
- CONFIG_BOARD_TYPES
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- move detection code from exynos5-dt.c to exynos5-dt-types.c
- add header with board type function declarations
- check for compatible before do the detection
- update the ADC max values with 20% tolerance
- fix XU4 adc value, related to mistake from table in XU4 schematic
- return "Not supported" for XU4 when calls one of: --dfu_get_alt_boot() --dfu_get_alt_system()
- extend ${dfu_alt_system} by strings: -- 'exynos5422-odroidxu3-lite.dtb' -- 'exynos5422-odroidxu4.dtb' - allows prepare card on XU3
board/samsung/common/Makefile | 5 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ configs/odroid-xu3_defconfig | 2 + include/configs/odroid_xu3.h | 12 ++ include/samsung/exynos5-dt-types.h | 27 +++++ 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 include/samsung/exynos5-dt-types.h
Reviewed-by: Simon Glass sjg@chromium.org
See nits below.
Ok.
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile index 6cbd906..ef1a8f3 100644 --- a/board/samsung/common/Makefile +++ b/board/samsung/common/Makefile @@ -11,5 +11,8 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_BOARD_COMMON) += board.o -obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o +ifdef CONFIG_EXYNOS5_DT +obj-y += exynos5-dt.o +obj-$(CONFIG_BOARD_TYPES) += exynos5-dt-types.o +endif endif diff --git a/board/samsung/common/exynos5-dt-types.c b/board/samsung/common/exynos5-dt-types.c new file mode 100644 index 0000000..1364e98 --- /dev/null +++ b/board/samsung/common/exynos5-dt-types.c @@ -0,0 +1,196 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <adc.h> +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/s2mps11.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h>
+DECLARE_GLOBAL_DATA_PTR;
+static const struct udevice_id board_ids[] = {
{ .compatible = "samsung,odroidxu3", .data =
EXYNOS5_BOARD_ODROID_XU3 },
{ .compatible = "samsung,exynos5", .data = EXYNOS5_BOARD_GENERIC
},
{ },
+};
+/**
- Odroix XU3/4 board revisions:
- Rev ADCmax Board
- 0.1 0 XU3 0.1
- 0.2 410 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 /
INA231)
- 0.3 1408 XU4 0.1
- Use +10 % for ADC value tolerance.
- */
+struct odroid_rev_info odroid_info[] = {
{ EXYNOS5_BOARD_ODROID_XU3_REV01, 1, 10, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU3_REV02, 2, 410, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU4_REV01, 1, 1408, "xu4" },
{ EXYNOS5_BOARD_ODROID_UNKNOWN, 0, 4095, "unknown" },
+};
+static unsigned int odroid_get_rev(void) +{
int i;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].board_rev;
}
return 0;
+}
+static int odroid_get_board_type(void) +{
unsigned int adcval;
int ret, i;
ret = adc_channel_single_shot("adc", CONFIG_ODROID_REV_AIN,
&adcval);
if (ret)
goto rev_default;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
/* ADC tolerance: +20 % */
if (adcval < odroid_info[i].adc_val)
return odroid_info[i].board_type;
}
+rev_default:
return EXYNOS5_BOARD_ODROID_XU3;
+}
+/**
- odroid_get_type_str - returns pointer to one of the board type
string.
- Board types: "xu3", "xu3-lite", "xu4". However the "xu3lite" can be
- detected only when the i2c controller is ready to use. Fortunately,
- XU3 and XU3L are compatible, and the information about board lite
- revision is needed before booting the linux, to set proper
environment
- variable: $fdtfile.
- */
+static const char *odroid_get_type_str(void) +{
const char *type_xu3l = "xu3-lite";
struct udevice *dev, *chip;
int i, ret;
if (gd->board_type != EXYNOS5_BOARD_ODROID_XU3_REV02)
goto exit;
ret = pmic_get("s2mps11", &dev);
if (ret)
goto exit;
/* Enable LDO26: 3.0V */
ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL,
S2MPS11_LDO26_ENABLE);
if (ret)
goto exit;
/* Check XU3Lite by probe INA231 I2C0:0x40 */
ret = uclass_get_device(UCLASS_I2C, 0, &dev);
Yikes! What happens if you want to add a driver for this?
This may look much more pretty, but the INA's driver is not needed at U-Boot and also I don't like implement everything at once, since as you can see it takes some time to review and fixing again and again.
if (ret)
goto exit;
ret = dm_i2c_probe(dev, 0x40, 0x0, &chip);
if (ret)
return type_xu3l;
+exit:
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].name;
}
return NULL;
+}
+bool board_is_odroidxu3(void) +{
if (gd->board_type >= EXYNOS5_BOARD_ODROID_XU3 &&
gd->board_type <= EXYNOS5_BOARD_ODROID_XU3_REV02)
return true;
return false;
+}
+bool board_is_odroidxu4(void) +{
if (gd->board_type == EXYNOS5_BOARD_ODROID_XU4_REV01)
return true;
return false;
+}
+bool board_is_generic(void) +{
if (gd->board_type == EXYNOS5_BOARD_GENERIC)
return true;
return false;
+}
+/**
- get_board_rev() - return detected board revision.
- @return: return board revision number for XU3 or 0 for generic
- */
+u32 get_board_rev(void) +{
if (board_is_generic())
return 0;
return odroid_get_rev();
+}
+/**
- get_board_type() - returns board type string.
- @return: return board type string for XU3 or empty string for
generic
- */
+const char *get_board_type(void) +{
const char *generic = "";
if (board_is_generic())
return generic;
return odroid_get_type_str();
+}
+/**
- set_board_type() - set board type in gd->board_type.
- As default type set EXYNOS5_BOARD_GENERIC, if detect Odroid,
- then set it's proper type.
its
Right.
- */
+void set_board_type(void) +{
const struct udevice_id *of_match = board_ids;
int ret;
gd->board_type = EXYNOS5_BOARD_GENERIC;
while (of_match->compatible) {
ret = fdt_node_check_compatible(gd->fdt_blob, 0,
of_match->compatible);
if (ret)
of_match++;
gd->board_type = of_match->data;
break;
}
/* If Odroid, then check it's revision */
its
ok.
if (board_is_odroidxu3())
gd->board_type = odroid_get_board_type();
+} diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 4250f72..4d9e151 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -27,7 +27,10 @@ #include <power/pmic.h> #include <power/max77686_pmic.h> #include <power/regulator.h> +#include <power/s2mps11.h> #include <power/s5m8767.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -335,15 +338,24 @@ int board_usb_init(int index, enum usb_init_type init) #ifdef CONFIG_SET_DFU_ALT_INFO char *get_dfu_alt_system(char *interface, char *devstr) {
char *info = "Not supported!";
if (board_is_odroidxu4())
return info;
return getenv("dfu_alt_system");
}
char *get_dfu_alt_boot(char *interface, char *devstr) {
char *info = "Not supported!"; struct mmc *mmc; char *alt_boot; int dev_num;
if (board_is_odroidxu4())
return info;
dev_num = simple_strtoul(devstr, NULL, 10); mmc = find_mmc_device(dev_num);
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index f38c37b..d7e5698 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -16,3 +16,5 @@ CONFIG_VIDEO_BRIDGE=y CONFIG_SYS_PROMPT="ODROID-XU3 # " CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_ADC=y +CONFIG_ADC_EXYNOS=y diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \
"exynos5422-odroidxu3-lite.dtb fat 0 1;" \
"exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES
+#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid"
- /* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \
diff --git a/include/samsung/exynos5-dt-types.h b/include/samsung/exynos5-dt-types.h new file mode 100644 index 0000000..479e2e7 --- /dev/null +++ b/include/samsung/exynos5-dt-types.h @@ -0,0 +1,27 @@ +#ifndef _EXYNOS5_DT_H_ +#define _EXYNOS5_DT_H_
+enum {
EXYNOS5_BOARD_GENERIC,
EXYNOS5_BOARD_ODROID_XU3,
EXYNOS5_BOARD_ODROID_XU3_REV01,
EXYNOS5_BOARD_ODROID_XU3_REV02,
EXYNOS5_BOARD_ODROID_XU4_REV01,
EXYNOS5_BOARD_ODROID_UNKNOWN,
EXYNOS5_BOARD_COUNT,
+};
+struct odroid_rev_info {
int board_type;
int board_rev;
int adc_val;
const char *name;
+};
+bool board_is_generic(void); +bool board_is_odroidxu3(void); +bool board_is_odroidxu4(void);
+#endif
1.9.1
I can't help wondering why we don't just have separate device trees for these boards. It seems a pain to try to support them all with this auto-detection. Anyway, I think I already asked this and you're pretty sure this is what you want. I do understand the need to make it painless for users.
Regards, Simon
It's much more easy for us, to support several Odroid revisions with the same SoC by the single U-Boot binary. It's also easy for the users, if they have a single binary for actually the same board variants.
And it's one less thing, that can be broken by the mistake :)
OK I see.
Regards, Simon

Hi Przemyslaw,
On 21 September 2015 at 17:56, Przemyslaw Marczak p.marczak@samsung.com wrote:
This patchset adds:
- CPU model in dts for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- new file for Exynos5: exynos5-dt-types.c
- board detection for Odroid XU3 / XU3lite / XU4
- fixed ADC val for XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2
Przemyslaw Marczak (11): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 ++- arch/arm/dts/exynos5422-odroidxu3.dts | 12 ++ arch/arm/dts/exynos54xx.dtsi | 7 ++ arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +-- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 +++++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 17 +++ drivers/adc/Makefile | 9 ++ drivers/adc/adc-uclass.c | 76 ++++++++++++ drivers/adc/exynos-adc.c | 102 ++++++++++++++++ drivers/power/pmic/Kconfig | 14 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 +++++++++ include/adc.h | 88 ++++++++++++++ include/configs/odroid_xu3.h | 12 ++ include/dm/uclass-id.h | 1 + include/power/s2mps11.h | 109 +++++++++++++++++ include/samsung/exynos5-dt-types.h | 27 ++++ 33 files changed, 854 insertions(+), 22 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h
I have tested this patch on Odroid-XU3 and Odroid-XU4.
Both using micoSD and eMMC cards.
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon
-- 1.9.1

Hello Anand,
On 09/27/2015 02:20 PM, Anand Moon wrote:
Hi Przemyslaw,
On 21 September 2015 at 17:56, Przemyslaw Marczak p.marczak@samsung.com wrote:
This patchset adds:
- CPU model in dts for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- new file for Exynos5: exynos5-dt-types.c
- board detection for Odroid XU3 / XU3lite / XU4
- fixed ADC val for XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2
Przemyslaw Marczak (11): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 ++- arch/arm/dts/exynos5422-odroidxu3.dts | 12 ++ arch/arm/dts/exynos54xx.dtsi | 7 ++ arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +-- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 +++++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 17 +++ drivers/adc/Makefile | 9 ++ drivers/adc/adc-uclass.c | 76 ++++++++++++ drivers/adc/exynos-adc.c | 102 ++++++++++++++++ drivers/power/pmic/Kconfig | 14 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 +++++++++ include/adc.h | 88 ++++++++++++++ include/configs/odroid_xu3.h | 12 ++ include/dm/uclass-id.h | 1 + include/power/s2mps11.h | 109 +++++++++++++++++ include/samsung/exynos5-dt-types.h | 27 ++++ 33 files changed, 854 insertions(+), 22 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h
I have tested this patch on Odroid-XU3 and Odroid-XU4.
Both using micoSD and eMMC cards.
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon
-- 1.9.1
Thank you for testing!
Best regards,

Hello,
On 09/21/2015 02:26 PM, Przemyslaw Marczak wrote:
This patchset adds:
- CPU model in dts for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- new file for Exynos5: exynos5-dt-types.c
- board detection for Odroid XU3 / XU3lite / XU4
- fixed ADC val for XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2
Przemyslaw Marczak (11): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 ++- arch/arm/dts/exynos5422-odroidxu3.dts | 12 ++ arch/arm/dts/exynos54xx.dtsi | 7 ++ arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +-- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 +++++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 17 +++ drivers/adc/Makefile | 9 ++ drivers/adc/adc-uclass.c | 76 ++++++++++++ drivers/adc/exynos-adc.c | 102 ++++++++++++++++ drivers/power/pmic/Kconfig | 14 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 +++++++++ include/adc.h | 88 ++++++++++++++ include/configs/odroid_xu3.h | 12 ++ include/dm/uclass-id.h | 1 + include/power/s2mps11.h | 109 +++++++++++++++++ include/samsung/exynos5-dt-types.h | 27 ++++ 33 files changed, 854 insertions(+), 22 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h
Simon, Are you going to to review this patchset or can I update it and ask Minkyu for taking it?
Best regards,

Hi Przemyslaw,
On 1 October 2015 at 12:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hello,
On 09/21/2015 02:26 PM, Przemyslaw Marczak wrote:
This patchset adds:
- CPU model in dts for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- new file for Exynos5: exynos5-dt-types.c
- board detection for Odroid XU3 / XU3lite / XU4
- fixed ADC val for XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2
Przemyslaw Marczak (11): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 ++- arch/arm/dts/exynos5422-odroidxu3.dts | 12 ++ arch/arm/dts/exynos54xx.dtsi | 7 ++ arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +-- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 +++++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 17 +++ drivers/adc/Makefile | 9 ++ drivers/adc/adc-uclass.c | 76 ++++++++++++ drivers/adc/exynos-adc.c | 102 ++++++++++++++++ drivers/power/pmic/Kconfig | 14 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 +++++++++ include/adc.h | 88 ++++++++++++++ include/configs/odroid_xu3.h | 12 ++ include/dm/uclass-id.h | 1 + include/power/s2mps11.h | 109 +++++++++++++++++ include/samsung/exynos5-dt-types.h | 27 ++++ 33 files changed, 854 insertions(+), 22 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h
Simon, Are you going to to review this patchset or can I update it and ask Minkyu for taking it?
I thought Minkyu would take it as it seems to be exynos-specific.
Regards, Simon

Hello,
On 10/03/2015 04:30 PM, Simon Glass wrote:
Hi Przemyslaw,
On 1 October 2015 at 12:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hello,
On 09/21/2015 02:26 PM, Przemyslaw Marczak wrote:
This patchset adds:
- CPU model in dts for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- new file for Exynos5: exynos5-dt-types.c
- board detection for Odroid XU3 / XU3lite / XU4
- fixed ADC val for XU4
This was tested on Odroid XU3 and XU3 Lite, without the XU4, but I'm waiting for reply from the Odroid forum users.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2
Przemyslaw Marczak (11): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4.
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 ++- arch/arm/dts/exynos5422-odroidxu3.dts | 12 ++ arch/arm/dts/exynos54xx.dtsi | 7 ++ arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +-- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 45 +++++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 17 +++ drivers/adc/Makefile | 9 ++ drivers/adc/adc-uclass.c | 76 ++++++++++++ drivers/adc/exynos-adc.c | 102 ++++++++++++++++ drivers/power/pmic/Kconfig | 14 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 60 +++++++++ include/adc.h | 88 ++++++++++++++ include/configs/odroid_xu3.h | 12 ++ include/dm/uclass-id.h | 1 + include/power/s2mps11.h | 109 +++++++++++++++++ include/samsung/exynos5-dt-types.h | 27 ++++ 33 files changed, 854 insertions(+), 22 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h
Simon, Are you going to to review this patchset or can I update it and ask Minkyu for taking it?
I thought Minkyu would take it as it seems to be exynos-specific.
Regards, Simon
Ok. I will prepare the V3 and notify you.
Best regards,

This patchset adds: - 'cpu-model' dts property for Chromebook Peach Pi as Exynos5800 - set the cpu id of Exynos5422 to 0x5422 - S2MPS11 PMIC I/O driver - ADC uclass implementation - Exynos5420-compatible (9-channel, 12-bit) ADC driver - new file for Exynos5: exynos5-dt-types.c - board detection for Odroid XU3 / XU3lite / XU4 - fixed ADC value for XU4 detection
This was tested on Odroid XU3/XU3 Lite/XU4 and sandbox.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v3
Przemyslaw Marczak (14): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: regulator: add function device_get_supply_regulator() dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4. sandbox: add ADC driver sandbox: add ADC unit tests
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +- arch/arm/dts/exynos5422-odroidxu3.dts | 12 + arch/arm/dts/exynos54xx.dtsi | 7 + arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 44 ++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- arch/sandbox/dts/sandbox_pmic.dtsi | 2 +- arch/sandbox/dts/test.dts | 6 + board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++ board/samsung/common/exynos5-dt.c | 12 + board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + configs/sandbox_defconfig | 2 + doc/device-tree-bindings/adc/adc.txt | 62 +++++ doc/device-tree-bindings/exynos/soc.txt | 21 ++ doc/device-tree-bindings/pmic/s2mps11.txt | 17 ++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 30 +++ drivers/adc/Makefile | 10 + drivers/adc/adc-uclass.c | 409 +++++++++++++++++++++++++++++ drivers/adc/exynos-adc.c | 145 ++++++++++ drivers/adc/sandbox.c | 174 ++++++++++++ drivers/power/pmic/Kconfig | 14 + drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 62 +++++ drivers/power/regulator/regulator-uclass.c | 7 + include/adc.h | 288 ++++++++++++++++++++ include/configs/odroid_xu3.h | 12 + include/dm/uclass-id.h | 1 + include/power/regulator.h | 16 ++ include/power/s2mps11.h | 109 ++++++++ include/power/sandbox_pmic.h | 4 + include/samsung/exynos5-dt-types.h | 27 ++ test/dm/Makefile | 1 + test/dm/adc.c | 165 ++++++++++++ 44 files changed, 1904 insertions(+), 23 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/adc/adc.txt create mode 100644 doc/device-tree-bindings/exynos/soc.txt create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/adc/sandbox.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h create mode 100644 test/dm/adc.c

The function get_board_type() is called in two places by common code, but the returned pointer was never check.
This commit adds checking the returned pointer, before use it.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com --- Changes V2: - new commit --- board/samsung/common/board.c | 4 ++-- board/samsung/common/misc.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c index d32c75d..1334c22 100644 --- a/board/samsung/common/board.c +++ b/board/samsung/common/board.c @@ -304,8 +304,8 @@ int checkboard(void) printf("Board: %s\n", board_info ? board_info : "unknown"); #ifdef CONFIG_BOARD_TYPES board_info = get_board_type(); - - printf("Model: %s\n", board_info ? board_info : "unknown"); + if (board_info) + printf("Type: %s\n", board_info); #endif return 0; } diff --git a/board/samsung/common/misc.c b/board/samsung/common/misc.c index e0e2c48..c8316d8 100644 --- a/board/samsung/common/misc.c +++ b/board/samsung/common/misc.c @@ -85,6 +85,9 @@ void set_board_info(void)
#ifdef CONFIG_BOARD_TYPES bdtype = get_board_type(); + if (!bdtype) + bdtype = ""; + sprintf(info, "%s%s", bdname, bdtype); setenv("boardname", info); #endif

On 27 October 2015 at 06:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
The function get_board_type() is called in two places by common code, but the returned pointer was never check.
This commit adds checking the returned pointer, before use it.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com
Changes V2:
- new commit
board/samsung/common/board.c | 4 ++-- board/samsung/common/misc.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

On 29 October 2015 at 00:20, Simon Glass sjg@chromium.org wrote:
On 27 October 2015 at 06:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
The function get_board_type() is called in two places by common code, but the returned pointer was never check.
This commit adds checking the returned pointer, before use it.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com
Changes V2:
- new commit
board/samsung/common/board.c | 4 ++-- board/samsung/common/misc.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon

The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined in device tree.
This commit introduces new device-tree property for Exynos: - "cpu-model" - with cpu name string If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - new commit Changes V3 - add cpu-model binding info --- arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +++++++++++++- doc/device-tree-bindings/exynos/soc.txt | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/exynos/soc.txt
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..764c661 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -5,9 +5,12 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <fdtdec.h> #include <asm/io.h> #include <asm/arch/clk.h>
+DECLARE_GLOBAL_DATA_PTR; + /* Default is s5pc100 */ unsigned int s5p_cpu_id = 0xC100; /* Default is EVT1 */ @@ -30,7 +33,16 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { - printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id); + const char *cpu_model; + int len; + + /* For SoC with no real CPU ID in naming convention. */ + cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len); + if (cpu_model) + printf("CPU: %.*s @ ", len, cpu_model); + else + printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id); + print_freq(get_arm_clk(), "\n");
return 0; diff --git a/doc/device-tree-bindings/exynos/soc.txt b/doc/device-tree-bindings/exynos/soc.txt new file mode 100644 index 0000000..9ba6f3b --- /dev/null +++ b/doc/device-tree-bindings/exynos/soc.txt @@ -0,0 +1,21 @@ +Exynos SoC model + +The "cpu-model" property is a non-standard extension for the device tree root +node. Since the cpu id of some Exynos variants does not correspond to product +name, this property fills the gap. + +For almost all Exynos based boards in the kernel, the product name corresponds +to the device tree file name. The same name is generated in U-Boot, so the new +property allows doing it automatically. + +Required properties: + - cpu-model : Exynos product name + +Example: + +/ { + model = "Samsung/Google Peach Pi board based on Exynos5800"; + cpu-model = "Exynos5800"; + + compatible = ... +};

On 27 October 2015 at 06:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined in device tree.
This commit introduces new device-tree property for Exynos:
- "cpu-model" - with cpu name string
If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit
Changes V3
- add cpu-model binding info
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +++++++++++++- doc/device-tree-bindings/exynos/soc.txt | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/exynos/soc.txt
Reviewed-by: Simon Glass sjg@chromium.org

Hi
On 27 October 2015 at 17:37, Przemyslaw Marczak p.marczak@samsung.com wrote:
The CPU name for Exynos was concatenated with cpu id, but for new Exynos platforms, like Chromebook Peach Pi based on Exynos5800, the name of SoC variant does not include the real SoC cpu id (0x5422).
For such case, the CPU name should be defined in device tree.
This commit introduces new device-tree property for Exynos:
- "cpu-model" - with cpu name string
If defined, then the cpu id is not printed.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit
Changes V3
- add cpu-model binding info
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +++++++++++++- doc/device-tree-bindings/exynos/soc.txt | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/exynos/soc.txt
diff --git a/arch/arm/cpu/armv7/s5p-common/cpu_info.c b/arch/arm/cpu/armv7/s5p-common/cpu_info.c index 154d674..764c661 100644 --- a/arch/arm/cpu/armv7/s5p-common/cpu_info.c +++ b/arch/arm/cpu/armv7/s5p-common/cpu_info.c @@ -5,9 +5,12 @@
- SPDX-License-Identifier: GPL-2.0+
*/ #include <common.h> +#include <fdtdec.h> #include <asm/io.h> #include <asm/arch/clk.h>
+DECLARE_GLOBAL_DATA_PTR;
/* Default is s5pc100 */ unsigned int s5p_cpu_id = 0xC100; /* Default is EVT1 */ @@ -30,7 +33,16 @@ u32 get_device_type(void) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) {
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
const char *cpu_model;
int len;
/* For SoC with no real CPU ID in naming convention. */
cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
if (cpu_model)
printf("CPU: %.*s @ ", len, cpu_model);
else
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
print_freq(get_arm_clk(), "\n"); return 0;
diff --git a/doc/device-tree-bindings/exynos/soc.txt b/doc/device-tree-bindings/exynos/soc.txt new file mode 100644 index 0000000..9ba6f3b --- /dev/null +++ b/doc/device-tree-bindings/exynos/soc.txt @@ -0,0 +1,21 @@ +Exynos SoC model
+The "cpu-model" property is a non-standard extension for the device tree root +node. Since the cpu id of some Exynos variants does not correspond to product +name, this property fills the gap.
+For almost all Exynos based boards in the kernel, the product name corresponds +to the device tree file name. The same name is generated in U-Boot, so the new +property allows doing it automatically.
+Required properties:
- cpu-model : Exynos product name
+Example:
+/ {
model = "Samsung/Google Peach Pi board based on Exynos5800";
cpu-model = "Exynos5800";
compatible = ...
+};
1.9.1
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon

This platform is based on Exynos5800 but the cpu id is 0x5422. This doesn't fit the common Exynos SoC name convention, so now, the CPU name is defined by device tree string, to be printed properly.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - move cpu name from config to dts --- arch/arm/dts/exynos5800-peach-pi.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts index 1d7ff23..76826dc 100644 --- a/arch/arm/dts/exynos5800-peach-pi.dts +++ b/arch/arm/dts/exynos5800-peach-pi.dts @@ -12,6 +12,7 @@
/ { model = "Samsung/Google Peach Pi board based on Exynos5800"; + cpu-model = "Exynos5800";
compatible = "google,pit-rev#", "google,pit", "google,peach", "samsung,exynos5800", "samsung,exynos5";

On 27 October 2015 at 06:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
This platform is based on Exynos5800 but the cpu id is 0x5422. This doesn't fit the common Exynos SoC name convention, so now, the CPU name is defined by device tree string, to be printed properly.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- move cpu name from config to dts
arch/arm/dts/exynos5800-peach-pi.dts | 1 + 1 file changed, 1 insertion(+)
Reviewed-by: Simon Glass sjg@chromium.org

Hi,
On 27 October 2015 at 17:37, Przemyslaw Marczak p.marczak@samsung.com wrote:
This platform is based on Exynos5800 but the cpu id is 0x5422. This doesn't fit the common Exynos SoC name convention, so now, the CPU name is defined by device tree string, to be printed properly.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- move cpu name from config to dts
arch/arm/dts/exynos5800-peach-pi.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts index 1d7ff23..76826dc 100644 --- a/arch/arm/dts/exynos5800-peach-pi.dts +++ b/arch/arm/dts/exynos5800-peach-pi.dts @@ -12,6 +12,7 @@
/ { model = "Samsung/Google Peach Pi board based on Exynos5800";
cpu-model = "Exynos5800"; compatible = "google,pit-rev#", "google,pit", "google,peach", "samsung,exynos5800", "samsung,exynos5";
-- 1.9.1
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon

The proper CPU ID for those Exynos variants is 0x5422, but before the 0x5800 was set. This commit fix this back.
Changes: - set cpu id to 0x5422 instead of 0x5800 - remove macro proid_is_exynos5800() - add macro proid_is_exynos5422() - change the calls to proid_is_exynos5800() with new macro
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - none --- arch/arm/mach-exynos/clock.c | 16 ++++++++-------- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 ++-- arch/arm/mach-exynos/include/mach/cpu.h | 6 +++--- arch/arm/mach-exynos/include/mach/gpio.h | 4 ++-- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c index 18eadf5..3d31f9d 100644 --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -159,8 +159,8 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) div = PLL_DIV_1024; else if (proid_is_exynos4412()) div = PLL_DIV_65535; - else if (proid_is_exynos5250() || proid_is_exynos5420() - || proid_is_exynos5800()) + else if (proid_is_exynos5250() || proid_is_exynos5420() || + proid_is_exynos5422()) div = PLL_DIV_65536; else return 0; @@ -346,7 +346,7 @@ static struct clk_bit_info *get_clk_bit_info(int peripheral) int i; struct clk_bit_info *info;
- if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) info = exynos542x_bit_info; else info = exynos5_bit_info; @@ -558,7 +558,7 @@ static unsigned long exynos542x_get_periph_rate(int peripheral) unsigned long clock_get_periph_rate(int peripheral) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_periph_rate(peripheral); return exynos5_get_periph_rate(peripheral); } else { @@ -1576,7 +1576,7 @@ static unsigned long exynos4_get_i2c_clk(void) unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_pll_clk(pllreg); return exynos5_get_pll_clk(pllreg); } else if (cpu_is_exynos4()) { @@ -1692,7 +1692,7 @@ void set_mmc_clk(int dev_index, unsigned int div) div -= 1;
if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_mmc_clk(dev_index, div); else exynos5_set_mmc_clk(dev_index, div); @@ -1708,7 +1708,7 @@ unsigned long get_lcd_clk(void) } else if (cpu_is_exynos5()) { if (proid_is_exynos5420()) return exynos5420_get_lcd_clk(); - else if (proid_is_exynos5800()) + else if (proid_is_exynos5422()) return exynos5800_get_lcd_clk(); else return exynos5_get_lcd_clk(); @@ -1740,7 +1740,7 @@ void set_mipi_clk(void) int set_spi_clk(int periph_id, unsigned int rate) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_set_spi_clk(periph_id, rate); return exynos5_set_spi_clk(periph_id, rate); } diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c index 0200fd1..1b7498d 100644 --- a/arch/arm/mach-exynos/clock_init_exynos5.c +++ b/arch/arm/mach-exynos/clock_init_exynos5.c @@ -971,7 +971,7 @@ static void exynos5420_system_clock_init(void)
void system_clock_init(void) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_system_clock_init(); else exynos5250_system_clock_init(); diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h index 67aac2d..2829fb2 100644 --- a/arch/arm/mach-exynos/common_setup.h +++ b/arch/arm/mach-exynos/common_setup.h @@ -78,7 +78,7 @@ static inline void configure_l2_ctlr(void) CACHE_TAG_RAM_LATENCY_2_CYCLES | CACHE_DATA_RAM_LATENCY_2_CYCLES;
- if (proid_is_exynos5420() || proid_is_exynos5800()) { + if (proid_is_exynos5420() || proid_is_exynos5422()) { val |= CACHE_ECC_AND_PARITY | CACHE_TAG_RAM_LATENCY_3_CYCLES | CACHE_DATA_RAM_LATENCY_3_CYCLES; @@ -97,7 +97,7 @@ static inline void configure_l2_actlr(void) { uint32_t val;
- if (proid_is_exynos5420() || proid_is_exynos5800()) { + if (proid_is_exynos5420() || proid_is_exynos5422()) { mrc_l2_aux_ctlr(val); val |= CACHE_ENABLE_FORCE_L2_LOGIC | CACHE_DISABLE_CLEAN_EVICT; diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index cb3d2cc..14a1692 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -237,7 +237,7 @@ static inline void s5p_set_cpu_id(void) * Exynos5800 is a variant of Exynos5420 * and has product id 0x5422 */ - s5p_cpu_id = 0x5800; + s5p_cpu_id = 0x5422; break; } } @@ -267,7 +267,7 @@ IS_EXYNOS_TYPE(exynos4210, 0x4210) IS_EXYNOS_TYPE(exynos4412, 0x4412) IS_EXYNOS_TYPE(exynos5250, 0x5250) IS_EXYNOS_TYPE(exynos5420, 0x5420) -IS_EXYNOS_TYPE(exynos5800, 0x5800) +IS_EXYNOS_TYPE(exynos5422, 0x5422)
#define SAMSUNG_BASE(device, base) \ static inline unsigned int __attribute__((no_instrument_function)) \ @@ -278,7 +278,7 @@ static inline unsigned int __attribute__((no_instrument_function)) \ return EXYNOS4X12_##base; \ return EXYNOS4_##base; \ } else if (cpu_is_exynos5()) { \ - if (proid_is_exynos5420() || proid_is_exynos5800()) \ + if (proid_is_exynos5420() || proid_is_exynos5422()) \ return EXYNOS5420_##base; \ return EXYNOS5_##base; \ } \ diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h index 9699954..7fc8e61 100644 --- a/arch/arm/mach-exynos/include/mach/gpio.h +++ b/arch/arm/mach-exynos/include/mach/gpio.h @@ -1398,7 +1398,7 @@ static struct gpio_info exynos5420_gpio_data[EXYNOS5420_GPIO_NUM_PARTS] = { static inline struct gpio_info *get_gpio_data(void) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_gpio_data; else return exynos5_gpio_data; @@ -1415,7 +1415,7 @@ static inline struct gpio_info *get_gpio_data(void) static inline unsigned int get_bank_num(void) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return EXYNOS5420_GPIO_NUM_PARTS; else return EXYNOS5_GPIO_NUM_PARTS; diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c index 179b294..a556e4a 100644 --- a/arch/arm/mach-exynos/pinmux.c +++ b/arch/arm/mach-exynos/pinmux.c @@ -858,7 +858,7 @@ static int exynos4x12_pinmux_config(int peripheral, int flags) int exynos_pinmux_config(int peripheral, int flags) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_pinmux_config(peripheral, flags); else if (proid_is_exynos5250()) return exynos5_pinmux_config(peripheral, flags); diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c index 1b12051..cd2d661 100644 --- a/arch/arm/mach-exynos/power.c +++ b/arch/arm/mach-exynos/power.c @@ -125,7 +125,7 @@ static void exynos5420_set_usbdev_phy_ctrl(unsigned int enable) void set_usbdrd_phy_ctrl(unsigned int enable) { if (cpu_is_exynos5()) { - if (proid_is_exynos5420() || proid_is_exynos5800()) + if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_usbdev_phy_ctrl(enable); else exynos5_set_usbdrd_phy_ctrl(enable);

hi,
On 27 October 2015 at 17:37, Przemyslaw Marczak p.marczak@samsung.com wrote:
The proper CPU ID for those Exynos variants is 0x5422, but before the 0x5800 was set. This commit fix this back.
Changes:
- set cpu id to 0x5422 instead of 0x5800
- remove macro proid_is_exynos5800()
- add macro proid_is_exynos5422()
- change the calls to proid_is_exynos5800() with new macro
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- none
arch/arm/mach-exynos/clock.c | 16 ++++++++-------- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 ++-- arch/arm/mach-exynos/include/mach/cpu.h | 6 +++--- arch/arm/mach-exynos/include/mach/gpio.h | 4 ++-- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c index 18eadf5..3d31f9d 100644 --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -159,8 +159,8 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) div = PLL_DIV_1024; else if (proid_is_exynos4412()) div = PLL_DIV_65535;
else if (proid_is_exynos5250() || proid_is_exynos5420()
|| proid_is_exynos5800())
else if (proid_is_exynos5250() || proid_is_exynos5420() ||
proid_is_exynos5422()) div = PLL_DIV_65536; else return 0;
@@ -346,7 +346,7 @@ static struct clk_bit_info *get_clk_bit_info(int peripheral) int i; struct clk_bit_info *info;
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) info = exynos542x_bit_info; else info = exynos5_bit_info;
@@ -558,7 +558,7 @@ static unsigned long exynos542x_get_periph_rate(int peripheral) unsigned long clock_get_periph_rate(int peripheral) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_periph_rate(peripheral); return exynos5_get_periph_rate(peripheral); } else {
@@ -1576,7 +1576,7 @@ static unsigned long exynos4_get_i2c_clk(void) unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos542x_get_pll_clk(pllreg); return exynos5_get_pll_clk(pllreg); } else if (cpu_is_exynos4()) {
@@ -1692,7 +1692,7 @@ void set_mmc_clk(int dev_index, unsigned int div) div -= 1;
if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_mmc_clk(dev_index, div); else exynos5_set_mmc_clk(dev_index, div);
@@ -1708,7 +1708,7 @@ unsigned long get_lcd_clk(void) } else if (cpu_is_exynos5()) { if (proid_is_exynos5420()) return exynos5420_get_lcd_clk();
else if (proid_is_exynos5800())
else if (proid_is_exynos5422()) return exynos5800_get_lcd_clk(); else return exynos5_get_lcd_clk();
@@ -1740,7 +1740,7 @@ void set_mipi_clk(void) int set_spi_clk(int periph_id, unsigned int rate) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_set_spi_clk(periph_id, rate); return exynos5_set_spi_clk(periph_id, rate); }
diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c index 0200fd1..1b7498d 100644 --- a/arch/arm/mach-exynos/clock_init_exynos5.c +++ b/arch/arm/mach-exynos/clock_init_exynos5.c @@ -971,7 +971,7 @@ static void exynos5420_system_clock_init(void)
void system_clock_init(void) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_system_clock_init(); else exynos5250_system_clock_init();
diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h index 67aac2d..2829fb2 100644 --- a/arch/arm/mach-exynos/common_setup.h +++ b/arch/arm/mach-exynos/common_setup.h @@ -78,7 +78,7 @@ static inline void configure_l2_ctlr(void) CACHE_TAG_RAM_LATENCY_2_CYCLES | CACHE_DATA_RAM_LATENCY_2_CYCLES;
if (proid_is_exynos5420() || proid_is_exynos5800()) {
if (proid_is_exynos5420() || proid_is_exynos5422()) { val |= CACHE_ECC_AND_PARITY | CACHE_TAG_RAM_LATENCY_3_CYCLES | CACHE_DATA_RAM_LATENCY_3_CYCLES;
@@ -97,7 +97,7 @@ static inline void configure_l2_actlr(void) { uint32_t val;
if (proid_is_exynos5420() || proid_is_exynos5800()) {
if (proid_is_exynos5420() || proid_is_exynos5422()) { mrc_l2_aux_ctlr(val); val |= CACHE_ENABLE_FORCE_L2_LOGIC | CACHE_DISABLE_CLEAN_EVICT;
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index cb3d2cc..14a1692 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -237,7 +237,7 @@ static inline void s5p_set_cpu_id(void) * Exynos5800 is a variant of Exynos5420 * and has product id 0x5422 */
s5p_cpu_id = 0x5800;
s5p_cpu_id = 0x5422; break; }
} @@ -267,7 +267,7 @@ IS_EXYNOS_TYPE(exynos4210, 0x4210) IS_EXYNOS_TYPE(exynos4412, 0x4412) IS_EXYNOS_TYPE(exynos5250, 0x5250) IS_EXYNOS_TYPE(exynos5420, 0x5420) -IS_EXYNOS_TYPE(exynos5800, 0x5800) +IS_EXYNOS_TYPE(exynos5422, 0x5422)
#define SAMSUNG_BASE(device, base) \ static inline unsigned int __attribute__((no_instrument_function)) \ @@ -278,7 +278,7 @@ static inline unsigned int __attribute__((no_instrument_function)) \ return EXYNOS4X12_##base; \ return EXYNOS4_##base; \ } else if (cpu_is_exynos5()) { \
if (proid_is_exynos5420() || proid_is_exynos5800()) \
if (proid_is_exynos5420() || proid_is_exynos5422()) \ return EXYNOS5420_##base; \ return EXYNOS5_##base; \ } \
diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h index 9699954..7fc8e61 100644 --- a/arch/arm/mach-exynos/include/mach/gpio.h +++ b/arch/arm/mach-exynos/include/mach/gpio.h @@ -1398,7 +1398,7 @@ static struct gpio_info exynos5420_gpio_data[EXYNOS5420_GPIO_NUM_PARTS] = { static inline struct gpio_info *get_gpio_data(void) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_gpio_data; else return exynos5_gpio_data;
@@ -1415,7 +1415,7 @@ static inline struct gpio_info *get_gpio_data(void) static inline unsigned int get_bank_num(void) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) return EXYNOS5420_GPIO_NUM_PARTS; else return EXYNOS5_GPIO_NUM_PARTS;
diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c index 179b294..a556e4a 100644 --- a/arch/arm/mach-exynos/pinmux.c +++ b/arch/arm/mach-exynos/pinmux.c @@ -858,7 +858,7 @@ static int exynos4x12_pinmux_config(int peripheral, int flags) int exynos_pinmux_config(int peripheral, int flags) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) return exynos5420_pinmux_config(peripheral, flags); else if (proid_is_exynos5250()) return exynos5_pinmux_config(peripheral, flags);
diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c index 1b12051..cd2d661 100644 --- a/arch/arm/mach-exynos/power.c +++ b/arch/arm/mach-exynos/power.c @@ -125,7 +125,7 @@ static void exynos5420_set_usbdev_phy_ctrl(unsigned int enable) void set_usbdrd_phy_ctrl(unsigned int enable) { if (cpu_is_exynos5()) {
if (proid_is_exynos5420() || proid_is_exynos5800())
if (proid_is_exynos5420() || proid_is_exynos5422()) exynos5420_set_usbdev_phy_ctrl(enable); else exynos5_set_usbdrd_phy_ctrl(enable);
-- 1.9.1
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon

This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with: - CONFIG_PMIC_S2MPS11 and additional, if were not defined: - CONFIG_CMD_PMIC - CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com --- Changes V2: - remove "DM" prefix from config name - fix word mistake in binding description Changes V3: - correct return values for driver's read/write methods --- doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 62 +++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..422f14f --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUNG, S2MPS11 PMIC + +This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c + +Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66 + +With those two properties, the pmic device can be used for read/write only. + +Example: + +s2mps11@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; +}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 547fd1a..fb29843 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -33,6 +33,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config PMIC_S2MPS11 + bool "Enable Driver Model for PMIC Samsung S2MPS11" + depends on DM_PMIC + ---help--- + The Samsung S2MPS11 PMIC provides: + - 38 adjustable LDO regulators + - 9 High-Efficiency Buck Converters + - 1 BuckBoost Converter + - RTC with two alarms + - Backup battery charger + - I2C Configuration Interface + This driver provides access to I/O interface only. + Binding info: doc/device-tree-bindings/pmic/s2mps11.txt + config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 00fde71..91e78f8 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..9d83059 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int s2mps11_reg_count(struct udevice *dev) +{ + return S2MPS11_REG_COUNT; +} + +static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + error("write error to device: %p register: %#x!", dev, reg); + + return ret; +} + +static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + error("read error from device: %p register: %#x!", dev, reg); + + return ret; +} + +static struct dm_pmic_ops s2mps11_ops = { + .reg_count = s2mps11_reg_count, + .read = s2mps11_read, + .write = s2mps11_write, +}; + +static const struct udevice_id s2mps11_ids[] = { + { .compatible = "samsung,s2mps11-pmic" }, + { } +}; + +U_BOOT_DRIVER(pmic_s2mps11) = { + .name = "s2mps11_pmic", + .id = UCLASS_PMIC, + .of_match = s2mps11_ids, + .ops = &s2mps11_ops, +}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..5da4719 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __S2MPS11__H__ +#define __S2MPS11__H__ + +enum s2mps11_reg { + S2MPS11_REG_ID = 0, + S2MPS11_REG_INT1, + S2MPS11_REG_INT2, + S2MPS11_REG_INT3, + S2MPS11_REG_INT1M, + S2MPS11_REG_INT2M, + S2MPS11_REG_INT3M, + S2MPS11_REG_STATUS1, + S2MPS11_REG_STATUS2, + S2MPS11_REG_OFFSRC, + S2MPS11_REG_PWRONSRC, + S2MPS11_REG_RTC_CTRL, + S2MPS11_REG_CTRL1, + S2MPS11_REG_ETC_TEST, + S2MPS11_REG_RSVD3, + S2MPS11_REG_BU_CHG, + S2MPS11_REG_RAMP, + S2MPS11_REG_RAMP_BUCK, + S2MPS11_REG_LDO1_8, + S2MPS11_REG_LDO9_16, + S2MPS11_REG_LDO17_24, + S2MPS11_REG_LDO25_32, + S2MPS11_REG_LDO33_38, + S2MPS11_REG_LDO1_8_OVC, + S2MPS11_REG_LDO9_16_OVC, + S2MPS11_REG_LDO17_24_OVC, + S2MPS11_REG_LDO25_32_OVC, + S2MPS11_REG_LDO33_38_OVC, + S2MPS11_REG_RESERVED1, + S2MPS11_REG_RESERVED2, + S2MPS11_REG_RESERVED3, + S2MPS11_REG_RESERVED4, + S2MPS11_REG_RESERVED5, + S2MPS11_REG_RESERVED6, + S2MPS11_REG_RESERVED7, + S2MPS11_REG_RESERVED8, + S2MPS11_REG_WDRSTEN_CTRL, + S2MPS11_REG_B1CTRL1, + S2MPS11_REG_B1CTRL2, + S2MPS11_REG_B2CTRL1, + S2MPS11_REG_B2CTRL2, + S2MPS11_REG_B3CTRL1, + S2MPS11_REG_B3CTRL2, + S2MPS11_REG_B4CTRL1, + S2MPS11_REG_B4CTRL2, + S2MPS11_REG_B5CTRL1, + S2MPS11_REG_BUCK5_SW, + S2MPS11_REG_B5CTRL2, + S2MPS11_REG_B5CTRL3, + S2MPS11_REG_B5CTRL4, + S2MPS11_REG_B5CTRL5, + S2MPS11_REG_B6CTRL1, + S2MPS11_REG_B6CTRL2, + S2MPS11_REG_B7CTRL1, + S2MPS11_REG_B7CTRL2, + S2MPS11_REG_B8CTRL1, + S2MPS11_REG_B8CTRL2, + S2MPS11_REG_B9CTRL1, + S2MPS11_REG_B9CTRL2, + S2MPS11_REG_B10CTRL1, + S2MPS11_REG_B10CTRL2, + S2MPS11_REG_L1CTRL, + S2MPS11_REG_L2CTRL, + S2MPS11_REG_L3CTRL, + S2MPS11_REG_L4CTRL, + S2MPS11_REG_L5CTRL, + S2MPS11_REG_L6CTRL, + S2MPS11_REG_L7CTRL, + S2MPS11_REG_L8CTRL, + S2MPS11_REG_L9CTRL, + S2MPS11_REG_L10CTRL, + S2MPS11_REG_L11CTRL, + S2MPS11_REG_L12CTRL, + S2MPS11_REG_L13CTRL, + S2MPS11_REG_L14CTRL, + S2MPS11_REG_L15CTRL, + S2MPS11_REG_L16CTRL, + S2MPS11_REG_L17CTRL, + S2MPS11_REG_L18CTRL, + S2MPS11_REG_L19CTRL, + S2MPS11_REG_L20CTRL, + S2MPS11_REG_L21CTRL, + S2MPS11_REG_L22CTRL, + S2MPS11_REG_L23CTRL, + S2MPS11_REG_L24CTRL, + S2MPS11_REG_L25CTRL, + S2MPS11_REG_L26CTRL, + S2MPS11_REG_L27CTRL, + S2MPS11_REG_L28CTRL, + S2MPS11_REG_L29CTRL, + S2MPS11_REG_L30CTRL, + S2MPS11_REG_L31CTRL, + S2MPS11_REG_L32CTRL, + S2MPS11_REG_L33CTRL, + S2MPS11_REG_L34CTRL, + S2MPS11_REG_L35CTRL, + S2MPS11_REG_L36CTRL, + S2MPS11_REG_L37CTRL, + S2MPS11_REG_L38CTRL, + S2MPS11_REG_COUNT, +}; + +#define S2MPS11_LDO26_ENABLE 0xec + +#endif

On 27 October 2015 at 06:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- remove "DM" prefix from config name
- fix word mistake in binding description
Changes V3:
- correct return values for driver's read/write methods
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 62 +++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
Reviewed-by: Simon Glass sjg@chromium.org

hi,
On 27 October 2015 at 17:37, Przemyslaw Marczak p.marczak@samsung.com wrote:
This driver allows I/O operations on the Samsung S2MPS11 PMIC, which provides lots of LDO/BUCK outputs.
To enable it, update defconfig with:
- CONFIG_PMIC_S2MPS11
and additional, if were not defined:
- CONFIG_CMD_PMIC
- CONFIG_ERRNO_STR
The binding info: doc/device-tree-bindings/pmic/s2mps11.txt
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com
Changes V2:
- remove "DM" prefix from config name
- fix word mistake in binding description
Changes V3:
- correct return values for driver's read/write methods
doc/device-tree-bindings/pmic/s2mps11.txt | 17 +++++ drivers/power/pmic/Kconfig | 14 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 62 +++++++++++++++++ include/power/s2mps11.h | 109 ++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/power/s2mps11.h
diff --git a/doc/device-tree-bindings/pmic/s2mps11.txt b/doc/device-tree-bindings/pmic/s2mps11.txt new file mode 100644 index 0000000..422f14f --- /dev/null +++ b/doc/device-tree-bindings/pmic/s2mps11.txt @@ -0,0 +1,17 @@ +SAMSUNG, S2MPS11 PMIC
+This file describes the binding info for the PMIC driver: +- drivers/power/pmic/s2mps11.c
+Required properties: +- compatible: "samsung,s2mps11-pmic" +- reg = 0x66
+With those two properties, the pmic device can be used for read/write only.
+Example:
+s2mps11@66 {
compatible = "samsung,s2mps11-pmic";
reg = <0x66>;
+}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 547fd1a..fb29843 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -33,6 +33,20 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config PMIC_S2MPS11
bool "Enable Driver Model for PMIC Samsung S2MPS11"
depends on DM_PMIC
---help---
The Samsung S2MPS11 PMIC provides:
- 38 adjustable LDO regulators
- 9 High-Efficiency Buck Converters
- 1 BuckBoost Converter
- RTC with two alarms
- Backup battery charger
- I2C Configuration Interface
This driver provides access to I/O interface only.
Binding info: doc/device-tree-bindings/pmic/s2mps11.txt
config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC " depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 00fde71..91e78f8 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c new file mode 100644 index 0000000..9d83059 --- /dev/null +++ b/drivers/power/pmic/s2mps11.c @@ -0,0 +1,62 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/s2mps11.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int s2mps11_reg_count(struct udevice *dev) +{
return S2MPS11_REG_COUNT;
+}
+static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
+{
int ret;
ret = dm_i2c_write(dev, reg, buff, len);
if (ret)
error("write error to device: %p register: %#x!", dev, reg);
return ret;
+}
+static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{
int ret;
ret = dm_i2c_read(dev, reg, buff, len);
if (ret)
error("read error from device: %p register: %#x!", dev, reg);
return ret;
+}
+static struct dm_pmic_ops s2mps11_ops = {
.reg_count = s2mps11_reg_count,
.read = s2mps11_read,
.write = s2mps11_write,
+};
+static const struct udevice_id s2mps11_ids[] = {
{ .compatible = "samsung,s2mps11-pmic" },
{ }
+};
+U_BOOT_DRIVER(pmic_s2mps11) = {
.name = "s2mps11_pmic",
.id = UCLASS_PMIC,
.of_match = s2mps11_ids,
.ops = &s2mps11_ops,
+}; diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h new file mode 100644 index 0000000..5da4719 --- /dev/null +++ b/include/power/s2mps11.h @@ -0,0 +1,109 @@ +#ifndef __S2MPS11__H__ +#define __S2MPS11__H__
+enum s2mps11_reg {
S2MPS11_REG_ID = 0,
S2MPS11_REG_INT1,
S2MPS11_REG_INT2,
S2MPS11_REG_INT3,
S2MPS11_REG_INT1M,
S2MPS11_REG_INT2M,
S2MPS11_REG_INT3M,
S2MPS11_REG_STATUS1,
S2MPS11_REG_STATUS2,
S2MPS11_REG_OFFSRC,
S2MPS11_REG_PWRONSRC,
S2MPS11_REG_RTC_CTRL,
S2MPS11_REG_CTRL1,
S2MPS11_REG_ETC_TEST,
S2MPS11_REG_RSVD3,
S2MPS11_REG_BU_CHG,
S2MPS11_REG_RAMP,
S2MPS11_REG_RAMP_BUCK,
S2MPS11_REG_LDO1_8,
S2MPS11_REG_LDO9_16,
S2MPS11_REG_LDO17_24,
S2MPS11_REG_LDO25_32,
S2MPS11_REG_LDO33_38,
S2MPS11_REG_LDO1_8_OVC,
S2MPS11_REG_LDO9_16_OVC,
S2MPS11_REG_LDO17_24_OVC,
S2MPS11_REG_LDO25_32_OVC,
S2MPS11_REG_LDO33_38_OVC,
S2MPS11_REG_RESERVED1,
S2MPS11_REG_RESERVED2,
S2MPS11_REG_RESERVED3,
S2MPS11_REG_RESERVED4,
S2MPS11_REG_RESERVED5,
S2MPS11_REG_RESERVED6,
S2MPS11_REG_RESERVED7,
S2MPS11_REG_RESERVED8,
S2MPS11_REG_WDRSTEN_CTRL,
S2MPS11_REG_B1CTRL1,
S2MPS11_REG_B1CTRL2,
S2MPS11_REG_B2CTRL1,
S2MPS11_REG_B2CTRL2,
S2MPS11_REG_B3CTRL1,
S2MPS11_REG_B3CTRL2,
S2MPS11_REG_B4CTRL1,
S2MPS11_REG_B4CTRL2,
S2MPS11_REG_B5CTRL1,
S2MPS11_REG_BUCK5_SW,
S2MPS11_REG_B5CTRL2,
S2MPS11_REG_B5CTRL3,
S2MPS11_REG_B5CTRL4,
S2MPS11_REG_B5CTRL5,
S2MPS11_REG_B6CTRL1,
S2MPS11_REG_B6CTRL2,
S2MPS11_REG_B7CTRL1,
S2MPS11_REG_B7CTRL2,
S2MPS11_REG_B8CTRL1,
S2MPS11_REG_B8CTRL2,
S2MPS11_REG_B9CTRL1,
S2MPS11_REG_B9CTRL2,
S2MPS11_REG_B10CTRL1,
S2MPS11_REG_B10CTRL2,
S2MPS11_REG_L1CTRL,
S2MPS11_REG_L2CTRL,
S2MPS11_REG_L3CTRL,
S2MPS11_REG_L4CTRL,
S2MPS11_REG_L5CTRL,
S2MPS11_REG_L6CTRL,
S2MPS11_REG_L7CTRL,
S2MPS11_REG_L8CTRL,
S2MPS11_REG_L9CTRL,
S2MPS11_REG_L10CTRL,
S2MPS11_REG_L11CTRL,
S2MPS11_REG_L12CTRL,
S2MPS11_REG_L13CTRL,
S2MPS11_REG_L14CTRL,
S2MPS11_REG_L15CTRL,
S2MPS11_REG_L16CTRL,
S2MPS11_REG_L17CTRL,
S2MPS11_REG_L18CTRL,
S2MPS11_REG_L19CTRL,
S2MPS11_REG_L20CTRL,
S2MPS11_REG_L21CTRL,
S2MPS11_REG_L22CTRL,
S2MPS11_REG_L23CTRL,
S2MPS11_REG_L24CTRL,
S2MPS11_REG_L25CTRL,
S2MPS11_REG_L26CTRL,
S2MPS11_REG_L27CTRL,
S2MPS11_REG_L28CTRL,
S2MPS11_REG_L29CTRL,
S2MPS11_REG_L30CTRL,
S2MPS11_REG_L31CTRL,
S2MPS11_REG_L32CTRL,
S2MPS11_REG_L33CTRL,
S2MPS11_REG_L34CTRL,
S2MPS11_REG_L35CTRL,
S2MPS11_REG_L36CTRL,
S2MPS11_REG_L37CTRL,
S2MPS11_REG_L38CTRL,
S2MPS11_REG_COUNT,
+};
+#define S2MPS11_LDO26_ENABLE 0xec
+#endif
1.9.1
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon

Some devices are supplied by configurable regulator's output. But there was no function for getting it. This commit adds function, that allows for getting the supply device by it's phandle.
The returned regulator device can be used with regulator uclass's API.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V3: - new commit --- drivers/power/regulator/regulator-uclass.c | 7 +++++++ include/power/regulator.h | 16 ++++++++++++++++ 2 files changed, 23 insertions(+)
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index a5170df..4241a4c 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -138,6 +138,13 @@ int regulator_get_by_devname(const char *devname, struct udevice **devp) return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp); }
+int device_get_supply_regulator(struct udevice *dev, const char *supply_name, + struct udevice **devp) +{ + return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + supply_name, devp); +} + int regulator_autoset(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; diff --git a/include/power/regulator.h b/include/power/regulator.h index 1a51c3f..63c0814 100644 --- a/include/power/regulator.h +++ b/include/power/regulator.h @@ -419,4 +419,20 @@ int regulator_get_by_devname(const char *devname, struct udevice **devp); */ int regulator_get_by_platname(const char *platname, struct udevice **devp);
+/** + * device_get_supply_regulator: returns the pointer to the supply regulator. + * Search by phandle, found in device's node. + * + * Note: Please pay attention to proper order of device bind sequence. + * The regulator device searched by the phandle, must be binded before + * this function call. + * + * @dev - device with supply phandle + * @supply_name - phandle name of regulator + * @devp - returned pointer to the supply device + * @return 0 on success or negative value of errno. + */ +int device_get_supply_regulator(struct udevice *dev, const char *supply_name, + struct udevice **devp); + #endif /* _INCLUDE_REGULATOR_H_ */

Hi Przemyslaw,
On 27 October 2015 at 06:07, Przemyslaw Marczak p.marczak@samsung.com wrote:
Some devices are supplied by configurable regulator's output. But there was no function for getting it. This commit adds function, that allows for getting the supply device by it's phandle.
The returned regulator device can be used with regulator uclass's API.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V3:
- new commit
drivers/power/regulator/regulator-uclass.c | 7 +++++++ include/power/regulator.h | 16 ++++++++++++++++ 2 files changed, 23 insertions(+)
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index a5170df..4241a4c 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -138,6 +138,13 @@ int regulator_get_by_devname(const char *devname, struct udevice **devp) return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp); }
+int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
struct udevice **devp)
Can we call this regulator_get_supply()? The 'device_' prefix is used by device.h.
+{
return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
supply_name, devp);
+}
int regulator_autoset(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; diff --git a/include/power/regulator.h b/include/power/regulator.h index 1a51c3f..63c0814 100644 --- a/include/power/regulator.h +++ b/include/power/regulator.h @@ -419,4 +419,20 @@ int regulator_get_by_devname(const char *devname, struct udevice **devp); */ int regulator_get_by_platname(const char *platname, struct udevice **devp);
+/**
- device_get_supply_regulator: returns the pointer to the supply regulator.
- Search by phandle, found in device's node.
- Note: Please pay attention to proper order of device bind sequence.
- The regulator device searched by the phandle, must be binded before
- this function call.
- @dev - device with supply phandle
- @supply_name - phandle name of regulator
- @devp - returned pointer to the supply device
- @return 0 on success or negative value of errno.
- */
+int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
struct udevice **devp);
#endif /* _INCLUDE_REGULATOR_H_ */
1.9.1
Regards, Simon

This commit adds: - new uclass id: UCLASS_ADC - new uclass driver: drivers/adc/adc-uclass.c
The new uclass's API allows for ADC operation on: * single-channel with channel selection by a number * multti-channel with channel selection by bit mask
ADC uclass's functions: * single-channel: - adc_start_channel() - start channel conversion - adc_channel_data() - get conversion data - adc_channel_single_shot() - start/get conversion data * multi-channel: - adc_start_channels() - start selected channels conversion - adc_channels_data() - get conversion data - adc_channels_single_shot() - start/get conversion data for channels selected by bit mask * general: - adc_stop() - stop the conversion - adc_vdd_value() - positive reference Voltage value with polarity [uV] - adc_vss_value() - negative reference Voltage value with polarity [uV] - adc_data_mask() - conversion data bit mask
The device tree can provide below constraints/properties: - vdd-polarity-negative: if true: Vdd = vdd-microvolts * (-1) - vss-polarity-negative: if true: Vss = vss-microvolts * (-1) - vdd-supply: phandle to Vdd regulator's node - vss-supply: phandle to Vss regulator's node And optional, checked only if the above corresponding, doesn't exist: - vdd-microvolts: positive reference Voltage [uV] - vss-microvolts: negative reference Voltage [uV]
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - new commit - introduce ADC uclass driver Changes V3: - Add binding info - ADC uclass's code rework, add single/multi-channel API - Select single channel by a number and multi, by a bit mask - Wait for conversion end in uclass's internal function - Add ADC supply polarity constraint - Add function for getting supply Voltage with polarity --- doc/device-tree-bindings/adc/adc.txt | 62 ++++++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 12 + drivers/adc/Makefile | 8 + drivers/adc/adc-uclass.c | 409 +++++++++++++++++++++++++++++++++++ include/adc.h | 288 ++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 8 files changed, 783 insertions(+) create mode 100644 doc/device-tree-bindings/adc/adc.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 include/adc.h
diff --git a/doc/device-tree-bindings/adc/adc.txt b/doc/device-tree-bindings/adc/adc.txt new file mode 100644 index 0000000..463de3c --- /dev/null +++ b/doc/device-tree-bindings/adc/adc.txt @@ -0,0 +1,62 @@ +ADC device binding + +There are no mandatory properties for ADC. However, if Voltage info is required, +then there are two options: +- use microvolts constraint or +- use regulator phandle to enable/read supply's Voltage + +Properties and constraints: +*optional and always checked, Voltage polarity info: +- vdd-polarity-negative: positive reference Voltage has a negative polarity +- vss-polarity-negative: negative reference Voltage has a negative polarity + +Chose one option, for each supply (Vdd/Vss): + +*optional and always checked, supply Voltage constants: +- vdd-supply: phandle to Vdd regulator's node +- vss-supply: phandle to Vss regulator's node + +*optional and checked only if the above corresponding, doesn't exist: +- vdd-microvolts: positive reference Voltage value [uV] +- vss-microvolts: negative reference Voltage value [uV] + +Example with constant 'Vdd' value: +adc@1000000 { + compatible = "some-adc"; + reg = <0xaabb000 0x100>; + status = "enabled"; + vdd-microvolts = <1800000>; +}; + +Example of supply phandle usage, for the ADC's VDD/VSS references as below: + _______ _______ + |Sandbox| |Sandbox| + : PMIC : : ADC : + . . . . + | | (Vdd) | AIN0|--> + | BUCK2|-------|VDDref | + | (3.3V)| _|VSSref | + |_______| | |_______| + _|_ + +For the above PMIC, the node can be defined as follows: +sandbox_pmic { + compatible = "sandbox,pmic"; + ... + buck2: buck2 { + regulator-name = "SUPPLY_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + ... +}; + +For the above ADC, the node can be defined as follows: +adc@0 { + compatible = "sandbox,adc"; + vdd-supply = <&buck2>; + vss-microvolts = <0>; +}; + +The ADC uclass code, will enable the supply before start of the conversion, +but it will not configure the regulator settings. diff --git a/drivers/Kconfig b/drivers/Kconfig index ba88b5e..c481e93 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -4,6 +4,8 @@ source "drivers/core/Kconfig"
# types of drivers sorted in alphabetical order
+source "drivers/adc/Kconfig" + source "drivers/block/Kconfig"
source "drivers/clk/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 4f49bfd..ad29a4f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
else
+obj-y += adc/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig new file mode 100644 index 0000000..b6e226a --- /dev/null +++ b/drivers/adc/Kconfig @@ -0,0 +1,12 @@ +config ADC + bool "Enable ADC drivers using Driver Model" + help + This enables ADC API for drivers, which allows driving ADC features + by single and multi-channel methods for: + - start/stop/get data for conversion of a single-channel selected by + a number or multi-channels selected by a bitmask + - get data mask (ADC resolution) + ADC reference Voltage supply options: + - methods for get Vdd/Vss reference Voltage values with polarity + - support supply's phandle with auto-enable + - supply polarity setting in fdt diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile new file mode 100644 index 0000000..c4d9618 --- /dev/null +++ b/drivers/adc/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2015 Samsung Electronics +# Przemyslaw Marczak p.marczak@samsung.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_ADC) += adc-uclass.o diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c new file mode 100644 index 0000000..9233fcd --- /dev/null +++ b/drivers/adc/adc-uclass.c @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <adc.h> +#include <power/regulator.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define ADC_UCLASS_PLATDATA_SIZE sizeof(struct adc_uclass_platdata) +#define CHECK_NUMBER true +#define CHECK_MASK (!CHECK_NUMBER) + +/* TODO: add support for timer uclass (for early calls) */ +#ifdef CONFIG_SANDBOX_ARCH +#define sdelay(x) udelay(x) +#else +extern void sdelay(unsigned long loops); +#endif + +static int check_channel(struct udevice *dev, int value, bool number_or_mask, + const char *caller_function) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + unsigned mask = number_or_mask ? (1 << value) : value; + + /* For the real ADC hardware, some ADC channels can be inactive. + * For example if device has 4 analog channels, and only channels + * 1-st and 3-rd are valid, then channel mask is: 0b1010, so request + * with mask 0b1110 should return an error. + */ + if ((uc_pdata->channel_mask >= mask) && (uc_pdata->channel_mask & mask)) + return 0; + + printf("Error in %s/%s().\nWrong channel selection for device: %s\n", + __FILE__, caller_function, dev->name); + + return -EINVAL; +} + +static int adc_supply_enable(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + const char *supply_type; + int ret = 0; + + if (uc_pdata->vdd_supply) { + supply_type = "vdd"; + ret = regulator_set_enable(uc_pdata->vdd_supply, true); + } + + if (!ret && uc_pdata->vss_supply) { + supply_type = "vss"; + ret = regulator_set_enable(uc_pdata->vss_supply, true); + } + + if (ret) + error("%s: can't enable %s-supply!", dev->name, supply_type); + + return ret; +} + +int adc_data_mask(struct udevice *dev, unsigned int *data_mask) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + + if (!uc_pdata) + return -ENOSYS; + + *data_mask = uc_pdata->data_mask; + return 0; +} + +int adc_stop(struct udevice *dev) +{ + const struct adc_ops *ops = dev_get_driver_ops(dev); + + if (!ops->stop) + return -ENOSYS; + + return ops->stop(dev); +} + +int adc_start_channel(struct udevice *dev, int channel) +{ + const struct adc_ops *ops = dev_get_driver_ops(dev); + int ret; + + if (!ops->start_channel) + return -ENOSYS; + + ret = check_channel(dev, channel, CHECK_NUMBER, __func__); + if (ret) + return ret; + + ret = adc_supply_enable(dev); + if (ret) + return ret; + + return ops->start_channel(dev, channel); +} + +int adc_start_channels(struct udevice *dev, unsigned int channel_mask) +{ + const struct adc_ops *ops = dev_get_driver_ops(dev); + int ret; + + if (!ops->start_channels) + return -ENOSYS; + + ret = check_channel(dev, channel_mask, CHECK_MASK, __func__); + if (ret) + return ret; + + ret = adc_supply_enable(dev); + if (ret) + return ret; + + return ops->start_channels(dev, channel_mask); +} + +int adc_channel_data(struct udevice *dev, int channel, unsigned int *data) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + const struct adc_ops *ops = dev_get_driver_ops(dev); + unsigned int timeout_us = uc_pdata->data_timeout_us; + int ret; + + if (!ops->channel_data) + return -ENOSYS; + + ret = check_channel(dev, channel, CHECK_NUMBER, __func__); + if (ret) + return ret; + + do { + ret = ops->channel_data(dev, channel, data); + if (!ret || ret != -EBUSY) + break; + + /* TODO: use timer uclass (for early calls). */ + sdelay(5); + } while (timeout_us--); + + return ret; +} + +int adc_channels_data(struct udevice *dev, unsigned int channel_mask, + struct adc_channel *channels) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + unsigned int timeout_us = uc_pdata->multidata_timeout_us; + const struct adc_ops *ops = dev_get_driver_ops(dev); + int ret; + + if (!ops->channels_data) + return -ENOSYS; + + ret = check_channel(dev, channel_mask, CHECK_MASK, __func__); + if (ret) + return ret; + + do { + ret = ops->channels_data(dev, channel_mask, channels); + if (!ret || ret != -EBUSY) + break; + + /* TODO: use timer uclass (for early calls). */ + sdelay(5); + } while (timeout_us--); + + return ret; +} + +int adc_channel_single_shot(const char *name, int channel, unsigned int *data) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev); + if (ret) + return ret; + + ret = adc_start_channel(dev, channel); + if (ret) + return ret; + + ret = adc_channel_data(dev, channel, data); + if (ret) + return ret; + + return 0; +} + +static int _adc_channels_single_shot(struct udevice *dev, + unsigned int channel_mask, + struct adc_channel *channels) +{ + unsigned int data; + int channel, ret; + + for (channel = 0; channel <= ADC_MAX_CHANNEL; channel++) { + /* Check channel bit. */ + if (!((channel_mask >> channel) & 0x1)) + continue; + + ret = adc_start_channel(dev, channel); + if (ret) + return ret; + + ret = adc_channel_data(dev, channel, &data); + if (ret) + return ret; + + channels->id = channel; + channels->data = data; + channels++; + } + + return 0; +} + +int adc_channels_single_shot(const char *name, unsigned int channel_mask, + struct adc_channel *channels) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev); + if (ret) + return ret; + + ret = adc_start_channels(dev, channel_mask); + if (ret) + goto try_manual; + + ret = adc_channels_data(dev, channel_mask, channels); + if (ret) + return ret; + + return 0; + +try_manual: + if (ret != -ENOSYS) + return ret; + + return _adc_channels_single_shot(dev, channel_mask, channels); +} + +static int adc_vdd_platdata_update(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + int ret; + + /* Warning! + * This function can't return supply device before its bind. + * Please pay attention to proper fdt scan sequence. If ADC device + * will bind before its supply regulator device, then the below 'get' + * will return an error. + */ + ret = device_get_supply_regulator(dev, "vdd-supply", + &uc_pdata->vdd_supply); + if (ret) + return ret; + + ret = regulator_get_value(uc_pdata->vdd_supply); + if (ret < 0) + return ret; + + uc_pdata->vdd_microvolts = ret; + + return 0; +} + +static int adc_vss_platdata_update(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + int ret; + + ret = device_get_supply_regulator(dev, "vss-supply", + &uc_pdata->vss_supply); + if (ret) + return ret; + + ret = regulator_get_value(uc_pdata->vss_supply); + if (ret < 0) + return ret; + + uc_pdata->vss_microvolts = ret; + + return 0; +} + +int adc_vdd_value(struct udevice *dev, int *uV) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + int ret, value_sign = uc_pdata->vdd_polarity_negative ? -1 : 1; + + if (!uc_pdata->vdd_supply) + goto nodev; + + /* Update the regulator Value. */ + ret = adc_vdd_platdata_update(dev); + if (ret) + return ret; +nodev: + if (uc_pdata->vdd_microvolts == -ENODATA) + return -ENODATA; + + *uV = uc_pdata->vdd_microvolts * value_sign; + + return 0; +} + +int adc_vss_value(struct udevice *dev, int *uV) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + int ret, value_sign = uc_pdata->vss_polarity_negative ? -1 : 1; + + if (!uc_pdata->vss_supply) + goto nodev; + + /* Update the regulator Value. */ + ret = adc_vss_platdata_update(dev); + if (ret) + return ret; +nodev: + if (uc_pdata->vss_microvolts == -ENODATA) + return -ENODATA; + + *uV = uc_pdata->vss_microvolts * value_sign; + + return 0; +} + +static int adc_vdd_platdata_set(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + int ret, offset = dev->of_offset; + const void *fdt = gd->fdt_blob; + char *prop; + + prop = "vdd-polarity-negative"; + uc_pdata->vdd_polarity_negative = fdtdec_get_bool(fdt, offset, prop); + + ret = adc_vdd_platdata_update(dev); + if (ret != -ENOENT) + return ret; + + /* No vdd-supply phandle. */ + prop = "vdd-microvolts"; + uc_pdata->vdd_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA); + + return 0; +} + +static int adc_vss_platdata_set(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + int ret, offset = dev->of_offset; + const void *fdt = gd->fdt_blob; + char *prop; + + prop = "vss-polarity-negative"; + uc_pdata->vss_polarity_negative = fdtdec_get_bool(fdt, offset, prop); + + ret = adc_vss_platdata_update(dev); + if (ret != -ENOENT) + return ret; + + /* No vss-supply phandle. */ + prop = "vss-microvolts"; + uc_pdata->vss_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA); + + return 0; +} + +static int adc_pre_probe(struct udevice *dev) +{ + int ret; + + /* Set ADC VDD platdata: polarity, uV, regulator (phandle). */ + ret = adc_vdd_platdata_set(dev); + if (ret) + error("%s: Can't update Vdd. Error: %d", dev->name, ret); + + /* Set ADC VSS platdata: polarity, uV, regulator (phandle). */ + ret = adc_vss_platdata_set(dev); + if (ret) + error("%s: Can't update Vss. Error: %d", dev->name, ret); + + return 0; +} + +UCLASS_DRIVER(adc) = { + .id = UCLASS_ADC, + .name = "adc", + .pre_probe = adc_pre_probe, + .per_device_platdata_auto_alloc_size = ADC_UCLASS_PLATDATA_SIZE, +}; diff --git a/include/adc.h b/include/adc.h new file mode 100644 index 0000000..4b14017 --- /dev/null +++ b/include/adc.h @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ADC_H_ +#define _ADC_H_ + +/* ADC_CHANNEL() - ADC channel bit mask, to select only required channels */ +#define ADC_CHANNEL(x) (1 << x) + +/* The last possible selected channel with 32-bit mask */ +#define ADC_MAX_CHANNEL 31 + +/** + * adc_data_format: define the ADC output data format, can be useful when + * the device's input Voltage range is bipolar. + * - ADC_DATA_FORMAT_BIN - binary offset + * - ADC_DATA_FORMAT_2S - two's complement + * + * Note: Device's driver should fill the 'data_format' field of its uclass's + * platform data using one of the above data format types. + */ +enum adc_data_format { + ADC_DATA_FORMAT_BIN, + ADC_DATA_FORMAT_2S, +}; + +/** + * struct adc_channel - structure to hold channel conversion data. + * Useful to keep the result of a multi-channel conversion output. + * + * @id - channel id + * @data - channel conversion data + */ +struct adc_channel { + int id; + unsigned int data; +}; + +/** + * struct adc_uclass_platdata - basic ADC info + * + * Note: The positive/negative reference Voltage is only a name and it doesn't + * provide an information about the value polarity. It is possible, for both + * values to be a negative or positive. For this purpose the uclass's platform + * data provides a bool fields: 'vdd/vss_supply_is_negative'. This is useful, + * since the regulator API returns only a positive Voltage values. + * + * To get the reference Voltage values with polarity, use functions: + * - adc_vdd_value() + * - adc_vss_value() + * Those are useful for some cases of ADC's references, e.g.: + * * Vdd: +3.3V; Vss: -3.3V -> 6.6 Vdiff + * * Vdd: +3.3V; Vss: +0.3V -> 3.0 Vdiff + * * Vdd: +3.3V; Vss: 0.0V -> 3.3 Vdiff + * The last one is usually standard and doesn't require the fdt polarity info. + * + * For more informations read binding info: + * - doc/device-tree-bindings/adc/adc.txt + * + * @data_mask - conversion output data mask + * @data_timeout_us - single channel conversion timeout + * @multidata_timeout_us - multi channel conversion timeout + * @channel_mask - bit mask of available channels [0:31] + * @vdd_supply - positive reference Voltage supply (regulator) + * @vss_supply - negative reference Voltage supply (regulator) + * @vdd_polarity_negative - positive reference Voltage has negative polarity + * @vss_polarity_negative - negative reference Voltage has negative polarity + * @vdd_microvolts - positive reference Voltage value + * @vss_microvolts - negative reference Voltage value + */ +struct adc_uclass_platdata { + int data_format; + unsigned int data_mask; + unsigned int data_timeout_us; + unsigned int multidata_timeout_us; + unsigned int channel_mask; + struct udevice *vdd_supply; + struct udevice *vss_supply; + bool vdd_polarity_negative; + bool vss_polarity_negative; + int vdd_microvolts; + int vss_microvolts; +}; + +/** + * struct adc_ops - ADC device operations for single/multi-channel operation. + */ +struct adc_ops { + /** + * start_channel() - start conversion with its default parameters + * for the given channel number. + * + * @dev: ADC device to init + * @channel: analog channel number + * @return: 0 if OK, -ve on error + */ + int (*start_channel)(struct udevice *dev, int channel); + + /** + * start_channels() - start conversion with its default parameters + * for the channel numbers selected by the bit mask. + * + * This is optional, useful when the hardware supports multichannel + * conversion by the single software trigger. + * + * @dev: ADC device to init + * @channel_mask: bit mask of selected analog channels + * @return: 0 if OK, -ve on error + */ + int (*start_channels)(struct udevice *dev, unsigned int channel_mask); + + /** + * channel_data() - get conversion output data for the given channel. + * + * Note: The implementation of this function should only check, that + * the conversion data is available at the call time. If the hardware + * requires some delay to get the data, then this function should + * return with -EBUSY value. The ADC API will call it in a loop, + * until the data is available or the timeout expires. The maximum + * timeout for this operation is defined by the field 'data_timeout_us' + * in ADC uclasses platform data structure. + * + * @dev: ADC device to trigger + * @channel: selected analog channel number + * @data: returned pointer to selected channel's output data + * @return: 0 if OK, -EBUSY if busy, and other negative on error + */ + int (*channel_data)(struct udevice *dev, int channel, + unsigned int *data); + + /** + * channels_data() - get conversion data for the selected channels. + * + * This is optional, useful when multichannel conversion is supported + * by the hardware, by the single software trigger. + * + * For the proper implementation, please look at the 'Note' for the + * above method. The only difference is in used timeout value, which + * is defined by field 'multidata_timeout_us'. + * + * @dev: ADC device to trigger + * @channel_mask: bit mask of selected analog channels + * @channels: returned pointer to array of output data for channels + * selected by the given mask + * @return: 0 if OK, -ve on error + */ + int (*channels_data)(struct udevice *dev, unsigned int channel_mask, + struct adc_channel *channels); + + /** + * stop() - stop conversion of the given ADC device + * + * @dev: ADC device to stop + * @return: 0 if OK, -ve on error + */ + int (*stop)(struct udevice *dev); +}; + +/** + * adc_start_channel() - start conversion for given device/channel and exit. + * + * @dev: ADC device + * @channel: analog channel number + * @return: 0 if OK, -ve on error + */ +int adc_start_channel(struct udevice *dev, int channel); + +/** + * adc_start_channels() - start conversion for given device/channels and exit. + * + * Note: + * To use this function, device must implement method: start_channels(). + * + * @dev: ADC device to start + * @channel_mask: channel selection - a bit mask + * @channel_mask: bit mask of analog channels + * @return: 0 if OK, -ve on error + */ +int adc_start_channels(struct udevice *dev, unsigned int channel_mask); + +/** + * adc_channel_data() - get conversion data for the given device channel number. + * + * @dev: ADC device to read + * @channel: analog channel number + * @data: pointer to returned channel's data + * @return: 0 if OK, -ve on error + */ +int adc_channel_data(struct udevice *dev, int channel, unsigned int *data); + +/** + * adc_channels_data() - get conversion data for the channels selected by mask + * + * Note: + * To use this function, device must implement methods: + * - start_channels() + * - channels_data() + * + * @dev: ADC device to read + * @channel_mask: channel selection - a bit mask + * @channels: pointer to structure array of returned data for each channel + * @return: 0 if OK, -ve on error + */ +int adc_channels_data(struct udevice *dev, unsigned int channel_mask, + struct adc_channel *channels); + +/** + * adc_data_mask() - get data mask (ADC resolution bitmask) for given ADC device + * + * This can be used if adc uclass platform data is filled. + * + * @dev: ADC device to check + * @data_mask: pointer to the returned data bitmask + * @return: 0 if OK, -ve on error + */ +int adc_data_mask(struct udevice *dev, unsigned int *data_mask); + +/** + * adc_channel_single_shot() - get output data of conversion for the ADC + * device's channel. This function searches for the device with the given name, + * starts the given channel conversion and returns the output data. + * + * Note: To use this function, device must implement metods: + * - start_channel() + * - channel_data() + * + * @name: device's name to search + * @channel: device's input channel to init + * @data: pointer to conversion output data + * @return: 0 if OK, -ve on error + */ +int adc_channel_single_shot(const char *name, int channel, unsigned int *data); + +/** + * adc_channels_single_shot() - get ADC conversion output data for the selected + * device's channels. This function searches for the device by the given name, + * starts the selected channels conversion and returns the output data as array + * of type 'struct adc_channel'. + * + * Note: This function can be used if device implements one of ADC's single + * or multi-channel operation API. If multi-channel operation is not supported, + * then each selected channel is triggered by the sequence start/data in a loop. + * + * @name: device's name to search + * @channel_mask: channel selection - a bit mask + * @channels: pointer to conversion output data for the selected channels + * @return: 0 if OK, -ve on error + */ +int adc_channels_single_shot(const char *name, unsigned int channel_mask, + struct adc_channel *channels); + +/** + * adc_vdd_value() - get the ADC device's positive reference Voltage value + * + * Note: Depending on bool value 'vdd_supply_is_negative' of platform data, + * the returned uV value can be negative, and it's not an error. + * + * @dev: ADC device to check + * @uV: Voltage value with polarization sign (uV) + * @return: 0 on success or -ve on error +*/ +int adc_vdd_value(struct udevice *dev, int *uV); + +/** + * adc_vss_value() - get the ADC device's negative reference Voltage value + * + * Note: Depending on bool value 'vdd_supply_is_negative' of platform data, + * the returned uV value can be negative, and it's not an error. + * + * @dev: ADC device to check + * @uV: Voltage value with polarization sign (uV) + * @return: 0 on success or -ve on error +*/ +int adc_vss_value(struct udevice *dev, int *uV); + +/** + * adc_stop() - stop operation for given ADC device. + * + * @dev: ADC device to stop + * @return: 0 if OK, -ve on error + */ +int adc_stop(struct udevice *dev); + +#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 886a44c..d0cf4ce 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -25,6 +25,7 @@ enum uclass_id { UCLASS_SIMPLE_BUS, /* bus with child devices */
/* U-Boot uclasses start here - in alphabetical order */ + UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_CLK, /* Clock source, e.g. used by peripherals */ UCLASS_CPU, /* CPU, typically part of an SoC */ UCLASS_CROS_EC, /* Chrome OS EC */

Hello all,
On 10/27/2015 01:08 PM, Przemyslaw Marczak wrote:
This commit adds:
- new uclass id: UCLASS_ADC
- new uclass driver: drivers/adc/adc-uclass.c
The new uclass's API allows for ADC operation on:
- single-channel with channel selection by a number
- multti-channel with channel selection by bit mask
ADC uclass's functions:
- single-channel:
- adc_start_channel() - start channel conversion
- adc_channel_data() - get conversion data
- adc_channel_single_shot() - start/get conversion data
- multi-channel:
- adc_start_channels() - start selected channels conversion
- adc_channels_data() - get conversion data
- adc_channels_single_shot() - start/get conversion data for channels selected by bit mask
- general:
- adc_stop() - stop the conversion
- adc_vdd_value() - positive reference Voltage value with polarity [uV]
- adc_vss_value() - negative reference Voltage value with polarity [uV]
- adc_data_mask() - conversion data bit mask
The device tree can provide below constraints/properties:
- vdd-polarity-negative: if true: Vdd = vdd-microvolts * (-1)
- vss-polarity-negative: if true: Vss = vss-microvolts * (-1)
- vdd-supply: phandle to Vdd regulator's node
- vss-supply: phandle to Vss regulator's node
And optional, checked only if the above corresponding, doesn't exist:
- vdd-microvolts: positive reference Voltage [uV]
- vss-microvolts: negative reference Voltage [uV]
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit - introduce ADC uclass driver
Changes V3:
- Add binding info
- ADC uclass's code rework, add single/multi-channel API
- Select single channel by a number and multi, by a bit mask
- Wait for conversion end in uclass's internal function
- Add ADC supply polarity constraint
- Add function for getting supply Voltage with polarity
doc/device-tree-bindings/adc/adc.txt | 62 ++++++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 12 + drivers/adc/Makefile | 8 + drivers/adc/adc-uclass.c | 409 +++++++++++++++++++++++++++++++++++ include/adc.h | 288 ++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 8 files changed, 783 insertions(+) create mode 100644 doc/device-tree-bindings/adc/adc.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 include/adc.h
--- cut ---
diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c new file mode 100644 index 0000000..9233fcd --- /dev/null +++ b/drivers/adc/adc-uclass.c @@ -0,0 +1,409 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <adc.h> +#include <power/regulator.h>
+DECLARE_GLOBAL_DATA_PTR;
+#define ADC_UCLASS_PLATDATA_SIZE sizeof(struct adc_uclass_platdata) +#define CHECK_NUMBER true +#define CHECK_MASK (!CHECK_NUMBER)
+/* TODO: add support for timer uclass (for early calls) */ +#ifdef CONFIG_SANDBOX_ARCH +#define sdelay(x) udelay(x) +#else +extern void sdelay(unsigned long loops); +#endif
--- cut ---
I would like precise the sdelay() calls in this code.
I didn't make the cleanup for the sdelay(), as Simon requested.
For some architectures it's declared in a different headers, but we have timer uclass now, so this sdelay mess can be used temporary.
Now, I don't have time for moving Exynos timer to driver model. And also it should be done as a separated patch set.
Best regards,

Hi Przemyslaw,
On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds:
- new uclass id: UCLASS_ADC
- new uclass driver: drivers/adc/adc-uclass.c
The new uclass's API allows for ADC operation on:
- single-channel with channel selection by a number
- multti-channel with channel selection by bit mask
ADC uclass's functions:
- single-channel:
- adc_start_channel() - start channel conversion
- adc_channel_data() - get conversion data
- adc_channel_single_shot() - start/get conversion data
- multi-channel:
- adc_start_channels() - start selected channels conversion
- adc_channels_data() - get conversion data
- adc_channels_single_shot() - start/get conversion data for channels selected by bit mask
- general:
- adc_stop() - stop the conversion
- adc_vdd_value() - positive reference Voltage value with polarity [uV]
- adc_vss_value() - negative reference Voltage value with polarity [uV]
- adc_data_mask() - conversion data bit mask
The device tree can provide below constraints/properties:
- vdd-polarity-negative: if true: Vdd = vdd-microvolts * (-1)
- vss-polarity-negative: if true: Vss = vss-microvolts * (-1)
- vdd-supply: phandle to Vdd regulator's node
- vss-supply: phandle to Vss regulator's node
And optional, checked only if the above corresponding, doesn't exist:
- vdd-microvolts: positive reference Voltage [uV]
- vss-microvolts: negative reference Voltage [uV]
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org
Some comments below.
Changes V2:
- new commit - introduce ADC uclass driver
Changes V3:
- Add binding info
- ADC uclass's code rework, add single/multi-channel API
- Select single channel by a number and multi, by a bit mask
- Wait for conversion end in uclass's internal function
- Add ADC supply polarity constraint
- Add function for getting supply Voltage with polarity
doc/device-tree-bindings/adc/adc.txt | 62 ++++++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 12 + drivers/adc/Makefile | 8 + drivers/adc/adc-uclass.c | 409 +++++++++++++++++++++++++++++++++++ include/adc.h | 288 ++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 8 files changed, 783 insertions(+) create mode 100644 doc/device-tree-bindings/adc/adc.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 include/adc.h
diff --git a/doc/device-tree-bindings/adc/adc.txt b/doc/device-tree-bindings/adc/adc.txt new file mode 100644 index 0000000..463de3c --- /dev/null +++ b/doc/device-tree-bindings/adc/adc.txt @@ -0,0 +1,62 @@ +ADC device binding
+There are no mandatory properties for ADC. However, if Voltage info is required, +then there are two options: +- use microvolts constraint or +- use regulator phandle to enable/read supply's Voltage
+Properties and constraints: +*optional and always checked, Voltage polarity info: +- vdd-polarity-negative: positive reference Voltage has a negative polarity +- vss-polarity-negative: negative reference Voltage has a negative polarity
+Chose one option, for each supply (Vdd/Vss):
+*optional and always checked, supply Voltage constants: +- vdd-supply: phandle to Vdd regulator's node +- vss-supply: phandle to Vss regulator's node
+*optional and checked only if the above corresponding, doesn't exist: +- vdd-microvolts: positive reference Voltage value [uV] +- vss-microvolts: negative reference Voltage value [uV]
+Example with constant 'Vdd' value: +adc@1000000 {
compatible = "some-adc";
reg = <0xaabb000 0x100>;
status = "enabled";
vdd-microvolts = <1800000>;
+};
+Example of supply phandle usage, for the ADC's VDD/VSS references as below:
- |Sandbox| |Sandbox|
- : PMIC : : ADC :
- . . . .
- | | (Vdd) | AIN0|-->
- | BUCK2|-------|VDDref |
- | (3.3V)| _|VSSref |
- |_______| | |_______|
_|_
+For the above PMIC, the node can be defined as follows: +sandbox_pmic {
compatible = "sandbox,pmic";
...
buck2: buck2 {
regulator-name = "SUPPLY_3.3V";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
...
+};
+For the above ADC, the node can be defined as follows: +adc@0 {
compatible = "sandbox,adc";
vdd-supply = <&buck2>;
vss-microvolts = <0>;
+};
+The ADC uclass code, will enable the supply before start of the conversion, +but it will not configure the regulator settings. diff --git a/drivers/Kconfig b/drivers/Kconfig index ba88b5e..c481e93 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -4,6 +4,8 @@ source "drivers/core/Kconfig"
# types of drivers sorted in alphabetical order
+source "drivers/adc/Kconfig"
source "drivers/block/Kconfig"
source "drivers/clk/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 4f49bfd..ad29a4f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
else
+obj-y += adc/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig new file mode 100644 index 0000000..b6e226a --- /dev/null +++ b/drivers/adc/Kconfig @@ -0,0 +1,12 @@ +config ADC
bool "Enable ADC drivers using Driver Model"
help
This enables ADC API for drivers, which allows driving ADC features
by single and multi-channel methods for:
- start/stop/get data for conversion of a single-channel selected by
a number or multi-channels selected by a bitmask
- get data mask (ADC resolution)
ADC reference Voltage supply options:
- methods for get Vdd/Vss reference Voltage values with polarity
- support supply's phandle with auto-enable
- supply polarity setting in fdt
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile new file mode 100644 index 0000000..c4d9618 --- /dev/null +++ b/drivers/adc/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2015 Samsung Electronics +# Przemyslaw Marczak p.marczak@samsung.com +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_ADC) += adc-uclass.o diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c new file mode 100644 index 0000000..9233fcd --- /dev/null +++ b/drivers/adc/adc-uclass.c @@ -0,0 +1,409 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <adc.h>
That should go below common.h
+#include <power/regulator.h>
+DECLARE_GLOBAL_DATA_PTR;
+#define ADC_UCLASS_PLATDATA_SIZE sizeof(struct adc_uclass_platdata)
Please drop this and just use sizeof() where needed.
+#define CHECK_NUMBER true +#define CHECK_MASK (!CHECK_NUMBER)
What are those for? I think you should convert this to an enum:
enum some_name_t { CHECK_NUMBER, CHECK_MASK }
and use an enum parameter instead of bool.
+/* TODO: add support for timer uclass (for early calls) */
TODO(email):
so we know who is going to send the follow-up patch.
+#ifdef CONFIG_SANDBOX_ARCH +#define sdelay(x) udelay(x) +#else +extern void sdelay(unsigned long loops); +#endif
+static int check_channel(struct udevice *dev, int value, bool number_or_mask,
const char *caller_function)
What does this function do? I think it needs a function comment.
+{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
unsigned mask = number_or_mask ? (1 << value) : value;
/* For the real ADC hardware, some ADC channels can be inactive.
Comment style
/* * For the....
* For example if device has 4 analog channels, and only channels
* 1-st and 3-rd are valid, then channel mask is: 0b1010, so request
* with mask 0b1110 should return an error.
*/
if ((uc_pdata->channel_mask >= mask) && (uc_pdata->channel_mask & mask))
return 0;
printf("Error in %s/%s().\nWrong channel selection for device: %s\n",
__FILE__, caller_function, dev->name);
return -EINVAL;
+}
+static int adc_supply_enable(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
const char *supply_type;
int ret = 0;
if (uc_pdata->vdd_supply) {
supply_type = "vdd";
ret = regulator_set_enable(uc_pdata->vdd_supply, true);
}
if (!ret && uc_pdata->vss_supply) {
supply_type = "vss";
ret = regulator_set_enable(uc_pdata->vss_supply, true);
}
if (ret)
error("%s: can't enable %s-supply!", dev->name, supply_type);
return ret;
+}
+int adc_data_mask(struct udevice *dev, unsigned int *data_mask) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
if (!uc_pdata)
return -ENOSYS;
*data_mask = uc_pdata->data_mask;
return 0;
+}
+int adc_stop(struct udevice *dev) +{
const struct adc_ops *ops = dev_get_driver_ops(dev);
if (!ops->stop)
return -ENOSYS;
return ops->stop(dev);
+}
+int adc_start_channel(struct udevice *dev, int channel) +{
const struct adc_ops *ops = dev_get_driver_ops(dev);
int ret;
if (!ops->start_channel)
return -ENOSYS;
ret = check_channel(dev, channel, CHECK_NUMBER, __func__);
if (ret)
return ret;
ret = adc_supply_enable(dev);
if (ret)
return ret;
return ops->start_channel(dev, channel);
+}
+int adc_start_channels(struct udevice *dev, unsigned int channel_mask) +{
const struct adc_ops *ops = dev_get_driver_ops(dev);
int ret;
if (!ops->start_channels)
return -ENOSYS;
ret = check_channel(dev, channel_mask, CHECK_MASK, __func__);
if (ret)
return ret;
ret = adc_supply_enable(dev);
if (ret)
return ret;
return ops->start_channels(dev, channel_mask);
+}
+int adc_channel_data(struct udevice *dev, int channel, unsigned int *data) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
const struct adc_ops *ops = dev_get_driver_ops(dev);
unsigned int timeout_us = uc_pdata->data_timeout_us;
int ret;
if (!ops->channel_data)
return -ENOSYS;
ret = check_channel(dev, channel, CHECK_NUMBER, __func__);
if (ret)
return ret;
do {
ret = ops->channel_data(dev, channel, data);
if (!ret || ret != -EBUSY)
break;
/* TODO: use timer uclass (for early calls). */
Remove '.'
sdelay(5);
} while (timeout_us--);
return ret;
+}
+int adc_channels_data(struct udevice *dev, unsigned int channel_mask,
struct adc_channel *channels)
+{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
unsigned int timeout_us = uc_pdata->multidata_timeout_us;
const struct adc_ops *ops = dev_get_driver_ops(dev);
int ret;
if (!ops->channels_data)
return -ENOSYS;
ret = check_channel(dev, channel_mask, CHECK_MASK, __func__);
if (ret)
return ret;
do {
ret = ops->channels_data(dev, channel_mask, channels);
if (!ret || ret != -EBUSY)
break;
/* TODO: use timer uclass (for early calls). */
sdelay(5);
} while (timeout_us--);
return ret;
+}
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data) +{
struct udevice *dev;
int ret;
ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
if (ret)
return ret;
ret = adc_start_channel(dev, channel);
if (ret)
return ret;
ret = adc_channel_data(dev, channel, data);
if (ret)
return ret;
return 0;
+}
+static int _adc_channels_single_shot(struct udevice *dev,
unsigned int channel_mask,
struct adc_channel *channels)
+{
unsigned int data;
int channel, ret;
for (channel = 0; channel <= ADC_MAX_CHANNEL; channel++) {
/* Check channel bit. */
if (!((channel_mask >> channel) & 0x1))
continue;
ret = adc_start_channel(dev, channel);
if (ret)
return ret;
ret = adc_channel_data(dev, channel, &data);
if (ret)
return ret;
channels->id = channel;
channels->data = data;
channels++;
}
return 0;
+}
+int adc_channels_single_shot(const char *name, unsigned int channel_mask,
struct adc_channel *channels)
+{
struct udevice *dev;
int ret;
ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
if (ret)
return ret;
ret = adc_start_channels(dev, channel_mask);
if (ret)
goto try_manual;
ret = adc_channels_data(dev, channel_mask, channels);
if (ret)
return ret;
return 0;
+try_manual:
if (ret != -ENOSYS)
return ret;
return _adc_channels_single_shot(dev, channel_mask, channels);
+}
+static int adc_vdd_platdata_update(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
int ret;
/* Warning!
* This function can't return supply device before its bind.
* Please pay attention to proper fdt scan sequence. If ADC device
* will bind before its supply regulator device, then the below 'get'
* will return an error.
*/
How could this happen? Is this function called before the device is probed?
It seems to be called from adc_pre_probe(), by which time all devices should be bound.
ret = device_get_supply_regulator(dev, "vdd-supply",
&uc_pdata->vdd_supply);
if (ret)
return ret;
ret = regulator_get_value(uc_pdata->vdd_supply);
if (ret < 0)
return ret;
uc_pdata->vdd_microvolts = ret;
return 0;
+}
+static int adc_vss_platdata_update(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
int ret;
ret = device_get_supply_regulator(dev, "vss-supply",
&uc_pdata->vss_supply);
if (ret)
return ret;
ret = regulator_get_value(uc_pdata->vss_supply);
if (ret < 0)
return ret;
uc_pdata->vss_microvolts = ret;
return 0;
+}
+int adc_vdd_value(struct udevice *dev, int *uV) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
int ret, value_sign = uc_pdata->vdd_polarity_negative ? -1 : 1;
if (!uc_pdata->vdd_supply)
goto nodev;
/* Update the regulator Value. */
ret = adc_vdd_platdata_update(dev);
if (ret)
return ret;
+nodev:
if (uc_pdata->vdd_microvolts == -ENODATA)
return -ENODATA;
*uV = uc_pdata->vdd_microvolts * value_sign;
return 0;
+}
+int adc_vss_value(struct udevice *dev, int *uV) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
int ret, value_sign = uc_pdata->vss_polarity_negative ? -1 : 1;
if (!uc_pdata->vss_supply)
goto nodev;
/* Update the regulator Value. */
ret = adc_vss_platdata_update(dev);
if (ret)
return ret;
+nodev:
if (uc_pdata->vss_microvolts == -ENODATA)
return -ENODATA;
*uV = uc_pdata->vss_microvolts * value_sign;
return 0;
+}
+static int adc_vdd_platdata_set(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
int ret, offset = dev->of_offset;
const void *fdt = gd->fdt_blob;
char *prop;
prop = "vdd-polarity-negative";
Can you just drop this variable and use the string?
uc_pdata->vdd_polarity_negative = fdtdec_get_bool(fdt, offset, prop);
ret = adc_vdd_platdata_update(dev);
if (ret != -ENOENT)
return ret;
/* No vdd-supply phandle. */
prop = "vdd-microvolts";
uc_pdata->vdd_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA);
return 0;
+}
+static int adc_vss_platdata_set(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
int ret, offset = dev->of_offset;
const void *fdt = gd->fdt_blob;
char *prop;
prop = "vss-polarity-negative";
Can you just drop this variable and use the string?
uc_pdata->vss_polarity_negative = fdtdec_get_bool(fdt, offset, prop);
ret = adc_vss_platdata_update(dev);
if (ret != -ENOENT)
return ret;
/* No vss-supply phandle. */
prop = "vss-microvolts";
uc_pdata->vss_microvolts = fdtdec_get_int(fdt, offset, prop, -ENODATA);
return 0;
+}
+static int adc_pre_probe(struct udevice *dev) +{
int ret;
/* Set ADC VDD platdata: polarity, uV, regulator (phandle). */
ret = adc_vdd_platdata_set(dev);
if (ret)
error("%s: Can't update Vdd. Error: %d", dev->name, ret);
Shouldn't this return ret?
/* Set ADC VSS platdata: polarity, uV, regulator (phandle). */
ret = adc_vss_platdata_set(dev);
if (ret)
error("%s: Can't update Vss. Error: %d", dev->name, ret);
and here?
return 0;
+}
+UCLASS_DRIVER(adc) = {
.id = UCLASS_ADC,
.name = "adc",
.pre_probe = adc_pre_probe,
.per_device_platdata_auto_alloc_size = ADC_UCLASS_PLATDATA_SIZE,
+}; diff --git a/include/adc.h b/include/adc.h new file mode 100644 index 0000000..4b14017 --- /dev/null +++ b/include/adc.h @@ -0,0 +1,288 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _ADC_H_ +#define _ADC_H_
+/* ADC_CHANNEL() - ADC channel bit mask, to select only required channels */ +#define ADC_CHANNEL(x) (1 << x)
(1U << (x))
+/* The last possible selected channel with 32-bit mask */ +#define ADC_MAX_CHANNEL 31
Can we use ADC_MAX_CHANNELS = 32 instead? You can adjust to for loop to use < instead of <=.
+/**
- adc_data_format: define the ADC output data format, can be useful when
- the device's input Voltage range is bipolar.
- ADC_DATA_FORMAT_BIN - binary offset
- ADC_DATA_FORMAT_2S - two's complement
- Note: Device's driver should fill the 'data_format' field of its uclass's
- platform data using one of the above data format types.
- */
+enum adc_data_format {
ADC_DATA_FORMAT_BIN,
ADC_DATA_FORMAT_2S,
+};
+/**
- struct adc_channel - structure to hold channel conversion data.
- Useful to keep the result of a multi-channel conversion output.
- @id - channel id
- @data - channel conversion data
- */
+struct adc_channel {
int id;
unsigned int data;
+};
+/**
- struct adc_uclass_platdata - basic ADC info
- Note: The positive/negative reference Voltage is only a name and it doesn't
- provide an information about the value polarity. It is possible, for both
- values to be a negative or positive. For this purpose the uclass's platform
- data provides a bool fields: 'vdd/vss_supply_is_negative'. This is useful,
- since the regulator API returns only a positive Voltage values.
- To get the reference Voltage values with polarity, use functions:
- adc_vdd_value()
- adc_vss_value()
- Those are useful for some cases of ADC's references, e.g.:
- Vdd: +3.3V; Vss: -3.3V -> 6.6 Vdiff
- Vdd: +3.3V; Vss: +0.3V -> 3.0 Vdiff
- Vdd: +3.3V; Vss: 0.0V -> 3.3 Vdiff
- The last one is usually standard and doesn't require the fdt polarity info.
- For more informations read binding info:
information
- doc/device-tree-bindings/adc/adc.txt
- @data_mask - conversion output data mask
Use : rather than -
@data_mask: conversion output data mask
- @data_timeout_us - single channel conversion timeout
- @multidata_timeout_us - multi channel conversion timeout
- @channel_mask - bit mask of available channels [0:31]
- @vdd_supply - positive reference Voltage supply (regulator)
- @vss_supply - negative reference Voltage supply (regulator)
- @vdd_polarity_negative - positive reference Voltage has negative polarity
- @vss_polarity_negative - negative reference Voltage has negative polarity
- @vdd_microvolts - positive reference Voltage value
- @vss_microvolts - negative reference Voltage value
- */
+struct adc_uclass_platdata {
int data_format;
unsigned int data_mask;
unsigned int data_timeout_us;
unsigned int multidata_timeout_us;
unsigned int channel_mask;
struct udevice *vdd_supply;
struct udevice *vss_supply;
bool vdd_polarity_negative;
bool vss_polarity_negative;
int vdd_microvolts;
Would vdd_uv be good enough?
int vss_microvolts;
+};
+/**
- struct adc_ops - ADC device operations for single/multi-channel operation.
- */
+struct adc_ops {
/**
* start_channel() - start conversion with its default parameters
* for the given channel number.
*
* @dev: ADC device to init
* @channel: analog channel number
* @return: 0 if OK, -ve on error
*/
int (*start_channel)(struct udevice *dev, int channel);
/**
* start_channels() - start conversion with its default parameters
* for the channel numbers selected by the bit mask.
*
* This is optional, useful when the hardware supports multichannel
* conversion by the single software trigger.
*
* @dev: ADC device to init
* @channel_mask: bit mask of selected analog channels
* @return: 0 if OK, -ve on error
*/
int (*start_channels)(struct udevice *dev, unsigned int channel_mask);
/**
* channel_data() - get conversion output data for the given channel.
*
* Note: The implementation of this function should only check, that
* the conversion data is available at the call time. If the hardware
* requires some delay to get the data, then this function should
* return with -EBUSY value. The ADC API will call it in a loop,
* until the data is available or the timeout expires. The maximum
* timeout for this operation is defined by the field 'data_timeout_us'
* in ADC uclasses platform data structure.
*
* @dev: ADC device to trigger
* @channel: selected analog channel number
* @data: returned pointer to selected channel's output data
* @return: 0 if OK, -EBUSY if busy, and other negative on error
*/
int (*channel_data)(struct udevice *dev, int channel,
unsigned int *data);
/**
* channels_data() - get conversion data for the selected channels.
*
* This is optional, useful when multichannel conversion is supported
* by the hardware, by the single software trigger.
*
* For the proper implementation, please look at the 'Note' for the
* above method. The only difference is in used timeout value, which
* is defined by field 'multidata_timeout_us'.
*
* @dev: ADC device to trigger
* @channel_mask: bit mask of selected analog channels
* @channels: returned pointer to array of output data for channels
* selected by the given mask
* @return: 0 if OK, -ve on error
*/
int (*channels_data)(struct udevice *dev, unsigned int channel_mask,
struct adc_channel *channels);
/**
* stop() - stop conversion of the given ADC device
*
* @dev: ADC device to stop
* @return: 0 if OK, -ve on error
*/
int (*stop)(struct udevice *dev);
Does this stop all channels? Should update the comment to explain the API better here.
+};
+/**
- adc_start_channel() - start conversion for given device/channel and exit.
- @dev: ADC device
- @channel: analog channel number
- @return: 0 if OK, -ve on error
- */
+int adc_start_channel(struct udevice *dev, int channel);
+/**
- adc_start_channels() - start conversion for given device/channels and exit.
- Note:
- To use this function, device must implement method: start_channels().
- @dev: ADC device to start
- @channel_mask: channel selection - a bit mask
- @channel_mask: bit mask of analog channels
- @return: 0 if OK, -ve on error
- */
+int adc_start_channels(struct udevice *dev, unsigned int channel_mask);
+/**
- adc_channel_data() - get conversion data for the given device channel number.
- @dev: ADC device to read
- @channel: analog channel number
- @data: pointer to returned channel's data
- @return: 0 if OK, -ve on error
- */
+int adc_channel_data(struct udevice *dev, int channel, unsigned int *data);
+/**
- adc_channels_data() - get conversion data for the channels selected by mask
- Note:
- To use this function, device must implement methods:
- start_channels()
- channels_data()
- @dev: ADC device to read
- @channel_mask: channel selection - a bit mask
- @channels: pointer to structure array of returned data for each channel
- @return: 0 if OK, -ve on error
- */
+int adc_channels_data(struct udevice *dev, unsigned int channel_mask,
struct adc_channel *channels);
+/**
- adc_data_mask() - get data mask (ADC resolution bitmask) for given ADC device
- This can be used if adc uclass platform data is filled.
- @dev: ADC device to check
- @data_mask: pointer to the returned data bitmask
- @return: 0 if OK, -ve on error
- */
+int adc_data_mask(struct udevice *dev, unsigned int *data_mask);
+/**
- adc_channel_single_shot() - get output data of conversion for the ADC
- device's channel. This function searches for the device with the given name,
- starts the given channel conversion and returns the output data.
- Note: To use this function, device must implement metods:
- start_channel()
- channel_data()
- @name: device's name to search
- @channel: device's input channel to init
- @data: pointer to conversion output data
- @return: 0 if OK, -ve on error
- */
+int adc_channel_single_shot(const char *name, int channel, unsigned int *data);
+/**
- adc_channels_single_shot() - get ADC conversion output data for the selected
- device's channels. This function searches for the device by the given name,
- starts the selected channels conversion and returns the output data as array
- of type 'struct adc_channel'.
- Note: This function can be used if device implements one of ADC's single
- or multi-channel operation API. If multi-channel operation is not supported,
- then each selected channel is triggered by the sequence start/data in a loop.
- @name: device's name to search
- @channel_mask: channel selection - a bit mask
- @channels: pointer to conversion output data for the selected channels
- @return: 0 if OK, -ve on error
- */
+int adc_channels_single_shot(const char *name, unsigned int channel_mask,
struct adc_channel *channels);
+/**
- adc_vdd_value() - get the ADC device's positive reference Voltage value
- Note: Depending on bool value 'vdd_supply_is_negative' of platform data,
- the returned uV value can be negative, and it's not an error.
- @dev: ADC device to check
- @uV: Voltage value with polarization sign (uV)
- @return: 0 on success or -ve on error
+*/ +int adc_vdd_value(struct udevice *dev, int *uV);
+/**
- adc_vss_value() - get the ADC device's negative reference Voltage value
- Note: Depending on bool value 'vdd_supply_is_negative' of platform data,
- the returned uV value can be negative, and it's not an error.
- @dev: ADC device to check
- @uV: Voltage value with polarization sign (uV)
- @return: 0 on success or -ve on error
+*/ +int adc_vss_value(struct udevice *dev, int *uV);
+/**
- adc_stop() - stop operation for given ADC device.
- @dev: ADC device to stop
- @return: 0 if OK, -ve on error
- */
+int adc_stop(struct udevice *dev);
+#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 886a44c..d0cf4ce 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -25,6 +25,7 @@ enum uclass_id { UCLASS_SIMPLE_BUS, /* bus with child devices */
/* U-Boot uclasses start here - in alphabetical order */
UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_CLK, /* Clock source, e.g. used by peripherals */ UCLASS_CPU, /* CPU, typically part of an SoC */ UCLASS_CROS_EC, /* Chrome OS EC */
-- 1.9.1
Regards, Simon

This commit adds driver for Exynos54xx ADC subsystem.
The driver is implemented using driver model, amd provides ADC uclass's methods for ADC single channel operations: - adc_start_channel() - adc_channel_data() - adc_stop()
The basic parameters of ADC conversion, are: - sample rate: 600KSPS - output the data as average of 8 time conversion
ADC features: - sample rate: 600KSPS - resolution: 12-bit - channels: 10 (analog multiplexer)
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - new commit - move previous adc driver from SoC directory to drivers/adc Changes V3: - rework the driver to fit new API - remove call to sdelay() from driver's code - add active_channel to keep consistency between ADC request and result --- arch/arm/mach-exynos/include/mach/adc.h | 44 ++++++++++ drivers/adc/Kconfig | 9 ++ drivers/adc/Makefile | 1 + drivers/adc/exynos-adc.c | 145 ++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 drivers/adc/exynos-adc.c
diff --git a/arch/arm/mach-exynos/include/mach/adc.h b/arch/arm/mach-exynos/include/mach/adc.h index a0e26d7..9af51ab 100644 --- a/arch/arm/mach-exynos/include/mach/adc.h +++ b/arch/arm/mach-exynos/include/mach/adc.h @@ -9,6 +9,39 @@ #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_MASK 0xf +#define ADC_V2_CON2_CHAN_SEL(x) ((x) & ADC_V2_CON2_CHAN_SEL_MASK) + +#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 +54,17 @@ 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; +}; #endif
#endif /* __ASM_ARM_ARCH_ADC_H_ */ diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index b6e226a..223b65e 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -10,3 +10,12 @@ config ADC - methods for get Vdd/Vss reference Voltage values with polarity - support supply's phandle with auto-enable - supply polarity setting in fdt + +config ADC_EXYNOS + bool "Enable Exynos 54xx ADC driver" + help + This enables basic driver for Exynos ADC compatible with Exynos54xx. + It provides: + - 10 analog input channels + - 12-bit resolution + - 600 KSPS of sample rate diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index c4d9618..eb85b8b 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -6,3 +6,4 @@ #
obj-$(CONFIG_ADC) += adc-uclass.o +obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c new file mode 100644 index 0000000..534e68d --- /dev/null +++ b/drivers/adc/exynos-adc.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <adc.h> +#include <asm/arch/adc.h> + +struct exynos_adc_priv { + int active_channel; + struct exynos_adc_v2 *regs; +}; + +int exynos_adc_channel_data(struct udevice *dev, int channel, + unsigned int *data) +{ + struct exynos_adc_priv *priv = dev_get_priv(dev); + struct exynos_adc_v2 *regs = priv->regs; + + if (channel != priv->active_channel) { + error("Requested channel is not active!"); + return -EINVAL; + } + + if (ADC_V2_GET_STATUS_FLAG(readl(®s->status)) != FLAG_CONV_END) + return -EBUSY; + + *data = readl(®s->dat) & ADC_V2_DAT_MASK; + + return 0; +} + +int exynos_adc_start_channel(struct udevice *dev, int channel) +{ + struct exynos_adc_priv *priv = dev_get_priv(dev); + struct exynos_adc_v2 *regs = priv->regs; + unsigned int cfg; + + /* Choose channel */ + cfg = readl(®s->con2); + cfg &= ~ADC_V2_CON2_CHAN_SEL_MASK; + cfg |= ADC_V2_CON2_CHAN_SEL(channel); + writel(cfg, ®s->con2); + + /* Start conversion */ + cfg = readl(®s->con1); + writel(cfg | ADC_V2_CON1_STC_EN, ®s->con1); + + priv->active_channel = channel; + + return 0; +} + +int exynos_adc_stop(struct udevice *dev) +{ + struct exynos_adc_priv *priv = dev_get_priv(dev); + struct exynos_adc_v2 *regs = priv->regs; + unsigned int cfg; + + /* Stop conversion */ + cfg = readl(®s->con1); + cfg |= ~ADC_V2_CON1_STC_EN; + + writel(cfg, ®s->con1); + + priv->active_channel = -1; + + return 0; +} + +int exynos_adc_probe(struct udevice *dev) +{ + struct exynos_adc_priv *priv = dev_get_priv(dev); + struct exynos_adc_v2 *regs = priv->regs; + unsigned int cfg; + + /* Check HW version */ + if (readl(®s->version) != ADC_V2_VERSION) { + error("This driver supports only ADC v2!"); + return -ENXIO; + } + + /* ADC Reset */ + writel(ADC_V2_CON1_SOFT_RESET, ®s->con1); + + /* Disable INT - will read status only */ + writel(0x0, ®s->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_ESEL(ESEL_ADC_EVAL_TIME_20CLK); + cfg |= ADC_V2_CON2_HIGHF(HIGHF_CONV_RATE_600KSPS); + writel(cfg, ®s->con2); + + priv->active_channel = -1; + + return 0; +} + +int exynos_adc_ofdata_to_platdata(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + struct exynos_adc_priv *priv = dev_get_priv(dev); + + priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev); + if (priv->regs == (struct exynos_adc_v2 *)FDT_ADDR_T_NONE) { + error("Dev: %s - can't get address!", dev->name); + return -ENODATA; + } + + uc_pdata->data_mask = ADC_V2_DAT_MASK; + uc_pdata->data_format = ADC_DATA_FORMAT_BIN; + uc_pdata->data_timeout_us = ADC_V2_CONV_TIMEOUT_US; + + /* Mask available channel bits: [0:9] */ + uc_pdata->channel_mask = (2 << ADC_V2_MAX_CHANNEL) - 1; + + return 0; +} + +static const struct adc_ops exynos_adc_ops = { + .start_channel = exynos_adc_start_channel, + .channel_data = exynos_adc_channel_data, + .stop = exynos_adc_stop, +}; + +static const struct udevice_id exynos_adc_ids[] = { + { .compatible = "samsung,exynos-adc-v2" }, + { } +}; + +U_BOOT_DRIVER(exynos_adc) = { + .name = "exynos-adc", + .id = UCLASS_ADC, + .of_match = exynos_adc_ids, + .ops = &exynos_adc_ops, + .probe = exynos_adc_probe, + .ofdata_to_platdata = exynos_adc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct exynos_adc_priv), +};

On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds driver for Exynos54xx ADC subsystem.
The driver is implemented using driver model, amd provides ADC uclass's methods for ADC single channel operations:
- adc_start_channel()
- adc_channel_data()
- adc_stop()
The basic parameters of ADC conversion, are:
- sample rate: 600KSPS
- output the data as average of 8 time conversion
ADC features:
- sample rate: 600KSPS
- resolution: 12-bit
- channels: 10 (analog multiplexer)
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit - move previous adc driver from SoC directory to drivers/adc
Changes V3:
- rework the driver to fit new API
- remove call to sdelay() from driver's code
- add active_channel to keep consistency between ADC request and result
arch/arm/mach-exynos/include/mach/adc.h | 44 ++++++++++ drivers/adc/Kconfig | 9 ++ drivers/adc/Makefile | 1 + drivers/adc/exynos-adc.c | 145 ++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 drivers/adc/exynos-adc.c
Reviewed-by: Simon Glass sjg@chromium.org
Some things below.
diff --git a/arch/arm/mach-exynos/include/mach/adc.h b/arch/arm/mach-exynos/include/mach/adc.h index a0e26d7..9af51ab 100644 --- a/arch/arm/mach-exynos/include/mach/adc.h +++ b/arch/arm/mach-exynos/include/mach/adc.h @@ -9,6 +9,39 @@ #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_MASK 0xf +#define ADC_V2_CON2_CHAN_SEL(x) ((x) & ADC_V2_CON2_CHAN_SEL_MASK)
+#define ADC_V2_GET_STATUS_FLAG(x) (((x) >> 2) & 0x1)
Can you please avoid these sorts of macro accessors? Instead define:
#define ADC_V2_STATUS_SHIFT 2 #define ADC_V2_STATUS_MASK (1 << ADC_V2_STATUS_SHIFT)
and then you can put the access directly in the code.
+#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 +54,17 @@ 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;
+}; #endif
#endif /* __ASM_ARM_ARCH_ADC_H_ */ diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index b6e226a..223b65e 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -10,3 +10,12 @@ config ADC - methods for get Vdd/Vss reference Voltage values with polarity - support supply's phandle with auto-enable - supply polarity setting in fdt
+config ADC_EXYNOS
bool "Enable Exynos 54xx ADC driver"
help
This enables basic driver for Exynos ADC compatible with Exynos54xx.
It provides:
- 10 analog input channels
- 12-bit resolution
- 600 KSPS of sample rate
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index c4d9618..eb85b8b 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -6,3 +6,4 @@ #
obj-$(CONFIG_ADC) += adc-uclass.o +obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c new file mode 100644 index 0000000..534e68d --- /dev/null +++ b/drivers/adc/exynos-adc.c @@ -0,0 +1,145 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <dm.h> +#include <adc.h>
That should go below common.h
+#include <asm/arch/adc.h>
+struct exynos_adc_priv {
int active_channel;
struct exynos_adc_v2 *regs;
+};
+int exynos_adc_channel_data(struct udevice *dev, int channel,
unsigned int *data)
+{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
if (channel != priv->active_channel) {
error("Requested channel is not active!");
return -EINVAL;
}
if (ADC_V2_GET_STATUS_FLAG(readl(®s->status)) != FLAG_CONV_END)
return -EBUSY;
*data = readl(®s->dat) & ADC_V2_DAT_MASK;
return 0;
+}
+int exynos_adc_start_channel(struct udevice *dev, int channel) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg;
/* Choose channel */
cfg = readl(®s->con2);
cfg &= ~ADC_V2_CON2_CHAN_SEL_MASK;
cfg |= ADC_V2_CON2_CHAN_SEL(channel);
writel(cfg, ®s->con2);
Can you use:
clrsetbits_le32(®s->con2, ADC_V2_CON2_CHAN_SEL_MASK, ADC_V2_CON2_CHAN_SEL(channel))
/* Start conversion */
cfg = readl(®s->con1);
writel(cfg | ADC_V2_CON1_STC_EN, ®s->con1);
setbits_le32
priv->active_channel = channel;
return 0;
+}
+int exynos_adc_stop(struct udevice *dev) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg;
/* Stop conversion */
cfg = readl(®s->con1);
cfg |= ~ADC_V2_CON1_STC_EN;
writel(cfg, ®s->con1);
clrbits_le32
etc.
priv->active_channel = -1;
return 0;
+}
+int exynos_adc_probe(struct udevice *dev) +{
struct exynos_adc_priv *priv = dev_get_priv(dev);
struct exynos_adc_v2 *regs = priv->regs;
unsigned int cfg;
/* Check HW version */
if (readl(®s->version) != ADC_V2_VERSION) {
error("This driver supports only ADC v2!");
return -ENXIO;
}
/* ADC Reset */
writel(ADC_V2_CON1_SOFT_RESET, ®s->con1);
/* Disable INT - will read status only */
writel(0x0, ®s->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_ESEL(ESEL_ADC_EVAL_TIME_20CLK);
cfg |= ADC_V2_CON2_HIGHF(HIGHF_CONV_RATE_600KSPS);
writel(cfg, ®s->con2);
priv->active_channel = -1;
return 0;
+}
+int exynos_adc_ofdata_to_platdata(struct udevice *dev) +{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
struct exynos_adc_priv *priv = dev_get_priv(dev);
priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev);
if (priv->regs == (struct exynos_adc_v2 *)FDT_ADDR_T_NONE) {
error("Dev: %s - can't get address!", dev->name);
return -ENODATA;
}
uc_pdata->data_mask = ADC_V2_DAT_MASK;
uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
uc_pdata->data_timeout_us = ADC_V2_CONV_TIMEOUT_US;
/* Mask available channel bits: [0:9] */
uc_pdata->channel_mask = (2 << ADC_V2_MAX_CHANNEL) - 1;
return 0;
+}
+static const struct adc_ops exynos_adc_ops = {
.start_channel = exynos_adc_start_channel,
.channel_data = exynos_adc_channel_data,
.stop = exynos_adc_stop,
+};
+static const struct udevice_id exynos_adc_ids[] = {
{ .compatible = "samsung,exynos-adc-v2" },
{ }
+};
+U_BOOT_DRIVER(exynos_adc) = {
.name = "exynos-adc",
.id = UCLASS_ADC,
.of_match = exynos_adc_ids,
.ops = &exynos_adc_ops,
.probe = exynos_adc_probe,
.ofdata_to_platdata = exynos_adc_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct exynos_adc_priv),
+};
1.9.1
Regards, Simon

Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - none Chabges V3: - fix merge conflict in configs/odroid-xu3_defconfig --- arch/arm/dts/exynos5422-odroidxu3.dts | 7 +++++++ configs/odroid-xu3_defconfig | 3 +++ 2 files changed, 10 insertions(+)
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts index d0a8621..9dec679 100644 --- a/arch/arm/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/dts/exynos5422-odroidxu3.dts @@ -31,6 +31,13 @@ 0xb0000000 0xea00000>; };
+ i2c@12CA0000 { + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + }; + }; + ehci@12110000 { samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>; }; diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 479af9e..780dcab 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -9,7 +9,10 @@ CONFIG_SYS_PROMPT="ODROID-XU3 # " # CONFIG_CMD_SETEXPR is not set CONFIG_DM_I2C_COMPAT=y CONFIG_DM_PMIC=y +CONFIG_CMD_PMIC=y +CONFIG_ERRNO_STR=y CONFIG_DM_REGULATOR=y +CONFIG_PMIC_S2MPS11=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_VIDEO_BRIDGE=y

hi,
On 27 October 2015 at 17:38, Przemyslaw Marczak p.marczak@samsung.com wrote:
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- none
Chabges V3:
- fix merge conflict in configs/odroid-xu3_defconfig
arch/arm/dts/exynos5422-odroidxu3.dts | 7 +++++++ configs/odroid-xu3_defconfig | 3 +++ 2 files changed, 10 insertions(+)
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts index d0a8621..9dec679 100644 --- a/arch/arm/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/dts/exynos5422-odroidxu3.dts @@ -31,6 +31,13 @@ 0xb0000000 0xea00000>; };
i2c@12CA0000 {
s2mps11_pmic@66 {
compatible = "samsung,s2mps11-pmic";
reg = <0x66>;
};
};
ehci@12110000 { samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>; };
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 479af9e..780dcab 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -9,7 +9,10 @@ CONFIG_SYS_PROMPT="ODROID-XU3 # " # CONFIG_CMD_SETEXPR is not set CONFIG_DM_I2C_COMPAT=y CONFIG_DM_PMIC=y +CONFIG_CMD_PMIC=y +CONFIG_ERRNO_STR=y CONFIG_DM_REGULATOR=y +CONFIG_PMIC_S2MPS11=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_VIDEO_BRIDGE=y -- 1.9.1
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon

This commit adds common ADC node, which is disabled as default.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - new commit --- arch/arm/dts/exynos54xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index bd3619d..daa6a33 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -42,6 +42,13 @@ xhci1 = "/xhci@12400000"; };
+ adc@12D10000 { + compatible = "samsung,exynos-adc-v2"; + reg = <0x12D10000 0x100>; + interrupts = <0 106 0>; + status = "disabled"; + }; + i2c@12CA0000 { #address-cells = <1>; #size-cells = <0>;

On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds common ADC node, which is disabled as default.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit
Reviewed-by: Simon Glass sjg@chromium.org
This does not look like a new commit.
arch/arm/dts/exynos54xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index bd3619d..daa6a33 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -42,6 +42,13 @@ xhci1 = "/xhci@12400000"; };
adc@12D10000 {
compatible = "samsung,exynos-adc-v2";
reg = <0x12D10000 0x100>;
interrupts = <0 106 0>;
status = "disabled";
};
i2c@12CA0000 { #address-cells = <1>; #size-cells = <0>;
-- 1.9.1

Hi Simon,
On 10/28/2015 07:50 PM, Simon Glass wrote:
On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds common ADC node, which is disabled as default.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit
Reviewed-by: Simon Glass sjg@chromium.org
This does not look like a new commit.
This is V3, and the commit was new in V2. I didn't edit commit message if no changes made in V3.
arch/arm/dts/exynos54xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index bd3619d..daa6a33 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -42,6 +42,13 @@ xhci1 = "/xhci@12400000"; };
adc@12D10000 {
compatible = "samsung,exynos-adc-v2";
reg = <0x12D10000 0x100>;
interrupts = <0 106 0>;
status = "disabled";
};
i2c@12CA0000 { #address-cells = <1>; #size-cells = <0>;
-- 1.9.1
Thank you for review. Are you going to review the rest of patches (11-14)?
Best regards,

Hi Przemyslaw,
On 29 October 2015 at 07:58, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hi Simon,
On 10/28/2015 07:50 PM, Simon Glass wrote:
On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds common ADC node, which is disabled as default.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit
Reviewed-by: Simon Glass sjg@chromium.org
This does not look like a new commit.
This is V3, and the commit was new in V2. I didn't edit commit message if no changes made in V3.
arch/arm/dts/exynos54xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index bd3619d..daa6a33 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -42,6 +42,13 @@ xhci1 = "/xhci@12400000"; };
adc@12D10000 {
compatible = "samsung,exynos-adc-v2";
reg = <0x12D10000 0x100>;
interrupts = <0 106 0>;
status = "disabled";
};
i2c@12CA0000 { #address-cells = <1>; #size-cells = <0>;
-- 1.9.1
Thank you for review. Are you going to review the rest of patches (11-14)?
I just took a look now and made a few comments.
Regards, Simon

Hello Simon,
On 11/06/2015 04:15 AM, Simon Glass wrote:
Hi Przemyslaw,
On 29 October 2015 at 07:58, Przemyslaw Marczak p.marczak@samsung.com wrote:
Hi Simon,
On 10/28/2015 07:50 PM, Simon Glass wrote:
On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds common ADC node, which is disabled as default.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- new commit
Reviewed-by: Simon Glass sjg@chromium.org
This does not look like a new commit.
This is V3, and the commit was new in V2. I didn't edit commit message if no changes made in V3.
arch/arm/dts/exynos54xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index bd3619d..daa6a33 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -42,6 +42,13 @@ xhci1 = "/xhci@12400000"; };
adc@12D10000 {
compatible = "samsung,exynos-adc-v2";
reg = <0x12D10000 0x100>;
interrupts = <0 106 0>;
status = "disabled";
};
i2c@12CA0000 { #address-cells = <1>; #size-cells = <0>;
-- 1.9.1
Thank you for review. Are you going to review the rest of patches (11-14)?
I just took a look now and made a few comments.
Regards, Simon
Thank you for the review again, but this patchset was applied to u-boot-samsung four days ago and yesterday the pull request was send. Now I can see that, it's merged to master.
Your comments are cosmetic only, so I can send the cleanup as a separated patch set.
Best regards,

This ADC is required for Odroid's board revision detection. The pre-reloc request is enabled, since board detection will be done in one of early function call.
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - new commit --- arch/arm/dts/exynos5422-odroidxu3.dts | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts index 9dec679..690c747 100644 --- a/arch/arm/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/dts/exynos5422-odroidxu3.dts @@ -31,6 +31,11 @@ 0xb0000000 0xea00000>; };
+ adc@12D10000 { + u-boot,dm-pre-reloc; + status = "okay"; + }; + i2c@12CA0000 { s2mps11_pmic@66 { compatible = "samsung,s2mps11-pmic";

This commit adds additional file with implementation of board detection code for Odroid-XU3/XU4.
The detection depends on compatible found in fdt: - "samsung,exynos5" - uses Exynos5 generic code - "samsung,odroidxu3" - try detect XU3 revision
There are few revisions of Odroid XU3/XU4, each can be detected by checking the value of channel 9 of built-in ADC: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 1280 XU4 0.1
The detection code depends on the ADC+10% value.
Implementation of functions: - set_board_type() - read ADC and set type - get_board_rev() - returns board revision: 1..3 - get_board_type() - returns board type string
Additional functions with return values of bool: - board_is_generic() - true if found compatible "samsung,exynos5" but not "samsung,odroidxu3" - board_is_odroidxu3() - true if found compatible "samsung,odroidxu3" and one of XU3 revision. - board_is_odroidxu4() - true if found compatible "samsung,odroidxu3" and XU4 revision.
After I2C controller init, the get_board_type() can check if the XU3 board is a "Lite" variant, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
Enabled configs: - CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG - CONFIG_ODROID_REV_AIN - CONFIG_REVISION_TAG - CONFIG_BOARD_TYPES
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V2: - move detection code from exynos5-dt.c to exynos5-dt-types.c - add header with board type function declarations - check for compatible before do the detection - update the ADC max values with 20% tolerance - fix XU4 adc value, related to mistake from table in XU4 schematic - return "Not supported" for XU4 when calls one of: --dfu_get_alt_boot() --dfu_get_alt_system() - extend ${dfu_alt_system} by strings: -- 'exynos5422-odroidxu3-lite.dtb' -- 'exynos5422-odroidxu4.dtb' - allows prepare card on XU3
Changes V3: - fix merge conflict in: configs/odroid-xu3_defconfig --- board/samsung/common/Makefile | 5 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ configs/odroid-xu3_defconfig | 2 + include/configs/odroid_xu3.h | 12 ++ include/samsung/exynos5-dt-types.h | 27 +++++ 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 include/samsung/exynos5-dt-types.h
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile index 6cbd906..ef1a8f3 100644 --- a/board/samsung/common/Makefile +++ b/board/samsung/common/Makefile @@ -11,5 +11,8 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_BOARD_COMMON) += board.o -obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o +ifdef CONFIG_EXYNOS5_DT +obj-y += exynos5-dt.o +obj-$(CONFIG_BOARD_TYPES) += exynos5-dt-types.o +endif endif diff --git a/board/samsung/common/exynos5-dt-types.c b/board/samsung/common/exynos5-dt-types.c new file mode 100644 index 0000000..48fd1f7 --- /dev/null +++ b/board/samsung/common/exynos5-dt-types.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <adc.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/s2mps11.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct udevice_id board_ids[] = { + { .compatible = "samsung,odroidxu3", .data = EXYNOS5_BOARD_ODROID_XU3 }, + { .compatible = "samsung,exynos5", .data = EXYNOS5_BOARD_GENERIC }, + { }, +}; + +/** + * Odroix XU3/4 board revisions: + * Rev ADCmax Board + * 0.1 0 XU3 0.1 + * 0.2 410 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231) + * 0.3 1408 XU4 0.1 + * Use +10 % for ADC value tolerance. + */ +struct odroid_rev_info odroid_info[] = { + { EXYNOS5_BOARD_ODROID_XU3_REV01, 1, 10, "xu3" }, + { EXYNOS5_BOARD_ODROID_XU3_REV02, 2, 410, "xu3" }, + { EXYNOS5_BOARD_ODROID_XU4_REV01, 1, 1408, "xu4" }, + { EXYNOS5_BOARD_ODROID_UNKNOWN, 0, 4095, "unknown" }, +}; + +static unsigned int odroid_get_rev(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(odroid_info); i++) { + if (odroid_info[i].board_type == gd->board_type) + return odroid_info[i].board_rev; + } + + return 0; +} + +static int odroid_get_board_type(void) +{ + unsigned int adcval; + int ret, i; + + ret = adc_channel_single_shot("adc", CONFIG_ODROID_REV_AIN, &adcval); + if (ret) + goto rev_default; + + for (i = 0; i < ARRAY_SIZE(odroid_info); i++) { + /* ADC tolerance: +20 % */ + if (adcval < odroid_info[i].adc_val) + return odroid_info[i].board_type; + } + +rev_default: + return EXYNOS5_BOARD_ODROID_XU3; +} + +/** + * odroid_get_type_str - returns pointer to one of the board type string. + * Board types: "xu3", "xu3-lite", "xu4". However the "xu3lite" can be + * detected only when the i2c controller is ready to use. Fortunately, + * XU3 and XU3L are compatible, and the information about board lite + * revision is needed before booting the linux, to set proper environment + * variable: $fdtfile. + */ +static const char *odroid_get_type_str(void) +{ + const char *type_xu3l = "xu3-lite"; + struct udevice *dev, *chip; + int i, ret; + + if (gd->board_type != EXYNOS5_BOARD_ODROID_XU3_REV02) + goto exit; + + ret = pmic_get("s2mps11", &dev); + if (ret) + goto exit; + + /* Enable LDO26: 3.0V */ + ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL, + S2MPS11_LDO26_ENABLE); + if (ret) + goto exit; + + /* Check XU3Lite by probe INA231 I2C0:0x40 */ + ret = uclass_get_device(UCLASS_I2C, 0, &dev); + if (ret) + goto exit; + + ret = dm_i2c_probe(dev, 0x40, 0x0, &chip); + if (ret) + return type_xu3l; + +exit: + for (i = 0; i < ARRAY_SIZE(odroid_info); i++) { + if (odroid_info[i].board_type == gd->board_type) + return odroid_info[i].name; + } + + return NULL; +} + +bool board_is_odroidxu3(void) +{ + if (gd->board_type >= EXYNOS5_BOARD_ODROID_XU3 && + gd->board_type <= EXYNOS5_BOARD_ODROID_XU3_REV02) + return true; + + return false; +} + +bool board_is_odroidxu4(void) +{ + if (gd->board_type == EXYNOS5_BOARD_ODROID_XU4_REV01) + return true; + + return false; +} + +bool board_is_generic(void) +{ + if (gd->board_type == EXYNOS5_BOARD_GENERIC) + return true; + + return false; +} + +/** + * get_board_rev() - return detected board revision. + * + * @return: return board revision number for XU3 or 0 for generic + */ +u32 get_board_rev(void) +{ + if (board_is_generic()) + return 0; + + return odroid_get_rev(); +} + +/** + * get_board_type() - returns board type string. + * + * @return: return board type string for XU3 or empty string for generic + */ +const char *get_board_type(void) +{ + const char *generic = ""; + + if (board_is_generic()) + return generic; + + return odroid_get_type_str(); +} + +/** + * set_board_type() - set board type in gd->board_type. + * As default type set EXYNOS5_BOARD_GENERIC, if detect Odroid, + * then set its proper type. + */ +void set_board_type(void) +{ + const struct udevice_id *of_match = board_ids; + int ret; + + gd->board_type = EXYNOS5_BOARD_GENERIC; + + while (of_match->compatible) { + ret = fdt_node_check_compatible(gd->fdt_blob, 0, + of_match->compatible); + if (ret) + of_match++; + + gd->board_type = of_match->data; + break; + } + + /* If Odroid, then check its revision */ + if (board_is_odroidxu3()) + gd->board_type = odroid_get_board_type(); +} diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 4250f72..4d9e151 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -27,7 +27,10 @@ #include <power/pmic.h> #include <power/max77686_pmic.h> #include <power/regulator.h> +#include <power/s2mps11.h> #include <power/s5m8767.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -335,15 +338,24 @@ int board_usb_init(int index, enum usb_init_type init) #ifdef CONFIG_SET_DFU_ALT_INFO char *get_dfu_alt_system(char *interface, char *devstr) { + char *info = "Not supported!"; + + if (board_is_odroidxu4()) + return info; + return getenv("dfu_alt_system"); }
char *get_dfu_alt_boot(char *interface, char *devstr) { + char *info = "Not supported!"; struct mmc *mmc; char *alt_boot; int dev_num;
+ if (board_is_odroidxu4()) + return info; + dev_num = simple_strtoul(devstr, NULL, 10);
mmc = find_mmc_device(dev_num); diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 780dcab..4ab91fa 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -16,3 +16,5 @@ CONFIG_PMIC_S2MPS11=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_VIDEO_BRIDGE=y +CONFIG_ADC=y +CONFIG_ADC_EXYNOS=y diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \ + "exynos5422-odroidxu3-lite.dtb fat 0 1;" \ + "exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES + +#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid" + /* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \ diff --git a/include/samsung/exynos5-dt-types.h b/include/samsung/exynos5-dt-types.h new file mode 100644 index 0000000..479e2e7 --- /dev/null +++ b/include/samsung/exynos5-dt-types.h @@ -0,0 +1,27 @@ +#ifndef _EXYNOS5_DT_H_ +#define _EXYNOS5_DT_H_ + +enum { + EXYNOS5_BOARD_GENERIC, + + EXYNOS5_BOARD_ODROID_XU3, + EXYNOS5_BOARD_ODROID_XU3_REV01, + EXYNOS5_BOARD_ODROID_XU3_REV02, + EXYNOS5_BOARD_ODROID_XU4_REV01, + EXYNOS5_BOARD_ODROID_UNKNOWN, + + EXYNOS5_BOARD_COUNT, +}; + +struct odroid_rev_info { + int board_type; + int board_rev; + int adc_val; + const char *name; +}; + +bool board_is_generic(void); +bool board_is_odroidxu3(void); +bool board_is_odroidxu4(void); + +#endif

hi,
On 27 October 2015 at 17:38, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds additional file with implementation of board detection code for Odroid-XU3/XU4.
The detection depends on compatible found in fdt:
- "samsung,exynos5" - uses Exynos5 generic code
- "samsung,odroidxu3" - try detect XU3 revision
There are few revisions of Odroid XU3/XU4, each can be detected by checking the value of channel 9 of built-in ADC: Rev ADC Board 0.1 0 XU3 0.1 0.2 372 XU3 0.2 | XU3L - no DISPLAYPORT 0.3 1280 XU4 0.1
The detection code depends on the ADC+10% value.
Implementation of functions:
- set_board_type() - read ADC and set type
- get_board_rev() - returns board revision: 1..3
- get_board_type() - returns board type string
Additional functions with return values of bool:
- board_is_generic() - true if found compatible "samsung,exynos5" but not "samsung,odroidxu3"
- board_is_odroidxu3() - true if found compatible "samsung,odroidxu3" and one of XU3 revision.
- board_is_odroidxu4() - true if found compatible "samsung,odroidxu3" and XU4 revision.
After I2C controller init, the get_board_type() can check if the XU3 board is a "Lite" variant, by probing chip 0x40 on I2C0 (INA231 - exists only on non-lite). This is useful for setting fdt file name at misc_init_r().
Enabled configs:
- CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
- CONFIG_ODROID_REV_AIN
- CONFIG_REVISION_TAG
- CONFIG_BOARD_TYPES
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Minkyu Kang mk7.kang@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V2:
- move detection code from exynos5-dt.c to exynos5-dt-types.c
- add header with board type function declarations
- check for compatible before do the detection
- update the ADC max values with 20% tolerance
- fix XU4 adc value, related to mistake from table in XU4 schematic
- return "Not supported" for XU4 when calls one of: --dfu_get_alt_boot() --dfu_get_alt_system()
- extend ${dfu_alt_system} by strings: -- 'exynos5422-odroidxu3-lite.dtb' -- 'exynos5422-odroidxu4.dtb' - allows prepare card on XU3
Changes V3:
- fix merge conflict in: configs/odroid-xu3_defconfig
board/samsung/common/Makefile | 5 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++++++++++++++++++++ board/samsung/common/exynos5-dt.c | 12 ++ configs/odroid-xu3_defconfig | 2 + include/configs/odroid_xu3.h | 12 ++ include/samsung/exynos5-dt-types.h | 27 +++++ 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 include/samsung/exynos5-dt-types.h
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile index 6cbd906..ef1a8f3 100644 --- a/board/samsung/common/Makefile +++ b/board/samsung/common/Makefile @@ -11,5 +11,8 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_BOARD_COMMON) += board.o -obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o +ifdef CONFIG_EXYNOS5_DT +obj-y += exynos5-dt.o +obj-$(CONFIG_BOARD_TYPES) += exynos5-dt-types.o +endif endif diff --git a/board/samsung/common/exynos5-dt-types.c b/board/samsung/common/exynos5-dt-types.c new file mode 100644 index 0000000..48fd1f7 --- /dev/null +++ b/board/samsung/common/exynos5-dt-types.c @@ -0,0 +1,196 @@ +/*
- Copyright (C) 2015 Samsung Electronics
- Przemyslaw Marczak p.marczak@samsung.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <adc.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/s2mps11.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h>
+DECLARE_GLOBAL_DATA_PTR;
+static const struct udevice_id board_ids[] = {
{ .compatible = "samsung,odroidxu3", .data = EXYNOS5_BOARD_ODROID_XU3 },
{ .compatible = "samsung,exynos5", .data = EXYNOS5_BOARD_GENERIC },
{ },
+};
+/**
- Odroix XU3/4 board revisions:
- Rev ADCmax Board
- 0.1 0 XU3 0.1
- 0.2 410 XU3 0.2 | XU3L - no DISPLAYPORT (probe I2C0:0x40 / INA231)
- 0.3 1408 XU4 0.1
- Use +10 % for ADC value tolerance.
- */
+struct odroid_rev_info odroid_info[] = {
{ EXYNOS5_BOARD_ODROID_XU3_REV01, 1, 10, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU3_REV02, 2, 410, "xu3" },
{ EXYNOS5_BOARD_ODROID_XU4_REV01, 1, 1408, "xu4" },
{ EXYNOS5_BOARD_ODROID_UNKNOWN, 0, 4095, "unknown" },
+};
+static unsigned int odroid_get_rev(void) +{
int i;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].board_rev;
}
return 0;
+}
+static int odroid_get_board_type(void) +{
unsigned int adcval;
int ret, i;
ret = adc_channel_single_shot("adc", CONFIG_ODROID_REV_AIN, &adcval);
if (ret)
goto rev_default;
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
/* ADC tolerance: +20 % */
if (adcval < odroid_info[i].adc_val)
return odroid_info[i].board_type;
}
+rev_default:
return EXYNOS5_BOARD_ODROID_XU3;
+}
+/**
- odroid_get_type_str - returns pointer to one of the board type string.
- Board types: "xu3", "xu3-lite", "xu4". However the "xu3lite" can be
- detected only when the i2c controller is ready to use. Fortunately,
- XU3 and XU3L are compatible, and the information about board lite
- revision is needed before booting the linux, to set proper environment
- variable: $fdtfile.
- */
+static const char *odroid_get_type_str(void) +{
const char *type_xu3l = "xu3-lite";
struct udevice *dev, *chip;
int i, ret;
if (gd->board_type != EXYNOS5_BOARD_ODROID_XU3_REV02)
goto exit;
ret = pmic_get("s2mps11", &dev);
if (ret)
goto exit;
/* Enable LDO26: 3.0V */
ret = pmic_reg_write(dev, S2MPS11_REG_L26CTRL,
S2MPS11_LDO26_ENABLE);
if (ret)
goto exit;
/* Check XU3Lite by probe INA231 I2C0:0x40 */
ret = uclass_get_device(UCLASS_I2C, 0, &dev);
if (ret)
goto exit;
ret = dm_i2c_probe(dev, 0x40, 0x0, &chip);
if (ret)
return type_xu3l;
+exit:
for (i = 0; i < ARRAY_SIZE(odroid_info); i++) {
if (odroid_info[i].board_type == gd->board_type)
return odroid_info[i].name;
}
return NULL;
+}
+bool board_is_odroidxu3(void) +{
if (gd->board_type >= EXYNOS5_BOARD_ODROID_XU3 &&
gd->board_type <= EXYNOS5_BOARD_ODROID_XU3_REV02)
return true;
return false;
+}
+bool board_is_odroidxu4(void) +{
if (gd->board_type == EXYNOS5_BOARD_ODROID_XU4_REV01)
return true;
return false;
+}
+bool board_is_generic(void) +{
if (gd->board_type == EXYNOS5_BOARD_GENERIC)
return true;
return false;
+}
+/**
- get_board_rev() - return detected board revision.
- @return: return board revision number for XU3 or 0 for generic
- */
+u32 get_board_rev(void) +{
if (board_is_generic())
return 0;
return odroid_get_rev();
+}
+/**
- get_board_type() - returns board type string.
- @return: return board type string for XU3 or empty string for generic
- */
+const char *get_board_type(void) +{
const char *generic = "";
if (board_is_generic())
return generic;
return odroid_get_type_str();
+}
+/**
- set_board_type() - set board type in gd->board_type.
- As default type set EXYNOS5_BOARD_GENERIC, if detect Odroid,
- then set its proper type.
- */
+void set_board_type(void) +{
const struct udevice_id *of_match = board_ids;
int ret;
gd->board_type = EXYNOS5_BOARD_GENERIC;
while (of_match->compatible) {
ret = fdt_node_check_compatible(gd->fdt_blob, 0,
of_match->compatible);
if (ret)
of_match++;
gd->board_type = of_match->data;
break;
}
/* If Odroid, then check its revision */
if (board_is_odroidxu3())
gd->board_type = odroid_get_board_type();
+} diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 4250f72..4d9e151 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -27,7 +27,10 @@ #include <power/pmic.h> #include <power/max77686_pmic.h> #include <power/regulator.h> +#include <power/s2mps11.h> #include <power/s5m8767.h> +#include <samsung/exynos5-dt-types.h> +#include <samsung/misc.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -335,15 +338,24 @@ int board_usb_init(int index, enum usb_init_type init) #ifdef CONFIG_SET_DFU_ALT_INFO char *get_dfu_alt_system(char *interface, char *devstr) {
char *info = "Not supported!";
if (board_is_odroidxu4())
return info;
return getenv("dfu_alt_system");
}
char *get_dfu_alt_boot(char *interface, char *devstr) {
char *info = "Not supported!"; struct mmc *mmc; char *alt_boot; int dev_num;
if (board_is_odroidxu4())
return info;
dev_num = simple_strtoul(devstr, NULL, 10); mmc = find_mmc_device(dev_num);
diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 780dcab..4ab91fa 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -16,3 +16,5 @@ CONFIG_PMIC_S2MPS11=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_VIDEO_BRIDGE=y +CONFIG_ADC=y +CONFIG_ADC_EXYNOS=y diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 3c70158..648e48b 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -94,6 +94,8 @@ "boot.scr fat 0 1;" \ "boot.cmd fat 0 1;" \ "exynos5422-odroidxu3.dtb fat 0 1;" \
"exynos5422-odroidxu3-lite.dtb fat 0 1;" \
"exynos5422-odroidxu4.dtb fat 0 1;" \ "boot part 0 1;" \ "root part 0 2\0"
@@ -113,9 +115,19 @@
/* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON +#define CONFIG_MISC_INIT_R #define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K)
+/* Set soc_rev, soc_id, board_rev, boardname, fdtfile */ +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_ODROID_REV_AIN 9 +#define CONFIG_REVISION_TAG +#define CONFIG_BOARD_TYPES
+#undef CONFIG_SYS_BOARD +#define CONFIG_SYS_BOARD "odroid"
/* Define new extra env settings, including DFU settings */ #undef CONFIG_EXTRA_ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \ diff --git a/include/samsung/exynos5-dt-types.h b/include/samsung/exynos5-dt-types.h new file mode 100644 index 0000000..479e2e7 --- /dev/null +++ b/include/samsung/exynos5-dt-types.h @@ -0,0 +1,27 @@ +#ifndef _EXYNOS5_DT_H_ +#define _EXYNOS5_DT_H_
+enum {
EXYNOS5_BOARD_GENERIC,
EXYNOS5_BOARD_ODROID_XU3,
EXYNOS5_BOARD_ODROID_XU3_REV01,
EXYNOS5_BOARD_ODROID_XU3_REV02,
EXYNOS5_BOARD_ODROID_XU4_REV01,
EXYNOS5_BOARD_ODROID_UNKNOWN,
EXYNOS5_BOARD_COUNT,
+};
+struct odroid_rev_info {
int board_type;
int board_rev;
int adc_val;
const char *name;
+};
+bool board_is_generic(void); +bool board_is_odroidxu3(void); +bool board_is_odroidxu4(void);
+#endif
1.9.1
Tested-by: Anand Moon linux.amoon@gmail.com
-Anand Moon

This commit adds implementation of Sandbox ADC device emulation. The device provides: - single and multi-channel conversion - 4 channels with predefined conversion output data - 16-bit resolution
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V3: - new commit --- arch/sandbox/dts/sandbox_pmic.dtsi | 2 +- arch/sandbox/dts/test.dts | 6 ++ configs/sandbox_defconfig | 2 + drivers/adc/Kconfig | 9 ++ drivers/adc/Makefile | 1 + drivers/adc/sandbox.c | 174 +++++++++++++++++++++++++++++++++++++ 6 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 drivers/adc/sandbox.c
diff --git a/arch/sandbox/dts/sandbox_pmic.dtsi b/arch/sandbox/dts/sandbox_pmic.dtsi index 44a26b1..ce261b9 100644 --- a/arch/sandbox/dts/sandbox_pmic.dtsi +++ b/arch/sandbox/dts/sandbox_pmic.dtsi @@ -55,7 +55,7 @@ regulator-always-on; };
- buck2 { + buck2: buck2 { regulator-name = "SUPPLY_3.3V"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 730de8a..e2c4971 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -189,6 +189,12 @@ }; };
+ adc@0 { + compatible = "sandbox,adc"; + vdd-supply = <&buck2>; + vss-microvolts = <0>; + }; + leds { compatible = "gpio-leds";
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 67ae99b..94c8e68 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -65,3 +65,5 @@ CONFIG_UT_DM=y CONFIG_UT_ENV=y CONFIG_REMOTEPROC_SANDBOX=y CONFIG_CMD_REMOTEPROC=y +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 223b65e..e5335f7 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -19,3 +19,12 @@ config ADC_EXYNOS - 10 analog input channels - 12-bit resolution - 600 KSPS of sample rate + +config ADC_SANDBOX + bool "Enable Sandbox ADC test driver" + help + This enables driver for Sandbox ADC device emulation. + It provides: + - 4 analog input channels + - 16-bit resolution + - single and multi-channel conversion mode diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index eb85b8b..cebf26d 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -7,3 +7,4 @@
obj-$(CONFIG_ADC) += adc-uclass.o obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o +obj-$(CONFIG_ADC_SANDBOX) += sandbox.o diff --git a/drivers/adc/sandbox.c b/drivers/adc/sandbox.c new file mode 100644 index 0000000..3718922 --- /dev/null +++ b/drivers/adc/sandbox.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <adc.h> +#include <sandbox-adc.h> + +/** + * struct sandbox_adc_priv - sandbox ADC device's operation status and data + * + * @conversion_status - conversion status: ACTIVE (started) / INACTIVE (stopped) + * @conversion_mode - conversion mode: single or multi-channel + * @active_channel - active channel number, valid for single channel mode + * data[] - channels data + */ +struct sandbox_adc_priv { + int conversion_status; + int conversion_mode; + int active_channel_mask; + unsigned int data[4]; +}; + +int sandbox_adc_start_channel(struct udevice *dev, int channel) +{ + struct sandbox_adc_priv *priv = dev_get_priv(dev); + + /* Set single-channel mode */ + priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL; + /* Select channel */ + priv->active_channel_mask = 1 << channel; + /* Start conversion */ + priv->conversion_status = SANDBOX_ADC_ACTIVE; + + return 0; +} + +int sandbox_adc_start_channels(struct udevice *dev, unsigned int channel_mask) +{ + struct sandbox_adc_priv *priv = dev_get_priv(dev); + + /* Set single-channel mode */ + priv->conversion_mode = SANDBOX_ADC_MODE_MULTI_CHANNEL; + /* Select channel */ + priv->active_channel_mask = channel_mask; + /* Start conversion */ + priv->conversion_status = SANDBOX_ADC_ACTIVE; + + return 0; +} + +int sandbox_adc_channel_data(struct udevice *dev, int channel, + unsigned int *data) +{ + struct sandbox_adc_priv *priv = dev_get_priv(dev); + + /* For single-channel conversion mode, check if channel was selected */ + if ((priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) && + !(priv->active_channel_mask & (1 << channel))) { + error("Request for an inactive channel!"); + return -EINVAL; + } + + /* The conversion must be started before reading the data */ + if (priv->conversion_status == SANDBOX_ADC_INACTIVE) + return -EIO; + + *data = priv->data[channel]; + + return 0; +} + +int sandbox_adc_channels_data(struct udevice *dev, unsigned int channel_mask, + struct adc_channel *channels) +{ + struct sandbox_adc_priv *priv = dev_get_priv(dev); + int i; + + /* Return error for single-channel conversion mode */ + if (priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) { + error("ADC in single-channel mode!"); + return -EPERM; + } + /* Check channel selection */ + if (!(priv->active_channel_mask & channel_mask)) { + error("Request for an inactive channel!"); + return -EINVAL; + } + /* The conversion must be started before reading the data */ + if (priv->conversion_status == SANDBOX_ADC_INACTIVE) + return -EIO; + + for (i = 0; i < SANDBOX_ADC_CHANNELS; i++) { + if (!((channel_mask >> i) & 0x1)) + continue; + + channels->data = priv->data[i]; + channels->id = i; + channels++; + } + + return 0; +} + +int sandbox_adc_stop(struct udevice *dev) +{ + struct sandbox_adc_priv *priv = dev_get_priv(dev); + + /* Start conversion */ + priv->conversion_status = SANDBOX_ADC_INACTIVE; + + return 0; +} + +int sandbox_adc_probe(struct udevice *dev) +{ + struct sandbox_adc_priv *priv = dev_get_priv(dev); + + /* Stop conversion */ + priv->conversion_status = SANDBOX_ADC_INACTIVE; + /* Set single-channel mode */ + priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL; + /* Deselect all channels */ + priv->active_channel_mask = 0; + + /* Set sandbox test data */ + priv->data[0] = SANDBOX_ADC_CHANNEL0_DATA; + priv->data[1] = SANDBOX_ADC_CHANNEL1_DATA; + priv->data[2] = SANDBOX_ADC_CHANNEL2_DATA; + priv->data[3] = SANDBOX_ADC_CHANNEL3_DATA; + + return 0; +} + +int sandbox_adc_ofdata_to_platdata(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->data_mask = SANDBOX_ADC_DATA_MASK; + uc_pdata->data_format = ADC_DATA_FORMAT_BIN; + uc_pdata->data_timeout_us = 0; + + /* Mask available channel bits: [0:3] */ + uc_pdata->channel_mask = (1 << SANDBOX_ADC_CHANNELS) - 1; + + return 0; +} + +static const struct adc_ops sandbox_adc_ops = { + .start_channel = sandbox_adc_start_channel, + .start_channels = sandbox_adc_start_channels, + .channel_data = sandbox_adc_channel_data, + .channels_data = sandbox_adc_channels_data, + .stop = sandbox_adc_stop, +}; + +static const struct udevice_id sandbox_adc_ids[] = { + { .compatible = "sandbox,adc" }, + { } +}; + +U_BOOT_DRIVER(sandbox_adc) = { + .name = "sandbox-adc", + .id = UCLASS_ADC, + .of_match = sandbox_adc_ids, + .ops = &sandbox_adc_ops, + .probe = sandbox_adc_probe, + .ofdata_to_platdata = sandbox_adc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct sandbox_adc_priv), +};

This should be squashed to commit:
sandbox: add ADC driver
This commit adds implementation of Sandbox ADC device emulation. The device provides: - single and multi-channel conversion - 4 channels with predefined conversion output data - 16-bit resolution
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V3: - new commit --- include/sandbox-adc.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 include/sandbox-adc.h
diff --git a/include/sandbox-adc.h b/include/sandbox-adc.h new file mode 100644 index 0000000..79ff01c --- /dev/null +++ b/include/sandbox-adc.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SANDBOX_ADC_H_ +#define _SANDBOX_ADC_H_ + +#define SANDBOX_ADC_DEVNAME "adc@0" +#define SANDBOX_ADC_DATA_MASK 0xffff /* 16-bits resolution */ +#define SANDBOX_ADC_CHANNELS 4 +#define SANDBOX_ADC_CHANNEL0_DATA 0x0 +#define SANDBOX_ADC_CHANNEL1_DATA 0x1000 +#define SANDBOX_ADC_CHANNEL2_DATA 0x2000 +#define SANDBOX_ADC_CHANNEL3_DATA 0x3000 + +enum sandbox_adc_mode { + SANDBOX_ADC_MODE_SINGLE_CHANNEL = 0, + SANDBOX_ADC_MODE_MULTI_CHANNEL, +}; + +enum sandbox_adc_status { + SANDBOX_ADC_INACTIVE = 0, + SANDBOX_ADC_ACTIVE, +}; + +#define SANDBOX_ADC_VSS_VALUE 0 + +#endif

On 4 November 2015 at 02:52, Przemyslaw Marczak p.marczak@samsung.com wrote:
This should be squashed to commit:
sandbox: add ADC driver
This commit adds implementation of Sandbox ADC device emulation. The device provides:
- single and multi-channel conversion
- 4 channels with predefined conversion output data
- 16-bit resolution
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V3:
- new commit
include/sandbox-adc.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 include/sandbox-adc.h
Agreed it should be squashed in:
Reviewed-by: Simon Glass sjg@chromium.org

Hi Przemyslaw,
On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds implementation of Sandbox ADC device emulation. The device provides:
- single and multi-channel conversion
- 4 channels with predefined conversion output data
- 16-bit resolution
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V3:
- new commit
arch/sandbox/dts/sandbox_pmic.dtsi | 2 +- arch/sandbox/dts/test.dts | 6 ++ configs/sandbox_defconfig | 2 + drivers/adc/Kconfig | 9 ++ drivers/adc/Makefile | 1 + drivers/adc/sandbox.c | 174 +++++++++++++++++++++++++++++++++++++ 6 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 drivers/adc/sandbox.c
Reviewed-by: Simon Glass sjg@chromium.org
(could fix the include order though)

This commit adds unit tests for ADC uclass's methods using sandbox ADC.
Testing proper ADC binding: - dm_test_adc_bind() - device binding - dm_test_adc_wrong_channel_selection() - checking wrong channel selection
Testing ADC supply operations: - dm_test_adc_supply(): - Vdd/Vss values validating - Vdd regulator updated value validating - Vdd regulator's auto enable state validating
Testing ADC operations results: - dm_test_adc_single_channel_conversion() - single channel start/data - dm_test_adc_single_channel_shot() - single channel shot - dm_test_adc_multi_channel_conversion() - multi channel start/data - dm_test_adc_multi_channel_shot() - multi channel single shot
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org --- Changes V3: - new commit --- include/power/sandbox_pmic.h | 4 ++ test/dm/Makefile | 1 + test/dm/adc.c | 165 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 test/dm/adc.c
diff --git a/include/power/sandbox_pmic.h b/include/power/sandbox_pmic.h index 8547674..7fdbfb9 100644 --- a/include/power/sandbox_pmic.h +++ b/include/power/sandbox_pmic.h @@ -126,6 +126,10 @@ enum { #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UA 200000 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_ENABLE true
+/* BUCK2: for testing sandbox ADC's supply */ +#define SANDBOX_BUCK2_INITIAL_EXPECTED_UV 3000000 +#define SANDBOX_BUCK2_SET_UV 3300000 + /* LDO1/2 for testing regulator_list_autoset() */ #define SANDBOX_LDO1_AUTOSET_EXPECTED_UV 1800000 #define SANDBOX_LDO1_AUTOSET_EXPECTED_UA 100000 diff --git a/test/dm/Makefile b/test/dm/Makefile index 7b3626c..39630f6 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -33,4 +33,5 @@ obj-y += syscon.o obj-$(CONFIG_DM_USB) += usb.o obj-$(CONFIG_DM_PMIC) += pmic.o obj-$(CONFIG_DM_REGULATOR) += regulator.o +obj-$(CONFIG_ADC) += adc.o endif diff --git a/test/dm/adc.c b/test/dm/adc.c new file mode 100644 index 0000000..b0d4fe5 --- /dev/null +++ b/test/dm/adc.c @@ -0,0 +1,165 @@ +/* + * Tests for the driver model ADC API + * + * Copyright (c) 2015 Samsung Electronics + * Przemyslaw Marczak p.marczak@samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <adc.h> +#include <dm.h> +#include <dm/root.h> +#include <dm/util.h> +#include <dm/test.h> +#include <errno.h> +#include <fdtdec.h> +#include <power/regulator.h> +#include <power/sandbox_pmic.h> +#include <sandbox-adc.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int dm_test_adc_bind(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev)); + ut_asserteq_str(SANDBOX_ADC_DEVNAME, dev->name); + + return 0; +} +DM_TEST(dm_test_adc_bind, DM_TESTF_SCAN_FDT); + +static int dm_test_adc_wrong_channel_selection(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev)); + ut_asserteq(-EINVAL, adc_start_channel(dev, SANDBOX_ADC_CHANNELS)); + + return 0; +} +DM_TEST(dm_test_adc_wrong_channel_selection, DM_TESTF_SCAN_FDT); + +static int dm_test_adc_supply(struct unit_test_state *uts) +{ + struct udevice *supply; + struct udevice *dev; + int uV; + + ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev)); + + /* Test Vss value - predefined 0 uV */ + ut_assertok(adc_vss_value(dev, &uV)); + ut_asserteq(SANDBOX_ADC_VSS_VALUE, uV); + + /* Test Vdd initial value - buck2 */ + ut_assertok(adc_vdd_value(dev, &uV)); + ut_asserteq(SANDBOX_BUCK2_INITIAL_EXPECTED_UV, uV); + + /* Change Vdd value - buck2 manual preset */ + ut_assertok(regulator_get_by_devname(SANDBOX_BUCK2_DEVNAME, &supply)); + ut_assertok(regulator_set_value(supply, SANDBOX_BUCK2_SET_UV)); + ut_asserteq(SANDBOX_BUCK2_SET_UV, regulator_get_value(supply)); + + /* Update ADC platdata and get new Vdd value */ + ut_assertok(adc_vdd_value(dev, &uV)); + ut_asserteq(SANDBOX_BUCK2_SET_UV, uV); + + /* Disable buck2 and test ADC supply enable function */ + ut_assertok(regulator_set_enable(supply, false)); + ut_asserteq(false, regulator_get_enable(supply)); + /* adc_start_channel() should enable the supply regulator */ + ut_assertok(adc_start_channel(dev, 0)); + ut_asserteq(true, regulator_get_enable(supply)); + + return 0; +} +DM_TEST(dm_test_adc_supply, DM_TESTF_SCAN_FDT); + +struct adc_channel adc_channel_test_data[] = { + { 0, SANDBOX_ADC_CHANNEL0_DATA }, + { 1, SANDBOX_ADC_CHANNEL1_DATA }, + { 2, SANDBOX_ADC_CHANNEL2_DATA }, + { 3, SANDBOX_ADC_CHANNEL3_DATA }, +}; + +static int dm_test_adc_single_channel_conversion(struct unit_test_state *uts) +{ + struct adc_channel *tdata = adc_channel_test_data; + unsigned int i, data; + struct udevice *dev; + + ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev)); + /* Test each ADC channel's value */ + for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++) { + ut_assertok(adc_start_channel(dev, tdata->id)); + ut_assertok(adc_channel_data(dev, tdata->id, &data)); + ut_asserteq(tdata->data, data); + } + + return 0; +} +DM_TEST(dm_test_adc_single_channel_conversion, DM_TESTF_SCAN_FDT); + +static int dm_test_adc_multi_channel_conversion(struct unit_test_state *uts) +{ + struct adc_channel channels[SANDBOX_ADC_CHANNELS]; + struct udevice *dev; + struct adc_channel *tdata = adc_channel_test_data; + unsigned int i, channel_mask; + + channel_mask = ADC_CHANNEL(0) | ADC_CHANNEL(1) | + ADC_CHANNEL(2) | ADC_CHANNEL(3); + + /* Start multi channel conversion */ + ut_assertok(uclass_get_device_by_name(UCLASS_ADC, "adc", &dev)); + ut_assertok(adc_start_channels(dev, channel_mask)); + ut_assertok(adc_channels_data(dev, channel_mask, channels)); + + /* Compare the expected and returned conversion data. */ + for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++) + ut_asserteq(tdata->data, channels[i].data); + + return 0; +} +DM_TEST(dm_test_adc_multi_channel_conversion, DM_TESTF_SCAN_FDT); + +static int dm_test_adc_single_channel_shot(struct unit_test_state *uts) +{ + struct adc_channel *tdata = adc_channel_test_data; + unsigned int i, data; + + for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++) { + /* Start single channel conversion */ + ut_assertok(adc_channel_single_shot("adc", tdata->id, &data)); + /* Compare the expected and returned conversion data. */ + ut_asserteq(tdata->data, data); + } + + return 0; +} +DM_TEST(dm_test_adc_single_channel_shot, DM_TESTF_SCAN_FDT); + +static int dm_test_adc_multi_channel_shot(struct unit_test_state *uts) +{ + struct adc_channel channels[SANDBOX_ADC_CHANNELS]; + struct adc_channel *tdata = adc_channel_test_data; + unsigned int i, channel_mask; + + channel_mask = ADC_CHANNEL(0) | ADC_CHANNEL(1) | + ADC_CHANNEL(2) | ADC_CHANNEL(3); + + /* Start single call and multi channel conversion */ + ut_assertok(adc_channels_single_shot("adc", channel_mask, channels)); + + /* Compare the expected and returned conversion data. */ + for (i = 0; i < SANDBOX_ADC_CHANNELS; i++, tdata++) + ut_asserteq(tdata->data, channels[i].data); + + return 0; +} +DM_TEST(dm_test_adc_multi_channel_shot, DM_TESTF_SCAN_FDT);

Hi Przemyslaw,
On 27 October 2015 at 06:08, Przemyslaw Marczak p.marczak@samsung.com wrote:
This commit adds unit tests for ADC uclass's methods using sandbox ADC.
Testing proper ADC binding:
- dm_test_adc_bind() - device binding
- dm_test_adc_wrong_channel_selection() - checking wrong channel selection
Testing ADC supply operations:
- dm_test_adc_supply():
- Vdd/Vss values validating
- Vdd regulator updated value validating
- Vdd regulator's auto enable state validating
Testing ADC operations results:
- dm_test_adc_single_channel_conversion() - single channel start/data
- dm_test_adc_single_channel_shot() - single channel shot
- dm_test_adc_multi_channel_conversion() - multi channel start/data
- dm_test_adc_multi_channel_shot() - multi channel single shot
Signed-off-by: Przemyslaw Marczak p.marczak@samsung.com Cc: Simon Glass sjg@chromium.org
Changes V3:
- new commit
include/power/sandbox_pmic.h | 4 ++ test/dm/Makefile | 1 + test/dm/adc.c | 165 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 test/dm/adc.c
Great test!
Reviewed-by: Simon Glass sjg@chromium.org

On 27/10/15 21:07, Przemyslaw Marczak wrote:
This patchset adds:
- 'cpu-model' dts property for Chromebook Peach Pi as Exynos5800
- set the cpu id of Exynos5422 to 0x5422
- S2MPS11 PMIC I/O driver
- ADC uclass implementation
- Exynos5420-compatible (9-channel, 12-bit) ADC driver
- new file for Exynos5: exynos5-dt-types.c
- board detection for Odroid XU3 / XU3lite / XU4
- fixed ADC value for XU4 detection
This was tested on Odroid XU3/XU3 Lite/XU4 and sandbox.
Tested with buildman for samsung.
Available on github: https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v1 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v2 https://github.com/bobenstein/u-boot/tree/xu3-detect-patchset-v3
Przemyslaw Marczak (14): samsung: board/misc: check returned pointer for get_board_type() calls s5p: cpu_info: print "cpu-model" if exists in dts Peach-Pi: dts: add cpu-model string Exynos5422/5800: set cpu id to 0x5422 dm: pmic: add s2mps11 PMIC I/O driver dm: regulator: add function device_get_supply_regulator() dm: adc: add simple ADC uclass implementation dm: adc: add Exynos54xx compatible ADC driver Odroid-XU3: enable s2mps11 PMIC support Exynos54xx: dts: add ADC node Odroid-XU3: dts: enable ADC, with request for pre-reloc bind exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4. sandbox: add ADC driver sandbox: add ADC unit tests
arch/arm/cpu/armv7/s5p-common/cpu_info.c | 14 +- arch/arm/dts/exynos5422-odroidxu3.dts | 12 + arch/arm/dts/exynos54xx.dtsi | 7 + arch/arm/dts/exynos5800-peach-pi.dts | 1 + arch/arm/mach-exynos/clock.c | 16 +- arch/arm/mach-exynos/clock_init_exynos5.c | 2 +- arch/arm/mach-exynos/common_setup.h | 4 +- arch/arm/mach-exynos/include/mach/adc.h | 44 ++++ arch/arm/mach-exynos/include/mach/cpu.h | 6 +- arch/arm/mach-exynos/include/mach/gpio.h | 4 +- arch/arm/mach-exynos/pinmux.c | 2 +- arch/arm/mach-exynos/power.c | 2 +- arch/sandbox/dts/sandbox_pmic.dtsi | 2 +- arch/sandbox/dts/test.dts | 6 + board/samsung/common/Makefile | 5 +- board/samsung/common/board.c | 4 +- board/samsung/common/exynos5-dt-types.c | 196 ++++++++++++++ board/samsung/common/exynos5-dt.c | 12 + board/samsung/common/misc.c | 3 + configs/odroid-xu3_defconfig | 5 + configs/sandbox_defconfig | 2 + doc/device-tree-bindings/adc/adc.txt | 62 +++++ doc/device-tree-bindings/exynos/soc.txt | 21 ++ doc/device-tree-bindings/pmic/s2mps11.txt | 17 ++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/adc/Kconfig | 30 +++ drivers/adc/Makefile | 10 + drivers/adc/adc-uclass.c | 409 +++++++++++++++++++++++++++++ drivers/adc/exynos-adc.c | 145 ++++++++++ drivers/adc/sandbox.c | 174 ++++++++++++ drivers/power/pmic/Kconfig | 14 + drivers/power/pmic/Makefile | 1 + drivers/power/pmic/s2mps11.c | 62 +++++ drivers/power/regulator/regulator-uclass.c | 7 + include/adc.h | 288 ++++++++++++++++++++ include/configs/odroid_xu3.h | 12 + include/dm/uclass-id.h | 1 + include/power/regulator.h | 16 ++ include/power/s2mps11.h | 109 ++++++++ include/power/sandbox_pmic.h | 4 + include/samsung/exynos5-dt-types.h | 27 ++ test/dm/Makefile | 1 + test/dm/adc.c | 165 ++++++++++++ 44 files changed, 1904 insertions(+), 23 deletions(-) create mode 100644 board/samsung/common/exynos5-dt-types.c create mode 100644 doc/device-tree-bindings/adc/adc.txt create mode 100644 doc/device-tree-bindings/exynos/soc.txt create mode 100644 doc/device-tree-bindings/pmic/s2mps11.txt create mode 100644 drivers/adc/Kconfig create mode 100644 drivers/adc/Makefile create mode 100644 drivers/adc/adc-uclass.c create mode 100644 drivers/adc/exynos-adc.c create mode 100644 drivers/adc/sandbox.c create mode 100644 drivers/power/pmic/s2mps11.c create mode 100644 include/adc.h create mode 100644 include/power/s2mps11.h create mode 100644 include/samsung/exynos5-dt-types.h create mode 100644 test/dm/adc.c
applied to u-boot-samsung.
Thanks, Minkyu Kang.
participants (6)
-
Anand Moon
-
Jaehoon Chung
-
Minkyu Kang
-
Przemyslaw Marczak
-
Siarhei Siamashka
-
Simon Glass