]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: typec: ucsi: Add support for READ_POWER_LEVEL command
authorVenkat Jayaraman <venkat.jayaraman@intel.com>
Thu, 14 Aug 2025 16:30:28 +0000 (09:30 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 17 Aug 2025 10:16:18 +0000 (12:16 +0200)
Add support for UCSI READ_POWER_LEVEL command as per
UCSI specification v2.1 and above to debugfs.

Following power related fields will be exposed as files in debugfs:-
peak_current (Peak current),
avg_current (Average current) and
vbus_voltage (VBUS voltage)

These files will be updated either when a READ_POWER_LEVEL
command is sent from OS or when a device is connected.

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Venkat Jayaraman <venkat.jayaraman@intel.com>
Link: https://lore.kernel.org/r/20250814163028.18058-1-venkat.jayaraman@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/ucsi/debugfs.c
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi.h

index 92ebf1a2defd20c51fcc5c75035d72808ac6bbc1..f73f2b54554e2afe64d8c235952c2ffdd8449421 100644 (file)
@@ -35,6 +35,7 @@ static int ucsi_cmd(void *data, u64 val)
        case UCSI_SET_SINK_PATH:
        case UCSI_SET_NEW_CAM:
        case UCSI_SET_USB:
+       case UCSI_READ_POWER_LEVEL:
                ret = ucsi_send_command(ucsi, val, NULL, 0);
                break;
        case UCSI_GET_CAPABILITY:
@@ -80,6 +81,33 @@ static int ucsi_resp_show(struct seq_file *s, void *not_used)
 }
 DEFINE_SHOW_ATTRIBUTE(ucsi_resp);
 
+static int ucsi_peak_curr_show(struct seq_file *m, void *v)
+{
+       struct ucsi *ucsi = m->private;
+
+       seq_printf(m, "%u mA\n", ucsi->connector->peak_current);
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ucsi_peak_curr);
+
+static int ucsi_avg_curr_show(struct seq_file *m, void *v)
+{
+       struct ucsi *ucsi = m->private;
+
+       seq_printf(m, "%u mA\n", ucsi->connector->avg_current);
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ucsi_avg_curr);
+
+static int ucsi_vbus_volt_show(struct seq_file *m, void *v)
+{
+       struct ucsi *ucsi = m->private;
+
+       seq_printf(m, "%u mV\n", ucsi->connector->vbus_voltage);
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ucsi_vbus_volt);
+
 void ucsi_debugfs_register(struct ucsi *ucsi)
 {
        ucsi->debugfs = kzalloc(sizeof(*ucsi->debugfs), GFP_KERNEL);
@@ -89,6 +117,9 @@ void ucsi_debugfs_register(struct ucsi *ucsi)
        ucsi->debugfs->dentry = debugfs_create_dir(dev_name(ucsi->dev), ucsi_debugfs_root);
        debugfs_create_file("command", 0200, ucsi->debugfs->dentry, ucsi, &ucsi_cmd_fops);
        debugfs_create_file("response", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_resp_fops);
+       debugfs_create_file("peak_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_peak_curr_fops);
+       debugfs_create_file("avg_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_avg_curr_fops);
+       debugfs_create_file("vbus_voltage", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_vbus_volt_fops);
 }
 
 void ucsi_debugfs_unregister(struct ucsi *ucsi)
index 5739ea2abdd1a7c3b09d8f79c0dac43c75eb6837..0d6b0cf5a7cd757e863342142ab9b66b37449aab 100644 (file)
@@ -1217,9 +1217,11 @@ static void ucsi_handle_connector_change(struct work_struct *work)
        struct ucsi_connector *con = container_of(work, struct ucsi_connector,
                                                  work);
        struct ucsi *ucsi = con->ucsi;
+       u8 curr_scale, volt_scale;
        enum typec_role role;
        u16 change;
        int ret;
+       u32 val;
 
        mutex_lock(&con->lock);
 
@@ -1291,6 +1293,20 @@ static void ucsi_handle_connector_change(struct work_struct *work)
        if (change & UCSI_CONSTAT_BC_CHANGE)
                ucsi_port_psy_changed(con);
 
+       if (UCSI_CONSTAT(con, PWR_READING_READY_V2_1)) {
+               curr_scale = UCSI_CONSTAT(con, CURRENT_SCALE_V2_1);
+               volt_scale = UCSI_CONSTAT(con, VOLTAGE_SCALE_V2_1);
+
+               val = UCSI_CONSTAT(con, PEAK_CURRENT_V2_1);
+               con->peak_current = UCSI_CONSTAT_CURR_SCALE_MULT * curr_scale * val;
+
+               val = UCSI_CONSTAT(con, AVG_CURRENT_V2_1);
+               con->avg_current = UCSI_CONSTAT_CURR_SCALE_MULT * curr_scale * val;
+
+               val = UCSI_CONSTAT(con, VBUS_VOLTAGE_V2_1);
+               con->vbus_voltage = UCSI_CONSTAT_VOLT_SCALE_MULT * volt_scale * val;
+       }
+
 out_unlock:
        mutex_unlock(&con->lock);
 }
index ebd7c27c2cc766d5e3778baa91e85d2dbffa789f..e301d9012936fb85eaff7f260a862ff099eb77c5 100644 (file)
@@ -131,6 +131,7 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
 #define UCSI_GET_PD_MESSAGE                    0x15
 #define UCSI_GET_CAM_CS                        0x18
 #define UCSI_SET_SINK_PATH                     0x1c
+#define UCSI_READ_POWER_LEVEL                  0x1e
 #define UCSI_SET_USB                           0x21
 #define UCSI_GET_LPM_PPM_INFO                  0x22
 
@@ -359,6 +360,14 @@ struct ucsi_cable_property {
 #define   UCSI_CONSTAT_BC_SLOW_CHARGING                2
 #define   UCSI_CONSTAT_BC_TRICKLE_CHARGING     3
 #define UCSI_CONSTAT_PD_VERSION_V1_2           UCSI_DECLARE_BITFIELD_V1_2(70, 16)
+#define UCSI_CONSTAT_PWR_READING_READY_V2_1    UCSI_DECLARE_BITFIELD_V2_1(89, 1)
+#define UCSI_CONSTAT_CURRENT_SCALE_V2_1                UCSI_DECLARE_BITFIELD_V2_1(90, 3)
+#define UCSI_CONSTAT_PEAK_CURRENT_V2_1         UCSI_DECLARE_BITFIELD_V2_1(93, 16)
+#define UCSI_CONSTAT_AVG_CURRENT_V2_1          UCSI_DECLARE_BITFIELD_V2_1(109, 16)
+#define UCSI_CONSTAT_VOLTAGE_SCALE_V2_1                UCSI_DECLARE_BITFIELD_V2_1(125, 4)
+#define UCSI_CONSTAT_VBUS_VOLTAGE_V2_1         UCSI_DECLARE_BITFIELD_V2_1(129, 16)
+#define UCSI_CONSTAT_CURR_SCALE_MULT           5
+#define UCSI_CONSTAT_VOLT_SCALE_MULT           5
 
 /* Connector Status Change Bits.  */
 #define UCSI_CONSTAT_EXT_SUPPLY_CHANGE         BIT(1)
@@ -519,6 +528,10 @@ struct ucsi_connector {
        u32 src_pdos[PDO_MAX_OBJECTS];
        int num_pdos;
 
+       u32 peak_current;
+       u32 avg_current;
+       u32 vbus_voltage;
+
        /* USB PD objects */
        struct usb_power_delivery *pd;
        struct usb_power_delivery_capabilities *port_source_caps;