]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
usb: typec: tcpci: add support to set connector orientation
authorMarco Felsch <m.felsch@pengutronix.de>
Mon, 1 Jul 2024 13:21:24 +0000 (15:21 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jul 2024 14:05:38 +0000 (16:05 +0200)
This add the support to set the optional connector orientation bit which
is part of the optional CONFIG_STANDARD_OUTPUT register 0x18 [1]. This
allows system designers to connect the tcpc orientation pin directly to
the 2:1 ss-mux.

[1] https://www.usb.org/sites/default/files/documents/usb-port_controller_specification_rev2.0_v1.0_0.pdf

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20240701132133.3054394-1-m.felsch@pengutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/tcpm/tcpci.c
include/linux/usb/tcpci.h

index c962014bba4e85e8585f2e2ab6677ef8b4d9b34f..8a18d561b063ba97163174998f6d41765be3c3f3 100644 (file)
@@ -67,6 +67,18 @@ static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
        return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u16));
 }
 
+static bool tcpci_check_std_output_cap(struct regmap *regmap, u8 mask)
+{
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(regmap, TCPC_STD_OUTPUT_CAP, &reg);
+       if (ret < 0)
+               return ret;
+
+       return (reg & mask) == mask;
+}
+
 static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -301,6 +313,28 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
                           TCPC_TCPC_CTRL_ORIENTATION : 0);
 }
 
+static int tcpci_set_orientation(struct tcpc_dev *tcpc,
+                                enum typec_orientation orientation)
+{
+       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+       unsigned int reg;
+
+       switch (orientation) {
+       case TYPEC_ORIENTATION_NONE:
+               /* We can't put a single output into high impedance */
+               fallthrough;
+       case TYPEC_ORIENTATION_NORMAL:
+               reg = TCPC_CONFIG_STD_OUTPUT_ORIENTATION_NORMAL;
+               break;
+       case TYPEC_ORIENTATION_REVERSE:
+               reg = TCPC_CONFIG_STD_OUTPUT_ORIENTATION_FLIPPED;
+               break;
+       }
+
+       return regmap_update_bits(tcpci->regmap, TCPC_CONFIG_STD_OUTPUT,
+                                 TCPC_CONFIG_STD_OUTPUT_ORIENTATION_MASK, reg);
+}
+
 static void tcpci_set_partner_usb_comm_capable(struct tcpc_dev *tcpc, bool capable)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -830,6 +864,9 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
        if (tcpci->data->vbus_vsafe0v)
                tcpci->tcpc.is_vbus_vsafe0v = tcpci_is_vbus_vsafe0v;
 
+       if (tcpci->data->set_orientation)
+               tcpci->tcpc.set_orientation = tcpci_set_orientation;
+
        err = tcpci_parse_config(tcpci);
        if (err < 0)
                return ERR_PTR(err);
@@ -873,6 +910,13 @@ static int tcpci_probe(struct i2c_client *client)
        if (err < 0)
                return err;
 
+       err = tcpci_check_std_output_cap(chip->data.regmap,
+                                        TCPC_STD_OUTPUT_CAP_ORIENTATION);
+       if (err < 0)
+               return err;
+
+       chip->data.set_orientation = err;
+
        chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
        if (IS_ERR(chip->tcpci))
                return PTR_ERR(chip->tcpci);
index 47a86b8a4a507b3c1e5719f27bed37fe3d3b42c2..0ab39b6ea205d54a3af794f12018942e944daa20 100644 (file)
@@ -47,6 +47,9 @@
 #define TCPC_SINK_FAST_ROLE_SWAP       BIT(0)
 
 #define TCPC_CONFIG_STD_OUTPUT         0x18
+#define TCPC_CONFIG_STD_OUTPUT_ORIENTATION_MASK                BIT(0)
+#define TCPC_CONFIG_STD_OUTPUT_ORIENTATION_NORMAL      0
+#define TCPC_CONFIG_STD_OUTPUT_ORIENTATION_FLIPPED     1
 
 #define TCPC_TCPC_CTRL                 0x19
 #define TCPC_TCPC_CTRL_ORIENTATION     BIT(0)
 #define TCPC_DEV_CAP_2                 0x26
 #define TCPC_STD_INPUT_CAP             0x28
 #define TCPC_STD_OUTPUT_CAP            0x29
+#define TCPC_STD_OUTPUT_CAP_ORIENTATION        BIT(0)
 
 #define TCPC_MSG_HDR_INFO              0x2e
 #define TCPC_MSG_HDR_INFO_DATA_ROLE    BIT(3)
@@ -209,6 +213,9 @@ struct tcpci;
  *             swap following Discover Identity on SOP' occurs.
  *             Return true when the TCPM is allowed to request a Vconn swap
  *             after Discovery Identity on SOP.
+ * @set_orientation:
+ *             Optional; Enable setting the connector orientation
+ *             CONFIG_STANDARD_OUTPUT (0x18) bit0.
  */
 struct tcpci_data {
        struct regmap *regmap;
@@ -216,6 +223,7 @@ struct tcpci_data {
        unsigned char auto_discharge_disconnect:1;
        unsigned char vbus_vsafe0v:1;
        unsigned char cable_comm_capable:1;
+       unsigned char set_orientation:1;
 
        int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
        int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,