blob: 557d61945c608d98e4f6d3c15306b86a1a2a3f69 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2023 Google, LLC
*
*/
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include "google_bms.h"
#include "max77779.h"
#include "max77779_charger.h"
static int gs201_otg_enable(struct max77779_usecase_data *uc_data, bool enable);
/* ----------------------------------------------------------------------- */
int gs201_wlc_en(struct max77779_usecase_data *uc_data, enum wlc_state_t state)
{
const int wlc_on = state == WLC_ENABLED;
int ret;
pr_debug("%s: wlc_en=%d wlc_on=%d wlc_state=%d\n", __func__,
uc_data->wlc_en, wlc_on, state);
if (uc_data->wlc_en < 0)
return 0;
if (state == WLC_SPOOFED && uc_data->wlc_spoof_vbyp > 0) {
ret = max77779_external_chg_reg_write(uc_data->dev, MAX77779_CHG_CNFG_11,
uc_data->wlc_spoof_vbyp);
pr_debug("%s: MAX77779_CHG_CNFG_11 write to %02x (ret = %d)\n",
__func__, uc_data->wlc_spoof_vbyp, ret);
}
gpio_set_value_cansleep(uc_data->wlc_spoof_gpio,
state == WLC_SPOOFED && uc_data->wlc_spoof_gpio);
gpio_set_value_cansleep(uc_data->wlc_en, wlc_on);
return 0;
}
/* RTX reverse wireless charging */
static int gs201_wlc_tx_enable(struct max77779_usecase_data *uc_data, int use_case,
bool enable)
{
int ret = 0;
pr_debug("%s: use_case:%d enable:%d\n", __func__, use_case, enable);
if (!enable) {
ret = max77779_external_chg_reg_write(uc_data->dev, MAX77779_CHG_CNFG_11, 0x0);
if (ret < 0)
pr_err("%s: fail to reset MAX77779_CHG_REVERSE_BOOST_VOUT\n",
__func__);
ret = gs201_wlc_en(uc_data, WLC_DISABLED);
if (ret < 0)
pr_err("%s: cannot disable WLC (%d)\n", __func__, ret);
return ret;
}
ret = gs201_wlc_en(uc_data, WLC_ENABLED);
if (ret < 0)
pr_err("%s: cannot enable WLC (%d)\n", __func__, ret);
if (uc_data->rtx_ready >= 0)
gpio_set_value_cansleep(uc_data->rtx_ready, 1);
return ret;
}
static int gs201_wlc_tx_config(struct max77779_usecase_data *uc_data, int use_case)
{
u8 val;
int ret = 0;
/* We need to configure max77779 */
if (use_case == GSU_MODE_WLC_TX) {
ret = max77779_external_chg_reg_write(uc_data->dev,
MAX77779_CHG_CNFG_11,
MAX77779_CHG_REVERSE_BOOST_VOUT_7V);
if (ret < 0)
pr_err("fail to configure MAX77779_CHG_REVERSE_BOOST_VOUT\n");
} else {
ret = max77779_external_chg_reg_write(uc_data->dev,
MAX77779_CHG_CNFG_11,
0x0);
if (ret < 0)
pr_err("fail to reset MAX77779_CHG_REVERSE_BOOST_VOUT\n");
}
/* Set WCSM to 1.4A */
ret = max77779_external_chg_reg_read(uc_data->dev, MAX77779_CHG_CNFG_05, &val);
if (ret < 0)
pr_err("%s: fail to read MAX77779_CHG_CNFG_05 ret:%d\n", __func__, ret);
ret = max77779_external_chg_reg_write(uc_data->dev, MAX77779_CHG_CNFG_05,
_max77779_chg_cnfg_05_wcsm_ilim_set(val,
MAX77779_CHG_CNFG_05_WCSM_ILIM_1400_MA));
if (ret < 0) {
pr_err("%s: fail to write MAX77779_CHG_CNFG_05 ret:%d\n", __func__, ret);
return ret;
}
return ret;
}
static int gs201_otg_update_ilim(struct max77779_usecase_data *uc_data, int enable)
{
u8 ilim;
if (uc_data->otg_orig == uc_data->otg_ilim)
return 0;
if (enable) {
int rc;
rc = max77779_external_chg_reg_read(uc_data->dev, MAX77779_CHG_CNFG_05,
&uc_data->otg_orig);
if (rc < 0) {
pr_err("%s: cannot read otg_ilim (%d), use default\n",
__func__, rc);
uc_data->otg_orig = MAX77779_CHG_CNFG_05_OTG_ILIM_1500MA;
} else {
uc_data->otg_orig &= MAX77779_CHG_CNFG_05_OTG_ILIM_MASK;
}
ilim = uc_data->otg_ilim;
} else {
ilim = uc_data->otg_orig;
}
return max77779_external_chg_reg_update(uc_data->dev, MAX77779_CHG_CNFG_05,
MAX77779_CHG_CNFG_05_OTG_ILIM_MASK,
ilim);
}
static int gs201_pogo_vout_enable(struct max77779_usecase_data *uc_data,
bool enable, bool otg)
{
pr_debug("%s: enable: %d, otg: %d\n", __func__, enable, otg);
if (enable && otg) {
if (uc_data->pogo_vout_en >= 0)
gpio_set_value_cansleep(uc_data->pogo_vout_en, 0);
if (uc_data->ext_bst_ctl >= 0)
gpio_set_value_cansleep(uc_data->ext_bst_ctl, 1);
return 0;
}
if (!otg && uc_data->ext_bst_ctl >= 0)
gpio_set_value_cansleep(uc_data->ext_bst_ctl, 0);
if (enable) {
if (uc_data->bst_on >= 0)
gpio_set_value_cansleep(uc_data->bst_on, true);
if (uc_data->pogo_vout_en >= 0)
gpio_set_value_cansleep(uc_data->pogo_vout_en, true);
} else {
if (uc_data->pogo_vout_en >= 0)
gpio_set_value_cansleep(uc_data->pogo_vout_en, false);
if (uc_data->bst_on >= 0)
gpio_set_value_cansleep(uc_data->bst_on, false);
}
return 0;
}
/*
* Transition to standby (if needed) at the beginning of the sequences
* @return <0 on error, 0 on success. ->use_case becomes GSU_MODE_STANDBY
* if the transition is necessary (and successful).
*/
int gs201_to_standby(struct max77779_usecase_data *uc_data, int use_case)
{
const int from_uc = uc_data->use_case;
bool need_stby = false;
bool from_otg = false;
int ret;
switch (from_uc) {
case GSU_MODE_USB_CHG:
if (use_case == GSU_MODE_USB_OTG) {
need_stby = uc_data->ext_bst_ctl >= 0;
break;
}
need_stby = use_case != GSU_MODE_DOCK &&
use_case != GSU_MODE_USB_DC &&
use_case != GSU_MODE_USB_OTG_FRS &&
use_case != GSU_MODE_USB_CHG_POGO_VOUT;
break;
case GSU_MODE_WLC_RX:
/* HPP supported by device handled by wlc driver */
need_stby = use_case != GSU_MODE_USB_OTG_WLC_RX &&
use_case != GSU_MODE_WLC_DC;
break;
case GSU_MODE_WLC_TX:
need_stby = true;
if (uc_data->rtx_ready >= 0)
gpio_set_value_cansleep(uc_data->rtx_ready, 0);
break;
case GSU_MODE_USB_OTG:
from_otg = true;
if (use_case == GSU_MODE_USB_OTG_WLC_RX)
break;
if (use_case == GSU_MODE_USB_OTG_POGO_VOUT)
break;
gs201_otg_enable(uc_data, false);
need_stby = true;
break;
case GSU_MODE_USB_OTG_FRS:
from_otg = true;
if (use_case == GSU_MODE_USB_OTG_WLC_RX) {
need_stby = uc_data->ext_bst_ctl >= 0;
break;
}
need_stby = use_case != GSU_MODE_USB_CHG;
break;
case GSU_MODE_USB_OTG_WLC_RX:
from_otg = true;
if (use_case == GSU_MODE_USB_OTG_FRS) {
need_stby = uc_data->ext_bst_ctl >= 0;
break;
}
need_stby = use_case != GSU_MODE_WLC_RX &&
use_case != GSU_MODE_DOCK &&
use_case != GSU_MODE_USB_OTG;
break;
case GSU_MODE_USB_DC:
need_stby = use_case != GSU_MODE_USB_CHG;
break;
case GSU_MODE_WLC_DC:
if (!uc_data->reverse12_en)
return -EINVAL;
need_stby = use_case != GSU_MODE_WLC_DC;
break;
case GSU_RAW_MODE:
need_stby = true;
break;
case GSU_MODE_USB_OTG_POGO_VOUT:
from_otg = true;
need_stby = use_case != GSU_MODE_POGO_VOUT &&
use_case != GSU_MODE_USB_OTG;
break;
case GSU_MODE_POGO_VOUT:
need_stby = use_case != GSU_MODE_USB_CHG_POGO_VOUT &&
use_case != GSU_MODE_USB_OTG_POGO_VOUT;
break;
case GSU_MODE_USB_CHG_POGO_VOUT:
if (use_case == GSU_MODE_USB_CHG) {
ret = gs201_pogo_vout_enable(uc_data, false, false);
if (ret < 0)
pr_err("%s: cannot tun off pogo_vout (%d)\n", __func__, ret);
break;
}
need_stby = use_case != GSU_MODE_POGO_VOUT;
break;
case GSU_MODE_STANDBY:
case GSU_MODE_STANDBY_BUCK_ON:
default:
need_stby = false;
break;
}
if (use_case == GSU_RAW_MODE)
need_stby = true;
else if (use_case == from_uc)
need_stby = false;
pr_info("%s: use_case=%d->%d from_otg=%d need_stby=%d\n", __func__,
from_uc, use_case, from_otg, need_stby);
if (!need_stby)
return 0;
/* from POGO_VOUT to STBY */
if (from_uc == GSU_MODE_POGO_VOUT ||
from_uc == GSU_MODE_USB_OTG_POGO_VOUT ||
from_uc == GSU_MODE_USB_CHG_POGO_VOUT) {
ret = gs201_pogo_vout_enable(uc_data, false, false);
if (ret < 0)
pr_err("%s: cannot tun off pogo_vout (%d)\n", __func__, ret);
}
/* transition to STBY (might need to be up) */
ret = max77779_external_chg_mode_write(uc_data->dev, MAX77779_CHGR_MODE_ALL_OFF);
if (ret < 0)
return -EIO;
if (uc_data->rtx_available >= 0)
gpio_set_value_cansleep(uc_data->rtx_available, 1);
uc_data->use_case = GSU_MODE_STANDBY;
return ret;
}
/* enable/disable soft-start */
static int gs201_ramp_bypass(struct max77779_usecase_data *uc_data, bool enable)
{
const u8 value = enable ? MAX77779_CHG_CNFG_00_BYPV_RAMP_BYPASS_MASK : 0;
return max77779_external_chg_reg_update(uc_data->dev, MAX77779_CHG_CNFG_00,
MAX77779_CHG_CNFG_00_BYPV_RAMP_BYPASS_MASK,
value);
}
/* cleanup from every usecase */
int gs201_force_standby(struct max77779_usecase_data *uc_data)
{
const u8 insel_mask = MAX77779_CHG_CNFG_12_CHGINSEL_MASK |
MAX77779_CHG_CNFG_12_WCINSEL_MASK;
const u8 insel_value = MAX77779_CHG_CNFG_12_CHGINSEL |
MAX77779_CHG_CNFG_12_WCINSEL;
int ret;
pr_debug("%s: recovery\n", __func__);
ret = gs201_ramp_bypass(uc_data, false);
if (ret < 0)
pr_err("%s: cannot reset ramp_bypass (%d)\n",
__func__, ret);
ret = gs201_pogo_vout_enable(uc_data, false, false);
if (ret < 0)
pr_err("%s: cannot tun off pogo_vout (%d)\n", __func__, ret);
ret = max77779_external_chg_mode_write(uc_data->dev, MAX77779_CHGR_MODE_ALL_OFF);
if (ret < 0)
pr_err("%s: cannot reset mode register (%d)\n",
__func__, ret);
ret = max77779_external_chg_insel_write(uc_data->dev, insel_mask, insel_value);
if (ret < 0)
pr_err("%s: cannot reset insel (%d)\n",
__func__, ret);
gs201_otg_enable(uc_data, false);
if (uc_data->rtx_ready >= 0)
gpio_set_value_cansleep(uc_data->rtx_ready, 0);
return 0;
}
static int gs201_otg_mode(struct max77779_usecase_data *uc_data, int to)
{
int ret = -EINVAL;
pr_debug("%s: to=%d\n", __func__, to);
if (to == GSU_MODE_USB_OTG) {
ret = max77779_external_chg_mode_write(uc_data->dev,
MAX77779_CHGR_MODE_ALL_OFF);
}
return ret;
}
/*
* This must follow different paths depending on the platforms.
*
* NOTE: the USB stack expects VBUS to be on after voting for the usecase.
*/
static int gs201_otg_enable_frs(struct max77779_usecase_data *uc_data)
{
int ret;
ret = gs201_otg_update_ilim(uc_data, true);
if (ret < 0) {
pr_debug("%s: cannot update otg ilim ret:%d\n", __func__, ret);
return ret;
}
/* the code default to write to the MODE register */
ret = max77779_external_chg_mode_write(uc_data->dev,
MAX77779_CHGR_MODE_OTG_BOOST_ON);
if (ret < 0) {
pr_debug("%s: cannot set CNFG_00 to 0xa ret:%d\n", __func__, ret);
return ret;
}
return ret;
}
static int gs201_otg_enable(struct max77779_usecase_data *uc_data, bool enable)
{
pr_debug("%s: enable:%d\n", __func__, enable);
if (enable) {
if (uc_data->bst_on >= 0)
gpio_set_value_cansleep(uc_data->bst_on, 1);
usleep_range(5 * USEC_PER_MSEC, 5 * USEC_PER_MSEC + 100);
if (uc_data->ext_bst_ctl >= 0)
gpio_set_value_cansleep(uc_data->ext_bst_ctl, 1);
} else {
if (uc_data->ext_bst_ctl >= 0)
gpio_set_value_cansleep(uc_data->ext_bst_ctl, 0);
usleep_range(5 * USEC_PER_MSEC, 5 * USEC_PER_MSEC + 100);
if (uc_data->bst_on >= 0)
gpio_set_value_cansleep(uc_data->bst_on, 0);
}
return 0;
}
/*
* Case USB_chg USB_otg WLC_chg WLC_TX PMIC_Charger Name
* -------------------------------------------------------------------------------------
* 7 0 1 1 0 IF-PMIC-WCIN USB_OTG_WLC_RX
* 9 0 1 0 0 0 USB_OTG / USB_OTG_FRS
* -------------------------------------------------------------------------------------
* WLC_chg = 0 off, 1 = on, 2 = PPS
*
* NOTE: do not call with (cb_data->wlc_rx && cb_data->wlc_tx)
*/
static int gs201_standby_to_otg(struct max77779_usecase_data *uc_data, int use_case)
{
int ret;
ret = gs201_otg_enable(uc_data, true);
if (ret == 0)
usleep_range(5 * USEC_PER_MSEC, 5 * USEC_PER_MSEC + 100);
/*
* Assumption: gs201_to_usecase() will write back cached values to
* CHG_CNFG_00.Mode. At the moment, the cached value at
* max77779_mode_callback is 0. If the cached value changes to something
* other than 0, then, the code has to be revisited.
*/
return ret;
}
/* was b/179816224 WLC_RX -> WLC_RX + OTG (Transition #10) */
static int gs201_wlcrx_to_wlcrx_otg(struct max77779_usecase_data *uc_data)
{
pr_warn("%s: disabled\n", __func__);
return 0;
}
static int gs201_to_otg_usecase(struct max77779_usecase_data *uc_data, int use_case)
{
const int from_uc = uc_data->use_case;
int ret = 0;
switch (from_uc) {
/* 9: stby to USB OTG */
/* 10: stby to USB_OTG_FRS */
case GSU_MODE_STANDBY:
ret = gs201_standby_to_otg(uc_data, use_case);
if (ret < 0) {
pr_err("%s: cannot enable OTG ret:%d\n", __func__, ret);
return ret;
}
break;
case GSU_MODE_USB_CHG:
/* need to go through stby out of this */
if (use_case != GSU_MODE_USB_OTG && use_case != GSU_MODE_USB_OTG_FRS)
return -EINVAL;
else if (use_case == GSU_MODE_USB_OTG)
ret = gs201_otg_enable(uc_data, true);
else
ret = gs201_otg_enable_frs(uc_data);
break;
case GSU_MODE_WLC_TX:
break;
case GSU_MODE_WLC_RX:
case GSU_MODE_DOCK:
if (use_case == GSU_MODE_USB_OTG_WLC_RX) {
if (uc_data->rx_otg_en) {
ret = gs201_standby_to_otg(uc_data, use_case);
} else {
ret = gs201_wlcrx_to_wlcrx_otg(uc_data);
}
}
break;
case GSU_MODE_USB_OTG:
/* b/179816224: OTG -> WLC_RX + OTG */
if (use_case == GSU_MODE_USB_OTG_WLC_RX) {
/* pvp TODO: Is it just WLC Rx enable? */
}
break;
case GSU_MODE_USB_OTG_WLC_RX:
if (use_case == GSU_MODE_USB_OTG_FRS)
return -EINVAL;
break;
case GSU_MODE_USB_OTG_FRS:
if (use_case == GSU_MODE_USB_OTG_WLC_RX)
return -EINVAL;
break;
case GSU_MODE_POGO_VOUT:
if (use_case == GSU_MODE_USB_OTG_POGO_VOUT) {
ret = max77779_external_chg_reg_write(uc_data->dev,
MAX77779_CHG_CNFG_00,
MAX77779_CHGR_MODE_BOOST_UNO_ON);
msleep(40);
ret = gs201_pogo_vout_enable(uc_data, true, true);
}
break;
case GSU_MODE_USB_OTG_POGO_VOUT:
break;
default:
return -ENOTSUPP;
}
return ret;
}
/* handles the transition data->use_case ==> use_case */
int gs201_to_usecase(struct max77779_usecase_data *uc_data, int use_case)
{
const int from_uc = uc_data->use_case;
bool rtx_avail = false;
int ret = 0;
switch (use_case) {
case GSU_MODE_USB_OTG:
case GSU_MODE_USB_OTG_FRS:
case GSU_MODE_USB_OTG_WLC_RX:
case GSU_MODE_USB_OTG_POGO_VOUT:
ret = gs201_to_otg_usecase(uc_data, use_case);
break;
case GSU_MODE_WLC_TX:
rtx_avail = true;
ret = gs201_wlc_tx_config(uc_data, use_case);
break;
case GSU_MODE_WLC_RX:
case GSU_MODE_DOCK:
if (from_uc == GSU_MODE_USB_OTG_WLC_RX) {
if (uc_data->ext_otg_only)
ret = gs201_otg_enable(uc_data, false);
else
ret = gs201_otg_mode(uc_data, GSU_MODE_USB_OTG);
}
break;
case GSU_MODE_USB_CHG:
case GSU_MODE_USB_DC:
rtx_avail = false;
break;
case GSU_MODE_STANDBY_BUCK_ON:
break;
case GSU_MODE_STANDBY:
case GSU_RAW_MODE:
/* just write the value to the register (it's in stby) */
rtx_avail = true;
break;
case GSU_MODE_USB_WLC_RX:
case GSU_MODE_WLC_DC:
break;
case GSU_MODE_POGO_VOUT:
ret = gs201_pogo_vout_enable(uc_data, true, false);
/* wait for ext boost ready */
if (ret == 0 && from_uc == GSU_MODE_USB_OTG_POGO_VOUT)
msleep(4);
break;
case GSU_MODE_USB_CHG_POGO_VOUT:
ret = gs201_pogo_vout_enable(uc_data, true, false);
break;
default:
break;
}
if (uc_data->rtx_available >= 0)
gpio_set_value_cansleep(uc_data->rtx_available, rtx_avail);
return ret;
}
/* finish usecase configuration after max77779 mode register is set */
int gs201_finish_usecase(struct max77779_usecase_data *uc_data, int use_case)
{
const int from_uc = uc_data->use_case;
int ret = 0;
switch (use_case) {
case GSU_MODE_WLC_TX:
/* p9412 will not be in RX when powered from EXT */
ret = gs201_wlc_tx_enable(uc_data, use_case, true);
if (ret < 0)
return ret;
break;
default:
if (from_uc == GSU_MODE_WLC_TX) {
/* p9412 is already off from insel */
ret = gs201_wlc_tx_enable(uc_data, use_case, false);
if (ret < 0)
return ret;
ret = gs201_wlc_en(uc_data, WLC_ENABLED); /* re-enable wlc in case of rx */
if (ret < 0)
return ret;
}
break;
}
return ret;
}
static int max77779_otg_ilim_ma_to_code(u8 *code, int otg_ilim)
{
if (otg_ilim == 0)
*code = 0;
else if (otg_ilim >= 500 && otg_ilim <= 1500)
*code = 1 + (otg_ilim - 500) / 100;
else
return -EINVAL;
return 0;
}
int max77779_otg_vbyp_mv_to_code(u8 *code, int vbyp)
{
if (vbyp >= 12000)
*code = 0x8c;
else if (vbyp >= 5000)
*code = (vbyp - 5000) / 50;
else
return -EINVAL;
return 0;
}
#define GS201_OTG_ILIM_DEFAULT_MA 1500
#define GS201_OTG_VBYPASS_DEFAULT_MV 5100
/* lazy init on the switches */
static bool gs201_setup_usecases_done(struct max77779_usecase_data *uc_data)
{
return (uc_data->wlc_en != -EPROBE_DEFER) &&
(uc_data->bst_on != -EPROBE_DEFER) &&
(uc_data->ext_bst_mode != -EPROBE_DEFER) &&
(uc_data->ext_bst_ctl != -EPROBE_DEFER) &&
(uc_data->rtx_ready != -EPROBE_DEFER) &&
(uc_data->wlc_spoof_gpio != -EPROBE_DEFER) &&
(uc_data->rtx_available != -EPROBE_DEFER);
/* TODO: handle platform specific differences.. */
}
static void gs201_setup_default_usecase(struct max77779_usecase_data *uc_data)
{
int ret;
/* external boost */
uc_data->bst_on = -EPROBE_DEFER;
uc_data->ext_bst_ctl = -EPROBE_DEFER;
uc_data->ext_bst_mode = -EPROBE_DEFER;
uc_data->pogo_vout_en = -EPROBE_DEFER;
uc_data->otg_enable = -EPROBE_DEFER;
uc_data->wlc_en = -EPROBE_DEFER;
uc_data->rtx_ready = -EPROBE_DEFER;
uc_data->rtx_available = -EPROBE_DEFER;
uc_data->wlc_spoof_gpio = -EPROBE_DEFER;
uc_data->wlc_spoof_vbyp = 0;
uc_data->init_done = false;
/* TODO: override in bootloader and remove */
ret = max77779_otg_ilim_ma_to_code(&uc_data->otg_ilim,
GS201_OTG_ILIM_DEFAULT_MA);
if (ret < 0)
uc_data->otg_ilim = MAX77779_CHG_CNFG_05_OTG_ILIM_1500MA;
ret = max77779_external_chg_reg_read(uc_data->dev, MAX77779_CHG_CNFG_05,
&uc_data->otg_orig);
if (ret == 0) {
uc_data->otg_orig &= MAX77779_CHG_CNFG_05_OTG_ILIM_MASK;
} else {
uc_data->otg_orig = uc_data->otg_ilim;
}
ret = max77779_otg_vbyp_mv_to_code(&uc_data->otg_vbyp,
GS201_OTG_VBYPASS_DEFAULT_MV);
if (ret < 0)
uc_data->otg_vbyp = MAX77779_CHG_CNFG_11_OTG_VBYP_5100MV;
}
bool gs201_setup_usecases(struct max77779_usecase_data *uc_data,
struct device_node *node)
{
u32 data;
int ret;
if (!node) {
gs201_setup_default_usecase(uc_data);
return false;
}
/* control external boost if present */
if (uc_data->bst_on == -EPROBE_DEFER) {
uc_data->bst_on = of_get_named_gpio(node, "max77779,bst-on", 0);
if (uc_data->bst_on >= 0)
gpio_direction_output(uc_data->bst_on, 0);
}
if (uc_data->ext_bst_ctl == -EPROBE_DEFER)
uc_data->ext_bst_ctl = of_get_named_gpio(node, "max77779,extbst-ctl", 0);
if (uc_data->ext_bst_mode == -EPROBE_DEFER) {
uc_data->ext_bst_mode = of_get_named_gpio(node, "max77779,extbst-mode", 0);
if (uc_data->ext_bst_mode >= 0)
gpio_set_value_cansleep(uc_data->ext_bst_mode, 0);
}
/* wlc_rx: disable when chgin, CPOUT is safe */
if (uc_data->wlc_en == -EPROBE_DEFER)
uc_data->wlc_en = of_get_named_gpio(node, "max77779,wlc-en", 0);
/* wlc_rx thermal throttle -> spoof online */
if (uc_data->wlc_spoof_gpio == -EPROBE_DEFER)
uc_data->wlc_spoof_gpio = of_get_named_gpio(node, "max77779,wlc-spoof", 0);
/* OPTIONAL: wlc-spoof-vol */
ret = of_property_read_u32(node, "max77779,wlc-spoof-vbyp", &data);
if (ret < 0)
uc_data->wlc_spoof_vbyp = 0;
else
uc_data->wlc_spoof_vbyp = data;
/* OPTIONAL: support wlc_rx -> wlc_rx+otg */
uc_data->rx_otg_en = of_property_read_bool(node, "max77779,rx-to-rx-otg-en");
/* OPTIONAL: support external boost OTG only */
uc_data->ext_otg_only = of_property_read_bool(node, "max77779,ext-otg-only");
/* OPTIONAL: support reverse 1:2 mode for RTx */
uc_data->reverse12_en = of_property_read_bool(node, "max77779,reverse_12-en");
if (uc_data->rtx_ready == -EPROBE_DEFER)
uc_data->rtx_ready = of_get_named_gpio(node, "max77779,rtx-ready", 0);
if (uc_data->rtx_available == -EPROBE_DEFER)
uc_data->rtx_available = of_get_named_gpio(node, "max77779,rtx-available", 0);
if (uc_data->pogo_vout_en == -EPROBE_DEFER) {
uc_data->pogo_vout_en = of_get_named_gpio(node, "max77779,pogo-vout-sw-en", 0);
if (uc_data->pogo_vout_en >= 0)
gpio_direction_output(uc_data->pogo_vout_en, 0);
}
return gs201_setup_usecases_done(uc_data);
}
void gs201_dump_usecasase_config(struct max77779_usecase_data *uc_data)
{
pr_info("bst_on:%d, ext_bst_ctl: %d, ext_bst_mode:%d, pogo_vout_en:%d\n",
uc_data->bst_on, uc_data->ext_bst_ctl, uc_data->ext_bst_mode,
uc_data->pogo_vout_en);
pr_info("wlc_en:%d, reverse12_en:%d rtx_ready:%d\n",
uc_data->wlc_en, uc_data->reverse12_en, uc_data->rtx_ready);
pr_info("rtx_available:%d, rx_to_rx_otg:%d ext_otg_only:%d wlc_spoof_gpio:%d\n",
uc_data->rtx_available, uc_data->rx_otg_en, uc_data->ext_otg_only,
uc_data->wlc_spoof_gpio);
}