pmic: 8917: Add support for new APIs

Add support for APIs to read battery voltage level, vbus status
and new LDO api.

Change-Id: I6205113b515768b96a50960fb4081f534c5382bf
diff --git a/dev/pmic/pm8921/include/dev/pm8921.h b/dev/pmic/pm8921/include/dev/pm8921.h
index 715e474..7200eb0 100644
--- a/dev/pmic/pm8921/include/dev/pm8921.h
+++ b/dev/pmic/pm8921/include/dev/pm8921.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- *     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     * Neither the name of Linux Foundation, Inc. nor the names of its
  *       contributors may be used to endorse or promote products derived
  *       from this software without specific prior written permission.
  *
@@ -61,6 +61,25 @@
 	mpp_end = mpp_12,
 };
 
+typedef enum {
+	BAT_VOL_2_8 = 0,
+	BAT_VOL_2_9,
+	BAT_VOL_3_0,
+	BAT_VOL_3_1,
+	BAT_VOL_3_2,
+	BAT_VOL_3_3,
+	BAT_VOL_3_4,
+	BAT_VOL_3_5,
+	BAT_VOL_3_6,
+	BAT_VOL_3_7,
+	BAT_VOL_3_8,
+	BAT_VOL_3_9,
+	BAT_VOL_4_0,
+	BAT_VOL_4_1,
+	BAT_VOL_4_2,
+	BAT_VOL_4_3,
+} bat_vol_t;
+
 #define PM_GPIO_DIR_OUT         0x01
 #define PM_GPIO_DIR_IN          0x02
 #define PM_GPIO_DIR_BOTH        (PM_GPIO_DIR_OUT | PM_GPIO_DIR_IN)
@@ -139,6 +158,13 @@
 	int disable_pin;
 };
 
+struct pm89xx_vreg {
+	const char *name;
+	uint8_t type;
+	uint16_t test_reg;
+	uint16_t ctrl_reg;
+};
+
 void pm8921_init(pm8921_dev_t *);
 int  pm8921_gpio_config(int gpio, struct pm8921_gpio *param);
 void pm8921_boot_done(void);
@@ -156,4 +182,8 @@
 int pm8921_low_voltage_switch_enable(uint8_t lvs_id);
 int pm8921_mpp_set_digital_output(uint8_t mpp_id);
 int pm8921_rtc_alarm_disable(void);
+int pm89xx_bat_alarm_set(bat_vol_t, bat_vol_t);
+int pm89xx_bat_alarm_status(uint8_t *, uint8_t *);
+int pm89xx_vbus_status(void);
+int pm89xx_ldo_set_voltage(const char * , uint32_t);
 #endif
diff --git a/dev/pmic/pm8921/pm8921.c b/dev/pmic/pm8921/pm8921.c
index 1acc021..231b8b6 100644
--- a/dev/pmic/pm8921/pm8921.c
+++ b/dev/pmic/pm8921/pm8921.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- *     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     * Neither the name of  Linux Foundation, Inc. nor the names of its
  *       contributors may be used to endorse or promote products derived
  *       from this software without specific prior written permission.
  *
@@ -27,9 +27,11 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <assert.h>
+#include <string.h>
 #include <sys/types.h>
 #include <err.h>
 #include <dev/pm8921.h>
+#include <platform/timer.h>
 #include "pm8921_hw.h"
 
 static pm8921_dev_t *dev;
@@ -539,3 +541,191 @@
 
 	return rc;
 }
