diff options
Diffstat (limited to 'drivers/staging/typec')
-rw-r--r-- | drivers/staging/typec/Kconfig | 23 | ||||
-rw-r--r-- | drivers/staging/typec/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/typec/TODO | 5 | ||||
-rw-r--r-- | drivers/staging/typec/tcpci.c | 596 | ||||
-rw-r--r-- | drivers/staging/typec/tcpci.h | 139 | ||||
-rw-r--r-- | drivers/staging/typec/tcpci_rt1711h.c | 312 |
6 files changed, 0 insertions, 1077 deletions
diff --git a/drivers/staging/typec/Kconfig b/drivers/staging/typec/Kconfig deleted file mode 100644 index e45ed08a5166..000000000000 --- a/drivers/staging/typec/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -menu "USB Power Delivery and Type-C drivers" - -if TYPEC_TCPM - -config TYPEC_TCPCI - tristate "Type-C Port Controller Interface driver" - depends on I2C - select REGMAP_I2C - help - Type-C Port Controller driver for TCPCI-compliant controller. - -config TYPEC_RT1711H - tristate "Richtek RT1711H Type-C chip driver" - depends on I2C - select TYPEC_TCPCI - help - Richtek RT1711H Type-C chip driver that works with - Type-C Port Controller Manager to provide USB PD and USB - Type-C functionalities. - -endif - -endmenu diff --git a/drivers/staging/typec/Makefile b/drivers/staging/typec/Makefile deleted file mode 100644 index 7803d485e1b3..000000000000 --- a/drivers/staging/typec/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o -obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o diff --git a/drivers/staging/typec/TODO b/drivers/staging/typec/TODO deleted file mode 100644 index 53fe2f726c88..000000000000 --- a/drivers/staging/typec/TODO +++ /dev/null @@ -1,5 +0,0 @@ -tcpci: -- Test with real hardware - -Please send patches to Guenter Roeck <linux@roeck-us.net> and copy -Heikki Krogerus <heikki.krogerus@linux.intel.com>. diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c deleted file mode 100644 index 076d97eaff6f..000000000000 --- a/drivers/staging/typec/tcpci.c +++ /dev/null @@ -1,596 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2015-2017 Google, Inc - * - * USB Type-C Port Controller Interface. - */ - -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/regmap.h> -#include <linux/usb/pd.h> -#include <linux/usb/tcpm.h> -#include <linux/usb/typec.h> - -#include "tcpci.h" - -#define PD_RETRY_COUNT 3 - -struct tcpci { - struct device *dev; - - struct tcpm_port *port; - - struct regmap *regmap; - - bool controls_vbus; - - struct tcpc_dev tcpc; - struct tcpci_data *data; -}; - -struct tcpci_chip { - struct tcpci *tcpci; - struct tcpci_data data; -}; - -static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) -{ - return container_of(tcpc, struct tcpci, tcpc); -} - -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) -{ - return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); -} - -static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val) -{ - return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u16)); -} - -static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg; - int ret; - - switch (cc) { - case TYPEC_CC_RA: - reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC2_SHIFT); - break; - case TYPEC_CC_RD: - reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); - break; - case TYPEC_CC_RP_DEF: - reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | - (TCPC_ROLE_CTRL_RP_VAL_DEF << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - case TYPEC_CC_RP_1_5: - reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | - (TCPC_ROLE_CTRL_RP_VAL_1_5 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - case TYPEC_CC_RP_3_0: - reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | - (TCPC_ROLE_CTRL_RP_VAL_3_0 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - case TYPEC_CC_OPEN: - default: - reg = (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT); - break; - } - - ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); - if (ret < 0) - return ret; - - return 0; -} - -static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, - enum typec_cc_status cc) -{ - int ret; - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg = TCPC_ROLE_CTRL_DRP; - - /* Handle vendor drp toggling */ - if (tcpci->data->start_drp_toggling) { - ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc); - if (ret < 0) - return ret; - } - - switch (cc) { - default: - case TYPEC_CC_RP_DEF: - reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - case TYPEC_CC_RP_1_5: - reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - case TYPEC_CC_RP_3_0: - reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - } - - if (cc == TYPEC_CC_RD) - reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); - else - reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT); - ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); - if (ret < 0) - return ret; - return regmap_write(tcpci->regmap, TCPC_COMMAND, - TCPC_CMD_LOOK4CONNECTION); -} - -static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) -{ - switch (cc) { - case 0x1: - return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA; - case 0x2: - return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD; - case 0x3: - if (sink) - return TYPEC_CC_RP_3_0; - /* fall through */ - case 0x0: - default: - return TYPEC_CC_OPEN; - } -} - -static int tcpci_get_cc(struct tcpc_dev *tcpc, - enum typec_cc_status *cc1, enum typec_cc_status *cc2) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg; - int ret; - - ret = regmap_read(tcpci->regmap, TCPC_CC_STATUS, ®); - if (ret < 0) - return ret; - - *cc1 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC1_SHIFT) & - TCPC_CC_STATUS_CC1_MASK, - reg & TCPC_CC_STATUS_TERM); - *cc2 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC2_SHIFT) & - TCPC_CC_STATUS_CC2_MASK, - reg & TCPC_CC_STATUS_TERM); - - return 0; -} - -static int tcpci_set_polarity(struct tcpc_dev *tcpc, - enum typec_cc_polarity polarity) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - int ret; - - ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, - (polarity == TYPEC_POLARITY_CC2) ? - TCPC_TCPC_CTRL_ORIENTATION : 0); - if (ret < 0) - return ret; - - return 0; -} - -static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - int ret; - - /* Handle vendor set vconn */ - if (tcpci->data->set_vconn) { - ret = tcpci->data->set_vconn(tcpci, tcpci->data, enable); - if (ret < 0) - return ret; - } - - ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL, - enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0); - if (ret < 0) - return ret; - - return 0; -} - -static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached, - enum typec_role role, enum typec_data_role data) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg; - int ret; - - reg = PD_REV20 << TCPC_MSG_HDR_INFO_REV_SHIFT; - if (role == TYPEC_SOURCE) - reg |= TCPC_MSG_HDR_INFO_PWR_ROLE; - if (data == TYPEC_HOST) - reg |= TCPC_MSG_HDR_INFO_DATA_ROLE; - ret = regmap_write(tcpci->regmap, TCPC_MSG_HDR_INFO, reg); - if (ret < 0) - return ret; - - return 0; -} - -static int tcpci_set_pd_rx(struct tcpc_dev *tcpc, bool enable) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg = 0; - int ret; - - if (enable) - reg = TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET; - ret = regmap_write(tcpci->regmap, TCPC_RX_DETECT, reg); - if (ret < 0) - return ret; - - return 0; -} - -static int tcpci_get_vbus(struct tcpc_dev *tcpc) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg; - int ret; - - ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, ®); - if (ret < 0) - return ret; - - return !!(reg & TCPC_POWER_STATUS_VBUS_PRES); -} - -static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - int ret; - - /* Disable both source and sink first before enabling anything */ - - if (!source) { - ret = regmap_write(tcpci->regmap, TCPC_COMMAND, - TCPC_CMD_DISABLE_SRC_VBUS); - if (ret < 0) - return ret; - } - - if (!sink) { - ret = regmap_write(tcpci->regmap, TCPC_COMMAND, - TCPC_CMD_DISABLE_SINK_VBUS); - if (ret < 0) - return ret; - } - - if (source) { - ret = regmap_write(tcpci->regmap, TCPC_COMMAND, - TCPC_CMD_SRC_VBUS_DEFAULT); - if (ret < 0) - return ret; - } - - if (sink) { - ret = regmap_write(tcpci->regmap, TCPC_COMMAND, - TCPC_CMD_SINK_VBUS); - if (ret < 0) - return ret; - } - - return 0; -} - -static int tcpci_pd_transmit(struct tcpc_dev *tcpc, - enum tcpm_transmit_type type, - const struct pd_message *msg) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - u16 header = msg ? le16_to_cpu(msg->header) : 0; - unsigned int reg, cnt; - int ret; - - cnt = msg ? pd_header_cnt(header) * 4 : 0; - ret = regmap_write(tcpci->regmap, TCPC_TX_BYTE_CNT, cnt + 2); - if (ret < 0) - return ret; - - ret = tcpci_write16(tcpci, TCPC_TX_HDR, header); - if (ret < 0) - return ret; - - if (cnt > 0) { - ret = regmap_raw_write(tcpci->regmap, TCPC_TX_DATA, - &msg->payload, cnt); - if (ret < 0) - return ret; - } - - reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) | - (type << TCPC_TRANSMIT_TYPE_SHIFT); - ret = regmap_write(tcpci->regmap, TCPC_TRANSMIT, reg); - if (ret < 0) - return ret; - - return 0; -} - -static int tcpci_init(struct tcpc_dev *tcpc) -{ - struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned long timeout = jiffies + msecs_to_jiffies(2000); /* XXX */ - unsigned int reg; - int ret; - - while (time_before_eq(jiffies, timeout)) { - ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, ®); - if (ret < 0) - return ret; - if (!(reg & TCPC_POWER_STATUS_UNINIT)) - break; - usleep_range(10000, 20000); - } - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - /* Handle vendor init */ - if (tcpci->data->init) { - ret = tcpci->data->init(tcpci, tcpci->data); - if (ret < 0) - return ret; - } - - /* Clear all events */ - ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff); - if (ret < 0) - return ret; - - if (tcpci->controls_vbus) - reg = TCPC_POWER_STATUS_VBUS_PRES; - else - reg = 0; - ret = regmap_write(tcpci->regmap, TCPC_POWER_STATUS_MASK, reg); - if (ret < 0) - return ret; - - reg = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_FAILED | - TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_RX_STATUS | - TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS; - if (tcpci->controls_vbus) - reg |= TCPC_ALERT_POWER_STATUS; - return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg); -} - -irqreturn_t tcpci_irq(struct tcpci *tcpci) -{ - u16 status; - - tcpci_read16(tcpci, TCPC_ALERT, &status); - - /* - * Clear alert status for everything except RX_STATUS, which shouldn't - * be cleared until we have successfully retrieved message. - */ - if (status & ~TCPC_ALERT_RX_STATUS) - tcpci_write16(tcpci, TCPC_ALERT, - status & ~TCPC_ALERT_RX_STATUS); - - if (status & TCPC_ALERT_CC_STATUS) - tcpm_cc_change(tcpci->port); - - if (status & TCPC_ALERT_POWER_STATUS) { - unsigned int reg; - - regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, ®); - - /* - * If power status mask has been reset, then the TCPC - * has reset. - */ - if (reg == 0xff) - tcpm_tcpc_reset(tcpci->port); - else - tcpm_vbus_change(tcpci->port); - } - - if (status & TCPC_ALERT_RX_STATUS) { - struct pd_message msg; - unsigned int cnt; - u16 header; - - regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt); - - tcpci_read16(tcpci, TCPC_RX_HDR, &header); - msg.header = cpu_to_le16(header); - - if (WARN_ON(cnt > sizeof(msg.payload))) - cnt = sizeof(msg.payload); - - if (cnt > 0) - regmap_raw_read(tcpci->regmap, TCPC_RX_DATA, - &msg.payload, cnt); - - /* Read complete, clear RX status alert bit */ - tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS); - - tcpm_pd_receive(tcpci->port, &msg); - } - - if (status & TCPC_ALERT_RX_HARD_RST) - tcpm_pd_hard_reset(tcpci->port); - - if (status & TCPC_ALERT_TX_SUCCESS) - tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_SUCCESS); - else if (status & TCPC_ALERT_TX_DISCARDED) - tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_DISCARDED); - else if (status & TCPC_ALERT_TX_FAILED) - tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL_GPL(tcpci_irq); - -static irqreturn_t _tcpci_irq(int irq, void *dev_id) -{ - struct tcpci_chip *chip = dev_id; - - return tcpci_irq(chip->tcpci); -} - -static const struct regmap_config tcpci_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0x7F, /* 0x80 .. 0xFF are vendor defined */ -}; - -static const struct tcpc_config tcpci_tcpc_config = { - .type = TYPEC_PORT_DFP, - .default_role = TYPEC_SINK, -}; - -static int tcpci_parse_config(struct tcpci *tcpci) -{ - tcpci->controls_vbus = true; /* XXX */ - - /* TODO: Populate struct tcpc_config from ACPI/device-tree */ - tcpci->tcpc.config = &tcpci_tcpc_config; - - return 0; -} - -struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) -{ - struct tcpci *tcpci; - int err; - - tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL); - if (!tcpci) - return ERR_PTR(-ENOMEM); - - tcpci->dev = dev; - tcpci->data = data; - tcpci->regmap = data->regmap; - - tcpci->tcpc.init = tcpci_init; - tcpci->tcpc.get_vbus = tcpci_get_vbus; - tcpci->tcpc.set_vbus = tcpci_set_vbus; - tcpci->tcpc.set_cc = tcpci_set_cc; - tcpci->tcpc.get_cc = tcpci_get_cc; - tcpci->tcpc.set_polarity = tcpci_set_polarity; - tcpci->tcpc.set_vconn = tcpci_set_vconn; - tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling; - - tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx; - tcpci->tcpc.set_roles = tcpci_set_roles; - tcpci->tcpc.pd_transmit = tcpci_pd_transmit; - - err = tcpci_parse_config(tcpci); - if (err < 0) - return ERR_PTR(err); - - tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); - if (PTR_ERR_OR_ZERO(tcpci->port)) - return ERR_CAST(tcpci->port); - - return tcpci; -} -EXPORT_SYMBOL_GPL(tcpci_register_port); - -void tcpci_unregister_port(struct tcpci *tcpci) -{ - tcpm_unregister_port(tcpci->port); -} -EXPORT_SYMBOL_GPL(tcpci_unregister_port); - -static int tcpci_probe(struct i2c_client *client, - const struct i2c_device_id *i2c_id) -{ - struct tcpci_chip *chip; - int err; - u16 val = 0; - - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); - if (IS_ERR(chip->data.regmap)) - return PTR_ERR(chip->data.regmap); - - /* Disable chip interrupts before requesting irq */ - err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val, - sizeof(u16)); - if (err < 0) - return err; - - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, - _tcpci_irq, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - dev_name(&client->dev), chip); - if (err < 0) - return err; - - chip->tcpci = tcpci_register_port(&client->dev, &chip->data); - if (PTR_ERR_OR_ZERO(chip->tcpci)) - return PTR_ERR(chip->tcpci); - - i2c_set_clientdata(client, chip); - return 0; -} - -static int tcpci_remove(struct i2c_client *client) -{ - struct tcpci_chip *chip = i2c_get_clientdata(client); - - tcpci_unregister_port(chip->tcpci); - - return 0; -} - -static const struct i2c_device_id tcpci_id[] = { - { "tcpci", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tcpci_id); - -#ifdef CONFIG_OF -static const struct of_device_id tcpci_of_match[] = { - { .compatible = "usb,tcpci", }, - {}, -}; -MODULE_DEVICE_TABLE(of, tcpci_of_match); -#endif - -static struct i2c_driver tcpci_i2c_driver = { - .driver = { - .name = "tcpci", - .of_match_table = of_match_ptr(tcpci_of_match), - }, - .probe = tcpci_probe, - .remove = tcpci_remove, - .id_table = tcpci_id, -}; -module_i2c_driver(tcpci_i2c_driver); - -MODULE_DESCRIPTION("USB Type-C Port Controller Interface driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h deleted file mode 100644 index 303ebde26546..000000000000 --- a/drivers/staging/typec/tcpci.h +++ /dev/null @@ -1,139 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2015-2017 Google, Inc - * - * USB Type-C Port Controller Interface. - */ - -#ifndef __LINUX_USB_TCPCI_H -#define __LINUX_USB_TCPCI_H - -#define TCPC_VENDOR_ID 0x0 -#define TCPC_PRODUCT_ID 0x2 -#define TCPC_BCD_DEV 0x4 -#define TCPC_TC_REV 0x6 -#define TCPC_PD_REV 0x8 -#define TCPC_PD_INT_REV 0xa - -#define TCPC_ALERT 0x10 -#define TCPC_ALERT_VBUS_DISCNCT BIT(11) -#define TCPC_ALERT_RX_BUF_OVF BIT(10) -#define TCPC_ALERT_FAULT BIT(9) -#define TCPC_ALERT_V_ALARM_LO BIT(8) -#define TCPC_ALERT_V_ALARM_HI BIT(7) -#define TCPC_ALERT_TX_SUCCESS BIT(6) -#define TCPC_ALERT_TX_DISCARDED BIT(5) -#define TCPC_ALERT_TX_FAILED BIT(4) -#define TCPC_ALERT_RX_HARD_RST BIT(3) -#define TCPC_ALERT_RX_STATUS BIT(2) -#define TCPC_ALERT_POWER_STATUS BIT(1) -#define TCPC_ALERT_CC_STATUS BIT(0) - -#define TCPC_ALERT_MASK 0x12 -#define TCPC_POWER_STATUS_MASK 0x14 -#define TCPC_FAULT_STATUS_MASK 0x15 -#define TCPC_CONFIG_STD_OUTPUT 0x18 - -#define TCPC_TCPC_CTRL 0x19 -#define TCPC_TCPC_CTRL_ORIENTATION BIT(0) - -#define TCPC_ROLE_CTRL 0x1a -#define TCPC_ROLE_CTRL_DRP BIT(6) -#define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4 -#define TCPC_ROLE_CTRL_RP_VAL_MASK 0x3 -#define TCPC_ROLE_CTRL_RP_VAL_DEF 0x0 -#define TCPC_ROLE_CTRL_RP_VAL_1_5 0x1 -#define TCPC_ROLE_CTRL_RP_VAL_3_0 0x2 -#define TCPC_ROLE_CTRL_CC2_SHIFT 2 -#define TCPC_ROLE_CTRL_CC2_MASK 0x3 -#define TCPC_ROLE_CTRL_CC1_SHIFT 0 -#define TCPC_ROLE_CTRL_CC1_MASK 0x3 -#define TCPC_ROLE_CTRL_CC_RA 0x0 -#define TCPC_ROLE_CTRL_CC_RP 0x1 -#define TCPC_ROLE_CTRL_CC_RD 0x2 -#define TCPC_ROLE_CTRL_CC_OPEN 0x3 - -#define TCPC_FAULT_CTRL 0x1b - -#define TCPC_POWER_CTRL 0x1c -#define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0) - -#define TCPC_CC_STATUS 0x1d -#define TCPC_CC_STATUS_TOGGLING BIT(5) -#define TCPC_CC_STATUS_TERM BIT(4) -#define TCPC_CC_STATUS_CC2_SHIFT 2 -#define TCPC_CC_STATUS_CC2_MASK 0x3 -#define TCPC_CC_STATUS_CC1_SHIFT 0 -#define TCPC_CC_STATUS_CC1_MASK 0x3 - -#define TCPC_POWER_STATUS 0x1e -#define TCPC_POWER_STATUS_UNINIT BIT(6) -#define TCPC_POWER_STATUS_VBUS_DET BIT(3) -#define TCPC_POWER_STATUS_VBUS_PRES BIT(2) - -#define TCPC_FAULT_STATUS 0x1f - -#define TCPC_COMMAND 0x23 -#define TCPC_CMD_WAKE_I2C 0x11 -#define TCPC_CMD_DISABLE_VBUS_DETECT 0x22 -#define TCPC_CMD_ENABLE_VBUS_DETECT 0x33 -#define TCPC_CMD_DISABLE_SINK_VBUS 0x44 -#define TCPC_CMD_SINK_VBUS 0x55 -#define TCPC_CMD_DISABLE_SRC_VBUS 0x66 -#define TCPC_CMD_SRC_VBUS_DEFAULT 0x77 -#define TCPC_CMD_SRC_VBUS_HIGH 0x88 -#define TCPC_CMD_LOOK4CONNECTION 0x99 -#define TCPC_CMD_RXONEMORE 0xAA -#define TCPC_CMD_I2C_IDLE 0xFF - -#define TCPC_DEV_CAP_1 0x24 -#define TCPC_DEV_CAP_2 0x26 -#define TCPC_STD_INPUT_CAP 0x28 -#define TCPC_STD_OUTPUT_CAP 0x29 - -#define TCPC_MSG_HDR_INFO 0x2e -#define TCPC_MSG_HDR_INFO_DATA_ROLE BIT(3) -#define TCPC_MSG_HDR_INFO_PWR_ROLE BIT(0) -#define TCPC_MSG_HDR_INFO_REV_SHIFT 1 -#define TCPC_MSG_HDR_INFO_REV_MASK 0x3 - -#define TCPC_RX_DETECT 0x2f -#define TCPC_RX_DETECT_HARD_RESET BIT(5) -#define TCPC_RX_DETECT_SOP BIT(0) - -#define TCPC_RX_BYTE_CNT 0x30 -#define TCPC_RX_BUF_FRAME_TYPE 0x31 -#define TCPC_RX_HDR 0x32 -#define TCPC_RX_DATA 0x34 /* through 0x4f */ - -#define TCPC_TRANSMIT 0x50 -#define TCPC_TRANSMIT_RETRY_SHIFT 4 -#define TCPC_TRANSMIT_RETRY_MASK 0x3 -#define TCPC_TRANSMIT_TYPE_SHIFT 0 -#define TCPC_TRANSMIT_TYPE_MASK 0x7 - -#define TCPC_TX_BYTE_CNT 0x51 -#define TCPC_TX_HDR 0x52 -#define TCPC_TX_DATA 0x54 /* through 0x6f */ - -#define TCPC_VBUS_VOLTAGE 0x70 -#define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72 -#define TCPC_VBUS_STOP_DISCHARGE_THRESH 0x74 -#define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76 -#define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78 - -struct tcpci; -struct tcpci_data { - struct regmap *regmap; - int (*init)(struct tcpci *tcpci, struct tcpci_data *data); - int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data, - bool enable); - int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data, - enum typec_cc_status cc); -}; - -struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); -void tcpci_unregister_port(struct tcpci *tcpci); -irqreturn_t tcpci_irq(struct tcpci *tcpci); - -#endif /* __LINUX_USB_TCPCI_H */ diff --git a/drivers/staging/typec/tcpci_rt1711h.c b/drivers/staging/typec/tcpci_rt1711h.c deleted file mode 100644 index 017389021b96..000000000000 --- a/drivers/staging/typec/tcpci_rt1711h.c +++ /dev/null @@ -1,312 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018, Richtek Technology Corporation - * - * Richtek RT1711H Type-C Chip Driver - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/gpio/consumer.h> -#include <linux/usb/tcpm.h> -#include <linux/regmap.h> -#include "tcpci.h" - -#define RT1711H_VID 0x29CF -#define RT1711H_PID 0x1711 - -#define RT1711H_RTCTRL8 0x9B - -/* Autoidle timeout = (tout * 2 + 1) * 6.4ms */ -#define RT1711H_RTCTRL8_SET(ck300, ship_off, auto_idle, tout) \ - (((ck300) << 7) | ((ship_off) << 5) | \ - ((auto_idle) << 3) | ((tout) & 0x07)) - -#define RT1711H_RTCTRL11 0x9E - -/* I2C timeout = (tout + 1) * 12.5ms */ -#define RT1711H_RTCTRL11_SET(en, tout) \ - (((en) << 7) | ((tout) & 0x0F)) - -#define RT1711H_RTCTRL13 0xA0 -#define RT1711H_RTCTRL14 0xA1 -#define RT1711H_RTCTRL15 0xA2 -#define RT1711H_RTCTRL16 0xA3 - -struct rt1711h_chip { - struct tcpci_data data; - struct tcpci *tcpci; - struct device *dev; -}; - -static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val) -{ - return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16)); -} - -static int rt1711h_write16(struct rt1711h_chip *chip, unsigned int reg, u16 val) -{ - return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16)); -} - -static int rt1711h_read8(struct rt1711h_chip *chip, unsigned int reg, u8 *val) -{ - return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8)); -} - -static int rt1711h_write8(struct rt1711h_chip *chip, unsigned int reg, u8 val) -{ - return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8)); -} - -static const struct regmap_config rt1711h_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xFF, /* 0x80 .. 0xFF are vendor defined */ -}; - -static struct rt1711h_chip *tdata_to_rt1711h(struct tcpci_data *tdata) -{ - return container_of(tdata, struct rt1711h_chip, data); -} - -static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) -{ - int ret; - struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); - - /* CK 300K from 320K, shipping off, auto_idle enable, tout = 32ms */ - ret = rt1711h_write8(chip, RT1711H_RTCTRL8, - RT1711H_RTCTRL8_SET(0, 1, 1, 2)); - if (ret < 0) - return ret; - - /* I2C reset : (val + 1) * 12.5ms */ - ret = rt1711h_write8(chip, RT1711H_RTCTRL11, - RT1711H_RTCTRL11_SET(1, 0x0F)); - if (ret < 0) - return ret; - - /* tTCPCfilter : (26.7 * val) us */ - ret = rt1711h_write8(chip, RT1711H_RTCTRL14, 0x0F); - if (ret < 0) - return ret; - - /* tDRP : (51.2 + 6.4 * val) ms */ - ret = rt1711h_write8(chip, RT1711H_RTCTRL15, 0x04); - if (ret < 0) - return ret; - - /* dcSRC.DRP : 33% */ - return rt1711h_write16(chip, RT1711H_RTCTRL16, 330); -} - -static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata, - bool enable) -{ - struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); - - return rt1711h_write8(chip, RT1711H_RTCTRL8, - RT1711H_RTCTRL8_SET(0, 1, !enable, 2)); -} - -static int rt1711h_start_drp_toggling(struct tcpci *tcpci, - struct tcpci_data *tdata, - enum typec_cc_status cc) -{ - struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); - int ret; - unsigned int reg = 0; - - switch (cc) { - default: - case TYPEC_CC_RP_DEF: - reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - case TYPEC_CC_RP_1_5: - reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - case TYPEC_CC_RP_3_0: - reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); - break; - } - - if (cc == TYPEC_CC_RD) - reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); - else - reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT); - - ret = rt1711h_write8(chip, TCPC_ROLE_CTRL, reg); - if (ret < 0) - return ret; - usleep_range(500, 1000); - - return 0; -} - -static irqreturn_t rt1711h_irq(int irq, void *dev_id) -{ - int ret; - u16 alert; - u8 status; - struct rt1711h_chip *chip = dev_id; - - if (!chip->tcpci) - return IRQ_HANDLED; - - ret = rt1711h_read16(chip, TCPC_ALERT, &alert); - if (ret < 0) - goto out; - - if (alert & TCPC_ALERT_CC_STATUS) { - ret = rt1711h_read8(chip, TCPC_CC_STATUS, &status); - if (ret < 0) - goto out; - /* Clear cc change event triggered by starting toggling */ - if (status & TCPC_CC_STATUS_TOGGLING) - rt1711h_write8(chip, TCPC_ALERT, TCPC_ALERT_CC_STATUS); - } - -out: - return tcpci_irq(chip->tcpci); -} - -static int rt1711h_init_alert(struct rt1711h_chip *chip, - struct i2c_client *client) -{ - int ret; - - /* Disable chip interrupts before requesting irq */ - ret = rt1711h_write16(chip, TCPC_ALERT_MASK, 0); - if (ret < 0) - return ret; - - ret = devm_request_threaded_irq(chip->dev, client->irq, NULL, - rt1711h_irq, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - dev_name(chip->dev), chip); - if (ret < 0) - return ret; - enable_irq_wake(client->irq); - return 0; -} - -static int rt1711h_sw_reset(struct rt1711h_chip *chip) -{ - int ret; - - ret = rt1711h_write8(chip, RT1711H_RTCTRL13, 0x01); - if (ret < 0) - return ret; - - usleep_range(1000, 2000); - return 0; -} - -static int rt1711h_check_revision(struct i2c_client *i2c) -{ - int ret; - - ret = i2c_smbus_read_word_data(i2c, TCPC_VENDOR_ID); - if (ret < 0) - return ret; - if (ret != RT1711H_VID) { - dev_err(&i2c->dev, "vid is not correct, 0x%04x\n", ret); - return -ENODEV; - } - ret = i2c_smbus_read_word_data(i2c, TCPC_PRODUCT_ID); - if (ret < 0) - return ret; - if (ret != RT1711H_PID) { - dev_err(&i2c->dev, "pid is not correct, 0x%04x\n", ret); - return -ENODEV; - } - return 0; -} - -static int rt1711h_probe(struct i2c_client *client, - const struct i2c_device_id *i2c_id) -{ - int ret; - struct rt1711h_chip *chip; - - ret = rt1711h_check_revision(client); - if (ret < 0) { - dev_err(&client->dev, "check vid/pid fail\n"); - return ret; - } - - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->data.regmap = devm_regmap_init_i2c(client, - &rt1711h_regmap_config); - if (IS_ERR(chip->data.regmap)) - return PTR_ERR(chip->data.regmap); - - chip->dev = &client->dev; - i2c_set_clientdata(client, chip); - - ret = rt1711h_sw_reset(chip); - if (ret < 0) - return ret; - - ret = rt1711h_init_alert(chip, client); - if (ret < 0) - return ret; - - chip->data.init = rt1711h_init; - chip->data.set_vconn = rt1711h_set_vconn; - chip->data.start_drp_toggling = rt1711h_start_drp_toggling; - chip->tcpci = tcpci_register_port(chip->dev, &chip->data); - if (IS_ERR_OR_NULL(chip->tcpci)) - return PTR_ERR(chip->tcpci); - - return 0; -} - -static int rt1711h_remove(struct i2c_client *client) -{ - struct rt1711h_chip *chip = i2c_get_clientdata(client); - - tcpci_unregister_port(chip->tcpci); - return 0; -} - -static const struct i2c_device_id rt1711h_id[] = { - { "rt1711h", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, rt1711h_id); - -#ifdef CONFIG_OF -static const struct of_device_id rt1711h_of_match[] = { - { .compatible = "richtek,rt1711h", }, - {}, -}; -MODULE_DEVICE_TABLE(of, rt1711h_of_match); -#endif - -static struct i2c_driver rt1711h_i2c_driver = { - .driver = { - .name = "rt1711h", - .of_match_table = of_match_ptr(rt1711h_of_match), - }, - .probe = rt1711h_probe, - .remove = rt1711h_remove, - .id_table = rt1711h_id, -}; -module_i2c_driver(rt1711h_i2c_driver); - -MODULE_AUTHOR("ShuFan Lee <shufan_lee@richtek.com>"); -MODULE_DESCRIPTION("RT1711H USB Type-C Port Controller Interface Driver"); -MODULE_LICENSE("GPL"); |