Skip to content

List USB-C ports, pd objects and associated info on Linux

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
COPYING
Notifications You must be signed in to change notification settings

doug-gilbert/lsucpd

Repository files navigation

                               lsucpd
                               ======

Introduction
------------
This utility belongs to the "ls*" family of utilities found in Linux whose
names derive from the Unix ls utility (command) for listing files and
directories. In the case of lsucpd, the "ucpd" is an abbreviation for USB-C
Power Delivery (PD) which is optional on USB Type-C interconnects. A typical
USB-C interconnect consists of a power adapter (e.g. an AC 65 Watt power
adapter) and a consumer of power (e.g. a laptop). Taking those examples,
both the power adapter and the laptop will have female USB-C connectors (also
known as receptacles). A USB-C cable will complete the circuit with a male
USB-C plug on either end.

The lsucpd utility will list local USB-C ports (e.g. each female USB-C
connector on a laptop) with one line output for each local port. Those local
ports are named "port<n>" where <n> is an integer starting at 0. Although
Linux does not guarantee it, the local port numbers are observed to be stable
from one boot to the next. For those local ports connected via a cable to a
remote device there will most likely be a "port<n>-partner" which is
shortened to "partner" as the "port<n>" part would otherwise be repeated.
Not all USB-C ports support the PD protocol, but for those that do, a
"pd<n>" is shown in square brackets immediately to the right of the port
it is associated with. For example:
    $ lsucpd 
    port0 [pd0]  <<====  partner [pd4] 
    port1 [pd1]  <<====  partner [pd5]
The direction that power is flowing is indicated by "====>>" or "<<===="
between each port<n> and its partner. Probably the most useful option
is --caps which will additionally list the source and sink capabilities of
each "pd<n>" instance.

Project Status
--------------
Can do:
    - show relationship between USB Type C objects (e.g. port0 and
      port1-partner) and "usb_power_delivery" objects (e.g. pd1 and pd7)
    - show the source and sink capabilities of both ends of existing
      PD connections
    - display partner's alternate modes, if any (with -ll option)
    - decode numeric PDOs and RDOs
    - optionally output JSON instead of plain text
Cannot do (yet):
    - show the PD contract that is active. In USB PD jargon this requires
      the active RDO to be visible via sysfs
    - show the actual voltage and current (and its direction) at the
      time this utility is executed

The last one is aspirational and may probably require extra hardware.

This is the initial version of this utility and has only been tested on one
platform: Thinkpad X13 G3 by Lenovo. That platform relies on the UCSI
interface exposed via sysfs starting with the Linux kernel 6 series (e.g.
lk 6.4). Note that normal, non-root user privileges are sufficient to use
lsucpd.

This project should be regarded as "work-in-progress" due to its immaturity
and the kernel support could be summarized as "shaky". Often after removing
and reconnecting USB-C cables carrying power, the ucsi_acpi and typec_ucsi
modules need to be removed then re-installed on the test platform. That
does not inspire confidence.

Not known is which versions of Intel and AMD CPUs will work apart from the
one from the above laptop: Intel i5-1240P. Intel calls that "12th generation"
which was superseded this year by the 13th generation. So this utility most
likely will only work with recent laptops.
Unfortunately another company's 12th generation laptop (ASUS VivoBook
K3502ZA) loads ucsi modules, creates the typec and usb_power_delivery class
directories in sysfs, but leaves them empty. The kernel log shows a
ENOTSUPPORTED error with BIOS version 307.

Bugs, suggestions, or reports of success on other platforms can be sent to
this email address or to "Issues" at:
    https://github.com/doug-gilbert/lsucpd

Like lsscsi, this utility has a --sysfsroot=SPATH option that allows it to
data-mine in another sub-tree (other than /sys ). That "other sub-tree" can
be from another machine (perhaps as a compressed tarball) and would be very
useful to the author in debugging problems. There is another utility
at github:
    https://github.com/doug-gilbert/clone_pseudo_fs