+
+/*
+ * Set battery alarm with low & high threshold values
+ */
+int pm89xx_bat_alarm_set(bat_vol_t up_thresh_vol, bat_vol_t low_thresh_vol)
+{
+	int rc;
+	uint8_t reg = 0;
+
+	if ((up_thresh_vol > BAT_VOL_4_3) || (low_thresh_vol > BAT_VOL_4_3)) {
+		dprintf(CRITICAL, "Input voltage not in permissible range\n");
+		return 1;
+	}
+
+	/*
+	 * Write upper & lower threshold values
+	 */
+	reg = (up_thresh_vol << PM89XX_BAT_UP_THRESH_VOL) | low_thresh_vol;
+
+	rc = dev->write(&reg, 1, PM89XX_BAT_ALRM_THRESH);
+	if (rc) {
+		dprintf(CRITICAL, "Failed to set BAT_THRESH reg = %d\n", rc);
+		return rc;
+	}
+
+	/* Read Alarm control to use the existing hysteresis values */
+	rc = dev->read(&reg, 1, PM89XX_BAT_ALRM_CTRL);
+	if (rc) {
+		dprintf(CRITICAL, "Failed to read BAT_ALARM reg = %d\n", rc);
+		return rc;
+	}
+
+	/* Enable battery alarm */
+	reg |= PM89XX_BAT_ALRM_ENABLE;
+	rc = dev->write(&reg, 1, PM89XX_BAT_ALRM_CTRL);
+	if (rc) {
+		dprintf(CRITICAL, "Failed to enable BAT_ALARM reg = %d\n", rc);
+		return rc;
+	}
+
+	/* Wait for the comparator o/p to settle */
+	mdelay(10);
+
+	return rc;
+}
+
+/*
+ * API to return status of battery
+ * if the vbatt is below upper threshold return 0
+ * if the vbatt is below lower threshold return 1
+ */
+int pm89xx_bat_alarm_status(uint8_t *high_status, uint8_t *low_status)
+{
+	int rc = 0;
+	uint8_t reg = 0;
+
+	/* Read the battery status */
+	rc = dev->read(&reg, 1, PM89XX_BAT_ALRM_CTRL);
+	if (rc) {
+		dprintf(CRITICAL, "Failed to read BAT_ALARM reg = %d\n", rc);
+		return rc;
+	}
+
+	/* Return the status if battery alarm is enabled */
+	if (reg & PM89XX_BAT_ALRM_ENABLE) {
+		*high_status = (reg & PM89XX_BAT_UPR_STATUS);
+		*low_status = (reg & PM89XX_BAT_LWR_STATUS);
+	} else {
+		dprintf(CRITICAL, "Battery alarm is not enabled\n");
+		return 1;
+	}
+
+	return rc;
+}
+
+/*
+ * Return 1 if VBUS is connected, 0 otherwise
+ */
+int pm89xx_vbus_status(void)
+{
+	int rc;
+	uint8_t reg = 0;
+
+	rc = dev->read(&reg, 1, PM89XX_USB_OVP_CTRL);
+	if (rc) {
+		dprintf(CRITICAL, "Failed to read USB OVP CTRL = %d\n", rc);
+		return rc;
+	}
+
+	reg &= PM89XX_VBUS_INPUT_STATUS;
+
+	return reg;
+}
+
+static struct pm89xx_vreg *ldo_get(const char *ldo_name)
+{
+	uint8_t i;
+	struct pm89xx_vreg *ldo = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(ldo_data); i++) {
+		ldo = &ldo_data[i];
+		if (!strncmp(ldo->name, ldo_name, strlen(ldo_name)))
+			break;
+	}
+
+	return ldo;
+}
+
+/*
+ * API takes LDO name & voltage as input
+ * Input voltage is taken in mVs
+ * PLDO voltage ranging from 1500mV to 3000mV
+ * NLDO voltage ranging from 750mV to 1525mV
+ */
+int pm89xx_ldo_set_voltage(const char *ldo_name, uint32_t voltage)
+{
+	uint8_t mult;
+	uint8_t val = 0;
+	int32_t ret = 0;
+	struct pm89xx_vreg *ldo;
+
+	/* Find the LDO info from table */
+	ldo = ldo_get(ldo_name);
+
+	if (!ldo) {
+		dprintf(CRITICAL, "Requested LDO is not supported : \
+				%s\n", ldo_name);
+		return -1;
+	}
+
+	/* Find the voltage multiplying factor */
+	if (ldo->type == PLDO_TYPE) {
+		if (voltage < PLDO_MV_VMIN)
+			voltage = PLDO_MV_VMIN;
+		else if (voltage > PLDO_MV_VMAX)
+			voltage = PLDO_MV_VMAX;
+		mult = (voltage - PLDO_MV_VMIN) / PLDO_MV_VSTEP;
+	} else {
+		if (voltage < NLDO_MV_VMIN)
+			voltage = NLDO_MV_VMIN;
+		else if (voltage > NLDO_MV_VMAX)
+			voltage = NLDO_MV_VMAX;
+		mult = (voltage - NLDO_MV_VMIN) / NLDO_MV_VSTEP;
+	}
+
+	/* Program the TEST reg */
+	if (ldo->type == PLDO_TYPE) {
+		/* Bank 2, only for p ldo, use 1.25V reference */
+		val = 0x0;
+		val |= (1 << PM8921_LDO_TEST_REG_RW);
+		val |= (2 << PM8921_LDO_TEST_REG_BANK_SEL);
+		ret = dev->write(&val, 1, ldo->test_reg);
+		if (ret) {
+			dprintf(CRITICAL, "Failed to write to PM8921 LDO Test \
+					Reg ret=%d.\n", ret);
+			return -1;
+		}
+
+		/*
+		 * Bank 4, only for p ldo, disable output range ext,
+		 * normal capacitance
+		 */
+		val = 0x0;
+		val |= (1 << PM8921_LDO_TEST_REG_RW);
+		val |= (4 << PM8921_LDO_TEST_REG_BANK_SEL);
+		ret = dev->write(&val, 1, ldo->test_reg);
+		if (ret) {
+			dprintf(CRITICAL, "Failed to write to PM8921 LDO Test \
+					Reg ret=%d.\n", ret);
+			return -1;
+		}
+	}
+
+	/* Program the CTRL reg */
+	val = 0x0;
+	val |= (1 << PM8921_LDO_CTRL_REG_ENABLE);
+	val |= (1 << PM8921_LDO_CTRL_REG_PULL_DOWN);
+	val |= (0 << PM8921_LDO_CTRL_REG_POWER_MODE);
+	val |= (mult << PM8921_LDO_CTRL_REG_VOLTAGE);
+	ret = dev->write(&val, 1, ldo->ctrl_reg);
+	if (ret) {
+		dprintf(CRITICAL, "Failed to write to PM8921 LDO Ctrl Reg \
+				ret=%d.\n", ret);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/dev/pmic/pm8921/pm8921_hw.h b/dev/pmic/pm8921/pm8921_hw.h
index bf43543..e75026e 100644
--- a/dev/pmic/pm8921/pm8921_hw.h
+++ b/dev/pmic/pm8921/pm8921_hw.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- *     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     * Neither the name of Linux Foundation, Inc. nor the names of its
  *       contributors may be used to endorse or promote products derived
  *       from this software without specific prior written permission.
  *
@@ -26,6 +26,7 @@
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+#include <bits.h>
 
 #define PBL_ACCESS_2                          0x005
 #define PBL_ACCESS_2_ENUM_TIMER_STOP          (1 << 1)
@@ -129,3 +130,44 @@
 #define PM8921_MPP_CTRL_DIGITAL_OUTPUT        (1 << 5)
 #define PM8921_MPP_CTRL_VIO_1                 (1 << 2)
 #define PM8921_MPP_CTRL_OUTPUT_HIGH           (1 << 0)
+
+#define PM89XX_BAT_UP_THRESH_VOL              4
+#define PM89XX_BAT_ALRM_THRESH                0x23
+#define PM89XX_BAT_ALRM_CTRL                  0x24
+#define PM89XX_USB_OVP_CTRL                   0x21C
+
+#define PM89XX_BAT_ALRM_ENABLE                BIT(7)
+#define PM89XX_BAT_UPR_STATUS                 BIT(1)
+#define PM89XX_BAT_LWR_STATUS                 BIT(0)
+
+#define PM89XX_VBUS_INPUT_STATUS              BIT(0)
+
+/* voltages are specified in mV */
+#define PLDO_MV_VMIN                          1500
+#define PLDO_MV_VMAX                          3000
+#define PLDO_MV_VSTEP                         50
+
+#define NLDO_MV_VMIN                          750
+#define NLDO_MV_VMAX                          1525
+#define NLDO_MV_VSTEP                         25
+
+#define PLDO_TYPE                             0
+#define NLDO_TYPE                             1
+
+#define LDO(_name, _type, _test_reg, _ctrl_reg) \
+{\
+	.name = _name,\
+	.type = _type,\
+	.test_reg = _test_reg,\
+	.ctrl_reg = _ctrl_reg, \
+}
+
+struct pm89xx_vreg ldo_data[] = {
+	LDO("LDO30", PLDO_TYPE, 0x0A3, 0x0A4),
+	LDO("LDO31", PLDO_TYPE, 0x0A5, 0x0A6),
+	LDO("LDO32", PLDO_TYPE, 0x0A7, 0x0A8),
+	LDO("LDO33", PLDO_TYPE, 0x0C6, 0x0C7),
+	LDO("LDO34", PLDO_TYPE, 0x0D2, 0x0D3),
+	LDO("LDO35", PLDO_TYPE, 0x0D4, 0x0D5),
+	LDO("LDO36", PLDO_TYPE, 0x0A9, 0x0AA),
+};