[U-Boot] [PATCH v2 0/12] Enable LCD display on snow

This series adds a driver for TPS65090 and plumbs it in to get the LCD working correctly on snow.
The display driver is already present, but needs information about the display to be provided in the device tree.
The backlight also needs to be enabled - it is controlled by a FET on the TPS65090. Note that the TPS65090 is controlled by the device tree so will only be present if the board's device tree file specifies it. At present this is only the case for snow, but other exynos5 boards will use it (e.g. pit).
Note: the TPS65090 driver was sent to the list around the middle of last year but was never applied.
Changes in v2: - Add new patch to drop smdk5250.c file - Add new patch to rename CHARGER_EN/DISABLE - Removed non-device-tree operation - Use errno.h for error return codes everywhere - Plumb into pmic charging framework - Fix style nit - Use correct license header - Use new Linux device tree bindings - Add partial battery charging support - Update patch name to exynos5-dt instead of smdk5250 - Move code to exynos5-dt.c - Fix comment style - Add #ifdef around tps65090 code - Add a device tree node for the snow EDP bridge chip - Only set up the EDP bridge for snow - Add a device tree compatibility string for the EDP bridge - Check for EDP failure and print an error in that case - Return immediately in exynos_backlight_on() if needed - Rebase to samsung/master
Aaron Durbin (3): exynos5: Enable tps65090 on exynos5-dt power: Explicitly select pmic device's bus exynos5: support tps65090 pmic
Simon Glass (8): exynos: Drop old smdk5250.c file power: Rename CONFIG_PMIC_... to CONFIG_POWER_... power: Add PMIC_ prefix to CHARGER_EN/DISABLE exynos: Enable PSHOLD in SPL exynos: dts: Disable cros_ec interrupts due to broken GPIOs exynos: dts: Enable LCD for snow exynos: Enable the LCD backlight for snow initcall: Improve debugging support
Tom Wai-Hong Tam (1): power: Add support for TPS65090 PMU chip.
arch/arm/cpu/armv7/exynos/lowlevel_init.c | 2 + arch/arm/dts/exynos5250-snow.dts | 69 ++++- board/samsung/smdk5250/Makefile | 4 - board/samsung/smdk5250/exynos5-dt.c | 241 ++++++++++++++++ board/samsung/smdk5250/smdk5250.c | 368 ------------------------ doc/device-tree-bindings/power/tps65090.txt | 17 ++ doc/device-tree-bindings/regulator/tps65090.txt | 122 ++++++++ drivers/power/battery/bat_trats.c | 4 +- drivers/power/battery/bat_trats2.c | 2 +- drivers/power/mfd/pmic_max77693.c | 2 +- drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pmic_max8997.c | 2 +- drivers/power/pmic/pmic_tps65090.c | 312 ++++++++++++++++++++ drivers/power/power_fsl.c | 6 +- drivers/power/power_i2c.c | 4 + include/configs/arndale.h | 4 +- include/configs/exynos5-dt.h | 1 + include/configs/exynos5250-dt.h | 2 +- include/configs/mx25pdk.h | 2 +- include/configs/mx35pdk.h | 2 +- include/configs/mx53evk.h | 2 +- include/configs/mx53loco.h | 2 +- include/configs/woodburn_common.h | 2 +- include/fdtdec.h | 2 + include/initcall.h | 2 +- include/power/max77693_pmic.h | 2 - include/power/max8997_pmic.h | 1 - include/power/pmic.h | 5 + include/power/tps65090_pmic.h | 73 +++++ lib/fdtdec.c | 2 + lib/initcall.c | 17 +- 31 files changed, 878 insertions(+), 399 deletions(-) delete mode 100644 board/samsung/smdk5250/smdk5250.c create mode 100644 doc/device-tree-bindings/power/tps65090.txt create mode 100644 doc/device-tree-bindings/regulator/tps65090.txt create mode 100644 drivers/power/pmic/pmic_tps65090.c create mode 100644 include/power/tps65090_pmic.h

This is not used by any boards now. Drop it to avoid confusion.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add new patch to drop smdk5250.c file
board/samsung/smdk5250/Makefile | 4 - board/samsung/smdk5250/exynos5-dt.c | 125 ++++++++++++ board/samsung/smdk5250/smdk5250.c | 368 ------------------------------------ 3 files changed, 125 insertions(+), 372 deletions(-) delete mode 100644 board/samsung/smdk5250/smdk5250.c
diff --git a/board/samsung/smdk5250/Makefile b/board/samsung/smdk5250/Makefile index 6a58655..3d96b07 100644 --- a/board/samsung/smdk5250/Makefile +++ b/board/samsung/smdk5250/Makefile @@ -7,9 +7,5 @@ obj-y += smdk5250_spl.o
ifndef CONFIG_SPL_BUILD -ifdef CONFIG_OF_CONTROL obj-y += exynos5-dt.o -else -obj-y += smdk5250.o -endif endif diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 379a45c..1a64b9b 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -44,6 +44,131 @@ int exynos_init(void) return 0; }
+#if defined(CONFIG_POWER) +#ifdef CONFIG_POWER_MAX77686 +static int pmic_reg_update(struct pmic *p, int reg, uint regval) +{ + u32 val; + int ret = 0; + + ret = pmic_reg_read(p, reg, &val); + if (ret) { + debug("%s: PMIC %d register read failed\n", __func__, reg); + return -1; + } + val |= regval; + ret = pmic_reg_write(p, reg, val); + if (ret) { + debug("%s: PMIC %d register write failed\n", __func__, reg); + return -1; + } + return 0; +} + +static int max77686_init(void) +{ + struct pmic *p; + + if (pmic_init(I2C_PMIC)) + return -1; + + p = pmic_get("MAX77686_PMIC"); + if (!p) + return -ENODEV; + + if (pmic_probe(p)) + return -1; + + if (pmic_reg_update(p, MAX77686_REG_PMIC_32KHZ, MAX77686_32KHCP_EN)) + return -1; + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BBAT, + MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V)) + return -1; + + /* VDD_MIF */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK1OUT, + MAX77686_BUCK1OUT_1V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK1OUT); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK1CRTL, + MAX77686_BUCK1CTRL_EN)) + return -1; + + /* VDD_ARM */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK2DVS1, + MAX77686_BUCK2DVS1_1_3V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK2DVS1); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK2CTRL1, + MAX77686_BUCK2CTRL_ON)) + return -1; + + /* VDD_INT */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK3DVS1, + MAX77686_BUCK3DVS1_1_0125V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK3DVS1); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK3CTRL, + MAX77686_BUCK3CTRL_ON)) + return -1; + + /* VDD_G3D */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK4DVS1, + MAX77686_BUCK4DVS1_1_2V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK4DVS1); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK4CTRL1, + MAX77686_BUCK3CTRL_ON)) + return -1; + + /* VDD_LDO2 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO2CTRL1, + MAX77686_LD02CTRL1_1_5V | EN_LDO)) + return -1; + + /* VDD_LDO3 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO3CTRL1, + MAX77686_LD03CTRL1_1_8V | EN_LDO)) + return -1; + + /* VDD_LDO5 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO5CTRL1, + MAX77686_LD05CTRL1_1_8V | EN_LDO)) + return -1; + + /* VDD_LDO10 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO10CTRL1, + MAX77686_LD10CTRL1_1_8V | EN_LDO)) + return -1; + + return 0; +} +#endif /* CONFIG_POWER_MAX77686 */ + +int exynos_power_init(void) +{ + int ret = 0; + +#ifdef CONFIG_POWER_MAX77686 + ret = max77686_init(); +#endif + return ret; +} +#endif /* CONFIG_POWER */ + #ifdef CONFIG_LCD void exynos_cfg_lcd_gpio(void) { diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c deleted file mode 100644 index 28a6d9e..0000000 --- a/board/samsung/smdk5250/smdk5250.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <cros_ec.h> -#include <fdtdec.h> -#include <asm/io.h> -#include <errno.h> -#include <i2c.h> -#include <lcd.h> -#include <netdev.h> -#include <spi.h> -#include <asm/arch/cpu.h> -#include <asm/arch/dwmmc.h> -#include <asm/arch/gpio.h> -#include <asm/arch/mmc.h> -#include <asm/arch/pinmux.h> -#include <asm/arch/power.h> -#include <asm/arch/sromc.h> -#include <asm/arch/dp_info.h> -#include <power/pmic.h> -#include <power/max77686_pmic.h> - -DECLARE_GLOBAL_DATA_PTR; - -#ifdef CONFIG_SOUND_MAX98095 -static void board_enable_audio_codec(void) -{ - struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *) - samsung_get_base_gpio_part1(); - - /* Enable MAX98095 Codec */ - s5p_gpio_direction_output(&gpio1->x1, 7, 1); - s5p_gpio_set_pull(&gpio1->x1, 7, GPIO_PULL_NONE); -} -#endif - -int exynos_init(void) -{ -#ifdef CONFIG_SOUND_MAX98095 - board_enable_audio_codec(); -#endif - return 0; -} - -int board_eth_init(bd_t *bis) -{ -#ifdef CONFIG_SMC911X - u32 smc_bw_conf, smc_bc_conf; - struct fdt_sromc config; - fdt_addr_t base_addr; - - /* Non-FDT configuration - bank number and timing parameters*/ - config.bank = CONFIG_ENV_SROM_BANK; - config.width = 2; - - config.timing[FDT_SROM_TACS] = 0x01; - config.timing[FDT_SROM_TCOS] = 0x01; - config.timing[FDT_SROM_TACC] = 0x06; - config.timing[FDT_SROM_TCOH] = 0x01; - config.timing[FDT_SROM_TAH] = 0x0C; - config.timing[FDT_SROM_TACP] = 0x09; - config.timing[FDT_SROM_PMC] = 0x01; - base_addr = CONFIG_SMC911X_BASE; - - /* Ethernet needs data bus width of 16 bits */ - if (config.width != 2) { - debug("%s: Unsupported bus width %d\n", __func__, - config.width); - return -1; - } - smc_bw_conf = SROMC_DATA16_WIDTH(config.bank) - | SROMC_BYTE_ENABLE(config.bank); - - smc_bc_conf = SROMC_BC_TACS(config.timing[FDT_SROM_TACS]) |\ - SROMC_BC_TCOS(config.timing[FDT_SROM_TCOS]) |\ - SROMC_BC_TACC(config.timing[FDT_SROM_TACC]) |\ - SROMC_BC_TCOH(config.timing[FDT_SROM_TCOH]) |\ - SROMC_BC_TAH(config.timing[FDT_SROM_TAH]) |\ - SROMC_BC_TACP(config.timing[FDT_SROM_TACP]) |\ - SROMC_BC_PMC(config.timing[FDT_SROM_PMC]); - - /* Select and configure the SROMC bank */ - exynos_pinmux_config(PERIPH_ID_SROMC, config.bank); - s5p_config_sromc(config.bank, smc_bw_conf, smc_bc_conf); - return smc911x_initialize(0, base_addr); -#endif - return 0; -} - -#ifdef CONFIG_DISPLAY_BOARDINFO -int checkboard(void) -{ - printf("\nBoard: SMDK5250\n"); - return 0; -} -#endif - -#ifdef CONFIG_GENERIC_MMC -int board_mmc_init(bd_t *bis) -{ - int err, ret = 0, index, bus_width; - u32 base; - - err = exynos_pinmux_config(PERIPH_ID_SDMMC0, PINMUX_FLAG_8BIT_MODE); - if (err) - debug("SDMMC0 not configured\n"); - ret |= err; - - /*EMMC: dwmmc Channel-0 with 8 bit bus width */ - index = 0; - base = samsung_get_base_mmc() + (0x10000 * index); - bus_width = 8; - err = exynos_dwmci_add_port(index, base, bus_width, (u32)NULL); - if (err) - debug("dwmmc Channel-0 init failed\n"); - ret |= err; - - err = exynos_pinmux_config(PERIPH_ID_SDMMC2, PINMUX_FLAG_NONE); - if (err) - debug("SDMMC2 not configured\n"); - ret |= err; - - /*SD: dwmmc Channel-2 with 4 bit bus width */ - index = 2; - base = samsung_get_base_mmc() + (0x10000 * index); - bus_width = 4; - err = exynos_dwmci_add_port(index, base, bus_width, (u32)NULL); - if (err) - debug("dwmmc Channel-2 init failed\n"); - ret |= err; - - return ret; -} -#endif - -void board_i2c_init(const void *blob) -{ - int i; - - for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) { - exynos_pinmux_config((PERIPH_ID_I2C0 + i), - PINMUX_FLAG_NONE); - } -} - -#if defined(CONFIG_POWER) -#ifdef CONFIG_POWER_MAX77686 -static int pmic_reg_update(struct pmic *p, int reg, uint regval) -{ - u32 val; - int ret = 0; - - ret = pmic_reg_read(p, reg, &val); - if (ret) { - debug("%s: PMIC %d register read failed\n", __func__, reg); - return -1; - } - val |= regval; - ret = pmic_reg_write(p, reg, val); - if (ret) { - debug("%s: PMIC %d register write failed\n", __func__, reg); - return -1; - } - return 0; -} - -static int max77686_init(void) -{ - struct pmic *p; - - if (pmic_init(I2C_PMIC)) - return -1; - - p = pmic_get("MAX77686_PMIC"); - if (!p) - return -ENODEV; - - if (pmic_probe(p)) - return -1; - - if (pmic_reg_update(p, MAX77686_REG_PMIC_32KHZ, MAX77686_32KHCP_EN)) - return -1; - - if (pmic_reg_update(p, MAX77686_REG_PMIC_BBAT, - MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V)) - return -1; - - /* VDD_MIF */ - if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK1OUT, - MAX77686_BUCK1OUT_1V)) { - debug("%s: PMIC %d register write failed\n", __func__, - MAX77686_REG_PMIC_BUCK1OUT); - return -1; - } - - if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK1CRTL, - MAX77686_BUCK1CTRL_EN)) - return -1; - - /* VDD_ARM */ - if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK2DVS1, - MAX77686_BUCK2DVS1_1_3V)) { - debug("%s: PMIC %d register write failed\n", __func__, - MAX77686_REG_PMIC_BUCK2DVS1); - return -1; - } - - if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK2CTRL1, - MAX77686_BUCK2CTRL_ON)) - return -1; - - /* VDD_INT */ - if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK3DVS1, - MAX77686_BUCK3DVS1_1_0125V)) { - debug("%s: PMIC %d register write failed\n", __func__, - MAX77686_REG_PMIC_BUCK3DVS1); - return -1; - } - - if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK3CTRL, - MAX77686_BUCK3CTRL_ON)) - return -1; - - /* VDD_G3D */ - if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK4DVS1, - MAX77686_BUCK4DVS1_1_2V)) { - debug("%s: PMIC %d register write failed\n", __func__, - MAX77686_REG_PMIC_BUCK4DVS1); - return -1; - } - - if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK4CTRL1, - MAX77686_BUCK3CTRL_ON)) - return -1; - - /* VDD_LDO2 */ - if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO2CTRL1, - MAX77686_LD02CTRL1_1_5V | EN_LDO)) - return -1; - - /* VDD_LDO3 */ - if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO3CTRL1, - MAX77686_LD03CTRL1_1_8V | EN_LDO)) - return -1; - - /* VDD_LDO5 */ - if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO5CTRL1, - MAX77686_LD05CTRL1_1_8V | EN_LDO)) - return -1; - - /* VDD_LDO10 */ - if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO10CTRL1, - MAX77686_LD10CTRL1_1_8V | EN_LDO)) - return -1; - - return 0; -} -#endif /* CONFIG_POWER_MAX77686 */ - -int exynos_power_init(void) -{ - int ret = 0; - -#ifdef CONFIG_POWER_MAX77686 - ret = max77686_init(); -#endif - return ret; -} -#endif /* CONFIG_POWER */ - -#ifdef CONFIG_LCD -void exynos_cfg_lcd_gpio(void) -{ - struct exynos5_gpio_part1 *gpio1 = - (struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); - - /* For Backlight */ - s5p_gpio_cfg_pin(&gpio1->b2, 0, GPIO_OUTPUT); - s5p_gpio_set_value(&gpio1->b2, 0, 1); - - /* LCD power on */ - s5p_gpio_cfg_pin(&gpio1->x1, 5, GPIO_OUTPUT); - s5p_gpio_set_value(&gpio1->x1, 5, 1); - - /* Set Hotplug detect for DP */ - s5p_gpio_cfg_pin(&gpio1->x0, 7, GPIO_FUNC(0x3)); -} - -void exynos_set_dp_phy(unsigned int onoff) -{ - set_dp_phy_ctrl(onoff); -} - -vidinfo_t panel_info = { - .vl_freq = 60, - .vl_col = 2560, - .vl_row = 1600, - .vl_width = 2560, - .vl_height = 1600, - .vl_clkp = CONFIG_SYS_LOW, - .vl_hsp = CONFIG_SYS_LOW, - .vl_vsp = CONFIG_SYS_LOW, - .vl_dp = CONFIG_SYS_LOW, - .vl_bpix = 4, /* LCD_BPP = 2^4, for output conosle on LCD */ - - /* wDP panel timing infomation */ - .vl_hspw = 32, - .vl_hbpd = 80, - .vl_hfpd = 48, - - .vl_vspw = 6, - .vl_vbpd = 37, - .vl_vfpd = 3, - .vl_cmd_allow_len = 0xf, - - .win_id = 3, - .dual_lcd_enabled = 0, - - .init_delay = 0, - .power_on_delay = 0, - .reset_delay = 0, - .interface_mode = FIMD_RGB_INTERFACE, - .dp_enabled = 1, -}; - -static struct edp_device_info edp_info = { - .disp_info = { - .h_res = 2560, - .h_sync_width = 32, - .h_back_porch = 80, - .h_front_porch = 48, - .v_res = 1600, - .v_sync_width = 6, - .v_back_porch = 37, - .v_front_porch = 3, - .v_sync_rate = 60, - }, - .lt_info = { - .lt_status = DP_LT_NONE, - }, - .video_info = { - .master_mode = 0, - .bist_mode = DP_DISABLE, - .bist_pattern = NO_PATTERN, - .h_sync_polarity = 0, - .v_sync_polarity = 0, - .interlaced = 0, - .color_space = COLOR_RGB, - .dynamic_range = VESA, - .ycbcr_coeff = COLOR_YCBCR601, - .color_depth = COLOR_8, - }, -}; - -static struct exynos_dp_platform_data dp_platform_data = { - .edp_dev_info = &edp_info, -}; - -void init_panel_info(vidinfo_t *vid) -{ - vid->rgb_mode = MODE_RGB_P; - exynos_set_dp_platform_data(&dp_platform_data); -} -#endif