designed to clone the likes of sysfs, procfs and devfs. The lsucpd utility
relies only on sysfs.
For compatibility with lsblk, lsmem and some other ls* utilities there is
also a --sysroot=AR_PT option that defaults to '/'. If AR_PT is set to /tmp
then this utility will attempt to data-mine in /tmp/sys directory.

Some background for USB PD in the Linux kernel is discussed in this post:
    https://marc.info/?l=linux-usb&m=169278141600478&w=2

The next sections of this document can be safely ignored for those familiar
with USB PD and the electrical concepts that underpin it. Instructions for
building this package are in the last section.


USB-C PD details
----------------
There are two USB standards covering this area, recent versions are:
   1) USB Type-C Cable and Connector Specification, Release 2.3
   2) USB Power Delivery Specification, Revision 3.2, Version 1.0
      - this is optional, so USB-C ports don't necessarily support PD

Both these documents are intimidating in size (424 and 1113 pages
respectively) but are freely available at usb.org in the Document library.
Both documents have extensive "Terms and Abbreviations" sections (1.5 and
1.6 respectively) that are very useful references because there are a lot
of obscure terms. For example the PD document summarizes the difference
between SOP' packet and SOP'' packet.

USB.org's use of release, revision and version defies logic. The above
standard names are taken from their front pages. Interconnects complying
with 1) do not necessarily support 2) (i.e. the PD protocol). In the absence
of PD, resistors on the CC lines determine which end is the source/host and
which end is the the sink/device. USB PD Revision 1 is history (an experiment
that failed). USB PD Revision 2 introduced fixed Vbus voltages up to 20 Volts
and with an appropriate ("Emarked") cable could carry 5 Amps for 100 Watts.
USB PD Revision 3 introduced the Programmable Power Supply (PPS) optional
capability which included current limiting (CL) by the source. Then USB PD
Revision 3.1 introduced "Extended Power Range" (EPR) with fixed voltages at
28, 36 and 48 Volts. To avoid confusion, all active PD standards prior to
Revision 3.1 were dubbed "Standard Power Range" (SPR). EPR also has a (sink)
adjustable voltage supply (AVS) range of 15 to 48 Volts _without_ current
limiting.

There are two power roles: source (power provider) and sink (power consumer).
USB-C power banks and laptops can often be both, but a single port can only
be one at a time. The USB PD term for this is "Dual Role Power" (DRP)
but most laptops, at this time, are not true DRP in the USB PD sense; they
tend to fall back to USB-A 5 Volt source/host mode when talking to a USB
memory key which is very unlikely to support USB PD. In a similar way there
are two data roles: host and device. A USB PD port that can play either role
is called "Dual Role Data" (DRD).

Some other related jargon is UFP for Upward Facing Port and DFP for
Downward Facing Port. The mental picture here is with the USB host at the
top of a hierarchy with USB devices at the bottom (i.e. the leaves) with
possibly a USB hub in the middle. So an UFP on a hub connects to a DFP on
the host (e.g. a laptop).

Electricity basics
------------------
All electrical units are metric, assuming power is not given in horsepower.
The SI unit for energy is a joule but that is a bit small as we often talk
about kiloWatt-hours, MegaWatt-hours and GigaWatt-hours. A joule is a
Watt-second (i.e. one Watt for one second) so a Watt-hour is 3,600 joules,
a kiloWatt-hour is 3,600,000 joules, etc. That naming reflects this formula:
    E = P . t       (1)
where E is in joules, P is in Watts and t is in seconds. [The dot is for
multiply.]

The next formula is for electrical power:
    P = V . I       (2)
