[PATCH v4] staging: typec: handle vendor defined part and modify drp toggling flow
From: ShuFanLee <shufan_...@richtek.com> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq. More operations can be extended in tcpci_data if needed. According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not start DRP toggling until subsequently the TCPM writes to the COMMAND register to start DRP toggling. DRP toggling flow is chagned as following: - Write DRP = 0 & Rd/Rd - Write DRP = 1 - Set LOOK4CONNECTION command Signed-off-by: ShuFanLee <shufan_...@richtek.com> --- drivers/staging/typec/tcpci.c | 127 +- drivers/staging/typec/tcpci.h | 13 + 2 files changed, 113 insertions(+), 27 deletions(-) patch changelogs between v1 & v2 - Remove unnecessary i2c_client in the structure of tcpci - Rename structure of tcpci_vendor_data to tcpci_data - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver - Add set_vconn ops in tcpci_data (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn) - Export tcpci_irq so that vendor can call it in their own IRQ handler patch changelogs between v2 & v3 - Change the return type of tcpci_irq from int to irqreturn_t patch changelogs between v3 & v4 - Directly return regmap_write at the end of drp_toggling function - Because tcpci_irq is called in _tcpci_irq, move _tcpci_irq to the place after tcpci_irq diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..5bafcc4 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -21,7 +21,6 @@ struct tcpci { struct device *dev; - struct i2c_client *client; struct tcpm_port *port; @@ -30,6 +29,12 @@ struct tcpci { 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) @@ -37,8 +42,7 @@ 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) +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) { return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); } @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) 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; + unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); switch (cc) { default: @@ -117,7 +123,16 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, break; } - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + usleep_range(500, 1000); + reg |= TCPC_ROLE_CTRL_DRP; + 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) @@ -178,6 +193,16 @@ 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) { + 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) @@ -323,6 +348,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->data) { + 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, 0x); if (ret < 0) @@ -344,9 +378,8 @@ static int tcpci_init(struct tcpc_dev *t
[PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
From: ShuFanLee <shufan_...@richtek.com> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq. More operations can be extended in tcpci_data if needed. According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not start DRP toggling until subsequently the TCPM writes to the COMMAND register to start DRP toggling. DRP toggling flow is chagned as following: - Write DRP = 0 & Rd/Rd - Write DRP = 1 - Set LOOK4CONNECTION command Signed-off-by: ShuFanLee <shufan_...@richtek.com> --- drivers/staging/typec/tcpci.c | 128 +- drivers/staging/typec/tcpci.h | 13 + 2 files changed, 115 insertions(+), 26 deletions(-) patch changelogs between v1 & v2 - Remove unnecessary i2c_client in the structure of tcpci - Rename structure of tcpci_vendor_data to tcpci_data - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver - Add set_vconn ops in tcpci_data (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn) - Export tcpci_irq so that vendor can call it in their own IRQ handler patch changelogs between v2 & v3 - Change the return type of tcpci_irq from int to irqreturn_t diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..4959c69 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -21,7 +21,6 @@ struct tcpci { struct device *dev; - struct i2c_client *client; struct tcpm_port *port; @@ -30,6 +29,12 @@ struct tcpci { 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) @@ -37,8 +42,7 @@ 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) +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) { return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); } @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) 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; + unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); switch (cc) { default: @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, break; } - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + usleep_range(500, 1000); + reg |= TCPC_ROLE_CTRL_DRP; + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + ret = regmap_write(tcpci->regmap, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); + if (ret < 0) + return ret; + return 0; } static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) @@ -178,6 +196,16 @@ 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) { + 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) @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->data) { + 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, 0x); if (ret < 0) @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg); } -static irqreturn_t tcpci_irq(int irq, void *dev_id) +static ir
[PATCH v3] Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq. More operations can be extended in tcpci_data if needed. According to TCPCI specification, 4.4.5.2 ROLE_C
From: ShuFanLee <shufan_...@richtek.com> Signed-off-by: ShuFanLee <shufan_...@richtek.com> --- drivers/staging/typec/tcpci.c | 128 +- drivers/staging/typec/tcpci.h | 13 + 2 files changed, 115 insertions(+), 26 deletions(-) patch changelogs between v1 & v2 - Remove unnecessary i2c_client in the structure of tcpci - Rename structure of tcpci_vendor_data to tcpci_data - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver - Add set_vconn ops in tcpci_data (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn) - Export tcpci_irq so that vendor can call it in their own IRQ handler patch changelogs between v2 & v3 - Change the return type of tcpci_irq from int to irqreturn_t - Disable IRQs and request threaded IRQ before registering tcpci port diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..4959c69 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -21,7 +21,6 @@ struct tcpci { struct device *dev; - struct i2c_client *client; struct tcpm_port *port; @@ -30,6 +29,12 @@ struct tcpci { 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) @@ -37,8 +42,7 @@ 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) +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) { return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); } @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) 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; + unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); switch (cc) { default: @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, break; } - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + usleep_range(500, 1000); + reg |= TCPC_ROLE_CTRL_DRP; + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + ret = regmap_write(tcpci->regmap, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); + if (ret < 0) + return ret; + return 0; } static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) @@ -178,6 +196,16 @@ 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) { + 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) @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->data) { + 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, 0x); if (ret < 0) @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg); } -static irqreturn_t tcpci_irq(int irq, void *dev_id) +static irqreturn_t _tcpci_irq(int irq, void *dev_id) { struct tcpci *tcpci = dev_id; + + return tcpci_irq(tcpci); +} + +irqreturn_t tcpci_irq(struct tcpci *tcpci) +{ u16 status; tcpci_read16(tcpci, TCPC_ALERT, ); @@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(tcpci_i
[PATCH v2] staging: typec: handle vendor defined part and modify drp toggling flow
From: ShuFanLee <shufan_...@richtek.com> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq. More operations can be extended in tcpci_data if needed. According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not start DRP toggling until subsequently the TCPM writes to the COMMAND register to start DRP toggling. DRP toggling flow is chagned as following: - Write DRP = 0 & Rd/Rd - Write DRP = 1 - Set LOOK4CONNECTION command Signed-off-by: ShuFanLee <shufan_...@richtek.com> --- drivers/staging/typec/tcpci.c | 111 ++ drivers/staging/typec/tcpci.h | 13 + 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..461fbd48 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -21,7 +21,6 @@ struct tcpci { struct device *dev; - struct i2c_client *client; struct tcpm_port *port; @@ -30,6 +29,7 @@ struct tcpci { bool controls_vbus; struct tcpc_dev tcpc; + struct tcpci_data *data; }; static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -98,8 +98,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) 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; + unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); switch (cc) { default: @@ -116,8 +118,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, TCPC_ROLE_CTRL_RP_VAL_SHIFT); break; } - - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + usleep_range(500, 1000); + reg |= TCPC_ROLE_CTRL_DRP; + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + ret = regmap_write(tcpci->regmap, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); + if (ret < 0) + return ret; + return 0; } static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) @@ -178,6 +191,16 @@ 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) { + 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) @@ -323,6 +346,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->data) { + 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, 0x); if (ret < 0) @@ -344,9 +376,16 @@ static int tcpci_init(struct tcpc_dev *tcpc) return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg); } -static irqreturn_t tcpci_irq(int irq, void *dev_id) +static irqreturn_t _tcpci_irq(int irq, void *dev_id) { struct tcpci *tcpci = dev_id; + + tcpci_irq(tcpci); + return IRQ_HANDLED; +} + +int tcpci_irq(struct tcpci *tcpci) +{ u16 status; tcpci_read16(tcpci, TCPC_ALERT, ); @@ -412,6 +451,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(tcpci_irq); static const struct regmap_config tcpci_regmap_config = { .reg_bits = 8, @@ -435,22 +475,18 @@ static int tcpci_parse_config(struct tcpci *tcpci) return 0; } -static int tcpci_probe(struct i2c_client *client, - const struct i2c_device_id *i2c_id) +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); + tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL); if (!tcpci) - r
[PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
From: ShuFanLee <shufan_...@richtek.com> Handle vendor defined behavior in tcpci_init and tcpci_irq. More operations can be extended in tcpci_vendor_data if needed. According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not start DRP toggling until subsequently the TCPM writes to the COMMAND register to start DRP toggling. DRP toggling flow is chagned as following: - Write DRP = 0 & Rd/Rd - Write DRP = 1 - Set LOOK4CONNECTION command Signed-off-by: ShuFanLee <shufan_...@richtek.com> --- drivers/staging/typec/tcpci.c | 98 --- drivers/staging/typec/tcpci.h | 15 +++ 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..b3a97b3 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -30,6 +30,7 @@ struct tcpci { bool controls_vbus; struct tcpc_dev tcpc; + struct tcpci_vendor_data *vdata; }; static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,16 +38,29 @@ 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) +int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) { return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); } +EXPORT_SYMBOL_GPL(tcpci_read16); -static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val) +int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val) { return regmap_raw_write(tcpci->regmap, reg, , sizeof(u16)); } +EXPORT_SYMBOL_GPL(tcpci_write16); + +int tcpci_read8(struct tcpci *tcpci, unsigned int reg, u8 *val) +{ + return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u8)); +} +EXPORT_SYMBOL_GPL(tcpci_read8); + +int tcpci_write8(struct tcpci *tcpci, unsigned int reg, u8 val) +{ + return regmap_raw_write(tcpci->regmap, reg, , sizeof(u8)); +} +EXPORT_SYMBOL_GPL(tcpci_write8); static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) { @@ -98,8 +112,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) 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; + unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); switch (cc) { default: @@ -116,8 +132,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, TCPC_ROLE_CTRL_RP_VAL_SHIFT); break; } - - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + usleep_range(500, 1000); + reg |= TCPC_ROLE_CTRL_DRP; + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + ret = regmap_write(tcpci->regmap, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); + if (ret < 0) + return ret; + return 0; } static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) @@ -323,6 +350,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->vdata) { + if (tcpci->vdata->init) { + ret = (*tcpci->vdata->init)(tcpci, tcpci->vdata); + if (ret < 0) + return ret; + } + } + /* Clear all events */ ret = tcpci_write16(tcpci, TCPC_ALERT, 0x); if (ret < 0) @@ -351,6 +387,13 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) tcpci_read16(tcpci, TCPC_ALERT, ); + /* Handle vendor defined interrupt */ + if (tcpci->vdata) { + if (tcpci->vdata->irq_handler) + (*tcpci->vdata->irq_handler)(tcpci, tcpci->vdata, +); + } + /* * Clear alert status for everything except RX_STATUS, which shouldn't * be cleared until we have successfully retrieved message. @@ -417,7 +460,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) .reg_bits = 8, .val_bits = 8, - .max_register = 0x7F, /* 0x80 .. 0xFF are vendor defined */ + .max_register = 0xFF, /* 0x80 .. 0xFF are vendor defined */ }; static const struct tcpc_config tcpci_tcpc_config = { @@ -
[PATCH] USB TYPEC: RT1711H Type-C Chip Driver
From: ShuFanLee <shufan_...@richtek.com> Richtek RT1711H Type-C chip driver that works with Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. Signed-off-by: ShuFanLee <shufan_...@richtek.com> --- .../devicetree/bindings/usb/richtek,rt1711h.txt| 38 + arch/arm64/boot/dts/hisilicon/rt1711h.dtsi | 11 + drivers/usb/typec/Kconfig |2 + drivers/usb/typec/Makefile |1 + drivers/usb/typec/rt1711h/Kconfig |7 + drivers/usb/typec/rt1711h/Makefile |2 + drivers/usb/typec/rt1711h/rt1711h.c| 2241 drivers/usb/typec/rt1711h/rt1711h.h| 300 +++ 8 files changed, 2602 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/richtek,rt1711h.txt create mode 100644 arch/arm64/boot/dts/hisilicon/rt1711h.dtsi create mode 100644 drivers/usb/typec/rt1711h/Kconfig create mode 100644 drivers/usb/typec/rt1711h/Makefile create mode 100644 drivers/usb/typec/rt1711h/rt1711h.c create mode 100644 drivers/usb/typec/rt1711h/rt1711h.h diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1711h.txt b/Documentation/devicetree/bindings/usb/richtek,rt1711h.txt new file mode 100644 index 000..c28299c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/richtek,rt1711h.txt @@ -0,0 +1,38 @@ +Richtek RT1711H Type-C Port Controller. + +Required properties: +- compatible : Must be "richtek,typec_rt1711h"; +- reg : Must be 0x4e, it's default slave address of RT1711H. +- rt,intr_gpio : IRQ GPIO pin that's connected to RT1711H interrupt. + +Optional node: +- rt,name : Name used for registering IRQ and creating kthread. + If this property is not specified, "default" will be applied. +- rt,def_role : Default port role (TYPEC_SINK(0) or TYPEC_SOURCE(1)). + Set to TYPEC_NO_PREFERRED_ROLE(-1) if no default role. + If this property is not specified, TYPEC_SINK will be applied. +- rt,port_type : Port type (TYPEC_PORT_DFP(0), TYPEC_PORT_UFP(1), +or TYPEC_PORT_DRP(2)). If this property is not specified, +TYPEC_PORT_DRP will be applied. +- rt,max_snk_mv : Maximum acceptable sink voltage in mV. + If this property is not specified, 5000mV will be applied. +- rt,max_snk_ma : Maximum sink current in mA. + If this property is not specified, 3000mA will be applied. +- rt,max_snk_mw : Maximum required sink power in mW. + If this property is not specified, 15000mW will be applied. +- rt,operating_snk_mw : Required operating sink power in mW. + If this property is not specified, + 2500mW will be applied. +- rt,try_role_hw : True if try.{Src,Snk} is implemented in hardware. + If this property is not specified, False will be applied. + +Example: +rt1711h@4e { + status = "ok"; + compatible = "richtek,typec_rt1711h"; + reg = <0x4e>; + rt,intr_gpio = < 0 0x0>; + rt,name = "rt1711h"; + rt,port_type = <2>; /* 0: DFP, 1: UFP, 2: DRP */ + rt,def_role = <0>; /* 0: SNK, 1: SRC, -1: TYPEC_NO_PREFERRED_ROLE */ +}; diff --git a/arch/arm64/boot/dts/hisilicon/rt1711h.dtsi b/arch/arm64/boot/dts/hisilicon/rt1711h.dtsi new file mode 100644 index 000..4196cc0 --- /dev/null +++ b/arch/arm64/boot/dts/hisilicon/rt1711h.dtsi @@ -0,0 +1,11 @@ + { + rt1711h@4e { + status = "ok"; + compatible = "richtek,typec_rt1711h"; + reg = <0x4e>; + rt,intr_gpio = < 0 0x0>; + rt,name = "rt1711h"; + rt,port_type = <2>; /* 0: DFP, 1: UFP, 2: DRP */ + rt,def_role = <0>; /* 0: SNK, 1: SRC */ + }; +}; diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index bcb2744..7bede0b 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -56,6 +56,8 @@ if TYPEC_TCPM source "drivers/usb/typec/fusb302/Kconfig" +source "drivers/usb/typec/rt1711h/Kconfig" + config TYPEC_WCOVE tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" depends on ACPI diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index bb3138a..e3aaf3c 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_TYPEC)+= typec.o obj-$(CONFIG_TYPEC_TCPM) += tcpm.o obj-y += fusb302/ +obj-$(CONFIG_TYPEC_RT1711H)+= rt1711h/ obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o obj-$(CONFIG_TYPEC_UCSI) += ucsi/ obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o diff --git a/drivers/usb/typec/rt1711h/Kconfig b/drivers/usb/typec/rt1711h/Kconfig new file mode 1006