Commit be3b51aa did this mostly, but several have been added since. Do the job again.
Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Lukasz Majewski l.majewski@samsung.com ---
Changes in v2: None
drivers/power/power_fsl.c | 6 +++--- include/configs/arndale.h | 4 ++-- include/configs/exynos5250-dt.h | 2 +- include/configs/mx25pdk.h | 2 +- include/configs/mx35pdk.h | 2 +- include/configs/mx53evk.h | 2 +- include/configs/mx53loco.h | 2 +- include/configs/woodburn_common.h | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/power/power_fsl.c b/drivers/power/power_fsl.c index ac0b541..a64161b 100644 --- a/drivers/power/power_fsl.c +++ b/drivers/power/power_fsl.c @@ -11,9 +11,9 @@ #include <fsl_pmic.h> #include <errno.h>
-#if defined(CONFIG_PMIC_FSL_MC13892) +#if defined(CONFIG_POWER_FSL_MC13892) #define FSL_PMIC_I2C_LENGTH 3 -#elif defined(CONFIG_PMIC_FSL_MC34704) +#elif defined(CONFIG_POWER_FSL_MC34704) #define FSL_PMIC_I2C_LENGTH 1 #endif
@@ -51,7 +51,7 @@ int pmic_init(unsigned char bus) p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR; p->hw.i2c.tx_num = FSL_PMIC_I2C_LENGTH; #else -#error "You must select CONFIG_POWER_SPI or CONFIG_PMIC_I2C" +#error "You must select CONFIG_POWER_SPI or CONFIG_POWER_I2C" #endif
return 0; diff --git a/include/configs/arndale.h b/include/configs/arndale.h index 515facf..30ecd45 100644 --- a/include/configs/arndale.h +++ b/include/configs/arndale.h @@ -224,8 +224,8 @@
/* PMIC */ #define CONFIG_PMIC -#define CONFIG_PMIC_I2C -#define CONFIG_PMIC_MAX77686 +#define CONFIG_POWER_I2C +#define CONFIG_POWER_MAX77686
#define CONFIG_DEFAULT_DEVICE_TREE exynos5250-arndale
diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index b7ff472..9d1d56a 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -45,7 +45,7 @@ #define CONFIG_SYS_INIT_SP_ADDR CONFIG_IRAM_STACK
/* PMIC */ -#define CONFIG_PMIC_MAX77686 +#define CONFIG_POWER_MAX77686
/* Sound */ #define CONFIG_CMD_SOUND diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h index aff2419..d464ad9 100644 --- a/include/configs/mx25pdk.h +++ b/include/configs/mx25pdk.h @@ -107,7 +107,7 @@ #define CONFIG_POWER #define CONFIG_POWER_I2C #define CONFIG_POWER_FSL -#define CONFIG_PMIC_FSL_MC34704 +#define CONFIG_POWER_FSL_MC34704 #define CONFIG_SYS_FSL_PMIC_I2C_ADDR 0x54
#define CONFIG_DOS_PARTITION diff --git a/include/configs/mx35pdk.h b/include/configs/mx35pdk.h index 0a46f4c..ab48144 100644 --- a/include/configs/mx35pdk.h +++ b/include/configs/mx35pdk.h @@ -52,7 +52,7 @@ #define CONFIG_POWER #define CONFIG_POWER_I2C #define CONFIG_POWER_FSL -#define CONFIG_PMIC_FSL_MC13892 +#define CONFIG_POWER_FSL_MC13892 #define CONFIG_SYS_FSL_PMIC_I2C_ADDR 0x08 #define CONFIG_RTC_MC13XXX
diff --git a/include/configs/mx53evk.h b/include/configs/mx53evk.h index 3f0d80a..042cdd0 100644 --- a/include/configs/mx53evk.h +++ b/include/configs/mx53evk.h @@ -45,7 +45,7 @@ #define CONFIG_POWER_I2C #define CONFIG_POWER_FSL #define CONFIG_SYS_FSL_PMIC_I2C_ADDR 8 -#define CONFIG_PMIC_FSL_MC13892 +#define CONFIG_POWER_FSL_MC13892 #define CONFIG_RTC_MC13XXX
/* MMC Configs */ diff --git a/include/configs/mx53loco.h b/include/configs/mx53loco.h index 1415584..365d072 100644 --- a/include/configs/mx53loco.h +++ b/include/configs/mx53loco.h @@ -80,7 +80,7 @@ #define CONFIG_POWER_I2C #define CONFIG_DIALOG_POWER #define CONFIG_POWER_FSL -#define CONFIG_PMIC_FSL_MC13892 +#define CONFIG_POWER_FSL_MC13892 #define CONFIG_SYS_DIALOG_PMIC_I2C_ADDR 0x48 #define CONFIG_SYS_FSL_PMIC_I2C_ADDR 0x8
diff --git a/include/configs/woodburn_common.h b/include/configs/woodburn_common.h index 695bc23..259205e 100644 --- a/include/configs/woodburn_common.h +++ b/include/configs/woodburn_common.h @@ -55,7 +55,7 @@ #define CONFIG_POWER #define CONFIG_POWER_I2C #define CONFIG_POWER_FSL -#define CONFIG_PMIC_FSL_MC13892 +#define CONFIG_POWER_FSL_MC13892 #define CONFIG_SYS_FSL_PMIC_I2C_ADDR 0x8 #define CONFIG_RTC_MC13XXX

