board: common: vid: Add support for LTC3882 voltage regulator chip

Restructures common driver to support LTC3882 voltage regulator
chip.

Signed-off-by: Ashish Kumar <Ashish.Kumar@nxp.com>
Signed-off-by: Rajesh Bhagat <rajesh.bhagat@nxp.com>
Reviewed-by: York Sun <york.sun@nxp.com>
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
index 47e8b5a..642df2f 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
@@ -201,10 +201,15 @@
 	u32	gpporcr3;
 	u32	gpporcr4;
 	u8	res_030[0x60-0x30];
-#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT	2
 #define FSL_CHASSIS3_DCFG_FUSESR_VID_MASK	0x1F
-#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT	7
 #define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK	0x1F
+#if defined(CONFIG_ARCH_LS1088A)
+#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT	25
+#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT	20
+#else
+#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT	2
+#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT	7
+#endif
 	u32	dcfg_fusesr;	/* Fuse status register */
 	u8	res_064[0x70-0x64];
 	u32	devdisr;	/* Device disable control 1 */
diff --git a/board/freescale/common/vid.c b/board/freescale/common/vid.c
index f68068e..a9451c5 100644
--- a/board/freescale/common/vid.c
+++ b/board/freescale/common/vid.c
@@ -174,6 +174,36 @@
 }
 #endif
 
+#ifdef CONFIG_VOL_MONITOR_LTC3882_READ
+/* read the current value of the LTC Regulator Voltage */
+static int read_voltage_from_LTC(int i2caddress)
+{
+	int  ret, vcode = 0;
+	u8 chan = PWM_CHANNEL0;
+
+	/* select the PAGE 0 using PMBus commands PAGE for VDD*/
+	ret = i2c_write(I2C_VOL_MONITOR_ADDR,
+			PMBUS_CMD_PAGE, 1, &chan, 1);
+	if (ret) {
+		printf("VID: failed to select VDD Page 0\n");
+		return ret;
+	}
+
+	/*read the output voltage using PMBus command READ_VOUT*/
+	ret = i2c_read(I2C_VOL_MONITOR_ADDR,
+		       PMBUS_CMD_READ_VOUT, 1, (void *)&vcode, 2);
+	if (ret) {
+		printf("VID: failed to read the volatge\n");
+		return ret;
+	}
+
+	/* Scale down to the real mV as LTC resolution is 1/4096V,rounding up */
+	vcode = DIV_ROUND_UP(vcode * 1000, 4096);
+
+	return vcode;
+}
+#endif
+
 static int read_voltage(int i2caddress)
 {
 	int voltage_read;
@@ -181,6 +211,8 @@
 	voltage_read = read_voltage_from_INA220(i2caddress);
 #elif defined CONFIG_VOL_MONITOR_IR36021_READ
 	voltage_read = read_voltage_from_IR(i2caddress);
+#elif defined CONFIG_VOL_MONITOR_LTC3882_READ
+	voltage_read = read_voltage_from_LTC(i2caddress);
 #else
 	return -1;
 #endif
@@ -281,6 +313,43 @@
 	debug("VID: Current voltage is %d mV\n", vdd_last);
 	return vdd_last;
 }
+
+#endif
+
+#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
+/* this function sets the VDD and returns the value set */
+static int set_voltage_to_LTC(int i2caddress, int vdd)
+{
+	int ret, vdd_last, vdd_target = vdd;
+
+	/* Scale up to the LTC resolution is 1/4096V */
+	vdd = (vdd * 4096) / 1000;
+
+	/* 5-byte buffer which needs to be sent following the
+	 * PMBus command PAGE_PLUS_WRITE.
+	 */
+	u8 buff[5] = {0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND,
+			vdd & 0xFF, (vdd & 0xFF00) >> 8};
+
+	/* Write the desired voltage code to the regulator */
+	ret = i2c_write(I2C_VOL_MONITOR_ADDR,
+			PMBUS_CMD_PAGE_PLUS_WRITE, 1, (void *)&buff, 5);
+	if (ret) {
+		printf("VID: I2C failed to write to the volatge regulator\n");
+		return -1;
+	}
+
+	/* Wait for the volatge to get to the desired value */
+	do {
+		vdd_last = read_voltage_from_LTC(i2caddress);
+		if (vdd_last < 0) {
+			printf("VID: Couldn't read sensor abort VID adjust\n");
+			return -1;
+		}
+	} while (vdd_last != vdd_target);
+
+	return vdd_last;
+}
 #endif
 
 static int set_voltage(int i2caddress, int vdd)
