From c2a8ea5997fdfeb43eda259d5533234c3cae05d7 Mon Sep 17 00:00:00 2001 From: ChiYuan Huang Date: Mon, 15 Aug 2022 17:01:20 +0800 Subject: usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver The MediaTek MT6370 is a highly-integrated smart power management IC, which includes a single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C & Power Delivery (PD) controller, dual Flash LED current sources, a RGB LED driver, a backlight WLED driver, a display bias driver and a general LDO for portable devices. Add support for the Type-C & Power Delivery controller in MediaTek MT6370 IC. Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Guenter Roeck Reviewed-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: ChiYuan Huang Signed-off-by: ChiaEn Wu Link: https://lore.kernel.org/r/20220815090125.27705-8-peterwu.pub@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/Kconfig | 11 ++ drivers/usb/typec/tcpm/Makefile | 1 + drivers/usb/typec/tcpm/tcpci_mt6370.c | 207 ++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index 073fd2ea5e0b..e6b88ca4a4b9 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -35,6 +35,17 @@ config TYPEC_MT6360 USB Type-C. It works with Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. +config TYPEC_TCPCI_MT6370 + tristate "MediaTek MT6370 Type-C driver" + depends on MFD_MT6370 + help + MediaTek MT6370 is a multi-functional IC that includes + USB Type-C. It works with Type-C Port Controller Manager + to provide USB PD and USB Type-C functionalities. + + This driver can also be built as a module. The module + will be called "tcpci_mt6370". + config TYPEC_TCPCI_MAXIM tristate "Maxim TCPCI based Type-C chip driver" help diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile index 7d499f3569fd..906d9dced8e7 100644 --- a/drivers/usb/typec/tcpm/Makefile +++ b/drivers/usb/typec/tcpm/Makefile @@ -6,4 +6,5 @@ typec_wcove-y := wcove.o obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o 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 diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c new file mode 100644 index 000000000000..c5bb201a5163 --- /dev/null +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiYuan Huang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_SYSCTRL8 0x9B + +#define MT6370_AUTOIDLE_MASK BIT(3) + +#define MT6370_VENDOR_ID 0x29CF +#define MT6370_TCPC_DID_A 0x2170 + +struct mt6370_priv { + struct device *dev; + struct regulator *vbus; + struct tcpci *tcpci; + struct tcpci_data tcpci_data; +}; + +static const struct reg_sequence mt6370_reg_init[] = { + REG_SEQ(0xA0, 0x1, 1000), + REG_SEQ(0x81, 0x38, 0), + REG_SEQ(0x82, 0x82, 0), + REG_SEQ(0xBA, 0xFC, 0), + REG_SEQ(0xBB, 0x50, 0), + REG_SEQ(0x9E, 0x8F, 0), + REG_SEQ(0xA1, 0x5, 0), + REG_SEQ(0xA2, 0x4, 0), + REG_SEQ(0xA3, 0x4A, 0), + REG_SEQ(0xA4, 0x01, 0), + REG_SEQ(0x95, 0x01, 0), + REG_SEQ(0x80, 0x71, 0), + REG_SEQ(0x9B, 0x3A, 1000), +}; + +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data) +{ + u16 did; + int ret; + + ret = regmap_register_patch(data->regmap, mt6370_reg_init, + ARRAY_SIZE(mt6370_reg_init)); + if (ret) + return ret; + + ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16)); + if (ret) + return ret; + + if (did == MT6370_TCPC_DID_A) + return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80); + + return 0; +} + +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data, + bool enable) +{ + return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8, + MT6370_AUTOIDLE_MASK, + enable ? 0 : MT6370_AUTOIDLE_MASK); +} + +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data, + bool source, bool sink) +{ + struct mt6370_priv *priv = container_of(data, struct mt6370_priv, + tcpci_data); + int ret; + + ret = regulator_is_enabled(priv->vbus); + if (ret < 0) + return ret; + + if (ret && !source) + return regulator_disable(priv->vbus); + + if (!ret && source) + return regulator_enable(priv->vbus); + + return 0; +} + +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id) +{ + struct mt6370_priv *priv = dev_id; + + return tcpci_irq(priv->tcpci); +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + struct regmap *regmap = priv->tcpci_data.regmap; + u16 vid; + int ret; + + ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16)); + if (ret) + return ret; + + if (vid != MT6370_VENDOR_ID) + return dev_err_probe(priv->dev, -ENODEV, + "Vendor ID not correct 0x%02x\n", vid); + + return 0; +} + +static void mt6370_unregister_tcpci_port(void *tcpci) +{ + tcpci_unregister_port(tcpci); +} + +static int mt6370_tcpc_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct device *dev = &pdev->dev; + int irq, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL); + if (!priv->tcpci_data.regmap) + return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n"); + + ret = mt6370_check_vendor_info(priv); + if (ret) + return ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get irq\n"); + + /* Assign TCPCI feature and ops */ + priv->tcpci_data.auto_discharge_disconnect = 1; + priv->tcpci_data.init = mt6370_tcpc_init; + priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn; + + priv->vbus = devm_regulator_get_optional(dev, "vbus"); + if (!IS_ERR(priv->vbus)) + priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus; + + priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data); + if (IS_ERR(priv->tcpci)) + return dev_err_probe(dev, PTR_ERR(priv->tcpci), + "Failed to register tcpci port\n"); + + ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port, priv->tcpci); + if (ret) + return ret; + + ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler, + IRQF_ONESHOT, dev_name(dev), priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to allocate irq\n"); + + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, irq); + + return 0; +} + +static int mt6370_tcpc_remove(struct platform_device *pdev) +{ + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + + return 0; +} + +static const struct of_device_id mt6370_tcpc_devid_table[] = { + { .compatible = "mediatek,mt6370-tcpc" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table); + +static struct platform_driver mt6370_tcpc_driver = { + .driver = { + .name = "mt6370-tcpc", + .of_match_table = mt6370_tcpc_devid_table, + }, + .probe = mt6370_tcpc_probe, + .remove = mt6370_tcpc_remove, +}; +module_platform_driver(mt6370_tcpc_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 35a78bb83c310dd042b0a7fb8f397ed8973b768f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 Aug 2022 13:30:18 +0100 Subject: usb: typec: ucsi: stm32g0: Fix spelling mistake "booloader" -> "bootloader" There is a spelling mistake in a dev_err_probe message. Fix it. Reviewed-by: Heikki Krogerus Reviewed-by: Fabrice Gasnier Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220803123018.913710-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 061551d464f1..6ced49e4d208 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -599,7 +599,7 @@ static int ucsi_stm32g0_probe_bootloader(struct ucsi *ucsi) g0->i2c_bl = i2c_new_dummy_device(g0->client->adapter, STM32G0_I2C_BL_ADDR); if (IS_ERR(g0->i2c_bl)) { ret = dev_err_probe(g0->dev, PTR_ERR(g0->i2c_bl), - "Failed to register booloader I2C address\n"); + "Failed to register bootloader I2C address\n"); return ret; } } -- cgit From 3b77b27155647dda2edc7f347ecc3b2828978d52 Mon Sep 17 00:00:00 2001 From: Gene Chen Date: Fri, 5 Aug 2022 15:17:08 +0800 Subject: usb: typec: tcpci_rt1711h: Fix vendor setting when set vconn replace overwrite whole register with update bits Reviewed-by: Heikki Krogerus Reviewed-by: Guenter Roeck Signed-off-by: Gene Chen Link: https://lore.kernel.org/r/20220805071714.150882-3-gene.chen.richtek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index 3291ca4948da..f2f1fb0d8bab 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -5,6 +5,7 @@ * Richtek RT1711H Type-C Chip Driver */ +#include #include #include #include @@ -23,6 +24,7 @@ #define RT1711H_RTCTRL8_SET(ck300, ship_off, auto_idle, tout) \ (((ck300) << 7) | ((ship_off) << 5) | \ ((auto_idle) << 3) | ((tout) & 0x07)) +#define RT1711H_AUTOIDLEEN BIT(3) #define RT1711H_RTCTRL11 0x9E @@ -109,8 +111,8 @@ static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata, { struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); - return rt1711h_write8(chip, RT1711H_RTCTRL8, - RT1711H_RTCTRL8_SET(0, 1, !enable, 2)); + return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL8, + RT1711H_AUTOIDLEEN, enable ? 0 : RT1711H_AUTOIDLEEN); } static int rt1711h_start_drp_toggling(struct tcpci *tcpci, -- cgit From 1e50ceb0397c14d7e934c65d862b499013847d9f Mon Sep 17 00:00:00 2001 From: Gene Chen Date: Fri, 5 Aug 2022 15:17:09 +0800 Subject: usb: typec: tcpci_rt1711h: Add regulator support when source vbus Add regulator support when source vbus Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Gene Chen Link: https://lore.kernel.org/r/20220805071714.150882-4-gene.chen.richtek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index f2f1fb0d8bab..fb19d7bf9d1c 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -14,6 +14,7 @@ #include #include #include +#include #define RT1711H_VID 0x29CF #define RT1711H_PID 0x1711 @@ -41,6 +42,8 @@ struct rt1711h_chip { struct tcpci_data data; struct tcpci *tcpci; struct device *dev; + struct regulator *vbus; + bool src_en; }; static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val) @@ -104,6 +107,26 @@ static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) /* dcSRC.DRP : 33% */ return rt1711h_write16(chip, RT1711H_RTCTRL16, 330); + +} + +static int rt1711h_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, + bool src, bool snk) +{ + struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); + int ret; + + if (chip->src_en == src) + return 0; + + if (src) + ret = regulator_enable(chip->vbus); + else + ret = regulator_disable(chip->vbus); + + if (!ret) + chip->src_en = src; + return ret; } static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata, @@ -247,7 +270,12 @@ static int rt1711h_probe(struct i2c_client *client, if (ret < 0) return ret; + chip->vbus = devm_regulator_get(&client->dev, "vbus"); + if (IS_ERR(chip->vbus)) + return PTR_ERR(chip->vbus); + chip->data.init = rt1711h_init; + chip->data.set_vbus = rt1711h_set_vbus; 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); -- cgit From a2ed34df5a11bd054a6588584cad174d62707f6e Mon Sep 17 00:00:00 2001 From: Gene Chen Date: Fri, 5 Aug 2022 15:17:10 +0800 Subject: usb: typec: tcpci_rt1711h: Add initial phy setting Add initial phy setting about phy dicard retry, rx filter deglitch time and BMC-encoded wait time Reviewed-by: Guenter Roeck Reviewed-by: Heikki Krogerus Signed-off-by: Gene Chen Link: https://lore.kernel.org/r/20220805071714.150882-5-gene.chen.richtek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index fb19d7bf9d1c..5c51d0474cfa 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -19,6 +19,9 @@ #define RT1711H_VID 0x29CF #define RT1711H_PID 0x1711 +#define RT1711H_PHYCTRL1 0x80 +#define RT1711H_PHYCTRL2 0x81 + #define RT1711H_RTCTRL8 0x9B /* Autoidle timeout = (tout * 2 + 1) * 6.4ms */ @@ -106,8 +109,18 @@ static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) return ret; /* dcSRC.DRP : 33% */ - return rt1711h_write16(chip, RT1711H_RTCTRL16, 330); + ret = rt1711h_write16(chip, RT1711H_RTCTRL16, 330); + if (ret < 0) + return ret; + + /* Enable phy discard retry, retry count 7, rx filter deglitch 100 us */ + ret = rt1711h_write8(chip, RT1711H_PHYCTRL1, 0xF1); + if (ret < 0) + return ret; + /* Decrease wait time of BMC-encoded 1 bit from 2.67us to 2.55us */ + /* wait time : (val * .4167) us */ + return rt1711h_write8(chip, RT1711H_PHYCTRL2, 62); } static int rt1711h_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, -- cgit From 24b5c2c824c526f5aff105463463cc15027b4cd2 Mon Sep 17 00:00:00 2001 From: Gene Chen Date: Fri, 5 Aug 2022 15:17:11 +0800 Subject: usb: typec: tcpci_rt1711h: Add compatible id with rt1715 Add compatible id with rt1715, and add initial setting for specific support PD30 command. Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Gene Chen Link: https://lore.kernel.org/r/20220805071714.150882-6-gene.chen.richtek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 43 +++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index 5c51d0474cfa..ff7deae69549 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -18,6 +18,8 @@ #define RT1711H_VID 0x29CF #define RT1711H_PID 0x1711 +#define RT1711H_DID 0x2171 +#define RT1715_DID 0x2173 #define RT1711H_PHYCTRL1 0x80 #define RT1711H_PHYCTRL2 0x81 @@ -29,6 +31,7 @@ (((ck300) << 7) | ((ship_off) << 5) | \ ((auto_idle) << 3) | ((tout) & 0x07)) #define RT1711H_AUTOIDLEEN BIT(3) +#define RT1711H_ENEXTMSG BIT(4) #define RT1711H_RTCTRL11 0x9E @@ -47,6 +50,7 @@ struct rt1711h_chip { struct device *dev; struct regulator *vbus; bool src_en; + u16 did; }; static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val) @@ -83,8 +87,9 @@ static struct rt1711h_chip *tdata_to_rt1711h(struct tcpci_data *tdata) static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) { - int ret; struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); + struct regmap *regmap = chip->data.regmap; + int ret; /* CK 300K from 320K, shipping off, auto_idle enable, tout = 32ms */ ret = rt1711h_write8(chip, RT1711H_RTCTRL8, @@ -92,6 +97,14 @@ static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) if (ret < 0) return ret; + /* Enable PD30 extended message for RT1715 */ + if (chip->did == RT1715_DID) { + ret = regmap_update_bits(regmap, RT1711H_RTCTRL8, + RT1711H_ENEXTMSG, RT1711H_ENEXTMSG); + if (ret < 0) + return ret; + } + /* I2C reset : (val + 1) * 12.5ms */ ret = rt1711h_write8(chip, RT1711H_RTCTRL11, RT1711H_RTCTRL11_SET(1, 0x0F)); @@ -229,7 +242,7 @@ static int rt1711h_sw_reset(struct rt1711h_chip *chip) return 0; } -static int rt1711h_check_revision(struct i2c_client *i2c) +static int rt1711h_check_revision(struct i2c_client *i2c, struct rt1711h_chip *chip) { int ret; @@ -247,7 +260,15 @@ static int rt1711h_check_revision(struct i2c_client *i2c) dev_err(&i2c->dev, "pid is not correct, 0x%04x\n", ret); return -ENODEV; } - return 0; + ret = i2c_smbus_read_word_data(i2c, TCPC_BCD_DEV); + if (ret < 0) + return ret; + if (ret != chip->did) { + dev_err(&i2c->dev, "did is not correct, 0x%04x\n", ret); + return -ENODEV; + } + dev_dbg(&i2c->dev, "did is 0x%04x\n", ret); + return ret; } static int rt1711h_probe(struct i2c_client *client, @@ -256,16 +277,18 @@ static int rt1711h_probe(struct i2c_client *client, int ret; struct rt1711h_chip *chip; - ret = rt1711h_check_revision(client); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->did = (size_t)device_get_match_data(&client->dev); + + ret = rt1711h_check_revision(client, chip); 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)) @@ -316,13 +339,15 @@ static int rt1711h_remove(struct i2c_client *client) static const struct i2c_device_id rt1711h_id[] = { { "rt1711h", 0 }, + { "rt1715", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt1711h_id); #ifdef CONFIG_OF static const struct of_device_id rt1711h_of_match[] = { - { .compatible = "richtek,rt1711h", }, + { .compatible = "richtek,rt1711h", .data = (void *)RT1711H_DID }, + { .compatible = "richtek,rt1715", .data = (void *)RT1715_DID }, {}, }; MODULE_DEVICE_TABLE(of, rt1711h_of_match); -- cgit From 2c8cc0946c14c39b02748fba34325ecae636530a Mon Sep 17 00:00:00 2001 From: Gene Chen Date: Fri, 5 Aug 2022 15:17:12 +0800 Subject: usb: typec: tcpci: Move function "tcpci_to_typec_cc" to common Move transition function "tcpci_to_typec_cc" to common header Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Gene Chen Link: https://lore.kernel.org/r/20220805071714.150882-7-gene.chen.richtek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 812784702d53..50674ecf430d 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -27,11 +27,6 @@ #define VPPS_VALID_MIN_MV 100 #define VSINKDISCONNECT_PD_MIN_PERCENT 90 -#define tcpc_presenting_rd(reg, cc) \ - (!(TCPC_ROLE_CTRL_DRP & (reg)) && \ - (((reg) & (TCPC_ROLE_CTRL_## cc ##_MASK << TCPC_ROLE_CTRL_## cc ##_SHIFT)) == \ - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_## cc ##_SHIFT))) - struct tcpci { struct device *dev; @@ -218,23 +213,6 @@ static int tcpci_start_toggling(struct tcpc_dev *tcpc, 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; - fallthrough; - 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) { -- cgit From e80cec306ac88f05d7d4c34e9309d38360ccec7d Mon Sep 17 00:00:00 2001 From: Gene Chen Date: Fri, 5 Aug 2022 15:17:13 +0800 Subject: usb: typec: tcpci_rt1711h: Fix CC PHY noise filter of voltage level Fix CC PHY noise filter of voltage level according to current cc voltage level Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Gene Chen Link: https://lore.kernel.org/r/20220805071714.150882-8-gene.chen.richtek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 58 +++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index ff7deae69549..5dc34f9d9f51 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -24,8 +24,11 @@ #define RT1711H_PHYCTRL1 0x80 #define RT1711H_PHYCTRL2 0x81 -#define RT1711H_RTCTRL8 0x9B +#define RT1711H_RTCTRL4 0x93 +/* rx threshold of rd/rp: 1b0 for level 0.4V/0.7V, 1b1 for 0.35V/0.75V */ +#define RT1711H_BMCIO_RXDZSEL BIT(0) +#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) | \ @@ -44,6 +47,10 @@ #define RT1711H_RTCTRL15 0xA2 #define RT1711H_RTCTRL16 0xA3 +#define RT1711H_RTCTRL18 0xAF +/* 1b0 as fixed rx threshold of rd/rp 0.55V, 1b1 depends on RTCRTL4[0] */ +#define BMCIO_RXDZEN BIT(0) + struct rt1711h_chip { struct tcpci_data data; struct tcpci *tcpci; @@ -164,6 +171,53 @@ static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata, RT1711H_AUTOIDLEEN, enable ? 0 : RT1711H_AUTOIDLEEN); } +/* + * Selects the CC PHY noise filter voltage level according to the remote current + * CC voltage level. + * + * @status: The port's current cc status read from IC + * Return 0 if writes succeed; failure code otherwise + */ +static inline int rt1711h_init_cc_params(struct rt1711h_chip *chip, u8 status) +{ + int ret, cc1, cc2; + u8 role = 0; + u32 rxdz_en, rxdz_sel; + + ret = rt1711h_read8(chip, TCPC_ROLE_CTRL, &role); + if (ret < 0) + return ret; + + cc1 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC1_SHIFT) & + TCPC_CC_STATUS_CC1_MASK, + status & TCPC_CC_STATUS_TERM || + tcpc_presenting_rd(role, CC1)); + cc2 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC2_SHIFT) & + TCPC_CC_STATUS_CC2_MASK, + status & TCPC_CC_STATUS_TERM || + tcpc_presenting_rd(role, CC2)); + + if ((cc1 >= TYPEC_CC_RP_1_5 && cc2 < TYPEC_CC_RP_DEF) || + (cc2 >= TYPEC_CC_RP_1_5 && cc1 < TYPEC_CC_RP_DEF)) { + rxdz_en = BMCIO_RXDZEN; + if (chip->did == RT1715_DID) + rxdz_sel = RT1711H_BMCIO_RXDZSEL; + else + rxdz_sel = 0; + } else { + rxdz_en = 0; + rxdz_sel = RT1711H_BMCIO_RXDZSEL; + } + + ret = regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL18, + BMCIO_RXDZEN, rxdz_en); + if (ret < 0) + return ret; + + return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL4, + RT1711H_BMCIO_RXDZSEL, rxdz_sel); +} + static int rt1711h_start_drp_toggling(struct tcpci *tcpci, struct tcpci_data *tdata, enum typec_cc_status cc) @@ -224,6 +278,8 @@ static irqreturn_t rt1711h_irq(int irq, void *dev_id) /* Clear cc change event triggered by starting toggling */ if (status & TCPC_CC_STATUS_TOGGLING) rt1711h_write8(chip, TCPC_ALERT, TCPC_ALERT_CC_STATUS); + else + rt1711h_init_cc_params(chip, status); } out: -- cgit From b7db5733a5ace9acc1f3104c9050c5aa1363f13b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Aug 2022 23:01:15 +0200 Subject: usb: move from strlcpy with unused retval to strscpy Follow the advice of the below link and prefer 'strscpy' in this subsystem. Conversion is 1:1 because the return value is not used. Generated by a coccinelle script. Link: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/ Reviewed-by: Richard Leitner Reviewed-by: Laurent Pinchart Acked-by: Shuah Khan Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20220818210116.7517-1-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/fusb302.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 96c55eaf3f80..ab89c014606e 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -151,7 +151,7 @@ static void _fusb302_log(struct fusb302_chip *chip, const char *fmt, if (fusb302_log_full(chip)) { chip->logbuffer_head = max(chip->logbuffer_head - 1, 0); - strlcpy(tmpbuffer, "overflow", sizeof(tmpbuffer)); + strscpy(tmpbuffer, "overflow", sizeof(tmpbuffer)); } if (chip->logbuffer_head < 0 || -- cgit From e45d7337dc0e4f7f1c2876e1b22c71a544ad12fd Mon Sep 17 00:00:00 2001 From: Liang He Date: Thu, 15 Sep 2022 17:22:09 +0800 Subject: usb: typec: anx7411: Use of_get_child_by_name() instead of of_find_node_by_name() In anx7411_typec_switch_probe(), we should call of_get_child_by_name() instead of of_find_node_by_name() as of_find_xxx API will decrease the refcount of the 'from' argument. Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") Acked-by: Heikki Krogerus Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220915092209.4009273-1-windhl@126.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index c0f0842d443c..f178d0eb47b1 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -1105,7 +1105,7 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx, int ret; struct device_node *node; - node = of_find_node_by_name(dev->of_node, "orientation_switch"); + node = of_get_child_by_name(dev->of_node, "orientation_switch"); if (!node) return 0; @@ -1115,7 +1115,7 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx, return ret; } - node = of_find_node_by_name(dev->of_node, "mode_switch"); + node = of_get_child_by_name(dev->of_node, "mode_switch"); if (!node) { dev_err(dev, "no typec mux exist"); ret = -ENODEV; -- cgit From 759fcaaf600e56ec0a33678e85f317c5347562c7 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 22 Sep 2022 21:52:28 +0800 Subject: usb: typec: stusb160x: Switch to use dev_err_probe() helper In the probe path, dev_err() can be replaced with dev_err_probe() which will check if error code is -EPROBE_DEFER and prints the error name. It also sets the defer probe reason which can be checked later through debugfs. It's more simple in error path. Signed-off-by: Yang Yingliang Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220922135228.2206755-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/stusb160x.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c index e7745d1c2a5c..283fa3ed0d93 100644 --- a/drivers/usb/typec/stusb160x.c +++ b/drivers/usb/typec/stusb160x.c @@ -750,11 +750,8 @@ static int stusb160x_probe(struct i2c_client *client) if (client->irq) { chip->role_sw = fwnode_usb_role_switch_get(fwnode); if (IS_ERR(chip->role_sw)) { - ret = PTR_ERR(chip->role_sw); - if (ret != -EPROBE_DEFER) - dev_err(chip->dev, - "Failed to get usb role switch: %d\n", - ret); + ret = dev_err_probe(chip->dev, PTR_ERR(chip->role_sw), + "Failed to get usb role switch\n"); goto port_unregister; } -- cgit From 3eab90ae9f5b8e7c40a619c4c8aadf9bcd8c24cf Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 22 Sep 2022 21:57:08 +0800 Subject: usb: typec: qcom-pmic-typec: Switch to use dev_err_probe() helper In the probe path, dev_err() can be replaced with dev_err_probe() which will check if error code is -EPROBE_DEFER and prints the error name. It also sets the defer probe reason which can be checked later through debugfs. It's more simple in error path. Signed-off-by: Yang Yingliang Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220922135708.2212249-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/qcom-pmic-typec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/qcom-pmic-typec.c b/drivers/usb/typec/qcom-pmic-typec.c index a0454a80c4a2..432ea62f1bab 100644 --- a/drivers/usb/typec/qcom-pmic-typec.c +++ b/drivers/usb/typec/qcom-pmic-typec.c @@ -195,9 +195,8 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) qcom_usb->role_sw = fwnode_usb_role_switch_get(dev_fwnode(qcom_usb->dev)); if (IS_ERR(qcom_usb->role_sw)) { - if (PTR_ERR(qcom_usb->role_sw) != -EPROBE_DEFER) - dev_err(dev, "failed to get role switch\n"); - ret = PTR_ERR(qcom_usb->role_sw); + ret = dev_err_probe(dev, PTR_ERR(qcom_usb->role_sw), + "failed to get role switch\n"); goto err_typec_port; } -- cgit From a075590c0aa2b9d1bc1204bf8ea97519aef2994a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 22 Sep 2022 21:48:06 +0800 Subject: usb: typec: fusb302: Switch to use dev_err_probe() helper In the probe path, dev_err() can be replaced with dev_err_probe() which will check if error code is -EPROBE_DEFER and prints the error name. It also sets the defer probe reason which can be checked later through debugfs. It's more simple in error path. Signed-off-by: Yang Yingliang Reviewed-by: Heikki Krogerus Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220922134806.2204579-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/fusb302.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index ab89c014606e..b0699bef985e 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -1743,9 +1743,8 @@ static int fusb302_probe(struct i2c_client *client, chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev); if (IS_ERR(chip->tcpm_port)) { fwnode_handle_put(chip->tcpc_dev.fwnode); - ret = PTR_ERR(chip->tcpm_port); - if (ret != -EPROBE_DEFER) - dev_err(dev, "cannot register tcpm port, ret=%d", ret); + ret = dev_err_probe(dev, PTR_ERR(chip->tcpm_port), + "cannot register tcpm port\n"); goto destroy_workqueue; } -- cgit From fce703a991b7e8c7e1371de95b9abaa832ecf9c3 Mon Sep 17 00:00:00 2001 From: Wayne Chang Date: Tue, 27 Sep 2022 21:45:12 +0800 Subject: usb: typec: ucsi: Don't warn on probe deferral Deferred probe is an expected return value for fwnode_usb_role_switch_get(). Given that the driver deals with it properly, there's no need to output a warning that may potentially confuse users. -- V2 -> V3: remove the Fixes and Cc V1 -> V2: adjust the coding style for better reading format. drivers/usb/typec/ucsi/ucsi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) Signed-off-by: Wayne Chang Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220927134512.2651067-1-waynec@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 7f2624f42724..e961ebecd7df 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1069,11 +1069,9 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) cap->fwnode = ucsi_find_fwnode(con); con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode); - if (IS_ERR(con->usb_role_sw)) { - dev_err(ucsi->dev, "con%d: failed to get usb role switch\n", - con->num); - return PTR_ERR(con->usb_role_sw); - } + if (IS_ERR(con->usb_role_sw)) + return dev_err_probe(ucsi->dev, PTR_ERR(con->usb_role_sw), + "con%d: failed to get usb role switch\n", con->num); /* Delay other interactions with the con until registration is complete */ mutex_lock(&con->lock); -- cgit From c9180362a920b99f2aef7d55b89ae94b8138474e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 27 Sep 2022 20:19:24 +0300 Subject: usb: typec: Replace custom implementation of device_match_fwnode() Replace custom implementation of the device_match_fwnode(). Signed-off-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220927171924.61908-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux.c | 4 ++-- drivers/usb/typec/retimer.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index 464330776cd6..941735c73161 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -29,7 +29,7 @@ static int switch_fwnode_match(struct device *dev, const void *fwnode) if (!is_typec_switch_dev(dev)) return 0; - return dev_fwnode(dev) == fwnode; + return device_match_fwnode(dev, fwnode); } static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id, @@ -259,7 +259,7 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode) if (!is_typec_mux_dev(dev)) return 0; - return dev_fwnode(dev) == fwnode; + return device_match_fwnode(dev, fwnode); } static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id, diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c index 2003731f1bee..ee94dbbe4745 100644 --- a/drivers/usb/typec/retimer.c +++ b/drivers/usb/typec/retimer.c @@ -31,7 +31,7 @@ static bool dev_name_ends_with(struct device *dev, const char *suffix) static int retimer_fwnode_match(struct device *dev, const void *fwnode) { - return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-retimer"); + return device_match_fwnode(dev, fwnode) && dev_name_ends_with(dev, "-retimer"); } static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data) -- cgit From 691f43cbfe631488cc3fe2d01658fd372c9ef0a7 Mon Sep 17 00:00:00 2001 From: Sing-Han Chen Date: Wed, 28 Sep 2022 23:08:40 +0800 Subject: usb: typec: ucsi_ccg: Disable UCSI ALT support on Tegra Firmware built for Tegra doesn't support UCSI ALT command and has known issue of reporting wrong capability info. This commit disables UCSI ALT support when reading the capability on Tegra. Signed-off-by: Sing-Han Chen Signed-off-by: Wayne Chang Link: https://lore.kernel.org/r/20220928150840.3804313-1-waynec@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_ccg.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/usb/typec') diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 5c0bf48be766..cbd93f893e48 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -125,6 +125,11 @@ struct version_format { #define CCG_FW_BUILD_NVIDIA (('n' << 8) | 'v') #define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10)) +/* Firmware for Tegra doesn't support UCSI ALT command, built + * for NVIDIA has known issue of reporting wrong capability info + */ +#define CCG_FW_BUILD_NVIDIA_TEGRA (('g' << 8) | 'n') + /* Altmode offset for NVIDIA Function Test Board (FTB) */ #define NVIDIA_FTB_DP_OFFSET (2) #define NVIDIA_FTB_DBG_OFFSET (3) @@ -513,6 +518,7 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); + struct ucsi_capability *cap; struct ucsi_altmode *alt; int ret; @@ -536,6 +542,12 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, ucsi_ccg_nvidia_altmode(uc, alt); } break; + case UCSI_GET_CAPABILITY: + if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) { + cap = val; + cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS; + } + break; default: break; } -- cgit