This enum should be common across all PMICs rather than having it independently defined with the same name in multiple places.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add new patch to rename CHARGER_EN/DISABLE
drivers/power/battery/bat_trats.c | 4 ++-- drivers/power/battery/bat_trats2.c | 2 +- drivers/power/mfd/pmic_max77693.c | 2 +- drivers/power/pmic/pmic_max8997.c | 2 +- include/power/max77693_pmic.h | 2 -- include/power/max8997_pmic.h | 1 - include/power/pmic.h | 5 +++++ 7 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/drivers/power/battery/bat_trats.c b/drivers/power/battery/bat_trats.c index 41b179f..bfde692 100644 --- a/drivers/power/battery/bat_trats.c +++ b/drivers/power/battery/bat_trats.c @@ -19,7 +19,7 @@ static int power_battery_charge(struct pmic *bat) struct battery *battery = p_bat->bat; int k;
- if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1;
for (k = 0; bat->chrg->chrg_bat_present(p_bat->chrg) && @@ -42,7 +42,7 @@ static int power_battery_charge(struct pmic *bat) } } exit: - bat->chrg->chrg_state(p_bat->chrg, CHARGER_DISABLE, 0); + bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_DISABLE, 0);
return 0; } diff --git a/drivers/power/battery/bat_trats2.c b/drivers/power/battery/bat_trats2.c index 94015aa..57221ad 100644 --- a/drivers/power/battery/bat_trats2.c +++ b/drivers/power/battery/bat_trats2.c @@ -17,7 +17,7 @@ static int power_battery_charge(struct pmic *bat) { struct power_battery *p_bat = bat->pbat;
- if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1;
return 0; diff --git a/drivers/power/mfd/pmic_max77693.c b/drivers/power/mfd/pmic_max77693.c index 1a4416b..6b28e28 100644 --- a/drivers/power/mfd/pmic_max77693.c +++ b/drivers/power/mfd/pmic_max77693.c @@ -22,7 +22,7 @@ static int max77693_charger_state(struct pmic *p, int state, int current) val = MAX77693_CHG_UNLOCK; pmic_reg_write(p, MAX77693_CHG_CNFG_06, val);
- if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX77693_CHG_CNFG_00, &val); val &= ~0x01; diff --git a/drivers/power/pmic/pmic_max8997.c b/drivers/power/pmic/pmic_max8997.c index ba01692..a36a9a0 100644 --- a/drivers/power/pmic/pmic_max8997.c +++ b/drivers/power/pmic/pmic_max8997.c @@ -35,7 +35,7 @@ static int pmic_charger_state(struct pmic *p, int state, int current) if (pmic_probe(p)) return -1;
- if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX8997_REG_MBCCTRL2, &val); val &= ~(MBCHOSTEN | VCHGR_FC); diff --git a/include/power/max77693_pmic.h b/include/power/max77693_pmic.h index 616d051..3d59e59 100644 --- a/include/power/max77693_pmic.h +++ b/include/power/max77693_pmic.h @@ -10,8 +10,6 @@
#include <power/power_chrg.h>
-enum {CHARGER_ENABLE, CHARGER_DISABLE}; - #define CHARGER_MIN_CURRENT 200 #define CHARGER_MAX_CURRENT 2000
diff --git a/include/power/max8997_pmic.h b/include/power/max8997_pmic.h index 74c5d54..728d60a 100644 --- a/include/power/max8997_pmic.h +++ b/include/power/max8997_pmic.h @@ -170,7 +170,6 @@ enum { #define SAFEOUT_3_30V 0x03
/* Charger */ -enum {CHARGER_ENABLE, CHARGER_DISABLE}; #define DETBAT (1 << 2) #define MBCICHFCSET (1 << 4) #define MBCHOSTEN (1 << 6) diff --git a/include/power/pmic.h b/include/power/pmic.h index 8f282dd..a62e6c9 100644 --- a/include/power/pmic.h +++ b/include/power/pmic.h @@ -17,6 +17,11 @@ enum { I2C_PMIC, I2C_NUM, }; enum { PMIC_READ, PMIC_WRITE, }; enum { PMIC_SENSOR_BYTE_ORDER_LITTLE, PMIC_SENSOR_BYTE_ORDER_BIG, };
+enum { + PMIC_CHARGER_DISABLE, + PMIC_CHARGER_ENABLE, +}; + struct p_i2c { unsigned char addr; unsigned char *buf;

From: Tom Wai-Hong Tam waihong@chromium.org
This adds driver support for the TPS65090 PMU. Support includes hooking into the pmic infrastructure so that the pmic commands can be used on the console. The TPS65090 supports the following functionality:
- fet enable/disable/querying - getting and setting of charge state
Even though it is connected to the pmic infrastructure it does not hook into the pmic charging charging infrastructure.
The device tree binding is from Linux, but only a small subset of functionality is supported.
Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Hatim Ali hatim.rv@samsung.com Signed-off-by: Katie Roberts-Hoffman katierh@chromium.org Signed-off-by: Rong Chang rongchang@chromium.org Signed-off-by: Sean Paul seanpaul@chromium.org Signed-off-by: Vincent Palatin vpalatin@chromium.org Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Removed non-device-tree operation - Use errno.h for error return codes everywhere - Plumb into pmic charging framework - Fix style nit - Use correct license header - Use new Linux device tree bindings - Add partial battery charging support
doc/device-tree-bindings/power/tps65090.txt | 17 ++ doc/device-tree-bindings/regulator/tps65090.txt | 122 +++++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pmic_tps65090.c | 312 ++++++++++++++++++++++++ include/fdtdec.h | 1 + include/power/tps65090_pmic.h | 73 ++++++ lib/fdtdec.c | 1 + 7 files changed, 527 insertions(+) create mode 100644 doc/device-tree-bindings/power/tps65090.txt create mode 100644 doc/device-tree-bindings/regulator/tps65090.txt create mode 100644 drivers/power/pmic/pmic_tps65090.c create mode 100644 include/power/tps65090_pmic.h
diff --git a/doc/device-tree-bindings/power/tps65090.txt b/doc/device-tree-bindings/power/tps65090.txt new file mode 100644 index 0000000..8e5e0d3 --- /dev/null +++ b/doc/device-tree-bindings/power/tps65090.txt @@ -0,0 +1,17 @@ +TPS65090 Frontend PMU with Switchmode Charger + +Required Properties: +-compatible: "ti,tps65090-charger" + +Optional Properties: +-ti,enable-low-current-chrg: Enables charging when a low current is detected + while the default logic is to stop charging. + +This node is a subnode of the tps65090 PMIC. + +Example: + + tps65090-charger { + compatible = "ti,tps65090-charger"; + ti,enable-low-current-chrg; + }; diff --git a/doc/device-tree-bindings/regulator/tps65090.txt b/doc/device-tree-bindings/regulator/tps65090.txt new file mode 100644 index 0000000..313a60b --- /dev/null +++ b/doc/device-tree-bindings/regulator/tps65090.txt @@ -0,0 +1,122 @@ +TPS65090 regulators + +Required properties: +- compatible: "ti,tps65090" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + dcdc[1-3], fet[1-7] and ldo[1-2] respectively. +- vsys[1-3]-supply: The input supply for DCDC[1-3] respectively. +- infet[1-7]-supply: The input supply for FET[1-7] respectively. +- vsys-l[1-2]-supply: The input supply for LDO[1-2] respectively. + +Optional properties: +- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3. + If DCDCs are externally controlled then this property should be there. +- "dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3. + If DCDCs are externally controlled and if it is from GPIO then GPIO + number should be provided. If it is externally controlled and no GPIO + entry then driver will just configure this rails as external control + and will not provide any enable/disable APIs. + +Each regulator is defined using the standard binding for regulators. + +Example: + + tps65090@48 { + compatible = "ti,tps65090"; + reg = <0x48>; + interrupts = <0 88 0x4>; + + vsys1-supply = <&some_reg>; + vsys2-supply = <&some_reg>; + vsys3-supply = <&some_reg>; + infet1-supply = <&some_reg>; + infet2-supply = <&some_reg>; + infet3-supply = <&some_reg>; + infet4-supply = <&some_reg>; + infet5-supply = <&some_reg>; + infet6-supply = <&some_reg>; + infet7-supply = <&some_reg>; + vsys_l1-supply = <&some_reg>; + vsys_l2-supply = <&some_reg>; + + regulators { + dcdc1 { + regulator-name = "dcdc1"; + regulator-boot-on; + regulator-always-on; + ti,enable-ext-control; + dcdc-ext-control-gpios = <&gpio 10 0>; + }; + + dcdc2 { + regulator-name = "dcdc2"; + regulator-boot-on; + regulator-always-on; + }; + + dcdc3 { + regulator-name = "dcdc3"; + regulator-boot-on; + regulator-always-on; + }; + + fet1 { + regulator-name = "fet1"; + regulator-boot-on; + regulator-always-on; + }; + + fet2 { + regulator-name = "fet2"; + regulator-boot-on; + regulator-always-on; + }; + + fet3 { + regulator-name = "fet3"; + regulator-boot-on; + regulator-always-on; + }; + + fet4 { + regulator-name = "fet4"; + regulator-boot-on; + regulator-always-on; + }; + + fet5 { + regulator-name = "fet5"; + regulator-boot-on; + regulator-always-on; + }; + + fet6 { + regulator-name = "fet6"; + regulator-boot-on; + regulator-always-on; + }; + + fet7 { + regulator-name = "fet7"; + regulator-boot-on; + regulator-always-on; + }; + + ldo1 { + regulator-name = "ldo1"; + regulator-boot-on; + regulator-always-on; + }; + + ldo2 { + regulator-name = "ldo2"; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 4129bda..3244f69 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o +obj-$(CONFIG_POWER_TPS65090) += pmic_tps65090.o obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c new file mode 100644 index 0000000..8558b43 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65090.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/tps65090_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define TPS65090_NAME "TPS65090_PMIC" + +/* TPS65090 register addresses */ +enum { + REG_IRQ1 = 0, + REG_CG_CTRL0 = 4, + REG_CG_STATUS1 = 0xa, + REG_FET1_CTRL = 0x0f, + REG_FET2_CTRL, + REG_FET3_CTRL, + REG_FET4_CTRL, + REG_FET5_CTRL, + REG_FET6_CTRL, + REG_FET7_CTRL, + TPS65090_NUM_REGS, +}; + +enum { + IRQ1_VBATG = 1 << 3, + CG_CTRL0_ENC_MASK = 0x01, + + MAX_FET_NUM = 7, + MAX_CTRL_READ_TRIES = 5, + + /* TPS65090 FET_CTRL register values */ + FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ + FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ + FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ + FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ + FET_CTRL_ENFET = 1 << 0, /* Enable FET */ +}; + +/** + * Checks for a valid FET number + * + * @param fet_id FET number to check + * @return 0 if ok, -EINVAL if FET value is out of range + */ +static int tps65090_check_fet(unsigned int fet_id) +{ + if (fet_id == 0 || fet_id > MAX_FET_NUM) { + debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", + fet_id, MAX_FET_NUM); + return -EINVAL; + } + + return 0; +} + +/** + * Set the power state for a FET + * + * @param pmic pmic structure for the tps65090 + * @param fet_id Fet number to set (1..MAX_FET_NUM) + * @param set 1 to power on FET, 0 to power off + * @return -EIO if we got a comms error, -EAGAIN if the FET failed to + * change state. If all is ok, returns 0. + */ +static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set) +{ + int retry; + u32 reg, value; + + value = FET_CTRL_ADENFET | FET_CTRL_WAIT; + if (set) + value |= FET_CTRL_ENFET; + + if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value)) + return -EIO; + + /* Try reading until we get a result */ + for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { + if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®)) + return -EIO; + + /* Check that the fet went into the expected state */ + if (!!(reg & FET_CTRL_PGFET) == set) + return 0; + + /* If we got a timeout, there is no point in waiting longer */ + if (reg & FET_CTRL_TOFET) + break; + + mdelay(1); + } + + debug("FET %d: Power good should have set to %d but reg=%#02x\n", + fet_id, set, reg); + return -EAGAIN; +} + +int tps65090_fet_enable(unsigned int fet_id) +{ + struct pmic *pmic; + ulong start; + int loops; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + start = get_timer(0); + for (loops = 0;; loops++) { + ret = tps65090_fet_set(pmic, fet_id, true); + if (!ret) + break; + + if (get_timer(start) > 100) + break; + + /* Turn it off and try again until we time out */ + tps65090_fet_set(pmic, fet_id, false); + } + + if (ret) + debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + else if (loops) + debug("%s: FET%d powered on after %lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + + /* + * Unfortunately, there are some conditions where the power + * good bit will be 0, but the fet still comes up. One such + * case occurs with the lcd backlight. We'll just return 0 here + * and assume that the fet will eventually come up. + */ + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + +int tps65090_fet_disable(unsigned int fet_id) +{ + struct pmic *pmic; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + ret = tps65090_fet_set(pmic, fet_id, false); + + return ret; +} + +int tps65090_fet_is_enabled(unsigned int fet_id) +{ + struct pmic *pmic; + u32 reg; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -ENODEV; + ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®); + if (ret) { + debug("fail to read FET%u_CTRL register over I2C", fet_id); + return -EIO; + } + + return reg & FET_CTRL_ENFET; +} + +int tps65090_get_charging(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (ret) + return ret; + + return val & CG_CTRL0_ENC_MASK ? 1 : 0; +} + +static int tps65090_charger_state(struct pmic *pmic, int state, + int current) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (!ret) { + if (state == PMIC_CHARGER_ENABLE) + val |= CG_CTRL0_ENC_MASK; + else + val &= ~CG_CTRL0_ENC_MASK; + ret = pmic_reg_write(pmic, REG_CG_CTRL0, val); + } + if (ret) { + debug("%s: Failed to read/write register\n", __func__); + return ret; + } + + return 0; +} + +int tps65090_get_status(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val); + if (ret) + return ret; + + return val; +} + +static int tps65090_charger_bat_present(struct pmic *pmic) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_IRQ1, &val); + if (ret) + return ret; + + return val & IRQ1_VBATG ? true : false; +} + + +static struct power_chrg power_chrg_pmic_ops = { + .chrg_bat_present = tps65090_charger_bat_present, + .chrg_state = tps65090_charger_state, +}; + +int tps65090_init(void) +{ + struct pmic *p; + int bus; + int addr; + + const void *blob = gd->fdt_blob; + int node, parent; + + node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090); + if (node < 0) { + debug("PMIC: No node for PMIC Chip in device tree\n"); + debug("node = %d\n", node); + return -ENODEV; + } + + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -EINVAL; + } + + bus = i2c_get_bus_num_fdt(parent); + if (p->bus < 0) { + debug("%s: Cannot find I2C bus\n", __func__); + return -ENOENT; + } + addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR); + p = pmic_alloc(); + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = TPS65090_NAME; + p->bus = bus; + p->interface = PMIC_I2C; + p->number_of_regs = TPS65090_NUM_REGS; + p->hw.i2c.addr = addr; + p->hw.i2c.tx_num = 1; + p->chrg = &power_chrg_pmic_ops; + + puts("TPS65090 PMIC init\n"); + + return 0; +} diff --git a/include/fdtdec.h b/include/fdtdec.h index 3196cf6..669ab90 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -92,6 +92,7 @@ enum fdt_compat_id { COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */ COMPAT_SANDBOX_HOST_EMULATION, /* Sandbox emulation of a function */ COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */ + COMPAT_TI_TPS65090, /* Texas Instrument TPS65090 */
COMPAT_COUNT, }; diff --git a/include/power/tps65090_pmic.h b/include/power/tps65090_pmic.h new file mode 100644 index 0000000..dcf99c9 --- /dev/null +++ b/include/power/tps65090_pmic.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __TPS65090_PMIC_H_ +#define __TPS65090_PMIC_H_ + +/* I2C device address for TPS65090 PMU */ +#define TPS65090_I2C_ADDR 0x48 + +enum { + /* Status register fields */ + TPS65090_ST1_OTC = 1 << 0, + TPS65090_ST1_OCC = 1 << 1, + TPS65090_ST1_STATE_SHIFT = 4, + TPS65090_ST1_STATE_MASK = 0xf << TPS65090_ST1_STATE_SHIFT, +}; + +/** + * Enable FET + * + * @param fet_id FET ID, value between 1 and 7 + * @return 0 on success, non-0 on failure + */ +int tps65090_fet_enable(unsigned int fet_id); + +/** + * Disable FET + * + * @param fet_id FET ID, value between 1 and 7 + * @return 0 on success, non-0 on failure + */ +int tps65090_fet_disable(unsigned int fet_id); + +/** + * Is FET enabled? + * + * @param fet_id FET ID, value between 1 and 7 + * @return 1 enabled, 0 disabled, negative value on failure + */ +int tps65090_fet_is_enabled(unsigned int fet_id); + +/** + * Enable / disable the battery charger + * + * @param enable 0 to disable charging, non-zero to enable + */ +int tps65090_set_charge_enable(int enable); + +/** + * Check whether we have enabled battery charging + * + * @return 1 if enabled, 0 if disabled + */ +int tps65090_get_charging(void); + +/** + * Return the value of the status register + * + * @return status register value, or -1 on error + */ +int tps65090_get_status(void); + +/** + * Initialize the TPS65090 PMU. + * + * @return 0 on success, non-0 on failure + */ +int tps65090_init(void); + +#endif /* __TPS65090_PMIC_H_ */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 33265ec..e15e0ad 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -65,6 +65,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"), + COMPAT(TI_TPS65090, "ti,tps65090"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

On 03/04/14 08:24, Simon Glass wrote:
From: Tom Wai-Hong Tam waihong@chromium.org
This adds driver support for the TPS65090 PMU. Support includes hooking into the pmic infrastructure so that the pmic commands can be used on the console. The TPS65090 supports the following functionality:
- fet enable/disable/querying
- getting and setting of charge state
Even though it is connected to the pmic infrastructure it does not hook into the pmic charging charging infrastructure.
The device tree binding is from Linux, but only a small subset of functionality is supported.
Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Hatim Ali hatim.rv@samsung.com Signed-off-by: Katie Roberts-Hoffman katierh@chromium.org Signed-off-by: Rong Chang rongchang@chromium.org Signed-off-by: Sean Paul seanpaul@chromium.org Signed-off-by: Vincent Palatin vpalatin@chromium.org Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Removed non-device-tree operation
- Use errno.h for error return codes everywhere
- Plumb into pmic charging framework
- Fix style nit
- Use correct license header
- Use new Linux device tree bindings
- Add partial battery charging support
doc/device-tree-bindings/power/tps65090.txt | 17 ++ doc/device-tree-bindings/regulator/tps65090.txt | 122 +++++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pmic_tps65090.c | 312 ++++++++++++++++++++++++ include/fdtdec.h | 1 + include/power/tps65090_pmic.h | 73 ++++++ lib/fdtdec.c | 1 + 7 files changed, 527 insertions(+) create mode 100644 doc/device-tree-bindings/power/tps65090.txt create mode 100644 doc/device-tree-bindings/regulator/tps65090.txt create mode 100644 drivers/power/pmic/pmic_tps65090.c create mode 100644 include/power/tps65090_pmic.h
diff --git a/doc/device-tree-bindings/power/tps65090.txt b/doc/device-tree-bindings/power/tps65090.txt new file mode 100644 index 0000000..8e5e0d3 --- /dev/null +++ b/doc/device-tree-bindings/power/tps65090.txt @@ -0,0 +1,17 @@ +TPS65090 Frontend PMU with Switchmode Charger
+Required Properties: +-compatible: "ti,tps65090-charger"
+Optional Properties: +-ti,enable-low-current-chrg: Enables charging when a low current is detected
- while the default logic is to stop charging.
+This node is a subnode of the tps65090 PMIC.
+Example:
- tps65090-charger {
compatible = "ti,tps65090-charger";
ti,enable-low-current-chrg;
- };
diff --git a/doc/device-tree-bindings/regulator/tps65090.txt b/doc/device-tree-bindings/regulator/tps65090.txt new file mode 100644 index 0000000..313a60b --- /dev/null +++ b/doc/device-tree-bindings/regulator/tps65090.txt @@ -0,0 +1,122 @@ +TPS65090 regulators
+Required properties: +- compatible: "ti,tps65090" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the
- device. Each sub-node is identified using the node's name, with valid
- values listed below. The content of each sub-node is defined by the
- standard binding for regulators; see regulator.txt.
- dcdc[1-3], fet[1-7] and ldo[1-2] respectively.
+- vsys[1-3]-supply: The input supply for DCDC[1-3] respectively. +- infet[1-7]-supply: The input supply for FET[1-7] respectively. +- vsys-l[1-2]-supply: The input supply for LDO[1-2] respectively.
+Optional properties: +- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3.
- If DCDCs are externally controlled then this property should be there.
+- "dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3.
- If DCDCs are externally controlled and if it is from GPIO then GPIO
- number should be provided. If it is externally controlled and no GPIO
- entry then driver will just configure this rails as external control
- and will not provide any enable/disable APIs.
+Each regulator is defined using the standard binding for regulators.
+Example:
- tps65090@48 {
compatible = "ti,tps65090";
reg = <0x48>;
interrupts = <0 88 0x4>;
vsys1-supply = <&some_reg>;
vsys2-supply = <&some_reg>;
vsys3-supply = <&some_reg>;
infet1-supply = <&some_reg>;
infet2-supply = <&some_reg>;
infet3-supply = <&some_reg>;
infet4-supply = <&some_reg>;
infet5-supply = <&some_reg>;
infet6-supply = <&some_reg>;
infet7-supply = <&some_reg>;
vsys_l1-supply = <&some_reg>;
vsys_l2-supply = <&some_reg>;
regulators {
dcdc1 {
regulator-name = "dcdc1";
regulator-boot-on;
regulator-always-on;
ti,enable-ext-control;
dcdc-ext-control-gpios = <&gpio 10 0>;
};
dcdc2 {
regulator-name = "dcdc2";
regulator-boot-on;
regulator-always-on;
};
dcdc3 {
regulator-name = "dcdc3";
regulator-boot-on;
regulator-always-on;
};
fet1 {
regulator-name = "fet1";
regulator-boot-on;
regulator-always-on;
};
fet2 {
regulator-name = "fet2";
regulator-boot-on;
regulator-always-on;
};
fet3 {
regulator-name = "fet3";
regulator-boot-on;
regulator-always-on;
};
fet4 {
regulator-name = "fet4";
regulator-boot-on;
regulator-always-on;
};
fet5 {
regulator-name = "fet5";
regulator-boot-on;
regulator-always-on;
};
fet6 {
regulator-name = "fet6";
regulator-boot-on;
regulator-always-on;
};
fet7 {
regulator-name = "fet7";
regulator-boot-on;
regulator-always-on;
};
ldo1 {
regulator-name = "ldo1";
regulator-boot-on;
regulator-always-on;
};
ldo2 {
regulator-name = "ldo2";
regulator-boot-on;
regulator-always-on;
};
};
- };
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 4129bda..3244f69 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o +obj-$(CONFIG_POWER_TPS65090) += pmic_tps65090.o obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c new file mode 100644 index 0000000..8558b43 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65090.c @@ -0,0 +1,312 @@ +/*
- Copyright (c) 2012 The Chromium OS Authors.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/tps65090_pmic.h>
+DECLARE_GLOBAL_DATA_PTR;
+#define TPS65090_NAME "TPS65090_PMIC"
+/* TPS65090 register addresses */ +enum {
- REG_IRQ1 = 0,
- REG_CG_CTRL0 = 4,
- REG_CG_STATUS1 = 0xa,
- REG_FET1_CTRL = 0x0f,
- REG_FET2_CTRL,
- REG_FET3_CTRL,
- REG_FET4_CTRL,
- REG_FET5_CTRL,
- REG_FET6_CTRL,
- REG_FET7_CTRL,
- TPS65090_NUM_REGS,
+};
+enum {
- IRQ1_VBATG = 1 << 3,
- CG_CTRL0_ENC_MASK = 0x01,
- MAX_FET_NUM = 7,
- MAX_CTRL_READ_TRIES = 5,
- /* TPS65090 FET_CTRL register values */
- FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */
- FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */
- FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */
- FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */
- FET_CTRL_ENFET = 1 << 0, /* Enable FET */
+};
Are there any special reason to use enum?
+/**
- Checks for a valid FET number
- @param fet_id FET number to check
- @return 0 if ok, -EINVAL if FET value is out of range
- */
+static int tps65090_check_fet(unsigned int fet_id) +{
- if (fet_id == 0 || fet_id > MAX_FET_NUM) {
debug("parameter fet_id is out of range, %u not in 1 ~ %u\n",
fet_id, MAX_FET_NUM);
return -EINVAL;
- }
- return 0;
+}
+/**
- Set the power state for a FET
- @param pmic pmic structure for the tps65090
- @param fet_id Fet number to set (1..MAX_FET_NUM)
- @param set 1 to power on FET, 0 to power off
- @return -EIO if we got a comms error, -EAGAIN if the FET failed to
- change state. If all is ok, returns 0.
- */
+static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set) +{
- int retry;
- u32 reg, value;
- value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
- if (set)
value |= FET_CTRL_ENFET;
- if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value))
return -EIO;
- /* Try reading until we get a result */
- for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®))
return -EIO;
/* Check that the fet went into the expected state */
if (!!(reg & FET_CTRL_PGFET) == set)
return 0;
/* If we got a timeout, there is no point in waiting longer */
if (reg & FET_CTRL_TOFET)
break;
mdelay(1);
- }
- debug("FET %d: Power good should have set to %d but reg=%#02x\n",
fet_id, set, reg);
- return -EAGAIN;
EAGAIN? why?
+}
+int tps65090_fet_enable(unsigned int fet_id) +{
- struct pmic *pmic;
- ulong start;
- int loops;
- int ret;
- ret = tps65090_check_fet(fet_id);
- if (ret)
return ret;
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
return -EACCES;
- start = get_timer(0);
- for (loops = 0;; loops++) {
ret = tps65090_fet_set(pmic, fet_id, true);
if (!ret)
break;
if (get_timer(start) > 100)
break;
/* Turn it off and try again until we time out */
tps65090_fet_set(pmic, fet_id, false);
- }
- if (ret)
debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
- else if (loops)
debug("%s: FET%d powered on after %lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
- /*
* Unfortunately, there are some conditions where the power
* good bit will be 0, but the fet still comes up. One such
* case occurs with the lcd backlight. We'll just return 0 here
* and assume that the fet will eventually come up.
*/
I can't understand it. If it is a special case, then it should be controlled at each caller.
- if (ret == -EAGAIN)
ret = 0;
It looks weird.
- return ret;
+}
+int tps65090_fet_disable(unsigned int fet_id) +{
- struct pmic *pmic;
- int ret;
- ret = tps65090_check_fet(fet_id);
- if (ret)
return ret;
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
return -EACCES;
- ret = tps65090_fet_set(pmic, fet_id, false);
- return ret;
+}
+int tps65090_fet_is_enabled(unsigned int fet_id) +{
- struct pmic *pmic;
- u32 reg;
- int ret;
- ret = tps65090_check_fet(fet_id);
- if (ret)
return ret;
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
return -ENODEV;
- ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®);
- if (ret) {
debug("fail to read FET%u_CTRL register over I2C", fet_id);
return -EIO;
- }
- return reg & FET_CTRL_ENFET;
+}
+int tps65090_get_charging(void) +{
- struct pmic *pmic;
- u32 val;
- int ret;
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
return -EACCES;
- ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
- if (ret)
return ret;
- return val & CG_CTRL0_ENC_MASK ? 1 : 0;
How about it?
return !!(val & CG_CTRL0_ENC_MASK);
+}
+static int tps65090_charger_state(struct pmic *pmic, int state,
int current)
+{
- u32 val;
- int ret;
- ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
- if (!ret) {
if (state == PMIC_CHARGER_ENABLE)
val |= CG_CTRL0_ENC_MASK;
else
val &= ~CG_CTRL0_ENC_MASK;
ret = pmic_reg_write(pmic, REG_CG_CTRL0, val);
- }
- if (ret) {
debug("%s: Failed to read/write register\n", __func__);
return ret;
- }
- return 0;
+}
+int tps65090_get_status(void) +{
- struct pmic *pmic;
- u32 val;
- int ret;
- pmic = pmic_get(TPS65090_NAME);
- if (!pmic)
return -EACCES;
- ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val);
- if (ret)
return ret;
- return val;
+}
+static int tps65090_charger_bat_present(struct pmic *pmic) +{
- u32 val;
- int ret;
- ret = pmic_reg_read(pmic, REG_IRQ1, &val);
- if (ret)
return ret;
- return val & IRQ1_VBATG ? true : false;
return !!(val & IRQ1_VBATG);
+}
please remove extra blank line.
+static struct power_chrg power_chrg_pmic_ops = {
- .chrg_bat_present = tps65090_charger_bat_present,
- .chrg_state = tps65090_charger_state,
+};
+int tps65090_init(void) +{
- struct pmic *p;
- int bus;
- int addr;
please remove blank line.
- const void *blob = gd->fdt_blob;
- int node, parent;
- node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090);
- if (node < 0) {
debug("PMIC: No node for PMIC Chip in device tree\n");
debug("node = %d\n", node);
return -ENODEV;
- }
- parent = fdt_parent_offset(blob, node);
- if (parent < 0) {
debug("%s: Cannot find node parent\n", __func__);
return -EINVAL;
- }
- bus = i2c_get_bus_num_fdt(parent);
- if (p->bus < 0) {
debug("%s: Cannot find I2C bus\n", __func__);
return -ENOENT;
- }
- addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR);
- p = pmic_alloc();
- if (!p) {
printf("%s: POWER allocation error!\n", __func__);
return -ENOMEM;
- }
- p->name = TPS65090_NAME;
- p->bus = bus;
- p->interface = PMIC_I2C;
- p->number_of_regs = TPS65090_NUM_REGS;
- p->hw.i2c.addr = addr;
- p->hw.i2c.tx_num = 1;
- p->chrg = &power_chrg_pmic_ops;
- puts("TPS65090 PMIC init\n");
- return 0;
+} diff --git a/include/fdtdec.h b/include/fdtdec.h index 3196cf6..669ab90 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -92,6 +92,7 @@ enum fdt_compat_id { COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */ COMPAT_SANDBOX_HOST_EMULATION, /* Sandbox emulation of a function */ COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */
COMPAT_TI_TPS65090, /* Texas Instrument TPS65090 */
COMPAT_COUNT,
}; diff --git a/include/power/tps65090_pmic.h b/include/power/tps65090_pmic.h new file mode 100644 index 0000000..dcf99c9 --- /dev/null +++ b/include/power/tps65090_pmic.h @@ -0,0 +1,73 @@ +/*
- Copyright (c) 2012 The Chromium OS Authors.
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __TPS65090_PMIC_H_ +#define __TPS65090_PMIC_H_
+/* I2C device address for TPS65090 PMU */ +#define TPS65090_I2C_ADDR 0x48
+enum {
- /* Status register fields */
- TPS65090_ST1_OTC = 1 << 0,
- TPS65090_ST1_OCC = 1 << 1,
- TPS65090_ST1_STATE_SHIFT = 4,
- TPS65090_ST1_STATE_MASK = 0xf << TPS65090_ST1_STATE_SHIFT,
+};
Are there any special reason to use enum?
+/**
- Enable FET
- @param fet_id FET ID, value between 1 and 7
- @return 0 on success, non-0 on failure
- */
+int tps65090_fet_enable(unsigned int fet_id);
+/**
- Disable FET
- @param fet_id FET ID, value between 1 and 7
- @return 0 on success, non-0 on failure
- */
+int tps65090_fet_disable(unsigned int fet_id);
+/**
- Is FET enabled?
- @param fet_id FET ID, value between 1 and 7
- @return 1 enabled, 0 disabled, negative value on failure
- */
+int tps65090_fet_is_enabled(unsigned int fet_id);
+/**
- Enable / disable the battery charger
- @param enable 0 to disable charging, non-zero to enable
- */
+int tps65090_set_charge_enable(int enable);
+/**
- Check whether we have enabled battery charging
- @return 1 if enabled, 0 if disabled
- */
+int tps65090_get_charging(void);
+/**
- Return the value of the status register
- @return status register value, or -1 on error
- */
+int tps65090_get_status(void);
+/**
- Initialize the TPS65090 PMU.
- @return 0 on success, non-0 on failure
- */
+int tps65090_init(void);
+#endif /* __TPS65090_PMIC_H_ */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 33265ec..e15e0ad 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -65,6 +65,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
- COMPAT(TI_TPS65090, "ti,tps65090"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
Thanks, Minkyu Kang.

Hi Minkyu,
On 15 May 2014 00:52, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
From: Tom Wai-Hong Tam waihong@chromium.org
This adds driver support for the TPS65090 PMU. Support includes hooking into the pmic infrastructure so that the pmic commands can be used on the console. The TPS65090 supports the following functionality:
- fet enable/disable/querying
- getting and setting of charge state
Even though it is connected to the pmic infrastructure it does not hook into the pmic charging charging infrastructure.
The device tree binding is from Linux, but only a small subset of functionality is supported.
Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Hatim Ali hatim.rv@samsung.com Signed-off-by: Katie Roberts-Hoffman katierh@chromium.org Signed-off-by: Rong Chang rongchang@chromium.org Signed-off-by: Sean Paul seanpaul@chromium.org Signed-off-by: Vincent Palatin vpalatin@chromium.org Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Removed non-device-tree operation
- Use errno.h for error return codes everywhere
- Plumb into pmic charging framework
- Fix style nit
- Use correct license header
- Use new Linux device tree bindings
- Add partial battery charging support
doc/device-tree-bindings/power/tps65090.txt | 17 ++ doc/device-tree-bindings/regulator/tps65090.txt | 122 +++++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pmic_tps65090.c | 312 ++++++++++++++++++++++++ include/fdtdec.h | 1 + include/power/tps65090_pmic.h | 73 ++++++ lib/fdtdec.c | 1 + 7 files changed, 527 insertions(+) create mode 100644 doc/device-tree-bindings/power/tps65090.txt create mode 100644 doc/device-tree-bindings/regulator/tps65090.txt create mode 100644 drivers/power/pmic/pmic_tps65090.c create mode 100644 include/power/tps65090_pmic.h
[snip]
diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c new file mode 100644 index 0000000..8558b43 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65090.c @@ -0,0 +1,312 @@ +/*
- Copyright (c) 2012 The Chromium OS Authors.
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/tps65090_pmic.h>
+DECLARE_GLOBAL_DATA_PTR;
+#define TPS65090_NAME "TPS65090_PMIC"
+/* TPS65090 register addresses */ +enum {
REG_IRQ1 = 0,
REG_CG_CTRL0 = 4,
REG_CG_STATUS1 = 0xa,
REG_FET1_CTRL = 0x0f,
REG_FET2_CTRL,
REG_FET3_CTRL,
REG_FET4_CTRL,
REG_FET5_CTRL,
REG_FET6_CTRL,
REG_FET7_CTRL,
TPS65090_NUM_REGS,
+};
+enum {
IRQ1_VBATG = 1 << 3,
CG_CTRL0_ENC_MASK = 0x01,
MAX_FET_NUM = 7,
MAX_CTRL_READ_TRIES = 5,
/* TPS65090 FET_CTRL register values */
FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */
FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */
FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */
FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */
FET_CTRL_ENFET = 1 << 0, /* Enable FET */
+};
Are there any special reason to use enum?
Yes it provides symbols for debugging and avoids needing brackets for expressions.
+/**
- Checks for a valid FET number
- @param fet_id FET number to check
- @return 0 if ok, -EINVAL if FET value is out of range
- */
+static int tps65090_check_fet(unsigned int fet_id) +{
if (fet_id == 0 || fet_id > MAX_FET_NUM) {
debug("parameter fet_id is out of range, %u not in 1 ~ %u\n",
fet_id, MAX_FET_NUM);
return -EINVAL;
}
return 0;
+}
+/**
- Set the power state for a FET
- @param pmic pmic structure for the tps65090
- @param fet_id Fet number to set (1..MAX_FET_NUM)
- @param set 1 to power on FET, 0 to power off
- @return -EIO if we got a comms error, -EAGAIN if the FET failed to
- change state. If all is ok, returns 0.
- */
+static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set) +{
int retry;
u32 reg, value;
value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
if (set)
value |= FET_CTRL_ENFET;
if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value))
return -EIO;
/* Try reading until we get a result */
for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®))
return -EIO;
/* Check that the fet went into the expected state */
if (!!(reg & FET_CTRL_PGFET) == set)
return 0;
/* If we got a timeout, there is no point in waiting longer */
if (reg & FET_CTRL_TOFET)
break;
mdelay(1);
}
debug("FET %d: Power good should have set to %d but reg=%#02x\n",
fet_id, set, reg);
return -EAGAIN;
EAGAIN? why?
This means that we managed to request that the FET change state, but could not confirm that it did so. It is therefore worth trying again.
+}
+int tps65090_fet_enable(unsigned int fet_id) +{
struct pmic *pmic;
ulong start;
int loops;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
start = get_timer(0);
for (loops = 0;; loops++) {
ret = tps65090_fet_set(pmic, fet_id, true);
if (!ret)
break;
if (get_timer(start) > 100)
break;
/* Turn it off and try again until we time out */
tps65090_fet_set(pmic, fet_id, false);
}
if (ret)
debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
else if (loops)
debug("%s: FET%d powered on after %lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
/*
* Unfortunately, there are some conditions where the power
* good bit will be 0, but the fet still comes up. One such
* case occurs with the lcd backlight. We'll just return 0 here
* and assume that the fet will eventually come up.
*/
I can't understand it. If it is a special case, then it should be controlled at each caller.
This is a problem with the chip itself so we wanted to localise the changes here, as is done in the kernel. It may happen with any application that uses this chip - the LCD backlight is just an example as it happens on snow.
if (ret == -EAGAIN)
ret = 0;
It looks weird.
This is the required logic to get this chip to work properly - see the comment above.
return ret;
+}
+int tps65090_fet_disable(unsigned int fet_id) +{
struct pmic *pmic;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
ret = tps65090_fet_set(pmic, fet_id, false);
return ret;
+}
+int tps65090_fet_is_enabled(unsigned int fet_id) +{
struct pmic *pmic;
u32 reg;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -ENODEV;
ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®);
if (ret) {
debug("fail to read FET%u_CTRL register over I2C", fet_id);
return -EIO;
}
return reg & FET_CTRL_ENFET;
+}
+int tps65090_get_charging(void) +{
struct pmic *pmic;
u32 val;
int ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
if (ret)
return ret;
return val & CG_CTRL0_ENC_MASK ? 1 : 0;
How about it?
return !!(val & CG_CTRL0_ENC_MASK);
done
+}
+static int tps65090_charger_state(struct pmic *pmic, int state,
int current)
+{
u32 val;
int ret;
ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
if (!ret) {
if (state == PMIC_CHARGER_ENABLE)
val |= CG_CTRL0_ENC_MASK;
else
val &= ~CG_CTRL0_ENC_MASK;
ret = pmic_reg_write(pmic, REG_CG_CTRL0, val);
}
if (ret) {
debug("%s: Failed to read/write register\n", __func__);
return ret;
}
return 0;
+}
+int tps65090_get_status(void) +{
struct pmic *pmic;
u32 val;
int ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val);
if (ret)
return ret;
return val;
+}
+static int tps65090_charger_bat_present(struct pmic *pmic) +{
u32 val;
int ret;
ret = pmic_reg_read(pmic, REG_IRQ1, &val);
if (ret)
return ret;
return val & IRQ1_VBATG ? true : false;
return !!(val & IRQ1_VBATG);
+}
please remove extra blank line.
done
+static struct power_chrg power_chrg_pmic_ops = {
.chrg_bat_present = tps65090_charger_bat_present,
.chrg_state = tps65090_charger_state,
+};
+int tps65090_init(void) +{
struct pmic *p;
int bus;
int addr;
please remove blank line.
done
const void *blob = gd->fdt_blob;
int node, parent;
node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090);
if (node < 0) {
debug("PMIC: No node for PMIC Chip in device tree\n");
debug("node = %d\n", node);
return -ENODEV;
}
parent = fdt_parent_offset(blob, node);
if (parent < 0) {
debug("%s: Cannot find node parent\n", __func__);
return -EINVAL;
}
bus = i2c_get_bus_num_fdt(parent);
if (p->bus < 0) {
debug("%s: Cannot find I2C bus\n", __func__);
return -ENOENT;
}
addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR);
p = pmic_alloc();
if (!p) {
printf("%s: POWER allocation error!\n", __func__);
return -ENOMEM;
}
p->name = TPS65090_NAME;
p->bus = bus;
p->interface = PMIC_I2C;
p->number_of_regs = TPS65090_NUM_REGS;
p->hw.i2c.addr = addr;
p->hw.i2c.tx_num = 1;
p->chrg = &power_chrg_pmic_ops;
puts("TPS65090 PMIC init\n");
return 0;
+} diff --git a/include/fdtdec.h b/include/fdtdec.h index 3196cf6..669ab90 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -92,6 +92,7 @@ enum fdt_compat_id { COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */ COMPAT_SANDBOX_HOST_EMULATION, /* Sandbox emulation of a function */ COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */
COMPAT_TI_TPS65090, /* Texas Instrument TPS65090 */ COMPAT_COUNT,
}; diff --git a/include/power/tps65090_pmic.h b/include/power/tps65090_pmic.h new file mode 100644 index 0000000..dcf99c9 --- /dev/null +++ b/include/power/tps65090_pmic.h @@ -0,0 +1,73 @@ +/*
- Copyright (c) 2012 The Chromium OS Authors.
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __TPS65090_PMIC_H_ +#define __TPS65090_PMIC_H_
+/* I2C device address for TPS65090 PMU */ +#define TPS65090_I2C_ADDR 0x48
+enum {
/* Status register fields */
TPS65090_ST1_OTC = 1 << 0,
TPS65090_ST1_OCC = 1 << 1,
TPS65090_ST1_STATE_SHIFT = 4,
TPS65090_ST1_STATE_MASK = 0xf << TPS65090_ST1_STATE_SHIFT,
+};
Are there any special reason to use enum?
See comment above.
+/**
- Enable FET
- @param fet_id FET ID, value between 1 and 7
- @return 0 on success, non-0 on failure
- */
+int tps65090_fet_enable(unsigned int fet_id);
+/**
- Disable FET
- @param fet_id FET ID, value between 1 and 7
- @return 0 on success, non-0 on failure
- */
+int tps65090_fet_disable(unsigned int fet_id);
+/**
- Is FET enabled?
- @param fet_id FET ID, value between 1 and 7
- @return 1 enabled, 0 disabled, negative value on failure
- */
+int tps65090_fet_is_enabled(unsigned int fet_id);
+/**
- Enable / disable the battery charger
- @param enable 0 to disable charging, non-zero to enable
- */
+int tps65090_set_charge_enable(int enable);
+/**
- Check whether we have enabled battery charging
- @return 1 if enabled, 0 if disabled
- */
+int tps65090_get_charging(void);
+/**
- Return the value of the status register
- @return status register value, or -1 on error
- */
+int tps65090_get_status(void);
+/**
- Initialize the TPS65090 PMU.
- @return 0 on success, non-0 on failure
- */
+int tps65090_init(void);
+#endif /* __TPS65090_PMIC_H_ */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 33265ec..e15e0ad 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -65,6 +65,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
COMPAT(TI_TPS65090, "ti,tps65090"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
Regards, Simon

From: Aaron Durbin adurbin@chromium.org
The TPS65090 pmic chip can be on exynos5250 boards. Therefore, select the appropriate config option for TPS65090 devices.
This commit should really use exynos5-dt.c, when it is available.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Update patch name to exynos5-dt instead of smdk5250
include/configs/exynos5-dt.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/configs/exynos5-dt.h b/include/configs/exynos5-dt.h index 414db42..fbf09f5 100644 --- a/include/configs/exynos5-dt.h +++ b/include/configs/exynos5-dt.h @@ -259,6 +259,7 @@ /* PMIC */ #define CONFIG_POWER #define CONFIG_POWER_I2C +#define CONFIG_POWER_TPS65090
/* Ethernet Controllor Driver */ #ifdef CONFIG_CMD_NET

From: Aaron Durbin adurbin@chromium.org
The current pmic i2c code assumes the current i2c bus is the same as the pmic device's bus. There is nothing ensuring that to be true. Therefore, select the proper bus before performing a transaction.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Heiko Schocher hs@denx.de Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
drivers/power/power_i2c.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/power/power_i2c.c b/drivers/power/power_i2c.c index ac76870..594cd11 100644 --- a/drivers/power/power_i2c.c +++ b/drivers/power/power_i2c.c @@ -23,6 +23,8 @@ int pmic_reg_write(struct pmic *p, u32 reg, u32 val) if (check_reg(p, reg)) return -1;
+ I2C_SET_BUS(p->bus); + switch (pmic_i2c_tx_num) { case 3: if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) { @@ -66,6 +68,8 @@ int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) if (check_reg(p, reg)) return -1;
+ I2C_SET_BUS(p->bus); + if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) return -1;

