summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBadhri Jagan Sridharan <badhri@google.com>2022-09-06 19:48:23 -0700
committerKyle Tso <kyletso@google.com>2022-09-22 09:16:10 +0000
commit6269afd8d08df762856d47c57bd73dcb2d1d550b (patch)
tree05b697335cd2b521df59aa8ce1c96a75a452082c
parentd24534ba18ee6cddbf028b619c9320b5023e3f50 (diff)
downloadgs-android-gs-bluejay-5.10-android13-qpr1-beta-3.tar.gz
When register reads/writes fail, exit early and retry after 3 seconds instead of continuing with successive I2C IO. This prevents I2C transactions that are anyways going to fail. Instead, The last read irq status is cached and retried after the 3 seconds. Bug: 235540519 Signed-off-by: Badhri Jagan Sridharan <badhri@google.com> Change-Id: Ie2a18c7fc9d310fe0a334b3c5b16840ef4159f29 (cherry picked from commit 105cf682df05aa51b0dbcdaba76999680e400633)
-rw-r--r--drivers/usb/typec/tcpm/google/max77759_contaminant.c257
-rw-r--r--drivers/usb/typec/tcpm/google/tcpci_max77759.c134
-rw-r--r--drivers/usb/typec/tcpm/google/tcpci_max77759.h13
3 files changed, 269 insertions, 135 deletions
diff --git a/drivers/usb/typec/tcpm/google/max77759_contaminant.c b/drivers/usb/typec/tcpm/google/max77759_contaminant.c
index 3f3ce534ee60..ee00c96ee678 100644
--- a/drivers/usb/typec/tcpm/google/max77759_contaminant.c
+++ b/drivers/usb/typec/tcpm/google/max77759_contaminant.c
@@ -103,29 +103,29 @@ static int read_adc_mv(struct max77759_contaminant *contaminant,
ret = max77759_update_bits8(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK,
channel << ADC_CHANNEL_OFFSET);
if (ret < 0)
- return ret;
+ return -EIO;
/* Enable ADC */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_ADC_CTRL1, ADCEN, ADCEN);
if (ret < 0)
- return ret;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_VENDOR_ADC_CTRL1, log);
usleep_range(sleep_msec * 1000, (sleep_msec + 1) * 1000);
ret = max77759_read8(regmap, TCPC_VENDOR_FLADC_STATUS, &fladc);
if (ret < 0)
- return ret;
+ return -EIO;
logbuffer_log(log, "Contaminant: ADC %u", fladc);
/* Disable ADC */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_ADC_CTRL1, ADCEN, 0);
if (ret < 0)
- return ret;
+ return -EIO;
ret = max77759_update_bits8(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK, 0);
if (ret < 0)
- return ret;
+ return -EIO;
if (!raw)
return adc_to_mv(contaminant, channel, ua_src, fladc);
@@ -149,7 +149,7 @@ static int read_resistance_kohm(struct max77759_contaminant *contaminant,
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
ULTRA_LOW_POWER_MODE);
if (ret < 0)
- return ret;
+ return -EIO;
/*
* CC resistive ladder is automatically disabled when
* 1uA source is ON and Flash ADC channel is not CC scale1.
@@ -161,12 +161,12 @@ static int read_resistance_kohm(struct max77759_contaminant *contaminant,
/* Enable 1uA current source */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_1_SRC);
if (ret < 0)
- return ret;
+ return -EIO;
/* OVP disable */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCOVPDIS, CCOVPDIS);
if (ret < 0)
- return ret;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_VENDOR_CC_CTRL2, log);
@@ -174,7 +174,7 @@ static int read_resistance_kohm(struct max77759_contaminant *contaminant,
/* OVP enable */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCOVPDIS, 0);
if (ret < 0)
- return ret;
+ return -EIO;
/* returns KOhm as 1uA source is used. */
return mv;
}
@@ -187,39 +187,39 @@ static int read_resistance_kohm(struct max77759_contaminant *contaminant,
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
ULTRA_LOW_POWER_MODE);
if (ret < 0)
- return ret;
+ return -EIO;
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, SBUOVPDIS, SBUOVPDIS);
if (ret < 0)
- return ret;
+ return -EIO;
/* Cache switch setting */
ret = max77759_read8(regmap, TCPC_VENDOR_SBUSW_CTRL, &switch_setting);
if (ret < 0)
- return ret;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_VENDOR_SBUSW_CTRL, log);
/* SBU switches auto configure when channel is selected. */
/* Enable 1ua current source */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, SBURPCTRL, SBURPCTRL);
if (ret < 0)
- return ret;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_VENDOR_CC_CTRL2, log);
mv = read_adc_mv(contaminant, channel, sleep_msec, raw, true);
/* Disable current source */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, SBURPCTRL, 0);
if (ret < 0)
- return ret;
+ return -EIO;
/* Set switch to original setting */
ret = max77759_write8(regmap, TCPC_VENDOR_SBUSW_CTRL, switch_setting);
if (ret < 0)
- return ret;
+ return -EIO;
/* OVP disable */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, SBUOVPDIS, 0);
if (ret < 0)
- return ret;
+ return -EIO;
/*
* 1ua current source on sbu;
@@ -229,9 +229,9 @@ static int read_resistance_kohm(struct max77759_contaminant *contaminant,
return mv;
}
-static void read_comparators(struct max77759_contaminant *contaminant,
- u8 *vendor_cc_status2_cc1,
- u8 *vendor_cc_status2_cc2)
+static int read_comparators(struct max77759_contaminant *contaminant,
+ u8 *vendor_cc_status2_cc1,
+ u8 *vendor_cc_status2_cc2)
{
struct regmap *regmap = contaminant->chip->data.regmap;
struct logbuffer *log = contaminant->chip->log;
@@ -242,12 +242,12 @@ static void read_comparators(struct max77759_contaminant *contaminant,
/* Enable 80uA source */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_80_SRC);
if (ret < 0)
- return;
+ return -EIO;
/* Enable comparators */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL1, CCCOMPEN, CCCOMPEN);
if (ret < 0)
- return;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_VENDOR_CC_CTRL1, log);
@@ -255,7 +255,7 @@ static void read_comparators(struct max77759_contaminant *contaminant,
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
LOW_POWER_MODE_DISABLE);
if (ret < 0)
- return;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_VENDOR_CC_CTRL2, log);
/* Sleep to allow comparators settle */
@@ -263,47 +263,55 @@ static void read_comparators(struct max77759_contaminant *contaminant,
ret = max77759_update_bits8(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION,
PLUG_ORNT_CC1);
if (ret < 0)
- return;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_TCPC_CTRL, log);
usleep_range(5000, 6000);
ret = max77759_read8(regmap, VENDOR_CC_STATUS2, vendor_cc_status2_cc1);
if (ret < 0)
- return;
+ return -EIO;
logbuffer_log(log, "Contaminant: VENDOR_CC_STATUS2: %u", *vendor_cc_status2_cc1);
ret = max77759_update_bits8(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION,
PLUG_ORNT_CC2);
if (ret < 0)
- return;
+ return -EIO;
MAX77759_LOG_REGISTER(regmap, TCPC_TCPC_CTRL, log);
usleep_range(5000, 6000);
ret = max77759_read8(regmap, VENDOR_CC_STATUS2, vendor_cc_status2_cc2);
if (ret < 0)
- return;
+ return -EIO;
logbuffer_log(contaminant->chip->log, "Contaminant: VENDOR_CC_STATUS2: %u",
*vendor_cc_status2_cc2);
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL1, CCCOMPEN, 0);
if (ret < 0)
- return;
- max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, 0);
+ return -EIO;
+ ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, 0);
+ if (ret < 0)
+ return -EIO;
+
+ return 0;
}
static int detect_contaminant(struct max77759_contaminant *contaminant)
{
- int cc1_k, cc2_k, sbu1_k, sbu2_k;
+ int cc1_k, cc2_k, sbu1_k, sbu2_k, ret;
u8 vendor_cc_status2_cc1 = 0xff, vendor_cc_status2_cc2 = 0xff;
u8 role_ctrl = 0, role_ctrl_backup = 0;
struct max77759_plat *chip = contaminant->chip;
int inferred_state = NOT_DETECTED;
struct regmap *regmap = contaminant->chip->data.regmap;
- max77759_read8(regmap, TCPC_ROLE_CTRL, &role_ctrl);
+ ret = max77759_read8(regmap, TCPC_ROLE_CTRL, &role_ctrl);
+ if (ret < 0)
+ return -EIO;
role_ctrl_backup = role_ctrl;
role_ctrl = 0x0F;
- max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl);
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl);
+ if (ret < 0)
+ return -EIO;
/* CCLPMODESEL_AUTO_LOW_POWER in use. */
cc1_k = read_resistance_kohm(contaminant, CC1_SCALE2, READ1_SLEEP_MS, false);
@@ -313,7 +321,9 @@ static int detect_contaminant(struct max77759_contaminant *contaminant)
sbu1_k = read_resistance_kohm(contaminant, SBU1, READ1_SLEEP_MS, false);
sbu2_k = read_resistance_kohm(contaminant, SBU2, READ2_SLEEP_MS, false);
logbuffer_log(chip->log, "Contaminant: sbu1_k:%u sbu2_k:%u", sbu1_k, sbu2_k);
- read_comparators(contaminant, &vendor_cc_status2_cc1, &vendor_cc_status2_cc2);
+ ret = read_comparators(contaminant, &vendor_cc_status2_cc1, &vendor_cc_status2_cc2);
+ if (ret == -EIO)
+ return ret;
logbuffer_log(chip->log, "Contaminant: vcc2_cc1:%u vcc2_cc2:%u", vendor_cc_status2_cc1,
vendor_cc_status2_cc2);
@@ -338,9 +348,12 @@ static int detect_contaminant(struct max77759_contaminant *contaminant)
}
if (inferred_state == NOT_DETECTED)
- max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl_backup);
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl_backup);
else
- max77759_write8(regmap, TCPC_ROLE_CTRL, (TCPC_ROLE_CTRL_DRP | 0xA));
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL, (TCPC_ROLE_CTRL_DRP | 0xA));
+
+ if (ret < 0)
+ return -EIO;
return inferred_state;
}
@@ -362,40 +375,40 @@ static int enable_dry_detection(struct max77759_contaminant *contaminant)
CCWTRSEL_1V << CCWTRSEL_SHIFT | WTRCYCLE_4_8_S <<
WTRCYCLE_SHIFT);
if (ret < 0)
- return ret;
+ return -EIO;
ret = max77759_update_bits8(regmap, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP,
TCPC_ROLE_CTRL_DRP);
if (ret < 0)
- return ret;
+ return -EIO;
/* tunable: 1ua / Ultra low power mode enabled. */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, CCCONNDRY);
if (ret < 0)
- return ret;
+ return -EIO;
ret = max77759_read8(regmap, TCPC_VENDOR_CC_CTRL1, &temp);
if (ret < 0)
- return ret;
+ return -EIO;
logbuffer_log(chip->log, "Contaminant: TCPC_VENDOR_CC_CTRL1 %u", temp);
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
ULTRA_LOW_POWER_MODE);
if (ret < 0)
- return ret;
+ return -EIO;
ret = max77759_read8(regmap, TCPC_VENDOR_CC_CTRL2, &temp);
if (ret < 0)
- return ret;
+ return -EIO;
logbuffer_log(chip->log, "Contaminant: TCPC_VENDOR_CC_CTRL2 %u", temp);
/* Enable Look4Connection before sending the command */
ret = max77759_update_bits8(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_EN_LK4CONN_ALRT,
TCPC_TCPC_CTRL_EN_LK4CONN_ALRT);
if (ret < 0)
- return ret;
+ return -EIO;
ret = max77759_write8(regmap, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION);
if (ret < 0)
- return ret;
+ return -EIO;
logbuffer_log(chip->log, "Contaminant: Dry detecion enabled");
return 0;
}
@@ -410,10 +423,14 @@ static int maxq_detect_contaminant(struct max77759_contaminant *contaminant, u8
struct regmap *regmap = contaminant->chip->data.regmap;
u8 response[5];
- max77759_read8(regmap, TCPC_ROLE_CTRL, &role_ctrl);
+ ret = max77759_read8(regmap, TCPC_ROLE_CTRL, &role_ctrl);
+ if (ret < 0)
+ return -EIO;
role_ctrl_backup = role_ctrl;
role_ctrl = 0x0F;
- max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl);
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl);
+ if (ret < 0)
+ return -EIO;
logbuffer_log(chip->log, "Contaminant: Query Maxq");
if (contaminant->state == NOT_DETECTED) {
@@ -449,9 +466,12 @@ static int maxq_detect_contaminant(struct max77759_contaminant *contaminant, u8
response[0], response[2], response[3], response[4]);
if (ret == NOT_DETECTED)
- max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl_backup);
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl_backup);
else
- max77759_write8(regmap, TCPC_ROLE_CTRL, (TCPC_ROLE_CTRL_DRP | 0xA));
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL, (TCPC_ROLE_CTRL_DRP | 0xA));
+
+ if (ret < 0)
+ return -EIO;
return ret;
}
@@ -481,23 +501,28 @@ static void update_contaminant_state(struct max77759_contaminant *contaminant,
* Don't want to be in workqueue as this is time critical for the state machine
* to forward progress.
*/
-bool process_contaminant_alert(struct max77759_contaminant *contaminant, bool debounce_path,
- bool tcpm_toggling)
+int process_contaminant_alert(struct max77759_contaminant *contaminant, bool debounce_path,
+ bool tcpm_toggling, bool *cc_update_handled)
{
u8 cc_status, pwr_cntl;
struct regmap *regmap = contaminant->chip->data.regmap;
enum contamiant_state state;
struct max77759_plat *chip = contaminant->chip;
+ int ret;
/*
* Contaminant alert should only be processed when ALERT.CC_STAT is set.
* Caller i.e. the top level interrupt handler can check this to
* prevent redundant reads.
*/
- max77759_read8(regmap, TCPC_CC_STATUS, &cc_status);
+ ret = max77759_read8(regmap, TCPC_CC_STATUS, &cc_status);
+ if (ret < 0)
+ return -EIO;
logbuffer_log(chip->log, "Contaminant: CC_STATUS: %#x", cc_status);
- max77759_read8(regmap, TCPC_POWER_CTRL, &pwr_cntl);
+ ret = max77759_read8(regmap, TCPC_POWER_CTRL, &pwr_cntl);
+ if (ret < 0)
+ return -EIO;
logbuffer_log(chip->log, "Contaminant: POWER_CONTROL: %#x", pwr_cntl);
/* Exit if still LookingForConnection. */
@@ -505,9 +530,13 @@ bool process_contaminant_alert(struct max77759_contaminant *contaminant, bool de
logbuffer_log(chip->log, "Contaminant: Looking for connection");
/* Restart toggling before returning in debounce path */
if (debounce_path && (contaminant->state == NOT_DETECTED ||
- contaminant->state == SINK))
- enable_contaminant_detection(contaminant->chip, contaminant_detect_maxq);
- return false;
+ contaminant->state == SINK)) {
+ ret = enable_contaminant_detection(contaminant->chip,
+ contaminant_detect_maxq);
+ if (ret == -EIO)
+ return ret;
+ }
+ *cc_update_handled = false;
}
if (contaminant->state == NOT_DETECTED || contaminant->state == SINK ||
@@ -520,19 +549,27 @@ bool process_contaminant_alert(struct max77759_contaminant *contaminant, bool de
TCPC_CC_STATE_WTRSEL << TCPC_CC_STATUS_CC2_SHIFT))) &&
(status_check(cc_status, TCPC_CC_STATUS_TOGGLING, 0))) {
logbuffer_log(chip->log, "Contaminant: Check if wet: CC 0x3");
- state = contaminant_detect_maxq ?
+ ret = contaminant_detect_maxq ?
maxq_detect_contaminant(contaminant, cc_status)
: detect_contaminant(contaminant);
+ if (ret == -EIO)
+ return ret;
+ state = ret;
update_contaminant_state(contaminant, state);
if (state == DETECTED) {
- enable_dry_detection(contaminant);
- return true;
+ ret = enable_dry_detection(contaminant);
+ if (ret == -EIO)
+ return ret;
+ *cc_update_handled = true;
}
/* Sink or Not detected */
- enable_contaminant_detection(contaminant->chip, contaminant_detect_maxq);
- return true;
+ ret = enable_contaminant_detection(contaminant->chip,
+ contaminant_detect_maxq);
+ if (ret == -EIO)
+ return ret;
+ *cc_update_handled = true;
} else {
/* Need to check again after tCCDebounce */
if (((cc_status & TCPC_CC_STATUS_TOGGLING) == 0) &&
@@ -546,42 +583,62 @@ bool process_contaminant_alert(struct max77759_contaminant *contaminant, bool de
msleep(100);
}
- max77759_read8(regmap, TCPC_CC_STATUS, &cc_status);
+ ret = max77759_read8(regmap, TCPC_CC_STATUS, &cc_status);
+ if (ret < 0)
+ return ret;
logbuffer_log(chip->log,
"Contaminant: CC_STATUS check stage 3 sw WAR: %#x",
cc_status);
if (is_cc_open(cc_status)) {
u8 role_ctrl, role_ctrl_backup;
- max77759_read8(regmap, TCPC_ROLE_CTRL, &role_ctrl);
+ ret = max77759_read8(regmap, TCPC_ROLE_CTRL, &role_ctrl);
+ if (ret < 0)
+ return ret;
role_ctrl_backup = role_ctrl;
role_ctrl |= 0x0F;
role_ctrl &= ~(TCPC_ROLE_CTRL_DRP);
- max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl);
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl);
+ if (ret < 0)
+ return ret;
logbuffer_log(chip->log,
"Contaminant: Check if wet (stage 3)");
- state = contaminant_detect_maxq ?
+ ret = contaminant_detect_maxq ?
maxq_detect_contaminant(contaminant, cc_status)
: detect_contaminant(contaminant);
+ if (ret == -EIO)
+ return ret;
+ state = ret;
update_contaminant_state(contaminant, state);
- max77759_write8(regmap, TCPC_ROLE_CTRL, role_ctrl_backup);
+ ret = max77759_write8(regmap, TCPC_ROLE_CTRL,
+ role_ctrl_backup);
+ if (ret < 0)
+ return ret;
if (state == DETECTED) {
- enable_dry_detection(contaminant);
- return true;
+ ret = enable_dry_detection(contaminant);
+ if (ret == -EIO)
+ return ret;
+ *cc_update_handled = true;
}
/* Sink or Not detected */
- enable_contaminant_detection(contaminant->chip,
- contaminant_detect_maxq);
+ ret = enable_contaminant_detection(contaminant->chip,
+ contaminant_detect_maxq);
+ if (ret == -EIO)
+ return ret;
}
}
}
/* Restart toggling before returning in debounce path */
- if (debounce_path)
- enable_contaminant_detection(contaminant->chip, contaminant_detect_maxq);
- return false;
+ if (debounce_path) {
+ ret = enable_contaminant_detection(contaminant->chip,
+ contaminant_detect_maxq);
+ if (ret == -EIO)
+ return ret;
+ }
+ *cc_update_handled = false;
} else if (contaminant->state == DETECTED) {
if (status_check(cc_status, TCPC_CC_STATUS_TOGGLING, 0)) {
logbuffer_log(chip->log, "Contaminant: Check if dry");
@@ -591,8 +648,10 @@ bool process_contaminant_alert(struct max77759_contaminant *contaminant, bool de
update_contaminant_state(contaminant, state);
if (state == DETECTED) {
- enable_dry_detection(contaminant);
- return true;
+ ret = enable_dry_detection(contaminant);
+ if (ret == -EIO)
+ return ret;
+ *cc_update_handled = true;
}
/*
@@ -600,59 +659,65 @@ bool process_contaminant_alert(struct max77759_contaminant *contaminant, bool de
* auto_ultra_low_power_mode as well.
*/
disable_auto_ultra_low_power_mode(chip, false);
- enable_contaminant_detection(contaminant->chip, contaminant_detect_maxq);
- return true;
+ ret = enable_contaminant_detection(contaminant->chip,
+ contaminant_detect_maxq);
+ if (ret == -EIO)
+ return ret;
+ *cc_update_handled = true;
}
/* TCPM does not manage ports in dry detection phase. */
- return true;
+ *cc_update_handled = true;
}
- return false;
+ *cc_update_handled = false;
+ return 0;
}
EXPORT_SYMBOL_GPL(process_contaminant_alert);
-void disable_contaminant_detection(struct max77759_plat *chip)
+int disable_contaminant_detection(struct max77759_plat *chip)
{
struct regmap *regmap = chip->data.regmap;
struct max77759_contaminant *contaminant = chip->contaminant;
int ret;
if (!contaminant)
- return;
+ return 0;
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK, 0);
if (ret < 0)
- return;
+ return -EIO;
ret = max77759_write8(regmap, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP |
(TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
(TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT));
if (ret < 0)
- return;
+ return -EIO;
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
LOW_POWER_MODE_DISABLE);
if (ret < 0)
- return;
+ return -EIO;
ret = max77759_update_bits8(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_EN_LK4CONN_ALRT,
TCPC_TCPC_CTRL_EN_LK4CONN_ALRT);
if (ret < 0)
- return;
+ return -EIO;
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, 0);
if (ret < 0)
- return;
+ return -EIO;
ret = max77759_write8(regmap, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION);
if (ret < 0)
- return;
+ return -EIO;
/* Reset state before disabling detection */
if (contaminant->state != NOT_DETECTED && contaminant->state != SINK)
contaminant->state = NOT_DETECTED;
logbuffer_log(chip->log, "Contaminant: Contaminant detection disabled");
+
+ return 0;
}
EXPORT_SYMBOL_GPL(disable_contaminant_detection);
@@ -677,43 +742,47 @@ int enable_contaminant_detection(struct max77759_plat *chip, bool maxq)
CCWTRSEL_1V << CCWTRSEL_SHIFT | WTRCYCLE_4_8_S <<
WTRCYCLE_SHIFT);
if (ret < 0)
- return ret;
+ return -EIO;
/* Contaminant detection mode: contaminant detection */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, 0);
if (ret < 0)
- return ret;
+ return -EIO;
ret = max77759_read8(regmap, TCPC_VENDOR_CC_CTRL2, &vcc2);
if (ret < 0)
- return ret;
+ return -EIO;
if (!contaminant->auto_ultra_low_power_mode_disabled) {
/* tunable: Periodic contaminant detection */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
AUTO_ULTRA_LOW_POWER_MODE);
if (ret < 0)
- return ret;
+ return -EIO;
}
ret = max77759_read8(regmap, TCPC_VENDOR_CC_CTRL2, &vcc2);
if (ret < 0)
- return ret;
+ return -EIO;
/* Mask flash adc interrupt */
ret = max77759_update_bits8(regmap, TCPC_VENDOR_ALERT_MASK2, MSK_FLASH_ADCINT, 0);
if (ret < 0)
- return ret;
+ return -EIO;
/* Disable Auto disacharge before enabling toggling */
ret = max77759_read8(regmap, TCPC_POWER_CTRL, &pwr_ctrl);
+ if (ret < 0)
+ return -EIO;
logbuffer_log(chip->log, "TCPC_POWER_CTRL:0x%x ret:%d", pwr_ctrl, ret);
if (pwr_ctrl & TCPC_POWER_CTRL_AUTO_DISCHARGE) {
logbuffer_log(chip->log, "TCPC_POWER_CTRL_AUTO_DISCHARGE not cleared");
ret = regmap_update_bits(regmap, TCPC_POWER_CTRL, TCPC_POWER_CTRL_AUTO_DISCHARGE,
0);
- if (ret < 0)
+ if (ret < 0) {
logbuffer_log(chip->log, "[%s]: Disabling auto discharge failed", __func__);
+ return -EIO;
+ }
}
ret = max77759_write8(regmap, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP |
@@ -724,7 +793,7 @@ int enable_contaminant_detection(struct max77759_plat *chip, bool maxq)
if (ret < 0) {
logbuffer_log(chip->log, "[%s]: Enabling DRP failed ret:%d", __func__,
ret);
- return ret;
+ return -EIO;
}
/* Enable Look4Connection before sending the command */
@@ -733,12 +802,12 @@ int enable_contaminant_detection(struct max77759_plat *chip, bool maxq)
if (ret < 0) {
logbuffer_log(chip->log, "[%s]: Enabling looking for connection failed ret:%d",
__func__, ret);
- return ret;
+ return -EIO;
}
ret = max77759_write8(regmap, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION);
if (ret < 0)
- return ret;
+ return -EIO;
logbuffer_log(chip->log, "Contaminant: Contaminant detection enabled");
diff --git a/drivers/usb/typec/tcpm/google/tcpci_max77759.c b/drivers/usb/typec/tcpm/google/tcpci_max77759.c
index f70087c1669d..a06ab515308b 100644
--- a/drivers/usb/typec/tcpm/google/tcpci_max77759.c
+++ b/drivers/usb/typec/tcpm/google/tcpci_max77759.c
@@ -51,6 +51,7 @@
#define TCPC_RECEIVE_BUFFER_LEN 32
#define PD_ACTIVITY_TIMEOUT_MS 10000
+#define IO_ERROR_RETRY_MS 3000
#define VSAFE0V_DEBOUNCE_MS 15
#define VBUS_RAMPUP_TIMEOUT_MS 250
#define VBUS_RAMPUP_MAX_RETRY 8
@@ -620,7 +621,7 @@ static void max77759_init_regs(struct regmap *regmap, struct logbuffer *log)
logbuffer_log(log, "TCPC_VENDOR_VCON_CTRL: update vcnilim to 300mA failed");
}
-static void process_rx(struct max77759_plat *chip, u16 status)
+static int process_rx(struct max77759_plat *chip, u16 status)
{
struct pd_message msg;
u8 count, frame_type, rx_buf[TCPC_RECEIVE_BUFFER_LEN];
@@ -639,17 +640,18 @@ static void process_rx(struct max77759_plat *chip, u16 status)
logbuffer_log(log, "%d", __LINE__);
if (ret < 0) {
dev_err(chip->dev, "TCPC_RX_BYTE_CNT read failed ret:%d", ret);
- return;
+ return -EIO;
}
count = rx_buf[TCPC_RECEIVE_BUFFER_COUNT_OFFSET];
frame_type = rx_buf[TCPC_RECEIVE_BUFFER_FRAME_TYPE_OFFSET];
if (count == 0 || frame_type != TCPC_RX_BUF_FRAME_TYPE_SOP) {
- max77759_write16(chip->data.regmap, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
+ ret = max77759_write16(chip->data.regmap, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
dev_err(chip->dev, "%s", count == 0 ? "error: count is 0" :
"error frame_type is not SOP");
- return;
+ if (ret < 0)
+ return -EIO;
}
/*
@@ -658,7 +660,7 @@ static void process_rx(struct max77759_plat *chip, u16 status)
*/
if (count > sizeof(struct pd_message) + 1 || count + 1 > TCPC_RECEIVE_BUFFER_LEN) {
dev_err(chip->dev, "Invalid TCPC_RX_BYTE_CNT %d", count);
- return;
+ return 0;
}
/*
@@ -670,7 +672,7 @@ static void process_rx(struct max77759_plat *chip, u16 status)
logbuffer_log(log, "%d", __LINE__);
if (ret < 0) {
dev_err(chip->dev, "Error: TCPC_RX_BYTE_CNT read failed: %d", ret);
- return;
+ return -EIO;
}
rx_buf_ptr = rx_buf + TCPC_RECEIVE_BUFFER_RX_BYTE_BUF_OFFSET;
@@ -690,7 +692,7 @@ static void process_rx(struct max77759_plat *chip, u16 status)
TCPC_ALERT_RX_STATUS | TCPC_ALERT_RX_BUF_OVF :
TCPC_ALERT_RX_STATUS);
if (ret < 0)
- return;
+ return -EIO;
logbuffer_log(log, "rx clear");
pd_type = pd_header_type_le(msg.header);
@@ -700,10 +702,11 @@ static void process_rx(struct max77759_plat *chip, u16 status)
ret = max77759_write16(chip->data.regmap, TCPC_VBUS_SINK_DISCONNECT_THRESH, 0);
/* TODO: tcpci->pr_swap = true; */
if (ret < 0)
- return;
+ return -EIO;
}
tcpm_pd_receive(chip->port, &msg);
+ return 0;
}
static void enable_dp_pulse(struct max77759_plat *chip)
@@ -1210,8 +1213,9 @@ static void max77759_cache_cc(struct max77759_plat *chip)
chip->cc2 = cc2;
}
-static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
- struct logbuffer *log)
+/* hold irq_status_lock before calling */
+static irqreturn_t _max77759_irq_locked(struct max77759_plat *chip, u16 status,
+ struct logbuffer *log)
{
u16 vendor_status = 0, vendor_status2 = 0, raw;
struct tcpci *tcpci = chip->tcpci;
@@ -1220,6 +1224,8 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
~(TCPC_ALERT_RX_STATUS | TCPC_ALERT_RX_BUF_OVF) :
status & ~TCPC_ALERT_RX_STATUS;
u8 reg_status;
+ bool contaminant_cc_update_handled = false;
+ bool invoke_tcpm_for_cc_update = false;
pm_wakeup_event(chip->dev, PD_ACTIVITY_TIMEOUT_MS);
logbuffer_log(log, "TCPC_ALERT status: %#x", status);
@@ -1230,7 +1236,7 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
if (status & ~TCPC_ALERT_RX_STATUS) {
ret = max77759_write16(tcpci->regmap, TCPC_ALERT, mask);
if (ret < 0)
- return ret;
+ goto reschedule;
}
if (status & TCPC_ALERT_RX_BUF_OVF && !(status &
@@ -1240,17 +1246,17 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
(TCPC_ALERT_RX_STATUS |
TCPC_ALERT_RX_BUF_OVF));
if (ret < 0)
- return ret;
+ goto reschedule;
}
if (status & TCPC_ALERT_EXTND) {
ret = max77759_read8(tcpci->regmap, TCPC_ALERT_EXTENDED, &reg_status);
if (ret < 0)
- return ret;
+ goto reschedule;
ret = max77759_write8(tcpci->regmap, TCPC_ALERT_EXTENDED, reg_status);
if (ret < 0)
- return ret;
+ goto reschedule;
if (reg_status & TCPC_SINK_FAST_ROLE_SWAP) {
logbuffer_log(log, "FRS Signal");
@@ -1261,7 +1267,9 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
if (status & TCPC_ALERT_RX_STATUS) {
logbuffer_log(log, "Enter process rx");
- process_rx(chip, status);
+ ret = process_rx(chip, status);
+ if (ret == -EIO)
+ goto reschedule;
}
if (status & TCPC_ALERT_TX_DISCARDED)
@@ -1272,18 +1280,18 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
ret = max77759_write8(tcpci->regmap, TCPC_VENDOR_ALERT_MASK
, 0x0);
if (ret < 0)
- return ret;
+ goto reschedule;
ret = max77759_write8(tcpci->regmap,
TCPC_VENDOR_ALERT_MASK2, 0x0);
if (ret < 0)
- return ret;
+ goto reschedule;
/* Clear VENDOR_ALERT*/
ret = max77759_read16(tcpci->regmap, TCPC_VENDOR_ALERT,
&vendor_status);
if (ret < 0)
- return ret;
+ goto reschedule;
logbuffer_log(log, "TCPC_VENDOR_ALERT 0x%x", vendor_status);
process_bc12_alert(chip->bc12, vendor_status);
@@ -1292,12 +1300,12 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
ret = max77759_read16(tcpci->regmap, TCPC_VENDOR_ALERT2, &vendor_status2);
if (ret < 0)
- return ret;
+ goto reschedule;
logbuffer_log(log, "TCPC_VENDOR_ALERT2 0x%x", vendor_status2);
ret = max77759_write16(tcpci->regmap, TCPC_VENDOR_ALERT2, vendor_status2);
if (ret < 0)
- return ret;
+ goto reschedule;
}
if (status & TCPC_ALERT_VBUS_DISCNCT) {
@@ -1309,6 +1317,8 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
ret = max77759_write8(tcpci->regmap, TCPC_VENDOR_USBSW_CTRL, USBSW_CONNECT);
logbuffer_log(chip->log, "Forcing on dp switches %s", ret < 0 ? "fail" :
"success");
+ if (ret < 0)
+ goto reschedule;
}
}
@@ -1318,8 +1328,30 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
* contaminant detection.
*/
mutex_lock(&chip->rc_lock);
- if (!chip->contaminant_detection || !tcpm_is_toggling(tcpci->port) ||
- !process_contaminant_alert(chip->contaminant, false, true)) {
+ if (chip->contaminant_detection && tcpm_is_toggling(tcpci->port)) {
+ ret = process_contaminant_alert(chip->contaminant, false, true,
+ &contaminant_cc_update_handled);
+ if (ret < 0)
+ goto reschedule;
+ /*
+ * Invoke TCPM when CC update not related to contaminant
+ * detection.
+ */
+ invoke_tcpm_for_cc_update = !contaminant_cc_update_handled;
+ /*
+ * CC status change handled by contaminant algorithm.
+ * Handle floating cable if detected.
+ */
+ if (contaminant_cc_update_handled) {
+ logbuffer_log(log, "CC update: Contaminant algorithm responded");
+ if (is_floating_cable_or_sink_detected(chip))
+ floating_cable_sink_detected_handler_locked(chip);
+ }
+ } else {
+ invoke_tcpm_for_cc_update = true;
+ }
+
+ if (invoke_tcpm_for_cc_update) {
tcpm_cc_change(tcpci->port);
max77759_cache_cc(chip);
/* TCPM has detected valid CC terminations */
@@ -1330,7 +1362,7 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
* when contaminant detection is enabled.
*/
if (chip->contaminant_detection_userspace !=
- CONTAMINANT_DETECT_DISABLE)
+ CONTAMINANT_DETECT_DISABLE)
disable_auto_ultra_low_power_mode(chip, false);
} else {
/*
@@ -1347,10 +1379,6 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
*/
floating_cable_sink_detected_handler_locked(chip);
}
- } else {
- logbuffer_log(log, "CC update: Contaminant algorithm responded");
- if (is_floating_cable_or_sink_detected(chip))
- floating_cable_sink_detected_handler_locked(chip);
}
mutex_unlock(&chip->rc_lock);
}
@@ -1361,7 +1389,7 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
if (status & TCPC_ALERT_V_ALARM_LO) {
ret = max77759_read16(tcpci->regmap, TCPC_VBUS_VOLTAGE_ALARM_LO_CFG, &raw);
if (ret < 0)
- return ret;
+ goto reschedule;
logbuffer_log(log, "VBUS LOW ALARM triggered: thresh:%umv vbus:%umv",
(raw & TCPC_VBUS_VOLTAGE_MASK) * TCPC_VBUS_VOLTAGE_LSB_MV,
@@ -1376,7 +1404,7 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
if (status & TCPC_ALERT_V_ALARM_HI) {
ret = max77759_read16(tcpci->regmap, TCPC_VBUS_VOLTAGE_ALARM_HI_CFG, &raw);
if (ret < 0)
- return ret;
+ goto reschedule;
logbuffer_log(log, "VBUS HIGH ALARM triggered: thresh:%umv vbus:%umv",
(raw & TCPC_VBUS_VOLTAGE_MASK) * TCPC_VBUS_VOLTAGE_LSB_MV,
@@ -1395,7 +1423,7 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
TCPC_VBUS_SINK_DISCONNECT_THRESH,
0);
if (ret < 0)
- return ret;
+ goto reschedule;
tcpm_pd_hard_reset(tcpci->port);
max77759_init_regs(tcpci->regmap, log);
@@ -1410,11 +1438,11 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
ret = max77759_write8(tcpci->regmap, TCPC_VENDOR_ALERT_MASK
, 0xff);
if (ret < 0)
- return ret;
+ goto reschedule;
ret = max77759_write8(tcpci->regmap,
TCPC_VENDOR_ALERT_MASK2, 0xff);
if (ret < 0)
- return ret;
+ goto reschedule;
}
if (status & TCPC_ALERT_EXTENDED_STATUS) {
@@ -1422,7 +1450,7 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
ret = max77759_read8(tcpci->regmap, TCPC_EXTENDED_STATUS,
(u8 *)&raw);
if (ret < 0)
- return ret;
+ goto reschedule;
vsafe0v = raw & TCPC_EXTENDED_STATUS_VSAFE0V;
logbuffer_log(log, "VSAFE0V (runtime): %c -> %c", chip->vsafe0v ? 'Y' : 'N',
@@ -1455,6 +1483,13 @@ static irqreturn_t _max77759_irq(struct max77759_plat *chip, u16 status,
logbuffer_log(log, "TCPC_ALERT status done: %#x", status);
return IRQ_HANDLED;
+reschedule:
+ chip->irq_status = status;
+ logbuffer_log(log, "TCPC_ALERT IO error occurred. status: %#x", status);
+ kthread_mod_delayed_work(chip->wq, &chip->max77759_io_error_work,
+ msecs_to_jiffies(IO_ERROR_RETRY_MS));
+ pm_wakeup_event(chip->dev, PD_ACTIVITY_TIMEOUT_MS + IO_ERROR_RETRY_MS);
+ return IRQ_HANDLED;
}
static irqreturn_t max77759_irq(int irq, void *dev_id)
@@ -1471,8 +1506,9 @@ static irqreturn_t max77759_irq(int irq, void *dev_id)
ret = max77759_read16(chip->tcpci->regmap, TCPC_ALERT, &status);
if (ret < 0)
return ret;
+ mutex_lock(&chip->irq_status_lock);
while (status) {
- irq_return = _max77759_irq(chip, status, chip->log);
+ irq_return = _max77759_irq_locked(chip, status, chip->log);
/* Do not return if the ALERT is already set. */
logbuffer_log(chip->log, "TCPC_ALERT read alert status");
ret = max77759_read16(chip->tcpci->regmap, TCPC_ALERT, &status);
@@ -1481,6 +1517,7 @@ static irqreturn_t max77759_irq(int irq, void *dev_id)
logbuffer_log(chip->log, "TCPC_ALERT status pending: %#x",
status);
}
+ mutex_unlock(&chip->irq_status_lock);
return irq_return;
}
@@ -1498,6 +1535,18 @@ static irqreturn_t max77759_isr(int irq, void *dev_id)
return IRQ_WAKE_THREAD;
}
+static void max77759_io_error_work(struct kthread_work *work)
+{
+ struct max77759_plat *chip =
+ container_of(container_of(work, struct kthread_delayed_work, work),
+ struct max77759_plat, max77759_io_error_work);
+ pm_wakeup_event(chip->dev, PD_ACTIVITY_TIMEOUT_MS);
+ mutex_lock(&chip->irq_status_lock);
+ logbuffer_log(chip->log, "IO error retry. status: %#x", chip->irq_status);
+ _max77759_irq_locked(chip, chip->irq_status, chip->log);
+ mutex_unlock(&chip->irq_status_lock);
+}
+
static int max77759_init_alert(struct max77759_plat *chip,
struct i2c_client *client)
{
@@ -1631,17 +1680,24 @@ unlock:
}
static void max77759_check_contaminant(void *unused, struct tcpci *tcpci, struct tcpci_data *tdata,
- int *ret)
+ int *restart_toggling)
{
struct max77759_plat *chip = tdata_to_max77759(tdata);
+ bool contaminant_cc_status_handled = false;
+ int ret = 0;
logbuffer_log(chip->log, "%s: debounce path", __func__);
mutex_lock(&chip->rc_lock);
if (chip->contaminant_detection) {
- process_contaminant_alert(chip->contaminant, true, false);
- *ret = CONTAMINANT_HANDLES_TOGGLING;
+ /*
+ * contaminant_cc_status_handled unused as contaminant detection
+ * is expected to restart toggling as needed unless EIO.
+ */
+ ret = process_contaminant_alert(chip->contaminant, true, false,
+ &contaminant_cc_status_handled);
+ *restart_toggling = ret < 0 ? TCPM_RESTART_TOGGLING : CONTAMINANT_HANDLES_TOGGLING;
} else {
- *ret = TCPM_RESTART_TOGGLING;
+ *restart_toggling = TCPM_RESTART_TOGGLING;
}
mutex_unlock(&chip->rc_lock);
@@ -2374,6 +2430,7 @@ static int max77759_probe(struct i2c_client *client,
mutex_init(&chip->icl_proto_el_lock);
mutex_init(&chip->data_path_lock);
mutex_init(&chip->rc_lock);
+ mutex_init(&chip->irq_status_lock);
spin_lock_init(&g_caps_lock);
chip->first_toggle = true;
@@ -2507,6 +2564,7 @@ static int max77759_probe(struct i2c_client *client,
kthread_init_delayed_work(&chip->icl_work, icl_work_item);
kthread_init_delayed_work(&chip->enable_vbus_work, enable_vbus_work);
kthread_init_delayed_work(&chip->vsafe0v_work, vsafe0v_debounce_work);
+ kthread_init_delayed_work(&chip->max77759_io_error_work, max77759_io_error_work);
/*
* b/218797880 Some OVP chips are restricted to quick Vin ramp-up time which means that if
diff --git a/drivers/usb/typec/tcpm/google/tcpci_max77759.h b/drivers/usb/typec/tcpm/google/tcpci_max77759.h
index 05ca1c5e905e..8fc48bdadc7b 100644
--- a/drivers/usb/typec/tcpm/google/tcpci_max77759.h
+++ b/drivers/usb/typec/tcpm/google/tcpci_max77759.h
@@ -22,6 +22,7 @@ struct gvotable_election;
struct logbuffer;
struct max77759_contaminant;
struct tcpci_data;
+struct max77759_io_error;
struct max77759_plat {
struct tcpci_data data;
@@ -140,6 +141,12 @@ struct max77759_plat {
/* Reflects whether BC1.2 is still running */
bool bc12_running;
+ /* To handle io error - Last cached IRQ status*/
+ u16 irq_status;
+ struct kthread_delayed_work max77759_io_error_work;
+ /* Hold before calling _max77759_irq */
+ struct mutex irq_status_lock;
+
/* EXT_BST_EN exposed as GPIO */
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio;
@@ -175,10 +182,10 @@ int __attribute__((weak)) maxq_query_contaminant(u8 cc1_raw, u8 cc2_raw, u8 sbu1
}
struct max77759_contaminant *max77759_contaminant_init(struct max77759_plat *plat, bool enable);
-bool process_contaminant_alert(struct max77759_contaminant *contaminant, bool debounce_path,
- bool tcpm_toggling);
+int process_contaminant_alert(struct max77759_contaminant *contaminant, bool debounce_path,
+ bool tcpm_toggling, bool *cc_status_handled);
int enable_contaminant_detection(struct max77759_plat *chip, bool maxq);
-void disable_contaminant_detection(struct max77759_plat *chip);
+int disable_contaminant_detection(struct max77759_plat *chip);
bool is_contaminant_detected(struct max77759_plat *chip);
bool is_floating_cable_or_sink_detected(struct max77759_plat *chip);
void disable_auto_ultra_low_power_mode(struct max77759_plat *chip, bool disable);