Patchwork [U-Boot,v6,04/26] pmic: Extend PMIC framework to support multiple instances of PMIC devices

login
register
mail settings
Submitter Łukasz Majewski
Date Nov. 9, 2012, 7:42 a.m.
Message ID <1352446951-12558-5-git-send-email-l.majewski@samsung.com>
Download mbox | patch
Permalink /patch/197967/
State Superseded
Delegated to: Anatolij Gustschin
Headers show

Comments

Łukasz Majewski - Nov. 9, 2012, 7:42 a.m.
The PMIC framework has been extended to support multiple instances of
the variety of devices responsible for power management.
This change allows supporting of e.g. fuel gauge, charger, MUIC (Micro USB
Interface Circuit).
Power related includes have been moved to ./include/power directory.
This is a first of a series of patches - in the future "pmic" will be
replaced with "power".

Two important issues:
1. The PMIC needs to be initialized just after malloc is configured
2. It uses list to hold information about available PMIC devices

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Stefano Babic <sbabic@denx.de>
---
Changes for v2:
- None
Changes for v3:
- None
Changes for v4:
- None
Changes for v5:
- Convert mx51_efikamx board from genesi to new pmic/power framework
Changes for v6:
- None
---
 board/davedenx/qong/qong.c               |    6 +-
 board/freescale/mx31pdk/mx31pdk.c        |    6 +-
 board/freescale/mx35pdk/mx35pdk.c        |    8 +-
 board/freescale/mx51evk/mx51evk.c        |    6 +-
 board/freescale/mx53evk/mx53evk.c        |    6 +-
 board/freescale/mx53loco/mx53loco.c      |   10 ++--
 board/genesi/mx51_efikamx/efikamx.c      |    6 +-
 board/hale/tt01/tt01.c                   |    6 +-
 board/samsung/goni/goni.c                |    9 ++-
 board/samsung/trats/trats.c              |   12 ++--
 board/samsung/universal_c210/universal.c |   10 ++--
 board/ttcontrol/vision2/vision2.c        |    6 +-
 drivers/misc/pmic_core.c                 |  108 ++++++++++++++++++++++--------
 drivers/misc/pmic_dialog.c               |    8 +-
 drivers/misc/pmic_fsl.c                  |    8 +-
 drivers/misc/pmic_i2c.c                  |    6 +-
 drivers/misc/pmic_max8997.c              |   10 ++--
 drivers/misc/pmic_max8998.c              |   10 ++--
 drivers/misc/pmic_spi.c                  |    4 +-
 drivers/rtc/mc13xxx-rtc.c                |    6 +-
 include/{ => power}/max8997_pmic.h       |   15 ++++-
 include/{ => power}/max8998_pmic.h       |    0
 include/{ => power}/pmic.h               |   19 ++++--
 23 files changed, 179 insertions(+), 106 deletions(-)
 rename include/{ => power}/max8997_pmic.h (92%)
 rename include/{ => power}/max8998_pmic.h (100%)
 rename include/{ => power}/pmic.h (84%)
Anatolij Gustschin - Nov. 10, 2012, 12:01 a.m.
Hi Lukasz,

On Fri, 09 Nov 2012 08:42:09 +0100
Lukasz Majewski <l.majewski@samsung.com> wrote:
...
> diff --git a/board/davedenx/qong/qong.c b/board/davedenx/qong/qong.c
> index c41f11d..e8c23f8 100644
> --- a/board/davedenx/qong/qong.c
> +++ b/board/davedenx/qong/qong.c
> @@ -28,7 +28,7 @@
>  #include <asm/arch/sys_proto.h>
>  #include <asm/io.h>
>  #include <nand.h>
> -#include <pmic.h>
> +#include <power/pmic.h>
>  #include <fsl_pmic.h>
>  #include <asm/gpio.h>
>  #include "qong_fpga.h"
> @@ -173,8 +173,8 @@ int board_late_init(void)
>  	u32 val;
>  	struct pmic *p;
>  
> -	pmic_init();
> -	p = get_pmic();
> +	pmic_init(I2C_PMIC);
> +	p = pmic_get("FSL_PMIC");

Now the pmic struct is allocated dynamically, we should check if the
allocation failed and bail out in this case to prevent dereferencing
null pointer in pmic_get().