From: Aaron Durbin adurbin@chromium.org
The TSP65090 is a PMIC on some exynos5 boards. The init function is called for the TPS65090 pmic. If that device is not a part of the device tree (returns -ENODEV) then continue. Otherwise return a failure.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Move code to exynos5-dt.c - Fix comment style - Add #ifdef around tps65090 code
board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 1a64b9b..2c1cf8a 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -20,6 +20,7 @@ #include <asm/arch/sromc.h> #include <power/pmic.h> #include <power/max77686_pmic.h> +#include <power/tps65090_pmic.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -164,7 +165,19 @@ int exynos_power_init(void)
#ifdef CONFIG_POWER_MAX77686 ret = max77686_init(); + if (ret) + return ret; #endif +#ifdef CONFIG_POWER_TPS65090 + /* + * The TPS65090 may not be in the device tree. If so, it is not + * an error. + */ + ret = tps65090_init(); + if (ret == 0 || ret == -ENODEV) + return 0; +#endif + return ret; } #endif /* CONFIG_POWER */

On 03/04/14 08:24, Simon Glass wrote:
From: Aaron Durbin adurbin@chromium.org
The TSP65090 is a PMIC on some exynos5 boards. The init function is called for the TPS65090 pmic. If that device is not a part of the device tree (returns -ENODEV) then continue. Otherwise return a failure.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2:
- Move code to exynos5-dt.c
- Fix comment style
- Add #ifdef around tps65090 code
board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 1a64b9b..2c1cf8a 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -20,6 +20,7 @@ #include <asm/arch/sromc.h> #include <power/pmic.h> #include <power/max77686_pmic.h> +#include <power/tps65090_pmic.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -164,7 +165,19 @@ int exynos_power_init(void)
#ifdef CONFIG_POWER_MAX77686 ret = max77686_init();
- if (ret)
return ret;
#endif +#ifdef CONFIG_POWER_TPS65090
- /*
* The TPS65090 may not be in the device tree. If so, it is not
* an error.
Then, how we can initialise the tps65090?
*/
- ret = tps65090_init();
- if (ret == 0 || ret == -ENODEV)
return 0;
+#endif
- return ret;
} #endif /* CONFIG_POWER */
Thanks, Minkyu Kang.

Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
From: Aaron Durbin adurbin@chromium.org
The TSP65090 is a PMIC on some exynos5 boards. The init function is called for the TPS65090 pmic. If that device is not a part of the device tree (returns -ENODEV) then continue. Otherwise return a failure.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2:
- Move code to exynos5-dt.c
- Fix comment style
- Add #ifdef around tps65090 code
board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 1a64b9b..2c1cf8a 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -20,6 +20,7 @@ #include <asm/arch/sromc.h> #include <power/pmic.h> #include <power/max77686_pmic.h> +#include <power/tps65090_pmic.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -164,7 +165,19 @@ int exynos_power_init(void)
#ifdef CONFIG_POWER_MAX77686 ret = max77686_init();
if (ret)
return ret;
#endif +#ifdef CONFIG_POWER_TPS65090
/*
* The TPS65090 may not be in the device tree. If so, it is not
* an error.
Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
*/
ret = tps65090_init();
if (ret == 0 || ret == -ENODEV)
return 0;
+#endif
return ret;
} #endif /* CONFIG_POWER */
Thanks, Minkyu Kang.
Regards, Simon