@@ -289,6 +358,8 @@
 
 #ifdef CONFIG_VOL_MONITOR_IR36021_SET
 	vdd_last = set_voltage_to_IR(i2caddress, vdd);
+#elif defined CONFIG_VOL_MONITOR_LTC3882_SET
+	vdd_last = set_voltage_to_LTC(i2caddress, vdd);
 #else
 	#error Specific voltage monitor must be defined
 #endif
@@ -472,6 +543,11 @@
 	}
 	vdd_current = vdd_last;
 	debug("VID: Core voltage is currently at %d mV\n", vdd_last);
+
+#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
+	/* Set the target voltage */
+	vdd_last = vdd_current = set_voltage(i2caddress, vdd_target);
+#else
 	/*
 	  * Adjust voltage to at or one step above target.
 	  * As measurements are less precise than setting the values
@@ -489,6 +565,7 @@
 		vdd_last = set_voltage(i2caddress, vdd_current);
 	}
 
+#endif
 	if (board_adjust_vdd(vdd_target) < 0) {
 		ret = -1;
 		goto exit;
diff --git a/include/configs/ls1088aqds.h b/include/configs/ls1088aqds.h
index 8fbf890..ff2f916 100644
--- a/include/configs/ls1088aqds.h
+++ b/include/configs/ls1088aqds.h
@@ -279,6 +279,22 @@
 #define I2C_MUX_CH_DEFAULT		0x8
 #define I2C_MUX_CH5			0xD
 
+#define I2C_MUX_CH_VOL_MONITOR          0xA
+
+/* Voltage monitor on channel 2*/
+#define I2C_VOL_MONITOR_ADDR           0x63
+#define I2C_VOL_MONITOR_BUS_V_OFFSET   0x2
+#define I2C_VOL_MONITOR_BUS_V_OVF      0x1
+#define I2C_VOL_MONITOR_BUS_V_SHIFT    3
+
+/* PM Bus commands code for LTC3882*/
+#define PMBUS_CMD_PAGE                  0x0
+#define PMBUS_CMD_READ_VOUT             0x8B
+#define PMBUS_CMD_PAGE_PLUS_WRITE       0x05
+#define PMBUS_CMD_VOUT_COMMAND          0x21
+
+#define PWM_CHANNEL0                    0x0
+
 /*
 * RTC configuration
 */
diff --git a/include/configs/ls1088ardb.h b/include/configs/ls1088ardb.h
index d0066e3..4c290c5 100644
--- a/include/configs/ls1088ardb.h
+++ b/include/configs/ls1088ardb.h
@@ -225,6 +225,21 @@
 
 #define CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS 5000
 
+#define I2C_MUX_CH_VOL_MONITOR          0xA
+/* Voltage monitor on channel 2*/
+#define I2C_VOL_MONITOR_ADDR           0x63
+#define I2C_VOL_MONITOR_BUS_V_OFFSET   0x2
+#define I2C_VOL_MONITOR_BUS_V_OVF      0x1
+#define I2C_VOL_MONITOR_BUS_V_SHIFT    3
+
+/* PM Bus commands code for LTC3882*/
+#define PMBUS_CMD_PAGE                  0x0
+#define PMBUS_CMD_READ_VOUT             0x8B
+#define PMBUS_CMD_PAGE_PLUS_WRITE       0x05
+#define PMBUS_CMD_VOUT_COMMAND          0x21
+
+#define PWM_CHANNEL0                    0x0
+
 /*
  * I2C bus multiplexer
  */