OSDN Git Service

usb: typec: ucsi: save power data objects in PD mode
authorK V, Abhilash <abhilash.k.v@intel.com>
Thu, 23 Apr 2020 13:20:57 +0000 (16:20 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Apr 2020 13:33:34 +0000 (15:33 +0200)
When connected to a PD-capable power-source, read & save all partner
power data objects (PDOs) by using GET_PDOS UCSI command.
Also, save the current power contract in request data object (RDO)
for that connector.

Signed-off-by: K V, Abhilash <abhilash.k.v@intel.com>
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20200423132058.6972-6-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi.h

index 0c7c3f9..ffea795 100644 (file)
@@ -492,19 +492,45 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient)
        }
 }
 
+static void ucsi_get_pdos(struct ucsi_connector *con, int is_partner)
+{
+       struct ucsi *ucsi = con->ucsi;
+       u64 command;
+       int ret;
+
+       command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num);
+       command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner);
+       command |= UCSI_GET_PDOS_NUM_PDOS(UCSI_MAX_PDOS - 1);
+       command |= UCSI_GET_PDOS_SRC_PDOS;
+       ret = ucsi_run_command(ucsi, command, con->src_pdos,
+                              sizeof(con->src_pdos));
+       if (ret < 0) {
+               dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret);
+               return;
+       }
+       con->num_pdos = ret / sizeof(u32); /* number of bytes to 32-bit PDOs */
+       if (ret == 0)
+               dev_warn(ucsi->dev, "UCSI_GET_PDOS returned 0 bytes\n");
+}
+
 static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
 {
        switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
        case UCSI_CONSTAT_PWR_OPMODE_PD:
+               con->rdo = con->status.request_data_obj;
                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD);
+               ucsi_get_pdos(con, 1);
                break;
        case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
+               con->rdo = 0;
                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_1_5A);
                break;
        case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
+               con->rdo = 0;
                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_3_0A);
                break;
        default:
+               con->rdo = 0;
                typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_USB);
                break;
        }
index f068356..28e21a1 100644 (file)
@@ -130,6 +130,11 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
 #define UCSI_GET_ALTMODE_OFFSET(_r_)           ((u64)(_r_) << 32)
 #define UCSI_GET_ALTMODE_NUM_ALTMODES(_r_)     ((u64)(_r_) << 40)
 
+/* GET_PDOS command bits */
+#define UCSI_GET_PDOS_PARTNER_PDO(_r_)         ((u64)(_r_) << 23)
+#define UCSI_GET_PDOS_NUM_PDOS(_r_)            ((u64)(_r_) << 32)
+#define UCSI_GET_PDOS_SRC_PDOS                 ((u64)1 << 34)
+
 /* -------------------------------------------------------------------------- */
 
 /* Error information returned by PPM in response to GET_ERROR_STATUS command. */
@@ -294,6 +299,7 @@ struct ucsi {
 
 #define UCSI_MAX_SVID          5
 #define UCSI_MAX_ALTMODES      (UCSI_MAX_SVID * 6)
+#define UCSI_MAX_PDOS          (4)
 
 struct ucsi_connector {
        int num;
@@ -313,6 +319,9 @@ struct ucsi_connector {
 
        struct ucsi_connector_status status;
        struct ucsi_connector_capability cap;
+       u32 rdo;
+       u32 src_pdos[UCSI_MAX_PDOS];
+       int num_pdos;
 };
 
 int ucsi_send_command(struct ucsi *ucsi, u64 command,