On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
From: Aaron Durbin adurbin@chromium.org
The TSP65090 is a PMIC on some exynos5 boards. The init function is called for the TPS65090 pmic. If that device is not a part of the device tree (returns -ENODEV) then continue. Otherwise return a failure.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2:
- Move code to exynos5-dt.c
- Fix comment style
- Add #ifdef around tps65090 code
board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 1a64b9b..2c1cf8a 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -20,6 +20,7 @@ #include <asm/arch/sromc.h> #include <power/pmic.h> #include <power/max77686_pmic.h> +#include <power/tps65090_pmic.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -164,7 +165,19 @@ int exynos_power_init(void)
#ifdef CONFIG_POWER_MAX77686 ret = max77686_init();
if (ret)
return ret;
#endif +#ifdef CONFIG_POWER_TPS65090
/*
* The TPS65090 may not be in the device tree. If so, it is not
* an error.
Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
*/
ret = tps65090_init();
if (ret == 0 || ret == -ENODEV)
return 0;
+#endif
return ret;
} #endif /* CONFIG_POWER */
Thanks, Minkyu Kang.
Regards, Simon
Thanks, Minkyu Kang.

Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
From: Aaron Durbin adurbin@chromium.org
The TSP65090 is a PMIC on some exynos5 boards. The init function is called for the TPS65090 pmic. If that device is not a part of the device tree (returns -ENODEV) then continue. Otherwise return a failure.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2:
- Move code to exynos5-dt.c
- Fix comment style
- Add #ifdef around tps65090 code
board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 1a64b9b..2c1cf8a 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -20,6 +20,7 @@ #include <asm/arch/sromc.h> #include <power/pmic.h> #include <power/max77686_pmic.h> +#include <power/tps65090_pmic.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -164,7 +165,19 @@ int exynos_power_init(void)
#ifdef CONFIG_POWER_MAX77686 ret = max77686_init();
if (ret)
return ret;
#endif +#ifdef CONFIG_POWER_TPS65090
/*
* The TPS65090 may not be in the device tree. If so, it is not
* an error.
Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Regards, Simon

On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
From: Aaron Durbin adurbin@chromium.org
The TSP65090 is a PMIC on some exynos5 boards. The init function is called for the TPS65090 pmic. If that device is not a part of the device tree (returns -ENODEV) then continue. Otherwise return a failure.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2:
- Move code to exynos5-dt.c
- Fix comment style
- Add #ifdef around tps65090 code
board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 1a64b9b..2c1cf8a 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -20,6 +20,7 @@ #include <asm/arch/sromc.h> #include <power/pmic.h> #include <power/max77686_pmic.h> +#include <power/tps65090_pmic.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -164,7 +165,19 @@ int exynos_power_init(void)
#ifdef CONFIG_POWER_MAX77686 ret = max77686_init();
if (ret)
return ret;
#endif +#ifdef CONFIG_POWER_TPS65090
/*
* The TPS65090 may not be in the device tree. If so, it is not
* an error.
Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
Thanks, Minkyu Kang.

Hi Minkyu,
On 21 May 2014 15:20, Minkyu Kang mk7.kang@samsung.com wrote:
On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
From: Aaron Durbin adurbin@chromium.org
The TSP65090 is a PMIC on some exynos5 boards. The init function is called for the TPS65090 pmic. If that device is not a part of the device tree (returns -ENODEV) then continue. Otherwise return a failure.
Signed-off-by: Aaron Durbin adurbin@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2:
- Move code to exynos5-dt.c
- Fix comment style
- Add #ifdef around tps65090 code
board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 1a64b9b..2c1cf8a 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -20,6 +20,7 @@ #include <asm/arch/sromc.h> #include <power/pmic.h> #include <power/max77686_pmic.h> +#include <power/tps65090_pmic.h> #include <tmu.h>
DECLARE_GLOBAL_DATA_PTR; @@ -164,7 +165,19 @@ int exynos_power_init(void)
#ifdef CONFIG_POWER_MAX77686 ret = max77686_init();
if (ret)
return ret;
#endif +#ifdef CONFIG_POWER_TPS65090
/*
* The TPS65090 may not be in the device tree. If so, it is not
* an error.
Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
The way it works at present is that there is a single exynos5-dt.h file which is used by all exynos5 boards. To the extent possible we have avoided putting particular features in things like snow.h and smdk5250.h - they just include exynos5-dt.h without changes.
The idea is that we can have one U-Boot binary that runs on any exynos5 device, rather than lots of different options. This makes it much easier to test changes sine we only need to build it once. If every exynos5 board has different #defines then there are more combinations to build and test. This is similar to what the kernel does with arch/arm/mach-exynos/mach-exynos5-dt.c.
Using this approach the only differences between smdk5250, daisy, snow, spring, etc. are in the device tree. I'd really like to avoid changing this now. It is easy enough for people to add their own private variants of these locally if they want to, but for mainline I believe it is better to be more generic.
Regards, Simon

On 14-05-22 11:27 AM, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 15:20, Minkyu Kang mk7.kang@samsung.com wrote:
On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote: > From: Aaron Durbin adurbin@chromium.org > > The TSP65090 is a PMIC on some exynos5 boards. The init function is > called for the TPS65090 pmic. If that device is not a part of the device > tree (returns -ENODEV) then continue. Otherwise return a failure. > > Signed-off-by: Aaron Durbin adurbin@chromium.org > Signed-off-by: Simon Glass sjg@chromium.org > Reviewed-by: Simon Glass sjg@chromium.org > --- > > Changes in v2: > - Move code to exynos5-dt.c > - Fix comment style > - Add #ifdef around tps65090 code > > board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ > 1 file changed, 13 insertions(+) > > diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c > index 1a64b9b..2c1cf8a 100644 > --- a/board/samsung/smdk5250/exynos5-dt.c > +++ b/board/samsung/smdk5250/exynos5-dt.c > @@ -20,6 +20,7 @@ > #include <asm/arch/sromc.h> > #include <power/pmic.h> > #include <power/max77686_pmic.h> > +#include <power/tps65090_pmic.h> > #include <tmu.h> > > DECLARE_GLOBAL_DATA_PTR; > @@ -164,7 +165,19 @@ int exynos_power_init(void) > > #ifdef CONFIG_POWER_MAX77686 > ret = max77686_init(); > + if (ret) > + return ret; > #endif > +#ifdef CONFIG_POWER_TPS65090 > + /* > + * The TPS65090 may not be in the device tree. If so, it is not > + * an error. Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
The way it works at present is that there is a single exynos5-dt.h file which is used by all exynos5 boards. To the extent possible we have avoided putting particular features in things like snow.h and smdk5250.h - they just include exynos5-dt.h without changes.
The idea is that we can have one U-Boot binary that runs on any exynos5 device, rather than lots of different options. This makes it much easier to test changes sine we only need to build it once. If every exynos5 board has different #defines then there are more combinations to build and test. This is similar to what the kernel does with arch/arm/mach-exynos/mach-exynos5-dt.c.
Using this approach the only differences between smdk5250, daisy, snow, spring, etc. are in the device tree. I'd really like to avoid changing this now. It is easy enough for people to add their own private variants of these locally if they want to, but for mainline I believe it is better to be more generic.
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Simon,
Would you say that we are approaching a state where *all* exynos 5 boards will be ready? I ask because I have the Universal5420 aka sm-t520 and I could really use a bootloader for it so I am eacer to assist any way neccessary. (but i need a little direction because i am a noob)
Regards David.

Hi David,
On 22 May 2014 08:24, David Nelson djhenjin1@gmail.com wrote:
On 14-05-22 11:27 AM, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 15:20, Minkyu Kang mk7.kang@samsung.com wrote:
On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote: > > On 03/04/14 08:24, Simon Glass wrote: >> >> From: Aaron Durbin adurbin@chromium.org >> >> The TSP65090 is a PMIC on some exynos5 boards. The init function is >> called for the TPS65090 pmic. If that device is not a part of the >> device >> tree (returns -ENODEV) then continue. Otherwise return a failure. >> >> Signed-off-by: Aaron Durbin adurbin@chromium.org >> Signed-off-by: Simon Glass sjg@chromium.org >> Reviewed-by: Simon Glass sjg@chromium.org >> --- >> >> Changes in v2: >> - Move code to exynos5-dt.c >> - Fix comment style >> - Add #ifdef around tps65090 code >> >> board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ >> 1 file changed, 13 insertions(+) >> >> diff --git a/board/samsung/smdk5250/exynos5-dt.c >> b/board/samsung/smdk5250/exynos5-dt.c >> index 1a64b9b..2c1cf8a 100644 >> --- a/board/samsung/smdk5250/exynos5-dt.c >> +++ b/board/samsung/smdk5250/exynos5-dt.c >> @@ -20,6 +20,7 @@ >> #include <asm/arch/sromc.h> >> #include <power/pmic.h> >> #include <power/max77686_pmic.h> >> +#include <power/tps65090_pmic.h> >> #include <tmu.h> >> >> DECLARE_GLOBAL_DATA_PTR; >> @@ -164,7 +165,19 @@ int exynos_power_init(void) >> >> #ifdef CONFIG_POWER_MAX77686 >> ret = max77686_init(); >> + if (ret) >> + return ret; >> #endif >> +#ifdef CONFIG_POWER_TPS65090 >> + /* >> + * The TPS65090 may not be in the device tree. If so, it is >> not >> + * an error. > > Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
The way it works at present is that there is a single exynos5-dt.h file which is used by all exynos5 boards. To the extent possible we have avoided putting particular features in things like snow.h and smdk5250.h - they just include exynos5-dt.h without changes.
The idea is that we can have one U-Boot binary that runs on any exynos5 device, rather than lots of different options. This makes it much easier to test changes sine we only need to build it once. If every exynos5 board has different #defines then there are more combinations to build and test. This is similar to what the kernel does with arch/arm/mach-exynos/mach-exynos5-dt.c.
Using this approach the only differences between smdk5250, daisy, snow, spring, etc. are in the device tree. I'd really like to avoid changing this now. It is easy enough for people to add their own private variants of these locally if they want to, but for mainline I believe it is better to be more generic.
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Simon,
Would you say that we are approaching a state where *all* exynos 5 boards will be ready? I ask because I have the Universal5420 aka sm-t520 and I could really use a bootloader for it so I am eacer to assist any way neccessary. (but i need a little direction because i am a noob)
I'm not familiar with that board. It doesn't seem to be in mainline / have a device tree file in U-Boot or Linux. You may be able to get it to boot just by trying one of the existing configs. If you need to change a device tree file, you could send a patch.
Regards, Simon

Dear Simon,
On 23/05/14 02:27, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 15:20, Minkyu Kang mk7.kang@samsung.com wrote:
On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote: > From: Aaron Durbin adurbin@chromium.org > > The TSP65090 is a PMIC on some exynos5 boards. The init function is > called for the TPS65090 pmic. If that device is not a part of the device > tree (returns -ENODEV) then continue. Otherwise return a failure. > > Signed-off-by: Aaron Durbin adurbin@chromium.org > Signed-off-by: Simon Glass sjg@chromium.org > Reviewed-by: Simon Glass sjg@chromium.org > --- > > Changes in v2: > - Move code to exynos5-dt.c > - Fix comment style > - Add #ifdef around tps65090 code > > board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ > 1 file changed, 13 insertions(+) > > diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c > index 1a64b9b..2c1cf8a 100644 > --- a/board/samsung/smdk5250/exynos5-dt.c > +++ b/board/samsung/smdk5250/exynos5-dt.c > @@ -20,6 +20,7 @@ > #include <asm/arch/sromc.h> > #include <power/pmic.h> > #include <power/max77686_pmic.h> > +#include <power/tps65090_pmic.h> > #include <tmu.h> > > DECLARE_GLOBAL_DATA_PTR; > @@ -164,7 +165,19 @@ int exynos_power_init(void) > > #ifdef CONFIG_POWER_MAX77686 > ret = max77686_init(); > + if (ret) > + return ret; > #endif > +#ifdef CONFIG_POWER_TPS65090 > + /* > + * The TPS65090 may not be in the device tree. If so, it is not > + * an error.
Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
The way it works at present is that there is a single exynos5-dt.h file which is used by all exynos5 boards. To the extent possible we have avoided putting particular features in things like snow.h and smdk5250.h - they just include exynos5-dt.h without changes.
The idea is that we can have one U-Boot binary that runs on any exynos5 device, rather than lots of different options. This makes it much easier to test changes sine we only need to build it once. If every exynos5 board has different #defines then there are more combinations to build and test. This is similar to what the kernel does with arch/arm/mach-exynos/mach-exynos5-dt.c.
Using this approach the only differences between smdk5250, daisy, snow, spring, etc. are in the device tree. I'd really like to avoid changing this now. It is easy enough for people to add their own private variants of these locally if they want to, but for mainline I believe it is better to be more generic.
I totally understood what you assert. But I can't agree with you. Do you think if we collect all features at exynos5-dt.h then it can be generic? even if some boards doesn't have the device? I think no. It just wrong definition. We should separate exynos5 generic features and board specific features.
+ ret = tps65090_init(); + if (ret == 0 || ret == -ENODEV) + return 0;
At here.. whatever, the error is an error. If you got NODEV then should return it, because that board does not have device.
Thanks, Minkyu Kang.

Hi Minkyu,
On 25 May 2014 21:15, Minkyu Kang mk7.kang@samsung.com wrote:
Dear Simon,
On 23/05/14 02:27, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 15:20, Minkyu Kang mk7.kang@samsung.com wrote:
On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote: > On 03/04/14 08:24, Simon Glass wrote: >> From: Aaron Durbin adurbin@chromium.org >> >> The TSP65090 is a PMIC on some exynos5 boards. The init function is >> called for the TPS65090 pmic. If that device is not a part of the device >> tree (returns -ENODEV) then continue. Otherwise return a failure. >> >> Signed-off-by: Aaron Durbin adurbin@chromium.org >> Signed-off-by: Simon Glass sjg@chromium.org >> Reviewed-by: Simon Glass sjg@chromium.org >> --- >> >> Changes in v2: >> - Move code to exynos5-dt.c >> - Fix comment style >> - Add #ifdef around tps65090 code >> >> board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ >> 1 file changed, 13 insertions(+) >> >> diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c >> index 1a64b9b..2c1cf8a 100644 >> --- a/board/samsung/smdk5250/exynos5-dt.c >> +++ b/board/samsung/smdk5250/exynos5-dt.c >> @@ -20,6 +20,7 @@ >> #include <asm/arch/sromc.h> >> #include <power/pmic.h> >> #include <power/max77686_pmic.h> >> +#include <power/tps65090_pmic.h> >> #include <tmu.h> >> >> DECLARE_GLOBAL_DATA_PTR; >> @@ -164,7 +165,19 @@ int exynos_power_init(void) >> >> #ifdef CONFIG_POWER_MAX77686 >> ret = max77686_init(); >> + if (ret) >> + return ret; >> #endif >> +#ifdef CONFIG_POWER_TPS65090 >> + /* >> + * The TPS65090 may not be in the device tree. If so, it is not >> + * an error. > > Then, how we can initialise the tps65090?
It is initialised if a suitable node is found in the device tree. If the device tree does not have it, then the hardware is assumed to not have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
The way it works at present is that there is a single exynos5-dt.h file which is used by all exynos5 boards. To the extent possible we have avoided putting particular features in things like snow.h and smdk5250.h - they just include exynos5-dt.h without changes.
The idea is that we can have one U-Boot binary that runs on any exynos5 device, rather than lots of different options. This makes it much easier to test changes sine we only need to build it once. If every exynos5 board has different #defines then there are more combinations to build and test. This is similar to what the kernel does with arch/arm/mach-exynos/mach-exynos5-dt.c.
Using this approach the only differences between smdk5250, daisy, snow, spring, etc. are in the device tree. I'd really like to avoid changing this now. It is easy enough for people to add their own private variants of these locally if they want to, but for mainline I believe it is better to be more generic.
I totally understood what you assert. But I can't agree with you. Do you think if we collect all features at exynos5-dt.h then it can be generic? even if some boards doesn't have the device? I think no. It just wrong definition. We should separate exynos5 generic features and board specific features.
Yes my intent is that we have an exynos5 build which (given the right device tree) can support any board. That has been the intent of the device tree effort for a while, and similar to the kernel approach.
What is the objection of having the driver compiled in for a board that doesn't have the device? Is it the extra 1KB of code space for smdk5250 etc.?
Anyway, it doesn't necessarily have to be exynos5-dt.h. If you really don't like that, we could create a new generic exynos5 board and I can target that instead. But I really want to avoid having to build multiple U-Boots for each board if possible.
ret = tps65090_init();
if (ret == 0 || ret == -ENODEV)
return 0;
At here.. whatever, the error is an error. If you got NODEV then should return it, because that board does not have device.
Then the caller would need to handle that error. The function is called exynos_power_init(), so I think it should return an error only when it failed to init the power, but in this case there is no problem.
Let me know the best way forward.
Regards, Simon

Dear Simon Glass,
On 27/05/14 09:01, Simon Glass wrote:
Hi Minkyu,
On 25 May 2014 21:15, Minkyu Kang mk7.kang@samsung.com wrote:
Dear Simon,
On 23/05/14 02:27, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 15:20, Minkyu Kang mk7.kang@samsung.com wrote:
On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 20:47, Simon Glass wrote: > Hi Minkyu, > > On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote: >> On 03/04/14 08:24, Simon Glass wrote: >>> From: Aaron Durbin adurbin@chromium.org >>> >>> The TSP65090 is a PMIC on some exynos5 boards. The init function is >>> called for the TPS65090 pmic. If that device is not a part of the device >>> tree (returns -ENODEV) then continue. Otherwise return a failure. >>> >>> Signed-off-by: Aaron Durbin adurbin@chromium.org >>> Signed-off-by: Simon Glass sjg@chromium.org >>> Reviewed-by: Simon Glass sjg@chromium.org >>> --- >>> >>> Changes in v2: >>> - Move code to exynos5-dt.c >>> - Fix comment style >>> - Add #ifdef around tps65090 code >>> >>> board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ >>> 1 file changed, 13 insertions(+) >>> >>> diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c >>> index 1a64b9b..2c1cf8a 100644 >>> --- a/board/samsung/smdk5250/exynos5-dt.c >>> +++ b/board/samsung/smdk5250/exynos5-dt.c >>> @@ -20,6 +20,7 @@ >>> #include <asm/arch/sromc.h> >>> #include <power/pmic.h> >>> #include <power/max77686_pmic.h> >>> +#include <power/tps65090_pmic.h> >>> #include <tmu.h> >>> >>> DECLARE_GLOBAL_DATA_PTR; >>> @@ -164,7 +165,19 @@ int exynos_power_init(void) >>> >>> #ifdef CONFIG_POWER_MAX77686 >>> ret = max77686_init(); >>> + if (ret) >>> + return ret; >>> #endif >>> +#ifdef CONFIG_POWER_TPS65090 >>> + /* >>> + * The TPS65090 may not be in the device tree. If so, it is not >>> + * an error. >> >> Then, how we can initialise the tps65090? > > It is initialised if a suitable node is found in the device tree. If > the device tree does not have it, then the hardware is assumed to not > have this chip.
then I think, it's an error. Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
The way it works at present is that there is a single exynos5-dt.h file which is used by all exynos5 boards. To the extent possible we have avoided putting particular features in things like snow.h and smdk5250.h - they just include exynos5-dt.h without changes.
The idea is that we can have one U-Boot binary that runs on any exynos5 device, rather than lots of different options. This makes it much easier to test changes sine we only need to build it once. If every exynos5 board has different #defines then there are more combinations to build and test. This is similar to what the kernel does with arch/arm/mach-exynos/mach-exynos5-dt.c.
Using this approach the only differences between smdk5250, daisy, snow, spring, etc. are in the device tree. I'd really like to avoid changing this now. It is easy enough for people to add their own private variants of these locally if they want to, but for mainline I believe it is better to be more generic.
I totally understood what you assert. But I can't agree with you. Do you think if we collect all features at exynos5-dt.h then it can be generic? even if some boards doesn't have the device? I think no. It just wrong definition. We should separate exynos5 generic features and board specific features.
Yes my intent is that we have an exynos5 build which (given the right device tree) can support any board. That has been the intent of the device tree effort for a while, and similar to the kernel approach.
What is the objection of having the driver compiled in for a board that doesn't have the device? Is it the extra 1KB of code space for smdk5250 etc.?
Yes, it's a tiny part of binary. But if we allow such things.. then it can be grew more and more.
Anyway, it doesn't necessarily have to be exynos5-dt.h. If you really don't like that, we could create a new generic exynos5 board and I can target that instead. But I really want to avoid having to build multiple U-Boots for each board if possible.
I want to define CONFIG_POWER_TPS65090 at snow.h and other each board's config file that have a device. But, I know what you want. So I will merge this patchset. But at future, I'll not allow any exception. It was not right way I think. I just want to keep clean our codes. That's all.
Thanks, Minkyu Kang.

Hi Minkyu,
On 28 May 2014 07:02, Minkyu Kang mk7.kang@samsung.com wrote:
Dear Simon Glass,
On 27/05/14 09:01, Simon Glass wrote:
Hi Minkyu,
On 25 May 2014 21:15, Minkyu Kang mk7.kang@samsung.com wrote:
Dear Simon,
On 23/05/14 02:27, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 15:20, Minkyu Kang mk7.kang@samsung.com wrote:
On 22/05/14 03:58, Simon Glass wrote:
Hi Minkyu,
On 21 May 2014 00:05, Minkyu Kang mk7.kang@samsung.com wrote: > On 20/05/14 20:47, Simon Glass wrote: >> Hi Minkyu, >> >> On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote: >>> On 03/04/14 08:24, Simon Glass wrote: >>>> From: Aaron Durbin adurbin@chromium.org >>>> >>>> The TSP65090 is a PMIC on some exynos5 boards. The init function is >>>> called for the TPS65090 pmic. If that device is not a part of the device >>>> tree (returns -ENODEV) then continue. Otherwise return a failure. >>>> >>>> Signed-off-by: Aaron Durbin adurbin@chromium.org >>>> Signed-off-by: Simon Glass sjg@chromium.org >>>> Reviewed-by: Simon Glass sjg@chromium.org >>>> --- >>>> >>>> Changes in v2: >>>> - Move code to exynos5-dt.c >>>> - Fix comment style >>>> - Add #ifdef around tps65090 code >>>> >>>> board/samsung/smdk5250/exynos5-dt.c | 13 +++++++++++++ >>>> 1 file changed, 13 insertions(+) >>>> >>>> diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c >>>> index 1a64b9b..2c1cf8a 100644 >>>> --- a/board/samsung/smdk5250/exynos5-dt.c >>>> +++ b/board/samsung/smdk5250/exynos5-dt.c >>>> @@ -20,6 +20,7 @@ >>>> #include <asm/arch/sromc.h> >>>> #include <power/pmic.h> >>>> #include <power/max77686_pmic.h> >>>> +#include <power/tps65090_pmic.h> >>>> #include <tmu.h> >>>> >>>> DECLARE_GLOBAL_DATA_PTR; >>>> @@ -164,7 +165,19 @@ int exynos_power_init(void) >>>> >>>> #ifdef CONFIG_POWER_MAX77686 >>>> ret = max77686_init(); >>>> + if (ret) >>>> + return ret; >>>> #endif >>>> +#ifdef CONFIG_POWER_TPS65090 >>>> + /* >>>> + * The TPS65090 may not be in the device tree. If so, it is not >>>> + * an error. >>> >>> Then, how we can initialise the tps65090? >> >> It is initialised if a suitable node is found in the device tree. If >> the device tree does not have it, then the hardware is assumed to not >> have this chip. > > then I think, it's an error. > Why you said, it is not an error?
I may be misunderstanding your question, but I'll try to answer what I think you are asking.
The device tree contains nodes for hardware in the machine that you want to initialise, and information about each one. Devices can be enabled or disabled by including or removing this information from the device tree (or marking a device disabled with a status = "disabled" property in the node).
The tps65090 chip is not used in all exynos5-dt boards, but is used in some. For example smdk5250 does not have it, but snow does. So we use the device tree to specify the difference, including (on snow) things like the tps65090, the display bridge chip, etc.
Hm, it doesn't make sense. Then it(#define CONFIG_POWER_TPS65090) should go into each config files. Not in exynos5-dt.h. Please modify it and patch 6/12 also.
The way it works at present is that there is a single exynos5-dt.h file which is used by all exynos5 boards. To the extent possible we have avoided putting particular features in things like snow.h and smdk5250.h - they just include exynos5-dt.h without changes.
The idea is that we can have one U-Boot binary that runs on any exynos5 device, rather than lots of different options. This makes it much easier to test changes sine we only need to build it once. If every exynos5 board has different #defines then there are more combinations to build and test. This is similar to what the kernel does with arch/arm/mach-exynos/mach-exynos5-dt.c.
Using this approach the only differences between smdk5250, daisy, snow, spring, etc. are in the device tree. I'd really like to avoid changing this now. It is easy enough for people to add their own private variants of these locally if they want to, but for mainline I believe it is better to be more generic.
I totally understood what you assert. But I can't agree with you. Do you think if we collect all features at exynos5-dt.h then it can be generic? even if some boards doesn't have the device? I think no. It just wrong definition. We should separate exynos5 generic features and board specific features.
Yes my intent is that we have an exynos5 build which (given the right device tree) can support any board. That has been the intent of the device tree effort for a while, and similar to the kernel approach.
What is the objection of having the driver compiled in for a board that doesn't have the device? Is it the extra 1KB of code space for smdk5250 etc.?
Yes, it's a tiny part of binary. But if we allow such things.. then it can be grew more and more.
Anyway, it doesn't necessarily have to be exynos5-dt.h. If you really don't like that, we could create a new generic exynos5 board and I can target that instead. But I really want to avoid having to build multiple U-Boots for each board if possible.
I want to define CONFIG_POWER_TPS65090 at snow.h and other each board's config file that have a device. But, I know what you want. So I will merge this patchset. But at future, I'll not allow any exception. It was not right way I think. I just want to keep clean our codes. That's all.
Thanks for being flexible. It is good to get this applied.
I'll take a look at how to improve this to separate out the 'generic' board from the others.
Regards, Simon

There is quite a tight deadline in enabling PSHOLD, less than a second. In some cases (e.g. with USB download), U-Boot takes longer than that to load, so the board powers off before U-Boot starts.
Add a call in SPL to enable PSHOLD.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Lukasz Majewski l.majewski@samsung.com ---
Changes in v2: None
arch/arm/cpu/armv7/exynos/lowlevel_init.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/cpu/armv7/exynos/lowlevel_init.c b/arch/arm/cpu/armv7/exynos/lowlevel_init.c index 11fe5b8..48b5511 100644 --- a/arch/arm/cpu/armv7/exynos/lowlevel_init.c +++ b/arch/arm/cpu/armv7/exynos/lowlevel_init.c @@ -48,6 +48,8 @@ int do_lowlevel_init(void)
arch_cpu_init();
+ set_ps_hold_ctrl(); + reset_status = get_reset_status();
switch (reset_status) {

At present the GPIO numbering patch has not been applied, so exynos GPIO numbering is inconsistent (there are large gaps). Disable interrupts to avoid a crash on boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
arch/arm/dts/exynos5250-snow.dts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts index 9b48a0c..42a687b 100644 --- a/arch/arm/dts/exynos5250-snow.dts +++ b/arch/arm/dts/exynos5250-snow.dts @@ -44,7 +44,11 @@ reg = <0x1e>; compatible = "google,cros-ec"; i2c-max-frequency = <100000>; - ec-interrupt = <&gpio 782 1>; + /* + * GPIO numbering is broken on exynos at present + * + * ec-interrupt = <&gpio 782 1>; + */ };
power-regulator@48 { @@ -60,7 +64,11 @@ reg = <0>; compatible = "google,cros-ec"; spi-max-frequency = <5000000>; - ec-interrupt = <&gpio 782 1>; + /* + * GPIO numbering is broken on exynos at present + * + * ec-interrupt = <&gpio 782 1>; + */ optimise-flash-write; status = "disabled"; };

