Merge git://git.denx.de/u-boot-samsung
This commit is contained in:
commit
60b25259a5
@ -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;
|
||||
|
@ -31,6 +31,18 @@
|
||||
0xb0000000 0xea00000>;
|
||||
};
|
||||
|
||||
adc@12D10000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
i2c@12CA0000 {
|
||||
s2mps11_pmic@66 {
|
||||
compatible = "samsung,s2mps11-pmic";
|
||||
reg = <0x66>;
|
||||
};
|
||||
};
|
||||
|
||||
ehci@12110000 {
|
||||
samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
@ -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>;
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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; \
|
||||
} \
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -55,7 +55,7 @@
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
buck2 {
|
||||
buck2: buck2 {
|
||||
regulator-name = "SUPPLY_3.3V";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
|
@ -189,6 +189,12 @@
|
||||
};
|
||||
};
|
||||
|
||||
adc@0 {
|
||||
compatible = "sandbox,adc";
|
||||
vdd-supply = <&buck2>;
|
||||
vss-microvolts = <0>;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
196
board/samsung/common/exynos5-dt-types.c
Normal file
196
board/samsung/common/exynos5-dt-types.c
Normal file
@ -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();
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
@ -256,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);
|
||||
@ -315,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)
|
||||
|
@ -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 = {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,12 @@ 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
|
||||
CONFIG_ADC=y
|
||||
CONFIG_ADC_EXYNOS=y
|
||||
|
@ -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
|
||||
|
62
doc/device-tree-bindings/adc/adc.txt
Normal file
62
doc/device-tree-bindings/adc/adc.txt
Normal file
@ -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.
|
21
doc/device-tree-bindings/exynos/soc.txt
Normal file
21
doc/device-tree-bindings/exynos/soc.txt
Normal file
@ -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 = ...
|
||||
};
|
17
doc/device-tree-bindings/pmic/s2mps11.txt
Normal file
17
doc/device-tree-bindings/pmic/s2mps11.txt
Normal file
@ -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>;
|
||||
};
|
@ -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"
|
||||
|
@ -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/
|
||||
|
30
drivers/adc/Kconfig
Normal file
30
drivers/adc/Kconfig
Normal file
@ -0,0 +1,30 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
10
drivers/adc/Makefile
Normal file
10
drivers/adc/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright (C) 2015 Samsung Electronics
|
||||
# Przemyslaw Marczak <p.marczak@samsung.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ADC) += adc-uclass.o
|
||||
obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o
|
||||
obj-$(CONFIG_ADC_SANDBOX) += sandbox.o
|
409
drivers/adc/adc-uclass.c
Normal file
409
drivers/adc/adc-uclass.c
Normal file
@ -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,
|
||||
};
|
145
drivers/adc/exynos-adc.c
Normal file
145
drivers/adc/exynos-adc.c
Normal file
@ -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),
|
||||
};
|
174
drivers/adc/sandbox.c
Normal file
174
drivers/adc/sandbox.c
Normal file
@ -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),
|
||||
};
|
@ -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++;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
62
drivers/power/pmic/s2mps11.c
Normal file
62
drivers/power/pmic/s2mps11.c
Normal file
@ -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,
|
||||
};
|
@ -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;
|
||||
|
288
include/adc.h
Normal file
288
include/adc.h
Normal file
@ -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
|
@ -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 \
|
||||
|
@ -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 */
|
||||
|
@ -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_ */
|
||||
|
109
include/power/s2mps11.h
Normal file
109
include/power/s2mps11.h
Normal file
@ -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
|
@ -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
|
||||
|
27
include/samsung/exynos5-dt-types.h
Normal file
27
include/samsung/exynos5-dt-types.h
Normal file
@ -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
|
31
include/sandbox-adc.h
Normal file
31
include/sandbox-adc.h
Normal file
@ -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
|
@ -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
|
||||
|
165
test/dm/adc.c
Normal file
165
test/dm/adc.c
Normal file
@ -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);
|
Loading…
Reference in New Issue
Block a user