...
> diff --git a/drivers/misc/pmic_fsl.c b/drivers/misc/pmic_fsl.c
> index 0ff75ed..868c3c4 100644
> --- a/drivers/misc/pmic_fsl.c
> +++ b/drivers/misc/pmic_fsl.c
> @@ -23,7 +23,7 @@
>  
>  #include <common.h>
>  #include <spi.h>
> -#include <pmic.h>
> +#include <power/pmic.h>
>  #include <fsl_pmic.h>
>  
>  #if defined(CONFIG_PMIC_SPI)
> @@ -33,9 +33,9 @@ static u32 pmic_spi_prepare_tx(u32 reg, u32 *val, u32 write)
>  }
>  #endif
>  
> -int pmic_init(void)
> +int pmic_init(unsigned char bus)
>  {
> -	struct pmic *p = get_pmic();
> +	struct pmic *p = pmic_alloc();
>  	static const char name[] = "FSL_PMIC";
>  
>  	p->name = name;
> @@ -54,7 +54,7 @@ int pmic_init(void)
>  	p->interface = PMIC_I2C;
>  	p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR;
>  	p->hw.i2c.tx_num = 3;
> -	p->bus = I2C_PMIC;
> +	p->bus = bus;

In the case the pmic_alloc() fails this code is now writing to pmic
struct at NULL. Please check the return value of pmic_alloc() and
bail out if needed. This applies to other drivers changed by this
patch. Can you please fix it and resubmit a fixed patch 04/26.

Thanks,
Anatolij
Łukasz Majewski - Nov. 12, 2012, 8:23 a.m.
Hi Anatolij,


Thank you for feedback.
> Hi Lukasz,
> 
> On Fri, 09 Nov 2012 08:42:09 +0100
> Lukasz Majewski <l.majewski@samsung.com> wrote:
> ...
> > diff --git a/board/davedenx/qong/qong.c b/board/davedenx/qong/qong.c
> > index c41f11d..e8c23f8 100644
> > --- a/board/davedenx/qong/qong.c
> > +++ b/board/davedenx/qong/qong.c
> > @@ -28,7 +28,7 @@
> >  #include <asm/arch/sys_proto.h>
> >  #include <asm/io.h>
> >  #include <nand.h>
> > -#include <pmic.h>
> > +#include <power/pmic.h>
> >  #include <fsl_pmic.h>
> >  #include <asm/gpio.h>
> >  #include "qong_fpga.h"
> > @@ -173,8 +173,8 @@ int board_late_init(void)
> >  	u32 val;
> >  	struct pmic *p;
> >  
> > -	pmic_init();
> > -	p = get_pmic();
> > +	pmic_init(I2C_PMIC);
> > +	p = pmic_get("FSL_PMIC");
> 
> Now the pmic struct is allocated dynamically, we should check if the
> allocation failed and bail out in this case to prevent dereferencing
> null pointer in pmic_get().
> 
> ...
> > diff --git a/drivers/misc/pmic_fsl.c b/drivers/misc/pmic_fsl.c
> > index 0ff75ed..868c3c4 100644
> > --- a/drivers/misc/pmic_fsl.c
> > +++ b/drivers/misc/pmic_fsl.c
> > @@ -23,7 +23,7 @@
> >  
> >  #include <common.h>
> >  #include <spi.h>
> > -#include <pmic.h>
> > +#include <power/pmic.h>
> >  #include <fsl_pmic.h>
> >  
> >  #if defined(CONFIG_PMIC_SPI)
> > @@ -33,9 +33,9 @@ static u32 pmic_spi_prepare_tx(u32 reg, u32 *val,
> > u32 write) }
> >  #endif
> >  
> > -int pmic_init(void)
> > +int pmic_init(unsigned char bus)
> >  {
> > -	struct pmic *p = get_pmic();
> > +	struct pmic *p = pmic_alloc();
> >  	static const char name[] = "FSL_PMIC";
> >  
> >  	p->name = name;
> > @@ -54,7 +54,7 @@ int pmic_init(void)
> >  	p->interface = PMIC_I2C;
> >  	p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR;
> >  	p->hw.i2c.tx_num = 3;
> > -	p->bus = I2C_PMIC;
> > +	p->bus = bus;
> 
> In the case the pmic_alloc() fails this code is now writing to pmic
> struct at NULL. Please check the return value of pmic_alloc() and
> bail out if needed. This applies to other drivers changed by this
> patch. Can you please fix it and resubmit a fixed patch 04/26.

One more time, thanks for spotting it. I will go through the patch
series and correct it.

BTW. I'm really stunned, how I managed to overlook this bug....

> 
> Thanks,
> Anatolij

Patch

diff --git a/board/davedenx/qong/qong.c b/board/davedenx/qong/qong.c
index c41f11d..e8c23f8 100644
--- a/board/davedenx/qong/qong.c
+++ b/board/davedenx/qong/qong.c
@@ -28,7 +28,7 @@ 
 #include <asm/arch/sys_proto.h>
 #include <asm/io.h>
 #include <nand.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 #include <asm/gpio.h>
 #include "qong_fpga.h"
@@ -173,8 +173,8 @@  int board_late_init(void)
 	u32 val;
 	struct pmic *p;
 
-	pmic_init();
-	p = get_pmic();
+	pmic_init(I2C_PMIC);
+	p = pmic_get("FSL_PMIC");
 
 	/* Enable RTC battery */
 	pmic_reg_read(p, REG_POWER_CTL0, &val);
diff --git a/board/freescale/mx31pdk/mx31pdk.c b/board/freescale/mx31pdk/mx31pdk.c
index 9f8bc53..24c0a1e 100644
--- a/board/freescale/mx31pdk/mx31pdk.c
+++ b/board/freescale/mx31pdk/mx31pdk.c
@@ -30,7 +30,7 @@ 
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/sys_proto.h>
 #include <watchdog.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -84,8 +84,8 @@  int board_late_init(void)
 	u32 val;
 	struct pmic *p;
 
-	pmic_init();
-	p = get_pmic();
+	pmic_init(I2C_PMIC);
+	p = pmic_get("FSL_PMIC");
 
 	/* Enable RTC battery */
 	pmic_reg_read(p, REG_POWER_CTL0, &val);
diff --git a/board/freescale/mx35pdk/mx35pdk.c b/board/freescale/mx35pdk/mx35pdk.c
index a12531f..4980391 100644
--- a/board/freescale/mx35pdk/mx35pdk.c
+++ b/board/freescale/mx35pdk/mx35pdk.c
@@ -31,7 +31,7 @@ 
 #include <asm/arch/mx35_pins.h>
 #include <asm/arch/iomux.h>
 #include <i2c.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 #include <mmc.h>
 #include <fsl_esdhc.h>
@@ -207,7 +207,7 @@  int board_init(void)
 static inline int pmic_detect(void)
 {
 	unsigned int id;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("FSL_PMIC");
 
 	pmic_reg_read(p, REG_IDENTIFICATION, &id);
 
@@ -232,9 +232,9 @@  int board_late_init(void)
 	u32 pmic_val;
 	struct pmic *p;
 
-	pmic_init();
+	pmic_init(I2C_PMIC);
 	if (pmic_detect()) {
-		p = get_pmic();
+		p = pmic_get("FSL_PMIC");
 		mxc_request_iomux(MX35_PIN_WATCHDOG_RST, MUX_CONFIG_SION |
 					MUX_CONFIG_ALT1);
 
diff --git a/board/freescale/mx51evk/mx51evk.c b/board/freescale/mx51evk/mx51evk.c
index 421d8c2..e1753aa 100644
--- a/board/freescale/mx51evk/mx51evk.c
+++ b/board/freescale/mx51evk/mx51evk.c
@@ -33,7 +33,7 @@ 
 #include <i2c.h>
 #include <mmc.h>
 #include <fsl_esdhc.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 #include <mc13892.h>
 #include <usb/ehci-fsl.h>
@@ -253,8 +253,8 @@  static void power_init(void)
 	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
 	struct pmic *p;
 
-	pmic_init();
-	p = get_pmic();
+	pmic_init(I2C_PMIC);
+	p = pmic_get("FSL_PMIC");
 
 	/* Write needed to Power Gate 2 register */
 	pmic_reg_read(p, REG_POWER_MISC, &val);
diff --git a/board/freescale/mx53evk/mx53evk.c b/board/freescale/mx53evk/mx53evk.c
index bb4621d..8541ce2 100644
--- a/board/freescale/mx53evk/mx53evk.c
+++ b/board/freescale/mx53evk/mx53evk.c
@@ -34,7 +34,7 @@ 
 #include <i2c.h>
 #include <mmc.h>
 #include <fsl_esdhc.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 #include <asm/gpio.h>
 #include <mc13892.h>
@@ -124,8 +124,8 @@  void power_init(void)
 	unsigned int val;
 	struct pmic *p;
 
-	pmic_init();
-	p = get_pmic();
+	pmic_init(I2C_PMIC);
+	p = pmic_get("FSL_PMIC");
 
 	/* Set VDDA to 1.25V */
 	pmic_reg_read(p, REG_SW_2, &val);
diff --git a/board/freescale/mx53loco/mx53loco.c b/board/freescale/mx53loco/mx53loco.c
index a11e883..467b698 100644
--- a/board/freescale/mx53loco/mx53loco.c
+++ b/board/freescale/mx53loco/mx53loco.c
@@ -36,7 +36,7 @@ 
 #include <mmc.h>
 #include <fsl_esdhc.h>
 #include <asm/gpio.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <dialog_pmic.h>
 #include <fsl_pmic.h>
 #include <linux/fb.h>
@@ -346,8 +346,8 @@  static int power_init(void)
 	struct pmic *p;
 
 	if (!i2c_probe(CONFIG_SYS_DIALOG_PMIC_I2C_ADDR)) {
-		pmic_dialog_init();
-		p = get_pmic();
+		pmic_dialog_init(I2C_PMIC);
+		p = pmic_get("DIALOG_PMIC");
 
 		/* Set VDDA to 1.25V */
 		val = DA9052_BUCKCORE_BCOREEN | DA_BUCKCORE_VBCORE_1_250V;
@@ -363,8 +363,8 @@  static int power_init(void)
 	}
 
 	if (!i2c_probe(CONFIG_SYS_FSL_PMIC_I2C_ADDR)) {
-		pmic_init();
-		p = get_pmic();
+		pmic_init(I2C_PMIC);
+		p = pmic_get("DIALOG_PMIC");
 
 		/* Set VDDGP to 1.25V for 1GHz on SW1 */
 		pmic_reg_read(p, REG_SW_0, &val);
diff --git a/board/genesi/mx51_efikamx/efikamx.c b/board/genesi/mx51_efikamx/efikamx.c
index c2b2823..f40def5 100644
--- a/board/genesi/mx51_efikamx/efikamx.c
+++ b/board/genesi/mx51_efikamx/efikamx.c
@@ -33,7 +33,7 @@ 
 #include <i2c.h>
 #include <mmc.h>
 #include <fsl_esdhc.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 #include <mc13892.h>
 
@@ -174,8 +174,8 @@  static void power_init(void)
 	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
 	struct pmic *p;
 
-	pmic_init();
-	p = get_pmic();
+	pmic_init(I2C_PMIC);
+	p = pmic_get("FSL_PMIC");
 
 	/* Write needed to Power Gate 2 register */
 	pmic_reg_read(p, REG_POWER_MISC, &val);
diff --git a/board/hale/tt01/tt01.c b/board/hale/tt01/tt01.c
index 143fcef..dd5833b 100644
--- a/board/hale/tt01/tt01.c
+++ b/board/hale/tt01/tt01.c
@@ -25,7 +25,7 @@ 
 #include <common.h>
 #include <netdev.h>
 #include <command.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 #include <mc13783.h>
 #include <asm/arch/clock.h>
@@ -201,8 +201,8 @@  int board_mmc_init(bd_t *bis)
 	* pmic_init() here. board_late_init() is too late for
 	* the MMC driver.
 	*/
-	pmic_init();
-	p = get_pmic();
+	pmic_init(I2C_PMIC);
+	p = pmic_get("FSL_PMIC");
 
 	/* configure pins for SDHC1 only */
 	mx31_gpio_mux(IOMUX_MODE(MUX_CTL_SD1_CLK, MUX_CTL_FUNC));
diff --git a/board/samsung/goni/goni.c b/board/samsung/goni/goni.c
index e8fb1ea..94731e4a 100644
--- a/board/samsung/goni/goni.c
+++ b/board/samsung/goni/goni.c
@@ -25,10 +25,10 @@ 
 #include <common.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <usb/s3c_udc.h>
 #include <asm/arch/cpu.h>
-#include <max8998_pmic.h>
+#include <power/max8998_pmic.h>
 DECLARE_GLOBAL_DATA_PTR;
 
 static struct s5pc110_gpio *s5pc110_gpio;
@@ -42,8 +42,9 @@  int board_init(void)
 	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
 
 #if defined(CONFIG_PMIC)
-	pmic_init();
+	pmic_init(I2C_5);
 #endif
+
 	return 0;
 }
 
@@ -108,7 +109,7 @@  static int s5pc1xx_phy_control(int on)
 {
 	int ret;
 	static int status;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("MAX8998_PMIC");
 
 	if (pmic_probe(p))
 		return -1;
diff --git a/board/samsung/trats/trats.c b/board/samsung/trats/trats.c
index e11a892..80ec4ad 100644
--- a/board/samsung/trats/trats.c
+++ b/board/samsung/trats/trats.c
@@ -34,9 +34,9 @@ 
 #include <asm/arch/mipi_dsim.h>
 #include <asm/arch/watchdog.h>
 #include <asm/arch/power.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <usb/s3c_udc.h>
-#include <max8997_pmic.h>
+#include <power/max8997_pmic.h>
 #include <libtizen.h>
 
 #include "setup.h"
@@ -69,7 +69,7 @@  int board_init(void)
 	printf("HW Revision:\t0x%x\n", board_rev);
 
 #if defined(CONFIG_PMIC)
-	pmic_init();
+	pmic_init(I2C_5);
 #endif
 
 	return 0;
@@ -238,7 +238,7 @@  static int s5pc210_phy_control(int on)
 {
 	int ret = 0;
 	u32 val = 0;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("MAX8997_PMIC");
 
 	if (pmic_probe(p))
 		return -1;
@@ -413,7 +413,7 @@  static void lcd_reset(void)
 static int lcd_power(void)
 {
 	int ret = 0;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("MAX8997_PMIC");
 
 	if (pmic_probe(p))
 		return 0;
@@ -473,7 +473,7 @@  static struct mipi_dsim_lcd_device mipi_lcd_device = {
 static int mipi_power(void)
 {
 	int ret = 0;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("MAX8997_PMIC");
 
 	if (pmic_probe(p))
 		return 0;
diff --git a/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c
index 90fff5c..80a7346 100644
--- a/board/samsung/universal_c210/universal.c
+++ b/board/samsung/universal_c210/universal.c
@@ -27,10 +27,10 @@ 
 #include <asm/arch/adc.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <usb/s3c_udc.h>
 #include <asm/arch/cpu.h>
-#include <max8998_pmic.h>
+#include <power/max8998_pmic.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -59,7 +59,7 @@  int board_init(void)
 	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
 
 #if defined(CONFIG_PMIC)
-	pmic_init();
+	pmic_init(I2C_5);
 #endif
 
 	check_hw_revision();
@@ -112,7 +112,7 @@  static unsigned short get_adc_value(int channel)
 static int adc_power_control(int on)
 {
 	int ret;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("MAX8998_PMIC");
 
 	if (pmic_probe(p))
 		return -1;
@@ -280,7 +280,7 @@  int board_mmc_init(bd_t *bis)
 static int s5pc210_phy_control(int on)
 {
 	int ret = 0;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("MAX8998_PMIC");
 
 	if (pmic_probe(p))
 		return -1;
diff --git a/board/ttcontrol/vision2/vision2.c b/board/ttcontrol/vision2/vision2.c
index abdd1aa..10ab678 100644
--- a/board/ttcontrol/vision2/vision2.c
+++ b/board/ttcontrol/vision2/vision2.c
@@ -34,7 +34,7 @@ 
 #include <asm/arch/sys_proto.h>
 #include <i2c.h>
 #include <mmc.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_esdhc.h>
 #include <fsl_pmic.h>
 #include <mc13892.h>
@@ -307,8 +307,8 @@  static void power_init_mx51(void)
 	unsigned int val;
 	struct pmic *p;
 
-	pmic_init();
-	p = get_pmic();
+	pmic_init(I2C_PMIC);
+	p = pmic_get("FSL_PMIC");
 
 	/* Write needed to Power Gate 2 register */
 	pmic_reg_read(p, REG_POWER_MISC, &val);
diff --git a/drivers/misc/pmic_core.c b/drivers/misc/pmic_core.c
index 5d62a56..2908f66 100644
--- a/drivers/misc/pmic_core.c
+++ b/drivers/misc/pmic_core.c
@@ -27,18 +27,21 @@ 
  */
 
 #include <common.h>
+#include <malloc.h>
 #include <linux/types.h>
-#include <pmic.h>
+#include <linux/list.h>
+#include <power/pmic.h>
 
-static struct pmic pmic;
+static LIST_HEAD(pmic_list);
 
-int check_reg(u32 reg)
+int check_reg(struct pmic *p, u32 reg)
 {
-	if (reg >= pmic.number_of_regs) {
+	if (reg >= p->number_of_regs) {
 		printf("<reg num> = %d is invalid. Should be less than %d\n",
-		       reg, pmic.number_of_regs);
+		       reg, p->number_of_regs);
 		return -1;
 	}
+
 	return 0;
 }
 
@@ -65,11 +68,16 @@  static void pmic_show_info(struct pmic *p)
 	printf("PMIC: %s\n", p->name);
 }
 
-static void pmic_dump(struct pmic *p)
+static int pmic_dump(struct pmic *p)
 {
 	int i, ret;
 	u32 val;
 
+	if (!p) {
+		puts("Wrong PMIC name!\n");
+		return -1;
+	}
+
 	pmic_show_info(p);
 	for (i = 0; i < p->number_of_regs; i++) {
 		ret = pmic_reg_read(p, i, &val);
@@ -82,36 +90,79 @@  static void pmic_dump(struct pmic *p)
 		printf("%08x ", val);
 	}
 	puts("\n");
+	return 0;
 }
 
-struct pmic *get_pmic(void)
+struct pmic *pmic_alloc(void)
 {
-	return &pmic;
+	struct pmic *p;
+
+	p = calloc(sizeof(*p), 1);
+	if (!p) {
+		printf("%s: No available memory for allocation!\n", __func__);
+		return NULL;
+	}
+
+	list_add_tail(&p->list, &pmic_list);
+
+	debug("%s: new pmic struct: 0x%p\n", __func__, p);
+
+	return p;
+}
+
+struct pmic *pmic_get(const char *s)
+{
+	struct pmic *p;
+
+	list_for_each_entry(p, &pmic_list, list) {
+		if (strcmp(p->name, s) == 0) {
+			debug("%s: pmic %s -> 0x%p\n", __func__, p->name, p);
+			return p;
+		}
+	}
+
+	return NULL;
+}
+
+static void pmic_list_names(void)
+{
+	struct pmic *p;
+
+	puts("PMIC devices:\n");
+	list_for_each_entry(p, &pmic_list, list) {
+		printf("name: %s\n", p->name);
+	}
 }
 
 int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	u32 ret, reg, val;
+	struct pmic *p;
 	char *cmd;
 
-	struct pmic *p = &pmic;
-
 	/* at least two arguments please */
 	if (argc < 2)
-		return cmd_usage(cmdtp);
+		return CMD_RET_USAGE;
 
 	cmd = argv[1];
+
+	if (strcmp(cmd, "list") == 0) {
+		pmic_list_names();
+		return CMD_RET_SUCCESS;
+	}
+
 	if (strcmp(cmd, "dump") == 0) {
-		pmic_dump(p);
-		return 0;
+		if (pmic_dump(pmic_get(argv[2])))
+			return CMD_RET_FAILURE;
+		return CMD_RET_SUCCESS;
 	}
 
 	if (strcmp(cmd, "read") == 0) {
-		if (argc < 3)
-			return cmd_usage(cmdtp);
-
-		reg = simple_strtoul(argv[2], NULL, 16);
+		if (argc < 4)
+			return CMD_RET_USAGE;
 
+		reg = simple_strtoul(argv[3], NULL, 16);
+		p = pmic_get(argv[2]);
 		ret = pmic_reg_read(p, reg, &val);
 
 		if (ret)
@@ -119,29 +170,30 @@  int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 		printf("\n0x%02x: 0x%08x\n", reg, val);
 
-		return 0;
+		return CMD_RET_SUCCESS;
 	}
 
 	if (strcmp(cmd, "write") == 0) {
-		if (argc < 4)
-			return cmd_usage(cmdtp);
-
-		reg = simple_strtoul(argv[2], NULL, 16);
-		val = simple_strtoul(argv[3], NULL, 16);
+		if (argc < 5)
+			return CMD_RET_USAGE;
 
+		reg = simple_strtoul(argv[3], NULL, 16);
+		val = simple_strtoul(argv[4], NULL, 16);
+		p = pmic_get(argv[2]);
 		pmic_reg_write(p, reg, val);
 
-		return 0;
+		return CMD_RET_SUCCESS;
 	}
 
 	/* No subcommand found */
-	return 1;
+	return CMD_RET_SUCCESS;
 }
 
 U_BOOT_CMD(
 	pmic,	CONFIG_SYS_MAXARGS, 1, do_pmic,
 	"PMIC",
-	"dump - dump PMIC registers\n"
-	"pmic read <reg> - read register\n"
-	"pmic write <reg> <value> - write register"
+	"list - list available PMICs\n"
+	"pmic dump name - dump named PMIC registers\n"
+	"pmic name read <reg> - read register\n"
+	"pmic name write <reg> <value> - write register"
 );
diff --git a/drivers/misc/pmic_dialog.c b/drivers/misc/pmic_dialog.c
index e97af1d..d972211 100644
--- a/drivers/misc/pmic_dialog.c
+++ b/drivers/misc/pmic_dialog.c
@@ -17,12 +17,12 @@ 
  */
 
 #include <common.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <dialog_pmic.h>
 
-int pmic_dialog_init(void)
+int pmic_dialog_init(unsigned char bus)
 {
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_alloc();
 	static const char name[] = "DIALOG_PMIC";
 
 	p->name = name;
@@ -31,7 +31,7 @@  int pmic_dialog_init(void)
 	p->interface = PMIC_I2C;
 	p->hw.i2c.addr = CONFIG_SYS_DIALOG_PMIC_I2C_ADDR;
 	p->hw.i2c.tx_num = 1;
-	p->bus = I2C_PMIC;
+	p->bus = bus;
 
 	return 0;
 }
diff --git a/drivers/misc/pmic_fsl.c b/drivers/misc/pmic_fsl.c
index 0ff75ed..868c3c4 100644
--- a/drivers/misc/pmic_fsl.c
+++ b/drivers/misc/pmic_fsl.c
@@ -23,7 +23,7 @@ 
 
 #include <common.h>
 #include <spi.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 
 #if defined(CONFIG_PMIC_SPI)
@@ -33,9 +33,9 @@  static u32 pmic_spi_prepare_tx(u32 reg, u32 *val, u32 write)
 }
 #endif
 
-int pmic_init(void)
+int pmic_init(unsigned char bus)
 {
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_alloc();
 	static const char name[] = "FSL_PMIC";
 
 	p->name = name;
@@ -54,7 +54,7 @@  int pmic_init(void)
 	p->interface = PMIC_I2C;
 	p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR;
 	p->hw.i2c.tx_num = 3;
-	p->bus = I2C_PMIC;
+	p->bus = bus;
 #else
 #error "You must select CONFIG_PMIC_SPI or CONFIG_PMIC_I2C"
 #endif
diff --git a/drivers/misc/pmic_i2c.c b/drivers/misc/pmic_i2c.c
index 1064bfe..3e5a784 100644
--- a/drivers/misc/pmic_i2c.c
+++ b/drivers/misc/pmic_i2c.c
@@ -28,7 +28,7 @@ 
 
 #include <common.h>
 #include <linux/types.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <i2c.h>
 #include <compiler.h>
 
@@ -36,7 +36,7 @@  int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
 {
 	unsigned char buf[4] = { 0 };
 
-	if (check_reg(reg))
+	if (check_reg(p, reg))
 		return -1;
 
 	switch (pmic_i2c_tx_num) {
@@ -79,7 +79,7 @@  int pmic_reg_read(struct pmic *p, u32 reg, u32 *val)
 	unsigned char buf[4] = { 0 };
 	u32 ret_val = 0;
 
-	if (check_reg(reg))
+	if (check_reg(p, reg))
 		return -1;
 
 	if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num))
diff --git a/drivers/misc/pmic_max8997.c b/drivers/misc/pmic_max8997.c
index 4943f66..4e8283a 100644
--- a/drivers/misc/pmic_max8997.c
+++ b/drivers/misc/pmic_max8997.c
@@ -22,13 +22,13 @@ 
  */
 
 #include <common.h>
-#include <pmic.h>
-#include <max8997_pmic.h>
+#include <power/pmic.h>
+#include <power/max8997_pmic.h>
 #include <i2c.h>
 
-int pmic_init(void)
+int pmic_init(unsigned char bus)
 {
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_alloc();
 	static const char name[] = "MAX8997_PMIC";
 
 	puts("Board PMIC init\n");
@@ -38,7 +38,7 @@  int pmic_init(void)
 	p->number_of_regs = PMIC_NUM_OF_REGS;
 	p->hw.i2c.addr = MAX8997_I2C_ADDR;
 	p->hw.i2c.tx_num = 1;
-	p->bus = I2C_0;
+	p->bus = bus;
 
 	return 0;
 }
diff --git a/drivers/misc/pmic_max8998.c b/drivers/misc/pmic_max8998.c
index cc69fd7..3cad60d 100644
--- a/drivers/misc/pmic_max8998.c
+++ b/drivers/misc/pmic_max8998.c
@@ -22,12 +22,12 @@ 
  */
 
 #include <common.h>
-#include <pmic.h>
-#include <max8998_pmic.h>
+#include <power/pmic.h>
+#include <power/max8998_pmic.h>
 
-int pmic_init(void)
+int pmic_init(unsigned char bus)
 {
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_alloc();
 	static const char name[] = "MAX8998_PMIC";
 
 	puts("Board PMIC init\n");
@@ -37,7 +37,7 @@  int pmic_init(void)
 	p->number_of_regs = PMIC_NUM_OF_REGS;
 	p->hw.i2c.addr = MAX8998_I2C_ADDR;
 	p->hw.i2c.tx_num = 1;
-	p->bus = I2C_PMIC;
+	p->bus = bus;
 
 	return 0;
 }
diff --git a/drivers/misc/pmic_spi.c b/drivers/misc/pmic_spi.c
index 5a0dd22..27488ea 100644
--- a/drivers/misc/pmic_spi.c
+++ b/drivers/misc/pmic_spi.c
@@ -28,7 +28,7 @@ 
 
 #include <common.h>
 #include <linux/types.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <spi.h>
 
 static struct spi_slave *slave;
@@ -59,7 +59,7 @@  static u32 pmic_reg(struct pmic *p, u32 reg, u32 *val, u32 write)
 			return -1;
 	}
 
-	if (check_reg(reg))
+	if (check_reg(p, reg))
 		return -1;
 
 	if (spi_claim_bus(slave))
diff --git a/drivers/rtc/mc13xxx-rtc.c b/drivers/rtc/mc13xxx-rtc.c
index 70ea8a1..1a10588 100644
--- a/drivers/rtc/mc13xxx-rtc.c
+++ b/drivers/rtc/mc13xxx-rtc.c
@@ -23,14 +23,14 @@ 
 #include <common.h>
 #include <rtc.h>
 #include <spi.h>
-#include <pmic.h>
+#include <power/pmic.h>
 #include <fsl_pmic.h>
 
 int rtc_get(struct rtc_time *rtc)
 {
 	u32 day1, day2, time;
 	int tim, i = 0;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("FSL_PMIC");
 	int ret;
 
 	do {
@@ -61,7 +61,7 @@  int rtc_get(struct rtc_time *rtc)
 int rtc_set(struct rtc_time *rtc)
 {
 	u32 time, day;
-	struct pmic *p = get_pmic();
+	struct pmic *p = pmic_get("FSL_PMIC");
 
 	time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday,
 		      rtc->tm_hour, rtc->tm_min, rtc->tm_sec);
diff --git a/include/max8997_pmic.h b/include/power/max8997_pmic.h
similarity index 92%
rename from include/max8997_pmic.h
rename to include/power/max8997_pmic.h
index 17ae24e..1db7deb 100644
--- a/include/max8997_pmic.h
+++ b/include/power/max8997_pmic.h
@@ -111,7 +111,7 @@  enum {
 	MAX8997_REG_MBCCTRL6	= 0x55,
 	MAX8997_REG_OTPCGHCVS	= 0x56,
 
-	MAX8997_REG_SAFEOUTCTRL	= 0x5a,
+	MAX8997_REG_SAFEOUTCTRL = 0x5a,
 
 	MAX8997_REG_LBCNFG1	= 0x5e,
 	MAX8997_REG_LBCNFG2	= 0x5f,
@@ -171,9 +171,22 @@  enum {
 	PMIC_NUM_OF_REGS = 0x9b,
 };
 
+#define ACTDISSAFEO1 (1 << 4)
+#define ACTDISSAFEO2 (1 << 5)
 #define ENSAFEOUT1 (1 << 6)
 #define ENSAFEOUT2 (1 << 7)
 
+/* Charger */
+enum {CHARGER_ENABLE, CHARGER_DISABLE};
+#define DETBAT                  (1 << 2)
+#define MBCICHFCSET             (1 << 4)
+#define MBCHOSTEN               (1 << 6)
+#define VCHGR_FC                (1 << 7)
+
+#define CHARGER_MIN_CURRENT 200
+#define CHARGER_MAX_CURRENT 950
+#define CHARGER_CURRENT_RESOLUTION 50
+
 #define MAX8997_I2C_ADDR        (0xCC >> 1)
 #define MAX8997_RTC_ADDR	(0x0C >> 1)
 #define MAX8997_MUIC_ADDR	(0x4A >> 1)
diff --git a/include/max8998_pmic.h b/include/power/max8998_pmic.h
similarity index 100%
rename from include/max8998_pmic.h
rename to include/power/max8998_pmic.h
diff --git a/include/pmic.h b/include/power/pmic.h
similarity index 84%
rename from include/pmic.h
rename to include/power/pmic.h
index 1a2db05..e9affc8 100644
--- a/include/pmic.h
+++ b/include/power/pmic.h
@@ -1,5 +1,5 @@ 
 /*
- *  Copyright (C) 2011 Samsung Electronics
+ *  Copyright (C) 2011-2012 Samsung Electronics
  *  Lukasz Majewski <l.majewski@samsung.com>
  *
  * See file CREDITS for list of people who contributed to this
@@ -24,6 +24,10 @@ 
 #ifndef __CORE_PMIC_H_
 #define __CORE_PMIC_H_
 
+#include <common.h>
+#include <linux/list.h>
+#include <i2c.h>
+
 enum { PMIC_I2C, PMIC_SPI, };
 enum { I2C_PMIC, I2C_NUM, };
 enum { PMIC_READ, PMIC_WRITE, };
@@ -49,17 +53,20 @@  struct pmic {
 	unsigned char bus;
 	unsigned char interface;
 	unsigned char sensor_byte_order;
-	unsigned char number_of_regs;
+	unsigned int number_of_regs;
 	union hw {
 		struct p_i2c i2c;
 		struct p_spi spi;
 	} hw;
+
+	struct list_head list;
 };
 
-int pmic_init(void);
-int pmic_dialog_init(void);
-int check_reg(u32 reg);
-struct pmic *get_pmic(void);
+int pmic_init(unsigned char bus);
+int pmic_dialog_init(unsigned char bus);
+int check_reg(struct pmic *p, u32 reg);
+struct pmic *pmic_alloc(void);
+struct pmic *pmic_get(const char *s);
 int pmic_probe(struct pmic *p);
 int pmic_reg_read(struct pmic *p, u32 reg, u32 *val);
 int pmic_reg_write(struct pmic *p, u32 reg, u32 val);