On 03/04/14 08:24, Simon Glass wrote:
At present the GPIO numbering patch has not been applied, so exynos GPIO numbering is inconsistent (there are large gaps). Disable interrupts to avoid a crash on boot.
now, gpio patch is merged to u-boot-samsung.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
arch/arm/dts/exynos5250-snow.dts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
Thanks, Minkyu Kang.

Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
At present the GPIO numbering patch has not been applied, so exynos GPIO numbering is inconsistent (there are large gaps). Disable interrupts to avoid a crash on boot.
now, gpio patch is merged to u-boot-samsung.
I don't see it in mainline yet, and there are conflicts. But I'll see if I can send a new series.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
arch/arm/dts/exynos5250-snow.dts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
Thanks, Minkyu Kang.
Regards, Simon

On 20/05/14 06:27, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
At present the GPIO numbering patch has not been applied, so exynos GPIO numbering is inconsistent (there are large gaps). Disable interrupts to avoid a crash on boot.
now, gpio patch is merged to u-boot-samsung.
I don't see it in mainline yet, and there are conflicts. But I'll see if I can send a new series.
please find this commit (f6ae1ca05839f92b103aaa0743d1d0012ba9773d)
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
arch/arm/dts/exynos5250-snow.dts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
Thanks, Minkyu Kang.
Regards, Simon
Thanks, Minkyu Kang.