where P is in Watts, V is in volts and I is current in Amps. The mechanical
analogy for Volts and Amps is to a pipe carrying some fluid. The voltage is
related to pressure and the current is the amount of fluid moving past a
cross-section of the pipe. Further the "fluid" in the case of electricity
is made up of electrons. Around 6.2 x 10^18 electrons is called a Coulomb
and a flow of one Coulomb per second is called an Amp. 

All electrical conductors have resistance which converts part of the power
passing through them to heat. That is usually wasteful (unless it is winter).
Georg Ohm is credited with the formula that bears his name:
   V = I . R	   (3)
where V is in Volts, I is current in Amps and R is resistance in Ohms.

Combining formula (2) and (3) by substituting V gives;
  P = I^2 . R      (4)

This is sometimes called the "i-squared-r" formula that even Elon Musk knows
about. Importantly it is the amount of power lost in a conductor or cable.
Resistance typically doubles when length (of a cable) doubles. Also for a
PD cable, power is lost both in the Vbus wire and the Ground wire (which
usually includes the shield). So that is two times the length of the cable.
Formula (4) tells us to reduce I as much as possible to reduce power lost
in the cable. Formula (2) tells us when we reduce I we must increase V to
maintain the same P sent across the cable. [For completeness:
superconductors have "zero" resistance, typically at cryogenic
temperatures.]

Direct Current (DC) refers to the situation where if V and I change, it
is relatively slow and not periodic. In DC circuits typically the V
(voltage) supplying power to electronics moves as little as possible.
In Alternating Current (AC) both V and I vary periodically (think
sine waves). Typically for houses incoming electrical power is at 50 or
60 Hertz AC. One Hertz is one cycle per second. Formulas (1) to (4) still
apply but become much more difficult in practice because V and I are
varying periodically.

Electric vehicles (EVs) typically have two electrical systems, a high
voltage one at 400 or 800 Volts (DC) for traction; and a low voltage
one for everything else. The low voltage electrical system has been
traditionally set at 12 Volts DC (or 6 Volts 70 years ago). Elon Musk
says that his company can save over 100 kg of copper in cables by
increasing the low voltage system from 12 to 48 Volts.

Higher voltages can be dangerous for humans. It is generally considered
that voltages above 60 Volts (DC) can be harmful. In practice (allowing
for some over-voltage situations) 48 Volts has been chosen as the highest
safe nominal voltage (DC). Both the car industry (for non-traction
purposes) and USB-C PD EPR have chosen 48 Volts DC as their highest
delivery voltage. These are for systems that humans may come in contact
with. Most laptops use around 20 Volts DC while some large MacBooks
use 28 Volts and Apple supplies a 140 Watt USB PD (EPR) charger.


Building package
================
The code can be found at: https://github.com/doug-gilbert/lsucpd

Installation instructions are in the INSTALL file.

Various options can be given to the ./configure script. Those
specific to this package are:

  --enable-debug          Turn on debugging

The build sequence is:
  ./autogen.sh ; ./configure ; make ; make install
or
  ./bootstrap ; ./configure ; make ; make install

Note that the final 'make install' will usually require root permissions
and will place binaries in the /usr/local/bin directory.

The code is written in C++ and assumes the features found in C++20 so
a relatively recent compiler will be required.
GNU and Clang C++ compilers forgot to add "partially" when they claimed
to support C++20. Areas of pain are the <format> and <source_location>
headers. Clang++ 14 was worse: it supported the <source_location> header
but not its functionality.
To build with g++ 12 or clang 15 the 'libfmt' library (and its header file)
may need to be installed. In Debian/Ubuntu this can be done with
'apt install libfmt-dev' .

Instruction for using cmake are in the INSTALL file.


Finally it is best to keep expectations low, especially if the
/sys/class/typec directory doesn't exist ...
 

Douglas Gilbert  <[email protected]>
13th December 2023
lsucpd pre-release 0.92 [svn revision: 21]

About

List USB-C ports, pd objects and associated info on Linux

Resources

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
COPYING

Stars

Watchers

Forks

Packages

No packages published