If the chip indicates its "Connection Orientation" standard output control
in STANDARD_OUTPUT_CAPABILITIES register, it can do the thing by
programming CONFIG_STANDARD_OUTPUT register. Due to the optional feature,
the chip which not present this capability currently doesn't have a way to
correctly set the data path. This add the support to set orientation via
a simple GPIO.
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
drivers/usb/typec/tcpm/tcpci.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index 2a951c585e92..079b7d574253 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
@@ -42,6 +43,7 @@ struct tcpci {
struct tcpc_dev tcpc;
struct tcpci_data *data;
+ struct gpio_desc *orientation_gpio;
};
struct tcpci_chip {
@@ -328,6 +330,10 @@ static int tcpci_set_orientation(struct tcpc_dev *tcpc,
break;
}
+ if (tcpci->orientation_gpio)
+ gpiod_set_value_cansleep(tcpci->orientation_gpio,
+ orientation == TYPEC_ORIENTATION_NORMAL ? 0 : 1);
+
return regmap_update_bits(tcpci->regmap, TCPC_CONFIG_STD_OUTPUT,
TCPC_CONFIG_STD_OUTPUT_ORIENTATION_MASK, reg);
}
@@ -903,6 +909,7 @@ EXPORT_SYMBOL_GPL(tcpci_unregister_port);
static int tcpci_probe(struct i2c_client *client)
{
struct tcpci_chip *chip;
+ struct gpio_desc *orient_gpio = NULL;
int err;
u16 val = 0;
@@ -931,12 +938,23 @@ static int tcpci_probe(struct i2c_client *client)
if (err < 0)
return err;
+ if (err == 0) {
+ orient_gpio = devm_gpiod_get_optional(&client->dev, "orientation",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(orient_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(orient_gpio),
+ "unable to acquire orientation gpio\n");
+ err = !!orient_gpio;
+ }
+
chip->data.set_orientation = err;
chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
if (IS_ERR(chip->tcpci))
return PTR_ERR(chip->tcpci);
+ chip->tcpci->orientation_gpio = orient_gpio;
+
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
_tcpci_irq,
IRQF_SHARED | IRQF_ONESHOT,
--
2.34.1
From: Frank Li (AI-BOT) <frank.li@nxp.com>
> + if (err == 0) {
> + orient_gpio = devm_gpiod_get_optional(&client->dev, "orientation",
> + GPIOD_OUT_LOW);
> + if (IS_ERR(orient_gpio))
> + return dev_err_probe(&client->dev, PTR_ERR(orient_gpio),
> + "unable to acquire orientation gpio\n");
> + err = !!orient_gpio;
> + }
AI: The logic here is confusing. You're converting a pointer to a boolean with
`!!orient_gpio`, then assigning it to `err`. This overwrites the error code
and makes the intent unclear. Consider using a separate flag variable or
restructuring to keep error handling explicit.
> + chip->tcpci->orientation_gpio = orient_gpio;
> +
> + err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
AI: This assignment happens after `tcpci_register_port()` returns. If that
function or any subsequent code path fails before this line, the GPIO
pointer is never stored in the chip structure. Consider moving the
assignment immediately after the GPIO acquisition, or ensure the pointer
is initialized in the struct at declaration time.
Frank
© 2016 - 2026 Red Hat, Inc.