Commit 02b332a0 authored by Badhri Jagan Sridharan's avatar Badhri Jagan Sridharan Committed by Greg Kroah-Hartman

usb: typec: maxim_contaminant: Implement check_contaminant callback

Maxim TCPC has additional ADCs and low current(1ua) current source
to measure the impedance of CC and SBU pins. When tcpm invokes
the check_contaminant callback, Maxim TCPC measures the impedance
of the CC & SBU pins and when the impedance measured is less than
1MOhm, it is assumed that USB-C port is contaminated. CC comparators
are also checked to differentiate between presence of sink and
contaminant. Once USB-C is deemed to be contaminated, MAXIM TCPC
has additional hardware to disable normal DRP toggling cycle and
enable 1ua on CC pins once every 2.4secs/4.8secs. Maxim TCPC
interrupts AP once the impedance on the CC pin is above the
1MOhm threshold. The Maxim tcpc driver then signals TCPM_PORT_CLEAN
to restart toggling.

Renaming tcpci_maxim.c to tcpci_maxim_core.c and moving reg read/write
helper functions to the tcpci_maxim.h header file.
Signed-off-by: default avatarBadhri Jagan Sridharan <badhri@google.com>
Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20230114093246.1933321-3-badhri@google.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent abc028a2
......@@ -8,3 +8,4 @@ obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o
obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o
obj-$(CONFIG_TYPEC_TCPCI_MT6370) += tcpci_mt6370.o
obj-$(CONFIG_TYPEC_TCPCI_MAXIM) += tcpci_maxim.o
tcpci_maxim-y += tcpci_maxim_core.o maxim_contaminant.o
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022 Google, Inc
*
* MAXIM TCPC header file.
*/
#ifndef TCPCI_MAXIM_H_
#define TCPCI_MAXIM_H_
#define VENDOR_CC_STATUS2 0x85
#define CC1_VUFP_RD0P5 BIT(1)
#define CC2_VUFP_RD0P5 BIT(5)
#define TCPC_VENDOR_FLADC_STATUS 0x89
#define TCPC_VENDOR_CC_CTRL1 0x8c
#define CCCONNDRY BIT(7)
#define CCCOMPEN BIT(5)
#define TCPC_VENDOR_CC_CTRL2 0x8d
#define SBUOVPDIS BIT(7)
#define CCOVPDIS BIT(6)
#define SBURPCTRL BIT(5)
#define CCLPMODESEL_MASK GENMASK(4, 3)
#define ULTRA_LOW_POWER_MODE BIT(3)
#define CCRPCTRL_MASK GENMASK(2, 0)
#define UA_1_SRC 1
#define UA_80_SRC 3
#define TCPC_VENDOR_CC_CTRL3 0x8e
#define CCWTRDEB_MASK GENMASK(7, 6)
#define CCWTRDEB_SHIFT 6
#define CCWTRDEB_1MS 1
#define CCWTRSEL_MASK GENMASK(5, 3)
#define CCWTRSEL_SHIFT 3
#define CCWTRSEL_1V 0x4
#define CCLADDERDIS BIT(2)
#define WTRCYCLE_MASK BIT(0)
#define WTRCYCLE_SHIFT 0
#define WTRCYCLE_2_4_S 0
#define WTRCYCLE_4_8_S 1
#define TCPC_VENDOR_ADC_CTRL1 0x91
#define ADCINSEL_MASK GENMASK(7, 5)
#define ADC_CHANNEL_OFFSET 5
#define ADCEN BIT(0)
enum contamiant_state {
NOT_DETECTED,
DETECTED,
SINK,
};
/*
* @potential_contaminant:
* Last returned result to tcpm indicating whether the TCPM port
* has potential contaminant.
*/
struct max_tcpci_chip {
struct tcpci_data data;
struct tcpci *tcpci;
struct device *dev;
struct i2c_client *client;
struct tcpm_port *port;
enum contamiant_state contaminant_state;
};
static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
{
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16));
}
static inline int max_tcpci_write16(struct max_tcpci_chip *chip, unsigned int reg, u16 val)
{
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16));
}
static inline int max_tcpci_read8(struct max_tcpci_chip *chip, unsigned int reg, u8 *val)
{
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8));
}
static inline int max_tcpci_write8(struct max_tcpci_chip *chip, unsigned int reg, u8 val)
{
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8));
}
bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce);
#endif // TCPCI_MAXIM_H_
// SPDX-License-Identifier: GPL-2.0
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2020, Google LLC
* Copyright (C) 2020 - 2022, Google LLC
*
* MAXIM TCPCI based TCPC driver
*/
......@@ -15,6 +15,8 @@
#include <linux/usb/tcpm.h>
#include <linux/usb/typec.h>
#include "tcpci_maxim.h"
#define PD_ACTIVITY_TIMEOUT_MS 10000
#define TCPC_VENDOR_ALERT 0x80
......@@ -39,14 +41,6 @@
#define MAX_BUCK_BOOST_SOURCE 0xa
#define MAX_BUCK_BOOST_SINK 0x5
struct max_tcpci_chip {
struct tcpci_data data;
struct tcpci *tcpci;
struct device *dev;
struct i2c_client *client;
struct tcpm_port *port;
};
static const struct regmap_range max_tcpci_tcpci_range[] = {
regmap_reg_range(0x00, 0x95)
};
......@@ -68,26 +62,6 @@ static struct max_tcpci_chip *tdata_to_max_tcpci(struct tcpci_data *tdata)
return container_of(tdata, struct max_tcpci_chip, data);
}
static int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
{
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16));
}
static int max_tcpci_write16(struct max_tcpci_chip *chip, unsigned int reg, u16 val)
{
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16));
}
static int max_tcpci_read8(struct max_tcpci_chip *chip, unsigned int reg, u8 *val)
{
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8));
}
static int max_tcpci_write8(struct max_tcpci_chip *chip, unsigned int reg, u8 val)
{
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8));
}
static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
{
u16 alert_mask = 0;
......@@ -348,8 +322,14 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
if (status & TCPC_ALERT_VBUS_DISCNCT)
tcpm_vbus_change(chip->port);
if (status & TCPC_ALERT_CC_STATUS)
tcpm_cc_change(chip->port);
if (status & TCPC_ALERT_CC_STATUS) {
if (chip->contaminant_state == DETECTED || tcpm_port_is_toggling(chip->port)) {
if (!max_contaminant_is_contaminant(chip, false))
tcpm_port_clean(chip->port);
} else {
tcpm_cc_change(chip->port);
}
}
if (status & TCPC_ALERT_POWER_STATUS)
process_power_status(chip);
......@@ -438,6 +418,14 @@ static int tcpci_init(struct tcpci *tcpci, struct tcpci_data *data)
return -1;
}
static void max_tcpci_check_contaminant(struct tcpci *tcpci, struct tcpci_data *tdata)
{
struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
if (!max_contaminant_is_contaminant(chip, true))
tcpm_port_clean(chip->port);
}
static int max_tcpci_probe(struct i2c_client *client)
{
int ret;
......@@ -471,6 +459,7 @@ static int max_tcpci_probe(struct i2c_client *client)
chip->data.auto_discharge_disconnect = true;
chip->data.vbus_vsafe0v = true;
chip->data.set_partner_usb_comm_capable = max_tcpci_set_partner_usb_comm_capable;
chip->data.check_contaminant = max_tcpci_check_contaminant;
max_tcpci_init_regs(chip);
chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment