Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: typec: Separate USB Power Delivery from USB Type-C

Introducing a small device class for USB Power Delivery.
The idea with it is that we do not mix any more USB Power
Delivery information into the USB Type-C connectors only.
This separation will make it possible to register USB Power
Delivery devices also from other places, for example from
USB Type-C Bridges (see USB Type-C Bridge Specification).

The device class will not always deal with only the messages
and objects that were negotiated with the partner, but
instead messages and objects that can be used in the
negotiation. That allows the USB PD devices to be shared and
reconfigured. The ports can decide which objects are to be
advertised to the partner before the contract is negotiated.
It is also possible to allow the user space to make that
decision if needed.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20220502132058.86236-2-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Heikki Krogerus and committed by
Greg Kroah-Hartman
662a6010 f061f43d

+1027 -1
+240
Documentation/ABI/testing/sysfs-class-usb_power_delivery
··· 1 + What: /sys/class/usb_power_delivery 2 + Date: May 2022 3 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 4 + Description: 5 + Directory for USB Power Delivery devices. 6 + 7 + What: /sys/class/usb_power_delivery/.../revision 8 + Date: May 2022 9 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 10 + Description: 11 + File showing the USB Power Delivery Specification Revision used 12 + in communication. 13 + 14 + What: /sys/class/usb_power_delivery/.../version 15 + Date: May 2022 16 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 17 + Description: 18 + This is an optional attribute file showing the version of the 19 + specific revision of the USB Power Delivery Specification. In 20 + most cases the specification version is not known and the file 21 + is not available. 22 + 23 + What: /sys/class/usb_power_delivery/.../source-capabilities 24 + Date: May 2022 25 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 26 + Description: 27 + The source capabilities message "Source_Capabilities" contains a 28 + set of Power Data Objects (PDO), each representing a type of 29 + power supply. The order of the PDO objects is defined in the USB 30 + Power Delivery Specification. Each PDO - power supply - will 31 + have its own device, and the PDO device name will start with the 32 + object position number as the first character followed by the 33 + power supply type name (":" as delimiter). 34 + 35 + /sys/class/usb_power_delivery/.../source_capabilities/<position>:<type> 36 + 37 + What: /sys/class/usb_power_delivery/.../sink-capabilities 38 + Date: May 2022 39 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 40 + Description: 41 + The sink capability message "Sink_Capabilities" contains a set 42 + of Power Data Objects (PDO) just like with source capabilities, 43 + but instead of describing the power capabilities, these objects 44 + describe the power requirements. 45 + 46 + The order of the objects in the sink capability message is the 47 + same as with the source capabilities message. 48 + 49 + Fixed Supplies 50 + 51 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:fixed_supply 52 + Date: May 2022 53 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 54 + Description: 55 + Devices containing the attributes (the bit fields) defined for 56 + Fixed Supplies. 57 + 58 + The device "1:fixed_supply" is special. USB Power Delivery 59 + Specification dictates that the first PDO (at object position 60 + 1), and the only mandatory PDO, is always the vSafe5V Fixed 61 + Supply Object. vSafe5V Object has additional fields defined for 62 + it that the other Fixed Supply Objects do not have and that are 63 + related to the USB capabilities rather than power capabilities. 64 + 65 + What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/dual_role_power 66 + Date: May 2022 67 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 68 + Description: 69 + This file contains boolean value that tells does the device 70 + support both source and sink power roles. 71 + 72 + What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/usb_suspend_supported 73 + Date: May 2022 74 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 75 + Description: 76 + This file shows the value of the USB Suspend Supported bit in 77 + vSafe5V Fixed Supply Object. If the bit is set then the device 78 + will follow the USB 2.0 and USB 3.2 rules for suspend and 79 + resume. 80 + 81 + What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/unconstrained_power 82 + Date: May 2022 83 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 84 + Description: 85 + This file shows the value of the Unconstrained Power bit in 86 + vSafe5V Fixed Supply Object. The bit is set when an external 87 + source of power, powerful enough to power the entire system on 88 + its own, is available for the device. 89 + 90 + What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/usb_communication_capable 91 + Date: May 2022 92 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 93 + Description: 94 + This file shows the value of the USB Communication Capable bit in 95 + vSafe5V Fixed Supply Object. 96 + 97 + What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/dual_role_data 98 + Date: May 2022 99 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 100 + Description: 101 + This file shows the value of the Dual-Role Data bit in vSafe5V 102 + Fixed Supply Object. Dual role data means ability act as both 103 + USB host and USB device. 104 + 105 + What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/unchunked_extended_messages_supported 106 + Date: May 2022 107 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 108 + Description: 109 + This file shows the value of the Unchunked Extended Messages 110 + Supported bit in vSafe5V Fixed Supply Object. 111 + 112 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:fixed_supply/voltage 113 + Date: May 2022 114 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 115 + Description: 116 + The voltage the supply supports in millivolts. 117 + 118 + What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:fixed_supply/maximum_current 119 + Date: May 2022 120 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 121 + Description: 122 + Maximum current of the fixed source supply in milliamperes. 123 + 124 + What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:fixed_supply/operational_current 125 + Date: May 2022 126 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 127 + Description: 128 + Operational current of the sink in milliamperes. 129 + 130 + What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:fixed_supply/fast_role_swap_current 131 + Date: May 2022 132 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 133 + Description: 134 + This file contains the value of the "Fast Role Swap USB Type-C 135 + Current" field that tells the current level the sink requires 136 + after a Fast Role Swap. 137 + 0 - Fast Swap not supported" 138 + 1 - Default USB Power" 139 + 2 - 1.5A@5V" 140 + 3 - 3.0A@5V" 141 + 142 + Variable Supplies 143 + 144 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:variable_supply 145 + Date: May 2022 146 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 147 + Description: 148 + Variable Power Supply PDO. 149 + 150 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:variable_supply/maximum_voltage 151 + Date: May 2022 152 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 153 + Description: 154 + Maximum Voltage in millivolts. 155 + 156 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:variable_supply/minimum_voltage 157 + Date: May 2022 158 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 159 + Description: 160 + Minimum Voltage in millivolts. 161 + 162 + What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:variable_supply/maximum_current 163 + Date: May 2022 164 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 165 + Description: 166 + The maximum current in milliamperes that the source can supply 167 + at the given Voltage range. 168 + 169 + What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:variable_supply/operational_current 170 + Date: May 2022 171 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 172 + Description: 173 + The operational current in milliamperes that the sink requires 174 + at the given Voltage range. 175 + 176 + Battery Supplies 177 + 178 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:battery 179 + Date: May 2022 180 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 181 + Description: 182 + Battery PDO. 183 + 184 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:battery/maximum_voltage 185 + Date: May 2022 186 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 187 + Description: 188 + Maximum Voltage in millivolts. 189 + 190 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:battery/minimum_voltage 191 + Date: May 2022 192 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 193 + Description: 194 + Minimum Voltage in millivolts. 195 + 196 + What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:battery/maximum_power 197 + Date: May 2022 198 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 199 + Description: 200 + Maximum allowable Power in milliwatts. 201 + 202 + What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:battery/operational_power 203 + Date: May 2022 204 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 205 + Description: 206 + The operational power that the sink requires at the given 207 + voltage range. 208 + 209 + Standard Power Range (SPR) Programmable Power Supplies 210 + 211 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply 212 + Date: May 2022 213 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 214 + Description: 215 + Programmable Power Supply (PPS) Augmented PDO (APDO). 216 + 217 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply/maximum_voltage 218 + Date: May 2022 219 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 220 + Description: 221 + Maximum Voltage in millivolts. 222 + 223 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply/minimum_voltage 224 + Date: May 2022 225 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 226 + Description: 227 + Minimum Voltage in millivolts. 228 + 229 + What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply/maximum_current 230 + Date: May 2022 231 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 232 + Description: 233 + Maximum Current in milliamperes. 234 + 235 + What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:programmable_supply/pps_power_limited 236 + Date: May 2022 237 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 238 + Description: 239 + The PPS Power Limited bit indicates whether or not the source 240 + supply will exceed the rated output power if requested.
+1 -1
drivers/usb/typec/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_TYPEC) += typec.o 3 - typec-y := class.o mux.o bus.o 3 + typec-y := class.o mux.o bus.o pd.o 4 4 typec-$(CONFIG_ACPI) += port-mapper.o 5 5 obj-$(CONFIG_TYPEC) += altmodes/ 6 6 obj-$(CONFIG_TYPEC_TCPM) += tcpm/
+708
drivers/usb/typec/pd.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * USB Power Delivery sysfs entries 4 + * 5 + * Copyright (C) 2022, Intel Corporation 6 + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 7 + */ 8 + 9 + #include <linux/slab.h> 10 + #include <linux/usb/pd.h> 11 + 12 + #include "pd.h" 13 + 14 + static DEFINE_IDA(pd_ida); 15 + 16 + static struct class pd_class = { 17 + .name = "usb_power_delivery", 18 + .owner = THIS_MODULE, 19 + }; 20 + 21 + #define to_pdo(o) container_of(o, struct pdo, dev) 22 + 23 + struct pdo { 24 + struct device dev; 25 + int object_position; 26 + u32 pdo; 27 + }; 28 + 29 + static void pdo_release(struct device *dev) 30 + { 31 + kfree(to_pdo(dev)); 32 + } 33 + 34 + /* -------------------------------------------------------------------------- */ 35 + /* Fixed Supply */ 36 + 37 + static ssize_t 38 + dual_role_power_show(struct device *dev, struct device_attribute *attr, char *buf) 39 + { 40 + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DUAL_ROLE)); 41 + } 42 + static DEVICE_ATTR_RO(dual_role_power); 43 + 44 + static ssize_t 45 + usb_suspend_supported_show(struct device *dev, struct device_attribute *attr, char *buf) 46 + { 47 + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_SUSPEND)); 48 + } 49 + static DEVICE_ATTR_RO(usb_suspend_supported); 50 + 51 + static ssize_t 52 + unconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf) 53 + { 54 + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER)); 55 + } 56 + static DEVICE_ATTR_RO(unconstrained_power); 57 + 58 + static ssize_t 59 + usb_communication_capable_show(struct device *dev, struct device_attribute *attr, char *buf) 60 + { 61 + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_USB_COMM)); 62 + } 63 + static DEVICE_ATTR_RO(usb_communication_capable); 64 + 65 + static ssize_t 66 + dual_role_data_show(struct device *dev, struct device_attribute *attr, char *buf) 67 + { 68 + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DATA_SWAP)); 69 + } 70 + static DEVICE_ATTR_RO(dual_role_data); 71 + 72 + static ssize_t 73 + unchunked_extended_messages_supported_show(struct device *dev, 74 + struct device_attribute *attr, char *buf) 75 + { 76 + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_UNCHUNK_EXT)); 77 + } 78 + static DEVICE_ATTR_RO(unchunked_extended_messages_supported); 79 + 80 + /* 81 + * REVISIT: Peak Current requires access also to the RDO. 82 + static ssize_t 83 + peak_current_show(struct device *dev, struct device_attribute *attr, char *buf) 84 + { 85 + ... 86 + } 87 + */ 88 + 89 + static ssize_t 90 + fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf) 91 + { 92 + return sysfs_emit(buf, "%u\n", to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3; 93 + } 94 + static DEVICE_ATTR_RO(fast_role_swap_current); 95 + 96 + static ssize_t voltage_show(struct device *dev, struct device_attribute *attr, char *buf) 97 + { 98 + return sysfs_emit(buf, "%umV\n", pdo_fixed_voltage(to_pdo(dev)->pdo)); 99 + } 100 + static DEVICE_ATTR_RO(voltage); 101 + 102 + /* Shared with Variable supplies, both source and sink */ 103 + static ssize_t current_show(struct device *dev, struct device_attribute *attr, char *buf) 104 + { 105 + return sysfs_emit(buf, "%umA\n", pdo_max_current(to_pdo(dev)->pdo)); 106 + } 107 + 108 + /* Shared with Variable type supplies */ 109 + static struct device_attribute maximum_current_attr = { 110 + .attr = { 111 + .name = "maximum_current", 112 + .mode = 0444, 113 + }, 114 + .show = current_show, 115 + }; 116 + 117 + static struct device_attribute operational_current_attr = { 118 + .attr = { 119 + .name = "operational_current", 120 + .mode = 0444, 121 + }, 122 + .show = current_show, 123 + }; 124 + 125 + static struct attribute *source_fixed_supply_attrs[] = { 126 + &dev_attr_dual_role_power.attr, 127 + &dev_attr_usb_suspend_supported.attr, 128 + &dev_attr_unconstrained_power.attr, 129 + &dev_attr_usb_communication_capable.attr, 130 + &dev_attr_dual_role_data.attr, 131 + &dev_attr_unchunked_extended_messages_supported.attr, 132 + /*&dev_attr_peak_current.attr,*/ 133 + &dev_attr_voltage.attr, 134 + &maximum_current_attr.attr, 135 + NULL 136 + }; 137 + 138 + static umode_t fixed_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) 139 + { 140 + if (to_pdo(kobj_to_dev(kobj))->object_position && 141 + /*attr != &dev_attr_peak_current.attr &&*/ 142 + attr != &dev_attr_voltage.attr && 143 + attr != &maximum_current_attr.attr && 144 + attr != &operational_current_attr.attr) 145 + return 0; 146 + 147 + return attr->mode; 148 + } 149 + 150 + static const struct attribute_group source_fixed_supply_group = { 151 + .is_visible = fixed_attr_is_visible, 152 + .attrs = source_fixed_supply_attrs, 153 + }; 154 + __ATTRIBUTE_GROUPS(source_fixed_supply); 155 + 156 + static struct device_type source_fixed_supply_type = { 157 + .name = "pdo", 158 + .release = pdo_release, 159 + .groups = source_fixed_supply_groups, 160 + }; 161 + 162 + static struct attribute *sink_fixed_supply_attrs[] = { 163 + &dev_attr_dual_role_power.attr, 164 + &dev_attr_usb_suspend_supported.attr, 165 + &dev_attr_unconstrained_power.attr, 166 + &dev_attr_usb_communication_capable.attr, 167 + &dev_attr_dual_role_data.attr, 168 + &dev_attr_unchunked_extended_messages_supported.attr, 169 + &dev_attr_fast_role_swap_current.attr, 170 + &dev_attr_voltage.attr, 171 + &operational_current_attr.attr, 172 + NULL 173 + }; 174 + 175 + static const struct attribute_group sink_fixed_supply_group = { 176 + .is_visible = fixed_attr_is_visible, 177 + .attrs = sink_fixed_supply_attrs, 178 + }; 179 + __ATTRIBUTE_GROUPS(sink_fixed_supply); 180 + 181 + static struct device_type sink_fixed_supply_type = { 182 + .name = "pdo", 183 + .release = pdo_release, 184 + .groups = sink_fixed_supply_groups, 185 + }; 186 + 187 + /* -------------------------------------------------------------------------- */ 188 + /* Variable Supply */ 189 + 190 + static ssize_t 191 + maximum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) 192 + { 193 + return sysfs_emit(buf, "%umV\n", pdo_max_voltage(to_pdo(dev)->pdo)); 194 + } 195 + static DEVICE_ATTR_RO(maximum_voltage); 196 + 197 + static ssize_t 198 + minimum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) 199 + { 200 + return sysfs_emit(buf, "%umV\n", pdo_min_voltage(to_pdo(dev)->pdo)); 201 + } 202 + static DEVICE_ATTR_RO(minimum_voltage); 203 + 204 + static struct attribute *source_variable_supply_attrs[] = { 205 + &dev_attr_maximum_voltage.attr, 206 + &dev_attr_minimum_voltage.attr, 207 + &maximum_current_attr.attr, 208 + NULL 209 + }; 210 + ATTRIBUTE_GROUPS(source_variable_supply); 211 + 212 + static struct device_type source_variable_supply_type = { 213 + .name = "pdo", 214 + .release = pdo_release, 215 + .groups = source_variable_supply_groups, 216 + }; 217 + 218 + static struct attribute *sink_variable_supply_attrs[] = { 219 + &dev_attr_maximum_voltage.attr, 220 + &dev_attr_minimum_voltage.attr, 221 + &operational_current_attr.attr, 222 + NULL 223 + }; 224 + ATTRIBUTE_GROUPS(sink_variable_supply); 225 + 226 + static struct device_type sink_variable_supply_type = { 227 + .name = "pdo", 228 + .release = pdo_release, 229 + .groups = sink_variable_supply_groups, 230 + }; 231 + 232 + /* -------------------------------------------------------------------------- */ 233 + /* Battery */ 234 + 235 + static ssize_t 236 + maximum_power_show(struct device *dev, struct device_attribute *attr, char *buf) 237 + { 238 + return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); 239 + } 240 + static DEVICE_ATTR_RO(maximum_power); 241 + 242 + static ssize_t 243 + operational_power_show(struct device *dev, struct device_attribute *attr, char *buf) 244 + { 245 + return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); 246 + } 247 + static DEVICE_ATTR_RO(operational_power); 248 + 249 + static struct attribute *source_battery_attrs[] = { 250 + &dev_attr_maximum_voltage.attr, 251 + &dev_attr_minimum_voltage.attr, 252 + &dev_attr_maximum_power.attr, 253 + NULL 254 + }; 255 + ATTRIBUTE_GROUPS(source_battery); 256 + 257 + static struct device_type source_battery_type = { 258 + .name = "pdo", 259 + .release = pdo_release, 260 + .groups = source_battery_groups, 261 + }; 262 + 263 + static struct attribute *sink_battery_attrs[] = { 264 + &dev_attr_maximum_voltage.attr, 265 + &dev_attr_minimum_voltage.attr, 266 + &dev_attr_operational_power.attr, 267 + NULL 268 + }; 269 + ATTRIBUTE_GROUPS(sink_battery); 270 + 271 + static struct device_type sink_battery_type = { 272 + .name = "pdo", 273 + .release = pdo_release, 274 + .groups = sink_battery_groups, 275 + }; 276 + 277 + /* -------------------------------------------------------------------------- */ 278 + /* Standard Power Range (SPR) Programmable Power Supply (PPS) */ 279 + 280 + static ssize_t 281 + pps_power_limited_show(struct device *dev, struct device_attribute *attr, char *buf) 282 + { 283 + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & BIT(27))); 284 + } 285 + static DEVICE_ATTR_RO(pps_power_limited); 286 + 287 + static ssize_t 288 + pps_max_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) 289 + { 290 + return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_max_voltage(to_pdo(dev)->pdo)); 291 + } 292 + 293 + static ssize_t 294 + pps_min_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) 295 + { 296 + return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_min_voltage(to_pdo(dev)->pdo)); 297 + } 298 + 299 + static ssize_t 300 + pps_max_current_show(struct device *dev, struct device_attribute *attr, char *buf) 301 + { 302 + return sysfs_emit(buf, "%umA\n", pdo_pps_apdo_max_current(to_pdo(dev)->pdo)); 303 + } 304 + 305 + static struct device_attribute pps_max_voltage_attr = { 306 + .attr = { 307 + .name = "maximum_voltage", 308 + .mode = 0444, 309 + }, 310 + .show = pps_max_voltage_show, 311 + }; 312 + 313 + static struct device_attribute pps_min_voltage_attr = { 314 + .attr = { 315 + .name = "minimum_voltage", 316 + .mode = 0444, 317 + }, 318 + .show = pps_min_voltage_show, 319 + }; 320 + 321 + static struct device_attribute pps_max_current_attr = { 322 + .attr = { 323 + .name = "maximum_current", 324 + .mode = 0444, 325 + }, 326 + .show = pps_max_current_show, 327 + }; 328 + 329 + static struct attribute *source_pps_attrs[] = { 330 + &dev_attr_pps_power_limited.attr, 331 + &pps_max_voltage_attr.attr, 332 + &pps_min_voltage_attr.attr, 333 + &pps_max_current_attr.attr, 334 + NULL 335 + }; 336 + ATTRIBUTE_GROUPS(source_pps); 337 + 338 + static struct device_type source_pps_type = { 339 + .name = "pdo", 340 + .release = pdo_release, 341 + .groups = source_pps_groups, 342 + }; 343 + 344 + static struct attribute *sink_pps_attrs[] = { 345 + &pps_max_voltage_attr.attr, 346 + &pps_min_voltage_attr.attr, 347 + &pps_max_current_attr.attr, 348 + NULL 349 + }; 350 + ATTRIBUTE_GROUPS(sink_pps); 351 + 352 + static struct device_type sink_pps_type = { 353 + .name = "pdo", 354 + .release = pdo_release, 355 + .groups = sink_pps_groups, 356 + }; 357 + 358 + /* -------------------------------------------------------------------------- */ 359 + 360 + static const char * const supply_name[] = { 361 + [PDO_TYPE_FIXED] = "fixed_supply", 362 + [PDO_TYPE_BATT] = "battery", 363 + [PDO_TYPE_VAR] = "variable_supply", 364 + }; 365 + 366 + static const char * const apdo_supply_name[] = { 367 + [APDO_TYPE_PPS] = "programmable_supply", 368 + }; 369 + 370 + static struct device_type *source_type[] = { 371 + [PDO_TYPE_FIXED] = &source_fixed_supply_type, 372 + [PDO_TYPE_BATT] = &source_battery_type, 373 + [PDO_TYPE_VAR] = &source_variable_supply_type, 374 + }; 375 + 376 + static struct device_type *source_apdo_type[] = { 377 + [APDO_TYPE_PPS] = &source_pps_type, 378 + }; 379 + 380 + static struct device_type *sink_type[] = { 381 + [PDO_TYPE_FIXED] = &sink_fixed_supply_type, 382 + [PDO_TYPE_BATT] = &sink_battery_type, 383 + [PDO_TYPE_VAR] = &sink_variable_supply_type, 384 + }; 385 + 386 + static struct device_type *sink_apdo_type[] = { 387 + [APDO_TYPE_PPS] = &sink_pps_type, 388 + }; 389 + 390 + /* REVISIT: Export when EPR_*_Capabilities need to be supported. */ 391 + static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position) 392 + { 393 + struct device_type *type; 394 + const char *name; 395 + struct pdo *p; 396 + int ret; 397 + 398 + p = kzalloc(sizeof(*p), GFP_KERNEL); 399 + if (!p) 400 + return -ENOMEM; 401 + 402 + p->pdo = pdo; 403 + p->object_position = position; 404 + 405 + if (pdo_type(pdo) == PDO_TYPE_APDO) { 406 + /* FIXME: Only PPS supported for now! Skipping others. */ 407 + if (pdo_apdo_type(pdo) > APDO_TYPE_PPS) { 408 + dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo); 409 + kfree(p); 410 + return 0; 411 + } 412 + 413 + if (is_source(cap->role)) 414 + type = source_apdo_type[pdo_apdo_type(pdo)]; 415 + else 416 + type = sink_apdo_type[pdo_apdo_type(pdo)]; 417 + 418 + name = apdo_supply_name[pdo_apdo_type(pdo)]; 419 + } else { 420 + if (is_source(cap->role)) 421 + type = source_type[pdo_type(pdo)]; 422 + else 423 + type = sink_type[pdo_type(pdo)]; 424 + 425 + name = supply_name[pdo_type(pdo)]; 426 + } 427 + 428 + p->dev.parent = &cap->dev; 429 + p->dev.type = type; 430 + dev_set_name(&p->dev, "%u:%s", position + 1, name); 431 + 432 + ret = device_register(&p->dev); 433 + if (ret) { 434 + put_device(&p->dev); 435 + return ret; 436 + } 437 + 438 + return 0; 439 + } 440 + 441 + static int remove_pdo(struct device *dev, void *data) 442 + { 443 + device_unregister(dev); 444 + return 0; 445 + } 446 + 447 + /* -------------------------------------------------------------------------- */ 448 + 449 + static const char * const cap_name[] = { 450 + [TYPEC_SINK] = "sink-capabilities", 451 + [TYPEC_SOURCE] = "source-capabilities", 452 + }; 453 + 454 + static void pd_capabilities_release(struct device *dev) 455 + { 456 + kfree(to_usb_power_delivery_capabilities(dev)); 457 + } 458 + 459 + static struct device_type pd_capabilities_type = { 460 + .name = "capabilities", 461 + .release = pd_capabilities_release, 462 + }; 463 + 464 + /** 465 + * usb_power_delivery_register_capabilities - Register a set of capabilities. 466 + * @pd: The USB PD instance that the capabilities belong to. 467 + * @desc: Description of the Capablities Message. 468 + * 469 + * This function registers a Capabilities Message described in @desc. The 470 + * capabilities will have their own sub-directory under @pd in sysfs. 471 + * 472 + * The function returns pointer to struct usb_power_delivery_capabilities, or 473 + * ERR_PRT(errno). 474 + */ 475 + struct usb_power_delivery_capabilities * 476 + usb_power_delivery_register_capabilities(struct usb_power_delivery *pd, 477 + struct usb_power_delivery_capabilities_desc *desc) 478 + { 479 + struct usb_power_delivery_capabilities *cap; 480 + int ret; 481 + int i; 482 + 483 + cap = kzalloc(sizeof(*cap), GFP_KERNEL); 484 + if (!cap) 485 + return ERR_PTR(-ENOMEM); 486 + 487 + cap->pd = pd; 488 + cap->role = desc->role; 489 + 490 + cap->dev.parent = &pd->dev; 491 + cap->dev.type = &pd_capabilities_type; 492 + dev_set_name(&cap->dev, "%s", cap_name[cap->role]); 493 + 494 + ret = device_register(&cap->dev); 495 + if (ret) { 496 + put_device(&cap->dev); 497 + return ERR_PTR(ret); 498 + } 499 + 500 + for (i = 0; i < PDO_MAX_OBJECTS && desc->pdo[i]; i++) { 501 + ret = add_pdo(cap, desc->pdo[i], i); 502 + if (ret) { 503 + usb_power_delivery_unregister_capabilities(cap); 504 + return ERR_PTR(ret); 505 + } 506 + } 507 + 508 + return cap; 509 + } 510 + EXPORT_SYMBOL_GPL(usb_power_delivery_register_capabilities); 511 + 512 + /** 513 + * usb_power_delivery_unregister_capabilities - Unregister a set of capabilities 514 + * @cap: The capabilities 515 + */ 516 + void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap) 517 + { 518 + if (!cap) 519 + return; 520 + 521 + device_for_each_child(&cap->dev, NULL, remove_pdo); 522 + device_unregister(&cap->dev); 523 + } 524 + EXPORT_SYMBOL_GPL(usb_power_delivery_unregister_capabilities); 525 + 526 + /* -------------------------------------------------------------------------- */ 527 + 528 + static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) 529 + { 530 + struct usb_power_delivery *pd = to_usb_power_delivery(dev); 531 + 532 + return sysfs_emit(buf, "%u.%u\n", (pd->revision >> 8) & 0xff, (pd->revision >> 4) & 0xf); 533 + } 534 + static DEVICE_ATTR_RO(revision); 535 + 536 + static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) 537 + { 538 + struct usb_power_delivery *pd = to_usb_power_delivery(dev); 539 + 540 + return sysfs_emit(buf, "%u.%u\n", (pd->version >> 8) & 0xff, (pd->version >> 4) & 0xf); 541 + } 542 + static DEVICE_ATTR_RO(version); 543 + 544 + static struct attribute *pd_attrs[] = { 545 + &dev_attr_revision.attr, 546 + &dev_attr_version.attr, 547 + NULL 548 + }; 549 + 550 + static umode_t pd_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) 551 + { 552 + struct usb_power_delivery *pd = to_usb_power_delivery(kobj_to_dev(kobj)); 553 + 554 + if (attr == &dev_attr_version.attr && !pd->version) 555 + return 0; 556 + 557 + return attr->mode; 558 + } 559 + 560 + static const struct attribute_group pd_group = { 561 + .is_visible = pd_attr_is_visible, 562 + .attrs = pd_attrs, 563 + }; 564 + __ATTRIBUTE_GROUPS(pd); 565 + 566 + static void pd_release(struct device *dev) 567 + { 568 + struct usb_power_delivery *pd = to_usb_power_delivery(dev); 569 + 570 + ida_simple_remove(&pd_ida, pd->id); 571 + kfree(pd); 572 + } 573 + 574 + static struct device_type pd_type = { 575 + .name = "usb_power_delivery", 576 + .release = pd_release, 577 + .groups = pd_groups, 578 + }; 579 + 580 + struct usb_power_delivery *usb_power_delivery_find(const char *name) 581 + { 582 + struct device *dev; 583 + 584 + dev = class_find_device_by_name(&pd_class, name); 585 + 586 + return dev ? to_usb_power_delivery(dev) : NULL; 587 + } 588 + 589 + /** 590 + * usb_power_delivery_register - Register USB Power Delivery Support. 591 + * @parent: Parent device. 592 + * @desc: Description of the USB PD contract. 593 + * 594 + * This routine can be used to register USB Power Delivery capabilities that a 595 + * device or devices can support. These capabilities represent all the 596 + * capabilities that can be negotiated with a partner, so not only the Power 597 + * Capabilities that are negotiated using the USB PD Capabilities Message. 598 + * 599 + * The USB Power Delivery Support object that this routine generates can be used 600 + * as the parent object for all the actual USB Power Delivery Messages and 601 + * objects that can be negotiated with the partner. 602 + * 603 + * Returns handle to struct usb_power_delivery or ERR_PTR. 604 + */ 605 + struct usb_power_delivery * 606 + usb_power_delivery_register(struct device *parent, struct usb_power_delivery_desc *desc) 607 + { 608 + struct usb_power_delivery *pd; 609 + int ret; 610 + 611 + pd = kzalloc(sizeof(*pd), GFP_KERNEL); 612 + if (!pd) 613 + return ERR_PTR(-ENOMEM); 614 + 615 + ret = ida_simple_get(&pd_ida, 0, 0, GFP_KERNEL); 616 + if (ret < 0) { 617 + kfree(pd); 618 + return ERR_PTR(ret); 619 + } 620 + 621 + pd->id = ret; 622 + pd->revision = desc->revision; 623 + pd->version = desc->version; 624 + 625 + pd->dev.parent = parent; 626 + pd->dev.type = &pd_type; 627 + pd->dev.class = &pd_class; 628 + dev_set_name(&pd->dev, "pd%d", pd->id); 629 + 630 + ret = device_register(&pd->dev); 631 + if (ret) { 632 + put_device(&pd->dev); 633 + return ERR_PTR(ret); 634 + } 635 + 636 + return pd; 637 + } 638 + EXPORT_SYMBOL_GPL(usb_power_delivery_register); 639 + 640 + /** 641 + * usb_power_delivery_unregister - Unregister USB Power Delivery Support. 642 + * @pd: The USB PD contract. 643 + */ 644 + void usb_power_delivery_unregister(struct usb_power_delivery *pd) 645 + { 646 + if (IS_ERR_OR_NULL(pd)) 647 + return; 648 + 649 + device_unregister(&pd->dev); 650 + } 651 + EXPORT_SYMBOL_GPL(usb_power_delivery_unregister); 652 + 653 + /** 654 + * usb_power_delivery_link_device - Link device to its USB PD object. 655 + * @pd: The USB PD instance. 656 + * @dev: The device. 657 + * 658 + * This function can be used to create a symlink named "usb_power_delivery" for 659 + * @dev that points to @pd. 660 + */ 661 + int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev) 662 + { 663 + int ret; 664 + 665 + if (IS_ERR_OR_NULL(pd) || !dev) 666 + return 0; 667 + 668 + ret = sysfs_create_link(&dev->kobj, &pd->dev.kobj, "usb_power_delivery"); 669 + if (ret) 670 + return ret; 671 + 672 + get_device(&pd->dev); 673 + get_device(dev); 674 + 675 + return 0; 676 + } 677 + EXPORT_SYMBOL_GPL(usb_power_delivery_link_device); 678 + 679 + /** 680 + * usb_power_delivery_unlink_device - Unlink device from its USB PD object. 681 + * @pd: The USB PD instance. 682 + * @dev: The device. 683 + * 684 + * Remove the symlink that was previously created with pd_link_device(). 685 + */ 686 + void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev) 687 + { 688 + if (IS_ERR_OR_NULL(pd) || !dev) 689 + return; 690 + 691 + sysfs_remove_link(&dev->kobj, "usb_power_delivery"); 692 + put_device(&pd->dev); 693 + put_device(dev); 694 + } 695 + EXPORT_SYMBOL_GPL(usb_power_delivery_unlink_device); 696 + 697 + /* -------------------------------------------------------------------------- */ 698 + 699 + int __init usb_power_delivery_init(void) 700 + { 701 + return class_register(&pd_class); 702 + } 703 + 704 + void __exit usb_power_delivery_exit(void) 705 + { 706 + ida_destroy(&pd_ida); 707 + class_unregister(&pd_class); 708 + }
+30
drivers/usb/typec/pd.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __USB_POWER_DELIVERY__ 4 + #define __USB_POWER_DELIVERY__ 5 + 6 + #include <linux/device.h> 7 + #include <linux/usb/typec.h> 8 + 9 + struct usb_power_delivery { 10 + struct device dev; 11 + int id; 12 + u16 revision; 13 + u16 version; 14 + }; 15 + 16 + struct usb_power_delivery_capabilities { 17 + struct device dev; 18 + struct usb_power_delivery *pd; 19 + enum typec_role role; 20 + }; 21 + 22 + #define to_usb_power_delivery_capabilities(o) container_of(o, struct usb_power_delivery_capabilities, dev) 23 + #define to_usb_power_delivery(o) container_of(o, struct usb_power_delivery, dev) 24 + 25 + struct usb_power_delivery *usb_power_delivery_find(const char *name); 26 + 27 + int usb_power_delivery_init(void); 28 + void usb_power_delivery_exit(void); 29 + 30 + #endif /* __USB_POWER_DELIVERY__ */
+38
include/linux/usb/pd.h
··· 495 495 496 496 #define PD_P_SNK_STDBY_MW 2500 /* 2500 mW */ 497 497 498 + #if IS_ENABLED(CONFIG_TYPEC) 499 + 500 + struct usb_power_delivery; 501 + 502 + /** 503 + * usb_power_delivery_desc - USB Power Delivery Descriptor 504 + * @revision: USB Power Delivery Specification Revision 505 + * @version: USB Power Delivery Specicication Version - optional 506 + */ 507 + struct usb_power_delivery_desc { 508 + u16 revision; 509 + u16 version; 510 + }; 511 + 512 + /** 513 + * usb_power_delivery_capabilities_desc - Description of USB Power Delivery Capabilities Message 514 + * @pdo: The Power Data Objects in the Capability Message 515 + * @role: Power role of the capabilities 516 + */ 517 + struct usb_power_delivery_capabilities_desc { 518 + u32 pdo[PDO_MAX_OBJECTS]; 519 + enum typec_role role; 520 + }; 521 + 522 + struct usb_power_delivery_capabilities * 523 + usb_power_delivery_register_capabilities(struct usb_power_delivery *pd, 524 + struct usb_power_delivery_capabilities_desc *desc); 525 + void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap); 526 + 527 + struct usb_power_delivery *usb_power_delivery_register(struct device *parent, 528 + struct usb_power_delivery_desc *desc); 529 + void usb_power_delivery_unregister(struct usb_power_delivery *pd); 530 + 531 + int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev); 532 + void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev); 533 + 534 + #endif /* CONFIG_TYPEC */ 535 + 498 536 #endif /* __LINUX_USB_PD_H */
+10
include/linux/usb/typec.h
··· 52 52 TYPEC_SOURCE, 53 53 }; 54 54 55 + static inline int is_sink(enum typec_role role) 56 + { 57 + return role == TYPEC_SINK; 58 + } 59 + 60 + static inline int is_source(enum typec_role role) 61 + { 62 + return role == TYPEC_SOURCE; 63 + } 64 + 55 65 enum typec_pwr_opmode { 56 66 TYPEC_PWR_MODE_USB, 57 67 TYPEC_PWR_MODE_1_5A,