Hi Minkyu,
On 19 May 2014 18:53, Minkyu Kang mk7.kang@samsung.com wrote:
On 20/05/14 06:27, Simon Glass wrote:
Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
At present the GPIO numbering patch has not been applied, so exynos GPIO numbering is inconsistent (there are large gaps). Disable interrupts to avoid a crash on boot.
now, gpio patch is merged to u-boot-samsung.
I don't see it in mainline yet, and there are conflicts. But I'll see if I can send a new series.
please find this commit (f6ae1ca05839f92b103aaa0743d1d0012ba9773d)
OK thanks, I think I have something that can be applied.
I can correct the GPIO numbers now, so will replace this patch.
Regards, Simon

Enable LCD for snow. This is a 1366 x 768 panel.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add a device tree node for the snow EDP bridge chip
arch/arm/dts/exynos5250-snow.dts | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts index 42a687b..2a6bc78 100644 --- a/arch/arm/dts/exynos5250-snow.dts +++ b/arch/arm/dts/exynos5250-snow.dts @@ -88,6 +88,19 @@ reg = <0x22>; compatible = "maxim,max98095-codec"; }; + + ptn3460-bridge@20 { + compatible = "nxp,ptn3460"; + reg = <0x20>; + /* + * TODO(sjg@chromium.org): Exynos GPIOs broken + * powerdown-gpio = <&gpy2 5 0>; + * reset-gpio = <&gpx1 5 0>; + * edid-emulation = <5>; + * pinctrl-names = "default"; + * pinctrl-0 = <&ptn3460_gpios>; + */ + }; };
i2c@12c60000 { @@ -192,4 +205,48 @@ /* UP LEFT */ 0x070b0067 0x070c0069>; }; + + fimd@14400000 { + samsung,vl-freq = <60>; + samsung,vl-col = <1366>; + samsung,vl-row = <768>; + samsung,vl-width = <1366>; + samsung,vl-height = <768>; + + samsung,vl-clkp; + samsung,vl-dp; + samsung,vl-hsp; + samsung,vl-vsp; + + samsung,vl-bpix = <4>; + + samsung,vl-hspw = <32>; + samsung,vl-hbpd = <80>; + samsung,vl-hfpd = <48>; + samsung,vl-vspw = <5>; + samsung,vl-vbpd = <14>; + samsung,vl-vfpd = <3>; + samsung,vl-cmd-allow-len = <0xf>; + + samsung,winid = <0>; + samsung,interface-mode = <1>; + samsung,dp-enabled = <1>; + samsung,dual-lcd-enabled = <0>; + }; + + dp@145b0000 { + samsung,lt-status = <0>; + + samsung,master-mode = <0>; + samsung,bist-mode = <0>; + samsung,bist-pattern = <0>; + samsung,h-sync-polarity = <0>; + samsung,v-sync-polarity = <0>; + samsung,interlaced = <0>; + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + }; + };

On 03/04/14 08:24, Simon Glass wrote:
Enable LCD for snow. This is a 1366 x 768 panel.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a device tree node for the snow EDP bridge chip
arch/arm/dts/exynos5250-snow.dts | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts index 42a687b..2a6bc78 100644 --- a/arch/arm/dts/exynos5250-snow.dts +++ b/arch/arm/dts/exynos5250-snow.dts @@ -88,6 +88,19 @@ reg = <0x22>; compatible = "maxim,max98095-codec"; };
ptn3460-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
/*
* TODO(sjg@chromium.org): Exynos GPIOs broken
* powerdown-gpio = <&gpy2 5 0>;
* reset-gpio = <&gpx1 5 0>;
* edid-emulation = <5>;
* pinctrl-names = "default";
* pinctrl-0 = <&ptn3460_gpios>;
*/
Now you can use GPIOs.
Thanks, Minkyu Kang.

Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
Enable LCD for snow. This is a 1366 x 768 panel.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add a device tree node for the snow EDP bridge chip
arch/arm/dts/exynos5250-snow.dts | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts index 42a687b..2a6bc78 100644 --- a/arch/arm/dts/exynos5250-snow.dts +++ b/arch/arm/dts/exynos5250-snow.dts @@ -88,6 +88,19 @@ reg = <0x22>; compatible = "maxim,max98095-codec"; };
ptn3460-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
/*
* TODO(sjg@chromium.org): Exynos GPIOs broken
* powerdown-gpio = <&gpy2 5 0>;
* reset-gpio = <&gpx1 5 0>;
* edid-emulation = <5>;
* pinctrl-names = "default";
* pinctrl-0 = <&ptn3460_gpios>;
*/
Now you can use GPIOs.
Yes it is a big help. However, I would like to make this change in a follow-on series. It involves changing the code to stop hard-coding the GPIOs. But there are many GPIOs involved, not just this bridge chip, and not just the LCD. So I think we need a separate series after this one to move the GPIOs to the device tree.
Regards, Simon

