Merge git://git.denx.de/u-boot-samsung

This commit is contained in:
Tom Rini 2015-11-05 07:46:45 -05:00
commit 60b25259a5
50 changed files with 1966 additions and 56 deletions

View File

@ -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;

View File

@ -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>;
};

View File

@ -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>;

View File

@ -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";

View File

@ -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);
}

View File

@ -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();

View File

@ -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;

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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; \
} \

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -55,7 +55,7 @@
regulator-always-on;
};
buck2 {
buck2: buck2 {
regulator-name = "SUPPLY_3.3V";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;

View File

@ -189,6 +189,12 @@
};
};
adc@0 {
compatible = "sandbox,adc";
vdd-supply = <&buck2>;
vss-microvolts = <0>;
};
leds {
compatible = "gpio-leds";

View File

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

View File

@ -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;
}

View 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();
}

View File

@ -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);

View File

@ -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)

View File

@ -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 = {

View File

@ -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));
}
/*

View File

@ -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);
}

View File

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

View File

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

View 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.

View 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 = ...
};

View 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>;
};

View File

@ -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"

View File

@ -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
View 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
View 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
View 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
View 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(&regs->status)) != FLAG_CONV_END)
return -EBUSY;
*data = readl(&regs->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(&regs->con2);
cfg &= ~ADC_V2_CON2_CHAN_SEL_MASK;
cfg |= ADC_V2_CON2_CHAN_SEL(channel);
writel(cfg, &regs->con2);
/* Start conversion */
cfg = readl(&regs->con1);
writel(cfg | ADC_V2_CON1_STC_EN, &regs->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(&regs->con1);
cfg |= ~ADC_V2_CON1_STC_EN;
writel(cfg, &regs->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(&regs->version) != ADC_V2_VERSION) {
error("This driver supports only ADC v2!");
return -ENXIO;
}
/* ADC Reset */
writel(ADC_V2_CON1_SOFT_RESET, &regs->con1);
/* Disable INT - will read status only */
writel(0x0, &regs->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, &regs->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
View 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),
};

View File

@ -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++;
}

View File

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

View File

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

View 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,
};

View File

@ -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
View 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

View File

@ -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 \

View File

@ -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 */

View File

@ -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
View 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

View File

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

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

View File

@ -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
View 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);