From bc3f39ea0d3c9339b7f09b1d766b6a62e1921033 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:07:54 +0100 Subject: samsung: board/misc: check returned pointer for get_board_type() calls 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 Cc: Minkyu Kang Reviewed-by: Simon Glass Tested-by: Anand Moon Signed-off-by: Minkyu Kang 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 -- cgit v0.10.2 From fdbb740d7c3fd701ca3af1f6033060cfd358c2bc Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:07:55 +0100 Subject: s5p: cpu_info: print "cpu-model" if exists in dts 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 Cc: Minkyu Kang Cc: Simon Glass Reviewed-by: Simon Glass Tested-by: Anand Moon Signed-off-by: Minkyu Kang 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 +#include #include #include +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 = ... +}; -- cgit v0.10.2 From 3b72b60099b87dedcc49cd6881d311515f23ac14 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:07:56 +0100 Subject: Peach-Pi: dts: add cpu-model string 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 Cc: Minkyu Kang Cc: Simon Glass Reviewed-by: Simon Glass Tested-by: Anand Moon Signed-off-by: Minkyu Kang 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"; -- cgit v0.10.2 From d64c8adedc6df41165ca08973a0057645ef72139 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:07:57 +0100 Subject: Exynos5422/5800: set cpu id to 0x5422 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 Cc: Minkyu Kang Cc: Simon Glass Tested-by: Anand Moon Signed-off-by: Minkyu Kang 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); -- cgit v0.10.2 From 35d460fbc8ced954fe23812e706d3eebc1dd2b4d Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:07:58 +0100 Subject: dm: pmic: add s2mps11 PMIC I/O driver 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 Reviewed-by: Simon Glass Tested-by: Anand Moon Signed-off-by: Minkyu Kang 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +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 -- cgit v0.10.2 From 7c816e24a4e980e2717e5c83090dec73bc4eac57 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:07:59 +0100 Subject: dm: regulator: add function device_get_supply_regulator() 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 Cc: Simon Glass Signed-off-by: Minkyu Kang 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_ */ -- cgit v0.10.2 From 5decbf53006c8e2aed8e5506b3961810c1544b3c Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:00 +0100 Subject: dm: adc: add simple ADC uclass implementation 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 Cc: Simon Glass Signed-off-by: Minkyu Kang 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 +# +# 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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 + * + * 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 */ -- cgit v0.10.2 From 3b3ad9015e95ccad1a06e2eed1f182c8ddc36b21 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:01 +0100 Subject: dm: adc: add Exynos54xx compatible ADC driver 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 Cc: Minkyu Kang Cc: Simon Glass Signed-off-by: Minkyu Kang 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include + +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), +}; -- cgit v0.10.2 From 4d577e0810ccc10cfb7ea61308061fa7ef832468 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:02 +0100 Subject: Odroid-XU3: enable s2mps11 PMIC support Signed-off-by: Przemyslaw Marczak Cc: Minkyu Kang Cc: Simon Glass Tested-by: Anand Moon Signed-off-by: Minkyu Kang 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 -- cgit v0.10.2 From 54b51e6b12f0667848e0d1d994673630d28b219e Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:03 +0100 Subject: Exynos54xx: dts: add ADC node This commit adds common ADC node, which is disabled as default. Signed-off-by: Przemyslaw Marczak Cc: Minkyu Kang Cc: Simon Glass Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang 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>; -- cgit v0.10.2 From 9090d1dd0e379d598b72c7176cf55f3343421dae Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:04 +0100 Subject: Odroid-XU3: dts: enable ADC, with request for pre-reloc bind 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 Cc: Minkyu Kang Cc: Simon Glass Signed-off-by: Minkyu Kang 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"; -- cgit v0.10.2 From 1611c8cbcfe2ee50cc5e96f3a5c666c99d235107 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:05 +0100 Subject: exynos5-dt-types: add board detection for Odroid XU3/XU3L/XU4. 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 Cc: Minkyu Kang Cc: Simon Glass Tested-by: Anand Moon Signed-off-by: Minkyu Kang 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 #include #include +#include #include +#include +#include #include 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 -- cgit v0.10.2 From 08d6300a35bf2eb7915f0fa2fea9fa60b5075b71 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:06 +0100 Subject: 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 Cc: Simon Glass Signed-off-by: Minkyu Kang 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include + +/** + * 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), +}; -- cgit v0.10.2 From c48cb7ebfb42d997a3f4317a412992f403c717aa Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Tue, 27 Oct 2015 13:08:07 +0100 Subject: sandbox: add ADC unit tests 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 Cc: Simon Glass Signed-off-by: Minkyu Kang 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); -- cgit v0.10.2 From 5d0434315c46a3a038a9842a6627f6a57d1538da Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Wed, 28 Oct 2015 15:41:49 +0100 Subject: Exynos4412: pinmux: disable pull for MMC pins There are 8 pins for SD card in Exynos, but the MUX was configured only for 7, since the one was used for card detection. This caused the pin's pull wrong configuration. This commit fixes this and the card detect can work properly, after call this function. Tested-on: Odroid U3 and Odroid X2. Signed-off-by: Przemyslaw Marczak Cc: Guillaume GARDET Cc: Lukasz Majewski Cc: Jaehoon Chung Cc: Minkyu Kang Cc: Simon Glass Acked-by: Jaehoon Chung Tested-by: Lukasz Majewski Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c index a556e4a..12eb79c 100644 --- a/arch/arm/mach-exynos/pinmux.c +++ b/arch/arm/mach-exynos/pinmux.c @@ -737,10 +737,10 @@ static int exynos4x12_mmc_config(int peripheral, int flags) return -1; } for (i = start; i < (start + 7); i++) { + gpio_set_pull(i, S5P_GPIO_PULL_NONE); if (i == (start + 2)) continue; gpio_cfg_pin(i, func); - gpio_set_pull(i, S5P_GPIO_PULL_NONE); gpio_set_drv(i, S5P_GPIO_DRV_4X); } if (flags & PINMUX_FLAG_8BIT_MODE) { -- cgit v0.10.2 From 96094d4c46ba6f0402fd6add9b246380dae54536 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Wed, 28 Oct 2015 15:41:50 +0100 Subject: s5p sdhci: call pinmux for card's gpio pins before use them The SD card detection depends on checking one pin state. But the pin was configured after card was detected, which is wrong. This commit fixes this, by moving call to pinmux before use the pin. Tested-on: Odroid U3 and Odroid X2. Signed-off-by: Przemyslaw Marczak Cc: Guillaume GARDET Cc: Lukasz Majewski Cc: Jaehoon Chung Cc: Minkyu Kang Cc: Simon Glass Acked-by: Jaehoon Chung Tested-by: Lukasz Majewski Signed-off-by: Minkyu Kang diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 15ecfee..44353c7 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -106,6 +106,12 @@ static int do_sdhci_init(struct sdhci_host *host) flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; dev_id = host->index + PERIPH_ID_SDMMC0; + ret = exynos_pinmux_config(dev_id, flag); + if (ret) { + printf("external SD not configured\n"); + return ret; + } + if (dm_gpio_is_valid(&host->pwr_gpio)) { dm_gpio_set_value(&host->pwr_gpio, 1); ret = exynos_pinmux_config(dev_id, flag); @@ -121,12 +127,6 @@ static int do_sdhci_init(struct sdhci_host *host) debug("no SD card detected (%d)\n", ret); return -ENODEV; } - - ret = exynos_pinmux_config(dev_id, flag); - if (ret) { - printf("external SD not configured\n"); - return ret; - } } return s5p_sdhci_core_init(host); @@ -193,7 +193,7 @@ static int process_nodes(const void *blob, int node_list[], int count) } ret = do_sdhci_init(host); - if (ret) { + if (ret && ret != -ENODEV) { printf("%s: failed to initialize dev %d (%d)\n", __func__, i, ret); failed++; } -- cgit v0.10.2 From 55a70c51acd20d52badbb0683699b7a11fee5f44 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Thu, 22 Oct 2015 14:51:58 +0900 Subject: arm: exynos: clean up checkpatch issues This patch will fix these checkpatch issues. ERROR: Macros with complex values should be enclosed in parentheses +#define DEFAULT_DQS_X4 (DEFAULT_DQS << 24) || (DEFAULT_DQS << 16) \ + || (DEFAULT_DQS << 8) || (DEFAULT_DQS << 0) ERROR: space prohibited before that ',' (ctx:WxW) + writel(val , &drex0->concontrol); ^ ERROR: space prohibited before that ',' (ctx:WxW) + writel(val , &drex1->concontrol); ^ Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/dmc_init_ddr3.c b/arch/arm/mach-exynos/dmc_init_ddr3.c index 7c0b12a..25a9df9 100644 --- a/arch/arm/mach-exynos/dmc_init_ddr3.c +++ b/arch/arm/mach-exynos/dmc_init_ddr3.c @@ -20,8 +20,8 @@ #define TIMEOUT_US 10000 #define NUM_BYTE_LANES 4 #define DEFAULT_DQS 8 -#define DEFAULT_DQS_X4 (DEFAULT_DQS << 24) || (DEFAULT_DQS << 16) \ - || (DEFAULT_DQS << 8) || (DEFAULT_DQS << 0) +#define DEFAULT_DQS_X4 ((DEFAULT_DQS << 24) || (DEFAULT_DQS << 16) \ + || (DEFAULT_DQS << 8) || (DEFAULT_DQS << 0)) #ifdef CONFIG_EXYNOS5250 static void reset_phy_ctrl(void) @@ -856,10 +856,10 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, int reset) */ val = readl(&drex0->concontrol); val |= CONCONTROL_UPDATE_MODE; - writel(val , &drex0->concontrol); + writel(val, &drex0->concontrol); val = readl(&drex1->concontrol); val |= CONCONTROL_UPDATE_MODE; - writel(val , &drex1->concontrol); + writel(val, &drex1->concontrol); return 0; } -- cgit v0.10.2 From 6b949ba8243342906a1f4a2e6f1f8c307de40ffd Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Fri, 23 Oct 2015 15:59:37 +0900 Subject: smdkv310: clean up checkpatch issues This patch will fix these checkpatch issues. WARNING: Avoid unnecessary line continuations + gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1, \ WARNING: Avoid unnecessary line continuations + gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2, \ WARNING: Avoid unnecessary line continuations + gd->bd->bi_dram[2].size = get_ram_size((long *)PHYS_SDRAM_3, \ WARNING: Avoid unnecessary line continuations + gd->bd->bi_dram[3].size = get_ram_size((long *)PHYS_SDRAM_4, \ Signed-off-by: Minkyu Kang diff --git a/board/samsung/smdkv310/smdkv310.c b/board/samsung/smdkv310/smdkv310.c index cb7f9b0..fc0e8d2 100644 --- a/board/samsung/smdkv310/smdkv310.c +++ b/board/samsung/smdkv310/smdkv310.c @@ -55,16 +55,16 @@ int dram_init(void) void dram_init_banksize(void) { gd->bd->bi_dram[0].start = PHYS_SDRAM_1; - gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1, \ + gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE); gd->bd->bi_dram[1].start = PHYS_SDRAM_2; - gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2, \ + gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2, PHYS_SDRAM_2_SIZE); gd->bd->bi_dram[2].start = PHYS_SDRAM_3; - gd->bd->bi_dram[2].size = get_ram_size((long *)PHYS_SDRAM_3, \ + gd->bd->bi_dram[2].size = get_ram_size((long *)PHYS_SDRAM_3, PHYS_SDRAM_3_SIZE); gd->bd->bi_dram[3].start = PHYS_SDRAM_4; - gd->bd->bi_dram[3].size = get_ram_size((long *)PHYS_SDRAM_4, \ + gd->bd->bi_dram[3].size = get_ram_size((long *)PHYS_SDRAM_4, PHYS_SDRAM_4_SIZE); } -- cgit v0.10.2 From 9eae8441251188287ddd706196596a3117802449 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Fri, 23 Oct 2015 16:12:28 +0900 Subject: smdk2410: clean up checkpatch issues This patch will fix these checkpatch issues. ERROR: spaces required around that '==' (ctx:VxV) +#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */ ERROR: spaces required around that '==' (ctx:VxV) +#elif FCLK_SPEED==1 /* Fout = 202.8MHz */ ERROR: spaces required around that '==' (ctx:VxV) +#if USB_CLOCK==0 ERROR: spaces required around that '==' (ctx:VxV) +#elif USB_CLOCK==1 CHECK: spaces required around that ':' (ctx:VxV) + "bne 1b":"=r" (loops):"0" (loops)); Signed-off-by: Minkyu Kang diff --git a/board/samsung/smdk2410/smdk2410.c b/board/samsung/smdk2410/smdk2410.c index b75a0e3..6e678c7 100644 --- a/board/samsung/smdk2410/smdk2410.c +++ b/board/samsung/smdk2410/smdk2410.c @@ -18,11 +18,11 @@ DECLARE_GLOBAL_DATA_PTR; #define FCLK_SPEED 1 -#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */ +#if (FCLK_SPEED == 0) /* Fout = 203MHz, Fin = 12MHz for Audio */ #define M_MDIV 0xC3 #define M_PDIV 0x4 #define M_SDIV 0x1 -#elif FCLK_SPEED==1 /* Fout = 202.8MHz */ +#elif (FCLK_SPEED == 1) /* Fout = 202.8MHz */ #define M_MDIV 0xA1 #define M_PDIV 0x3 #define M_SDIV 0x1 @@ -30,11 +30,11 @@ DECLARE_GLOBAL_DATA_PTR; #define USB_CLOCK 1 -#if USB_CLOCK==0 +#if (USB_CLOCK == 0) #define U_M_MDIV 0xA1 #define U_M_PDIV 0x3 #define U_M_SDIV 0x1 -#elif USB_CLOCK==1 +#elif (USB_CLOCK == 1) #define U_M_MDIV 0x48 #define U_M_PDIV 0x3 #define U_M_SDIV 0x2 @@ -44,7 +44,7 @@ static inline void pll_delay(unsigned long loops) { __asm__ volatile ("1:\n" "subs %0, %1, #1\n" - "bne 1b":"=r" (loops):"0" (loops)); + "bne 1b" : "=r" (loops) : "0" (loops)); } /* -- cgit v0.10.2 From 1d83970f6f6003276373843b8e2fd75f78f1caf3 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Fri, 23 Oct 2015 16:15:04 +0900 Subject: odroid: clean up checkpatch issues This patch will fix these checkpatch issues. +static const char *mmc_regulators[] = { CHECK: Blank lines aren't necessary before a close brace '}' + +} Signed-off-by: Minkyu Kang diff --git a/board/samsung/odroid/odroid.c b/board/samsung/odroid/odroid.c index 32155f1..36d493d 100644 --- a/board/samsung/odroid/odroid.c +++ b/board/samsung/odroid/odroid.c @@ -33,13 +33,6 @@ enum { ODROID_TYPES, }; -static const char *mmc_regulators[] = { - "VDDQ_EMMC_1.8V", - "VDDQ_EMMC_2.8V", - "TFLASH_2.8V", - NULL, -}; - void set_board_type(void) { /* Set GPA1 pin 1 to HI - enable XCL205 output */ @@ -428,6 +421,13 @@ int exynos_init(void) int exynos_power_init(void) { + const char *mmc_regulators[] = { + "VDDQ_EMMC_1.8V", + "VDDQ_EMMC_2.8V", + "TFLASH_2.8V", + NULL, + }; + if (regulator_list_autoset(mmc_regulators, NULL, true)) error("Unable to init all mmc regulators"); @@ -450,7 +450,6 @@ static int s5pc210_phy_control(int on) return regulator_set_mode(dev, OPMODE_ON); else return regulator_set_mode(dev, OPMODE_LPM); - } struct s3c_plat_otg_data s5pc210_otg_data = { -- cgit v0.10.2 From de5f9733f653091d4b227914d04432099a6448dc Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Fri, 23 Oct 2015 16:21:20 +0900 Subject: samsung: clean up checkpatch issues This patch will fix these checkpatch issues. CHECK: Alignment should match open parenthesis + printf("Enter: %s %s\n", mode_name[mode][0], + mode_info[mode]); CHECK: Alignment should match open parenthesis + lcd_printf("\n\n\t%s %s\n", mode_name[mode][0], + mode_info[mode]); CHECK: Alignment should match open parenthesis + lcd_printf("\t%s %s - %s\n\n", selection[i], + mode_name[i][0], Signed-off-by: Minkyu Kang diff --git a/board/samsung/common/misc.c b/board/samsung/common/misc.c index c8316d8..da0d4db 100644 --- a/board/samsung/common/misc.c +++ b/board/samsung/common/misc.c @@ -259,9 +259,9 @@ static int mode_leave_menu(int mode) cmd = find_cmd(mode_name[mode][1]); if (cmd) { printf("Enter: %s %s\n", mode_name[mode][0], - mode_info[mode]); + mode_info[mode]); lcd_printf("\n\n\t%s %s\n", mode_name[mode][0], - mode_info[mode]); + mode_info[mode]); lcd_puts("\n\tDo not turn off device before finish!\n"); cmd_result = run_command(mode_cmd[mode], 0); @@ -318,8 +318,7 @@ static void display_download_menu(int mode) for (i = 0; i <= BOOT_MODE_EXIT; i++) lcd_printf("\t%s %s - %s\n\n", selection[i], - mode_name[i][0], - mode_info[i]); + mode_name[i][0], mode_info[i]); } static void download_menu(void) -- cgit v0.10.2 From 58cb44cf6623faeebd9b04ac44cf11d2eb39ea36 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Wed, 4 Nov 2015 18:30:09 +0100 Subject: sandbox: adc: Add missing header file Commit: sandbox: add ADC driver adds the driver without its main header file. It causes build brake for sandbox_defonfig. This commit adds a missing header: - include/sandbox-adc.h Signed-off-by: Przemyslaw Marczak Cc: Minkyu Kang Cc: Simon Glass Signed-off-by: Minkyu Kang 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 + * + * 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 -- cgit v0.10.2