The backlight uses FETs on the TPS65090. Enable this so that the display is visible.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Lukasz Majewski l.majewski@samsung.com ---
Changes in v2: - Only set up the EDP bridge for snow - Add a device tree compatibility string for the EDP bridge - Check for EDP failure and print an error in that case - Return immediately in exynos_backlight_on() if needed
board/samsung/smdk5250/exynos5-dt.c | 103 ++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 3 files changed, 105 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 2c1cf8a..73c9a35 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -183,6 +183,61 @@ int exynos_power_init(void) #endif /* CONFIG_POWER */
#ifdef CONFIG_LCD +static int board_dp_bridge_setup(void) +{ + struct exynos5_gpio_part1 *gpio1 = + (struct exynos5_gpio_part1 *)samsung_get_base_gpio_part1(); + const int MAX_TRIES = 10; + int num_tries, node; + + /* + * TODO(sjg): Use device tree for GPIOs when exynos GPIO + * numbering patch is in mainline. + */ + debug("%s\n", __func__); + node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_NXP_PTN3460); + if (node < 0) { + debug("%s: No node for DP bridge in device tree\n", __func__); + return -ENODEV; + } + + /* Setup the GPIOs */ + + /* PD is ACTIVE_LOW, and initially de-asserted */ + s5p_gpio_set_pull(&gpio1->y2, 5, GPIO_PULL_NONE); + s5p_gpio_direction_output(&gpio1->y2, 5, 1); + + /* Reset is ACTIVE_LOW */ + s5p_gpio_set_pull(&gpio1->x1, 5, GPIO_PULL_NONE); + s5p_gpio_direction_output(&gpio1->x1, 5, 0); + + udelay(10); + s5p_gpio_set_value(&gpio1->x1, 5, 1); + + s5p_gpio_direction_input(&gpio1->x0, 7); + + /* + * We need to wait for 90ms after bringing up the bridge since there + * is a phantom "high" on the HPD chip during its bootup. The phantom + * high comes within 7ms of de-asserting PD and persists for at least + * 15ms. The real high comes roughly 50ms after PD is de-asserted. The + * phantom high makes it hard for us to know when the NXP chip is up. + */ + mdelay(90); + + for (num_tries = 0; num_tries < MAX_TRIES; num_tries++) { + /* Check HPD. If it's high, we're all good. */ + if (s5p_gpio_get_value(&gpio1->x0, 7)) + return 0; + + debug("%s: eDP bridge failed to come up; try %d of %d\n", + __func__, num_tries, MAX_TRIES); + } + + /* Immediately go into bridge reset if the hp line is not high */ + return -ENODEV; +} + void exynos_cfg_lcd_gpio(void) { struct exynos5_gpio_part1 *gpio1 = @@ -204,4 +259,52 @@ void exynos_set_dp_phy(unsigned int onoff) { set_dp_phy_ctrl(onoff); } + +void exynos_backlight_on(unsigned int onoff) +{ + debug("%s(%u)\n", __func__, onoff); + + if (!onoff) + return; + +#ifdef CONFIG_POWER_TPS65090 + struct exynos5_gpio_part1 *gpio1 = + (struct exynos5_gpio_part1 *) + samsung_get_base_gpio_part1(); + int ret; + + ret = tps65090_fet_enable(1); /* Enable FET1, backlight */ + if (ret) + return; + + /* T5 in the LCD timing spec (defined as > 10ms) */ + mdelay(10); + + /* board_dp_backlight_pwm */ + s5p_gpio_direction_output(&gpio1->b2, 0, 1); + + /* T6 in the LCD timing spec (defined as > 10ms) */ + mdelay(10); + + /* board_dp_backlight_en */ + s5p_gpio_direction_output(&gpio1->x3, 0, 1); +#endif +} + +void exynos_lcd_power_on(void) +{ + int ret; + + debug("%s\n", __func__); + +#ifdef CONFIG_POWER_TPS65090 + /* board_dp_lcd_vdd */ + tps65090_fet_enable(6); /* Enable FET6, lcd panel */ +#endif + + ret = board_dp_bridge_setup(); + if (ret && ret != -ENODEV) + printf("LCD bridge failed to enable: %d\n", ret); +} + #endif diff --git a/include/fdtdec.h b/include/fdtdec.h index 669ab90..ea50d75 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -93,6 +93,7 @@ enum fdt_compat_id { COMPAT_SANDBOX_HOST_EMULATION, /* Sandbox emulation of a function */ COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */ COMPAT_TI_TPS65090, /* Texas Instrument TPS65090 */ + COMPAT_NXP_PTN3460, /* NXP PTN3460 DP/LVDS bridge */
COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e15e0ad..13e3f45 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -66,6 +66,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"), COMPAT(TI_TPS65090, "ti,tps65090"), + COMPAT(COMPAT_NXP_PTN3460, "nxp,ptn3460"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

On 03/04/14 08:24, Simon Glass wrote:
The backlight uses FETs on the TPS65090. Enable this so that the display is visible.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Lukasz Majewski l.majewski@samsung.com
Changes in v2:
- Only set up the EDP bridge for snow
- Add a device tree compatibility string for the EDP bridge
- Check for EDP failure and print an error in that case
- Return immediately in exynos_backlight_on() if needed
board/samsung/smdk5250/exynos5-dt.c | 103 ++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 3 files changed, 105 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 2c1cf8a..73c9a35 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -183,6 +183,61 @@ int exynos_power_init(void) #endif /* CONFIG_POWER */
#ifdef CONFIG_LCD +static int board_dp_bridge_setup(void) +{
- struct exynos5_gpio_part1 *gpio1 =
(struct exynos5_gpio_part1 *)samsung_get_base_gpio_part1();
- const int MAX_TRIES = 10;
please don't use upper case at local variable. If need, please define it.
- int num_tries, node;
- /*
* TODO(sjg): Use device tree for GPIOs when exynos GPIO
* numbering patch is in mainline.
*/
- debug("%s\n", __func__);
- node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_NXP_PTN3460);
- if (node < 0) {
debug("%s: No node for DP bridge in device tree\n", __func__);
return -ENODEV;
- }
- /* Setup the GPIOs */
- /* PD is ACTIVE_LOW, and initially de-asserted */
- s5p_gpio_set_pull(&gpio1->y2, 5, GPIO_PULL_NONE);
- s5p_gpio_direction_output(&gpio1->y2, 5, 1);
- /* Reset is ACTIVE_LOW */
- s5p_gpio_set_pull(&gpio1->x1, 5, GPIO_PULL_NONE);
- s5p_gpio_direction_output(&gpio1->x1, 5, 0);
- udelay(10);
- s5p_gpio_set_value(&gpio1->x1, 5, 1);
- s5p_gpio_direction_input(&gpio1->x0, 7);
seems to need rebase this patch.
- /*
* We need to wait for 90ms after bringing up the bridge since there
* is a phantom "high" on the HPD chip during its bootup. The phantom
* high comes within 7ms of de-asserting PD and persists for at least
* 15ms. The real high comes roughly 50ms after PD is de-asserted. The
* phantom high makes it hard for us to know when the NXP chip is up.
*/
- mdelay(90);
- for (num_tries = 0; num_tries < MAX_TRIES; num_tries++) {
/* Check HPD. If it's high, we're all good. */
if (s5p_gpio_get_value(&gpio1->x0, 7))
return 0;
debug("%s: eDP bridge failed to come up; try %d of %d\n",
__func__, num_tries, MAX_TRIES);
- }
- /* Immediately go into bridge reset if the hp line is not high */
- return -ENODEV;
+}
void exynos_cfg_lcd_gpio(void) { struct exynos5_gpio_part1 *gpio1 = @@ -204,4 +259,52 @@ void exynos_set_dp_phy(unsigned int onoff) { set_dp_phy_ctrl(onoff); }
+void exynos_backlight_on(unsigned int onoff)
onoff, then value is 1. is it on or off? How about rename it to "on"?
+{
- debug("%s(%u)\n", __func__, onoff);
- if (!onoff)
return;
+#ifdef CONFIG_POWER_TPS65090
- struct exynos5_gpio_part1 *gpio1 =
(struct exynos5_gpio_part1 *)
samsung_get_base_gpio_part1();
- int ret;
- ret = tps65090_fet_enable(1); /* Enable FET1, backlight */
- if (ret)
return;
- /* T5 in the LCD timing spec (defined as > 10ms) */
- mdelay(10);
- /* board_dp_backlight_pwm */
- s5p_gpio_direction_output(&gpio1->b2, 0, 1);
- /* T6 in the LCD timing spec (defined as > 10ms) */
- mdelay(10);
- /* board_dp_backlight_en */
- s5p_gpio_direction_output(&gpio1->x3, 0, 1);
+#endif +}
+void exynos_lcd_power_on(void) +{
- int ret;
- debug("%s\n", __func__);
+#ifdef CONFIG_POWER_TPS65090
- /* board_dp_lcd_vdd */
- tps65090_fet_enable(6); /* Enable FET6, lcd panel */
+#endif
- ret = board_dp_bridge_setup();
- if (ret && ret != -ENODEV)
printf("LCD bridge failed to enable: %d\n", ret);
+}
#endif diff --git a/include/fdtdec.h b/include/fdtdec.h index 669ab90..ea50d75 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -93,6 +93,7 @@ enum fdt_compat_id { COMPAT_SANDBOX_HOST_EMULATION, /* Sandbox emulation of a function */ COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */ COMPAT_TI_TPS65090, /* Texas Instrument TPS65090 */
COMPAT_NXP_PTN3460, /* NXP PTN3460 DP/LVDS bridge */
COMPAT_COUNT,
}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e15e0ad..13e3f45 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -66,6 +66,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"), COMPAT(TI_TPS65090, "ti,tps65090"),
- COMPAT(COMPAT_NXP_PTN3460, "nxp,ptn3460"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
Thanks, Minkyu Kang.

Hi Minkyu,
On 15 May 2014 00:51, Minkyu Kang mk7.kang@samsung.com wrote:
On 03/04/14 08:24, Simon Glass wrote:
The backlight uses FETs on the TPS65090. Enable this so that the display is visible.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Lukasz Majewski l.majewski@samsung.com
Changes in v2:
- Only set up the EDP bridge for snow
- Add a device tree compatibility string for the EDP bridge
- Check for EDP failure and print an error in that case
- Return immediately in exynos_backlight_on() if needed
board/samsung/smdk5250/exynos5-dt.c | 103 ++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 3 files changed, 105 insertions(+)
diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 2c1cf8a..73c9a35 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -183,6 +183,61 @@ int exynos_power_init(void) #endif /* CONFIG_POWER */
#ifdef CONFIG_LCD +static int board_dp_bridge_setup(void) +{
struct exynos5_gpio_part1 *gpio1 =
(struct exynos5_gpio_part1 *)samsung_get_base_gpio_part1();
const int MAX_TRIES = 10;
please don't use upper case at local variable. If need, please define it.
Done
int num_tries, node;
/*
* TODO(sjg): Use device tree for GPIOs when exynos GPIO
* numbering patch is in mainline.
*/
debug("%s\n", __func__);
node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_NXP_PTN3460);
if (node < 0) {
debug("%s: No node for DP bridge in device tree\n", __func__);
return -ENODEV;
}
/* Setup the GPIOs */
/* PD is ACTIVE_LOW, and initially de-asserted */
s5p_gpio_set_pull(&gpio1->y2, 5, GPIO_PULL_NONE);
s5p_gpio_direction_output(&gpio1->y2, 5, 1);
/* Reset is ACTIVE_LOW */
s5p_gpio_set_pull(&gpio1->x1, 5, GPIO_PULL_NONE);
s5p_gpio_direction_output(&gpio1->x1, 5, 0);
udelay(10);
s5p_gpio_set_value(&gpio1->x1, 5, 1);
s5p_gpio_direction_input(&gpio1->x0, 7);
seems to need rebase this patch.
Done
/*
* We need to wait for 90ms after bringing up the bridge since there
* is a phantom "high" on the HPD chip during its bootup. The phantom
* high comes within 7ms of de-asserting PD and persists for at least
* 15ms. The real high comes roughly 50ms after PD is de-asserted. The
* phantom high makes it hard for us to know when the NXP chip is up.
*/
mdelay(90);
for (num_tries = 0; num_tries < MAX_TRIES; num_tries++) {
/* Check HPD. If it's high, we're all good. */
if (s5p_gpio_get_value(&gpio1->x0, 7))
return 0;
debug("%s: eDP bridge failed to come up; try %d of %d\n",
__func__, num_tries, MAX_TRIES);
}
/* Immediately go into bridge reset if the hp line is not high */
return -ENODEV;
+}
void exynos_cfg_lcd_gpio(void) { struct exynos5_gpio_part1 *gpio1 = @@ -204,4 +259,52 @@ void exynos_set_dp_phy(unsigned int onoff) { set_dp_phy_ctrl(onoff); }
+void exynos_backlight_on(unsigned int onoff)
onoff, then value is 1. is it on or off? How about rename it to "on"?
Done
+{
debug("%s(%u)\n", __func__, onoff);
if (!onoff)
return;
+#ifdef CONFIG_POWER_TPS65090
struct exynos5_gpio_part1 *gpio1 =
(struct exynos5_gpio_part1 *)
samsung_get_base_gpio_part1();
int ret;
ret = tps65090_fet_enable(1); /* Enable FET1, backlight */
if (ret)
return;
/* T5 in the LCD timing spec (defined as > 10ms) */
mdelay(10);
/* board_dp_backlight_pwm */
s5p_gpio_direction_output(&gpio1->b2, 0, 1);
/* T6 in the LCD timing spec (defined as > 10ms) */
mdelay(10);
/* board_dp_backlight_en */
s5p_gpio_direction_output(&gpio1->x3, 0, 1);
+#endif +}
+void exynos_lcd_power_on(void) +{
int ret;
debug("%s\n", __func__);
+#ifdef CONFIG_POWER_TPS65090
/* board_dp_lcd_vdd */
tps65090_fet_enable(6); /* Enable FET6, lcd panel */
+#endif
ret = board_dp_bridge_setup();
if (ret && ret != -ENODEV)
printf("LCD bridge failed to enable: %d\n", ret);
+}
#endif diff --git a/include/fdtdec.h b/include/fdtdec.h index 669ab90..ea50d75 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -93,6 +93,7 @@ enum fdt_compat_id { COMPAT_SANDBOX_HOST_EMULATION, /* Sandbox emulation of a function */ COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */ COMPAT_TI_TPS65090, /* Texas Instrument TPS65090 */
COMPAT_NXP_PTN3460, /* NXP PTN3460 DP/LVDS bridge */ COMPAT_COUNT,
}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e15e0ad..13e3f45 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -66,6 +66,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"), COMPAT(TI_TPS65090, "ti,tps65090"),
COMPAT(COMPAT_NXP_PTN3460, "nxp,ptn3460"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
Regards, Simon

Add the ability to display the code offset of an initcall even after it is relocated. This makes it much easier to relate initcalls back to the U-Boot System.map file.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Rebase to samsung/master
include/initcall.h | 2 +- lib/initcall.c | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/include/initcall.h b/include/initcall.h index 2378077..65f67dc 100644 --- a/include/initcall.h +++ b/include/initcall.h @@ -6,4 +6,4 @@
typedef int (*init_fnc_t)(void);
-int initcall_run_list(init_fnc_t init_sequence[]); +int initcall_run_list(const init_fnc_t init_sequence[]); diff --git a/lib/initcall.c b/lib/initcall.c index fa76dd7..7597bad 100644 --- a/lib/initcall.c +++ b/lib/initcall.c @@ -7,15 +7,22 @@ #include <common.h> #include <initcall.h>
-int initcall_run_list(init_fnc_t init_sequence[]) +DECLARE_GLOBAL_DATA_PTR; + +int initcall_run_list(const init_fnc_t init_sequence[]) { - init_fnc_t *init_fnc_ptr; + const init_fnc_t *init_fnc_ptr;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { - debug("initcall: %p\n", *init_fnc_ptr); + unsigned long reloc_ofs = 0; + + if (gd->flags & GD_FLG_RELOC) + reloc_ofs = gd->reloc_off; + debug("initcall: %p\n", (char *)*init_fnc_ptr - reloc_ofs); if ((*init_fnc_ptr)()) { - debug("initcall sequence %p failed at call %p\n", - init_sequence, *init_fnc_ptr); + printf("initcall sequence %p failed at call %p\n", + init_sequence, + (char *)*init_fnc_ptr - reloc_ofs); return -1; } }

Hi,
On 2 April 2014 17:24, Simon Glass sjg@chromium.org wrote:
This series adds a driver for TPS65090 and plumbs it in to get the LCD working correctly on snow.
The display driver is already present, but needs information about the display to be provided in the device tree.
The backlight also needs to be enabled - it is controlled by a FET on the TPS65090. Note that the TPS65090 is controlled by the device tree so will only be present if the board's device tree file specifies it. At present this is only the case for snow, but other exynos5 boards will use it (e.g. pit).
Note: the TPS65090 driver was sent to the list around the middle of last year but was never applied.
Is there any news on this series please?

Dear Simon Glass,
On 13/05/14 07:45, Simon Glass wrote:
Hi,
On 2 April 2014 17:24, Simon Glass sjg@chromium.org wrote:
This series adds a driver for TPS65090 and plumbs it in to get the LCD working correctly on snow.
The display driver is already present, but needs information about the display to be provided in the device tree.
The backlight also needs to be enabled - it is controlled by a FET on the TPS65090. Note that the TPS65090 is controlled by the device tree so will only be present if the board's device tree file specifies it. At present this is only the case for snow, but other exynos5 boards will use it (e.g. pit).
Note: the TPS65090 driver was sent to the list around the middle of last year but was never applied.
Is there any news on this series please?
I'll check them soon.
Thanks, Minkyu Kang.
participants (3)
-
David Nelson
-
Minkyu Kang
-
Simon Glass