power: pm8921-charger: api to control trkl charging
Provide mechanism to set trickle, weak voltage and currents via
board file. These settings are used to configure the hardware
controlled auto trickle charging.
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index b6f88b7..976e351 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -193,6 +193,10 @@
struct work_struct battery_id_valid_work;
int64_t batt_id_min;
int64_t batt_id_max;
+ int trkl_voltage;
+ int weak_voltage;
+ int trkl_current;
+ int weak_current;
};
static int charging_disabled;
@@ -453,6 +457,90 @@
temp);
}
+#define PM8921_CHG_VTRKL_MIN_MV 2050
+#define PM8921_CHG_VTRKL_MAX_MV 2800
+#define PM8921_CHG_VTRKL_STEP_MV 50
+#define PM8921_CHG_VTRKL_SHIFT 4
+#define PM8921_CHG_VTRKL_MASK 0xF0
+static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
+{
+ u8 temp;
+
+ if (millivolts < PM8921_CHG_VTRKL_MIN_MV
+ || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
+ pr_err("bad voltage = %dmV asked to set\n", millivolts);
+ return -EINVAL;
+ }
+
+ temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
+ temp = temp << PM8921_CHG_VTRKL_SHIFT;
+ return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
+ temp);
+}
+
+#define PM8921_CHG_VWEAK_MIN_MV 2100
+#define PM8921_CHG_VWEAK_MAX_MV 3600
+#define PM8921_CHG_VWEAK_STEP_MV 100
+#define PM8921_CHG_VWEAK_MASK 0x0F
+static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
+{
+ u8 temp;
+
+ if (millivolts < PM8921_CHG_VWEAK_MIN_MV
+ || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
+ pr_err("bad voltage = %dmV asked to set\n", millivolts);
+ return -EINVAL;
+ }
+
+ temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
+ return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
+ temp);
+}
+
+#define PM8921_CHG_ITRKL_MIN_MA 50
+#define PM8921_CHG_ITRKL_MAX_MA 200
+#define PM8921_CHG_ITRKL_MASK 0x0F
+#define PM8921_CHG_ITRKL_STEP_MA 10
+static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
+{
+ u8 temp;
+
+ if (milliamps < PM8921_CHG_ITRKL_MIN_MA
+ || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
+ pr_err("bad current = %dmA asked to set\n", milliamps);
+ return -EINVAL;
+ }
+
+ temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
+
+ return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
+ temp);
+}
+
+#define PM8921_CHG_IWEAK_MIN_MA 325
+#define PM8921_CHG_IWEAK_MAX_MA 525
+#define PM8921_CHG_IWEAK_SHIFT 7
+#define PM8921_CHG_IWEAK_MASK 0x80
+static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
+{
+ u8 temp;
+
+ if (milliamps < PM8921_CHG_IWEAK_MIN_MA
+ || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
+ pr_err("bad current = %dmA asked to set\n", milliamps);
+ return -EINVAL;
+ }
+
+ if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
+ temp = 0;
+ else
+ temp = 1;
+
+ temp = temp << PM8921_CHG_IWEAK_SHIFT;
+ return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
+ temp);
+}
+
static int64_t read_battery_id(struct pm8921_chg_chip *chip)
{
int rc;
@@ -1629,6 +1717,42 @@
return rc;
}
+ if (chip->trkl_voltage != 0) {
+ rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
+ if (rc) {
+ pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
+ chip->trkl_voltage, rc);
+ return rc;
+ }
+ }
+
+ if (chip->weak_voltage != 0) {
+ rc = pm_chg_vweak_set(chip, chip->weak_voltage);
+ if (rc) {
+ pr_err("Failed to set weak voltage to %dmv rc=%d\n",
+ chip->weak_voltage, rc);
+ return rc;
+ }
+ }
+
+ if (chip->trkl_current != 0) {
+ rc = pm_chg_itrkl_set(chip, chip->trkl_current);
+ if (rc) {
+ pr_err("Failed to set trkl current to %dmA rc=%d\n",
+ chip->trkl_voltage, rc);
+ return rc;
+ }
+ }
+
+ if (chip->weak_current != 0) {
+ rc = pm_chg_iweak_set(chip, chip->weak_current);
+ if (rc) {
+ pr_err("Failed to set weak current to %dmA rc=%d\n",
+ chip->weak_current, rc);
+ return rc;
+ }
+ }
+
/* Workarounds for die 1.1 and 1.0 */
if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
@@ -1829,6 +1953,10 @@
chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
chip->cool_bat_voltage = pdata->cool_bat_voltage;
chip->warm_bat_voltage = pdata->warm_bat_voltage;
+ chip->trkl_voltage = pdata->trkl_voltage;
+ chip->weak_voltage = pdata->weak_voltage;
+ chip->trkl_current = pdata->trkl_current;
+ chip->weak_current = pdata->weak_current;
rc = pm8921_chg_hw_init(chip);
if (rc) {
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 948d25c..a37a7d2 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -51,6 +51,12 @@
* @get_batt_capacity_percent:
* a board specific function to return battery
* capacity. If null - a default one will be used
+ * @trkl_voltage: the trkl voltage in (mV) below which hw controlled
+ * trkl charging happens with linear charger
+ * @weak_voltage: the weak voltage (mV) below which hw controlled
+ * trkl charging happens with switching mode charger
+ * @trkl_current: the trkl current in (mA) to use for trkl charging phase
+ * @weak_current: the weak current in (mA) to use for weak charging phase
*
*/
struct pm8921_charger_platform_data {
@@ -73,6 +79,10 @@
unsigned int (*get_batt_capacity_percent) (void);
int64_t batt_id_min;
int64_t batt_id_max;
+ int trkl_voltage;
+ int weak_voltage;
+ int trkl_current;
+ int weak_current;
};
enum pm8921_charger_source {