Hello Myungjoo/Chanwoo, Wondering if you have any comments? On Sat, Nov 2, 2024 at 7:54 PM anish kumar <yesanishhere@xxxxxxxxx> wrote: > > The Extcon (External Connector) subsystem driver lacked proper > documentation. This commit adds comprehensive documentation > explaining the purpose, key components, and usage of the Extcon > framework. > > The new documentation includes: > - An overview of the Extcon subsystem > - Descriptions of key structures > - Explanations of core functions > - Information on the sysfs interface > - A usage example for driver developers > > Signed-off-by: anish kumar <yesanishhere@xxxxxxxxx> > --- > Documentation/driver-api/extcon.rst | 255 ++++++++++++++++++++++++++++ > Documentation/driver-api/index.rst | 1 + > MAINTAINERS | 1 + > 3 files changed, 257 insertions(+) > create mode 100644 Documentation/driver-api/extcon.rst > > diff --git a/Documentation/driver-api/extcon.rst b/Documentation/driver-api/extcon.rst > new file mode 100644 > index 000000000000..d3217b9cdcd5 > --- /dev/null > +++ b/Documentation/driver-api/extcon.rst > @@ -0,0 +1,255 @@ > +======================= > +Extcon Device Subsystem > +======================= > + > +Overview > +======== > + > +The Extcon (External Connector) subsystem provides a unified framework for > +managing external connectors in Linux systems. It allows drivers to report > +the state of external connectors and provides a standardized interface for > +userspace to query and monitor these states. > + > +Extcon is particularly useful in modern devices with multiple connectivity > +options, such as smartphones, tablets, and laptops. It helps manage various > +types of connectors, including: > + > +1. USB connectors (e.g., USB-C, micro-USB) > +2. Charging ports (e.g., fast charging, wireless charging) > +3. Audio jacks (e.g., 3.5mm headphone jack) > +4. Video outputs (e.g., HDMI, DisplayPort) > +5. Docking stations > + > +Real-world examples: > + > +1. Smartphone USB-C port: > + A single USB-C port on a smartphone can serve multiple functions. Extcon > + can manage the different states of this port, such as: > + - USB data connection > + - Charging (various types like fast charging, USB Power Delivery) > + - Audio output (USB-C headphones) > + - Video output (USB-C to HDMI adapter) > + > +2. Laptop docking station: > + When a laptop is connected to a docking station, multiple connections are > + made simultaneously. Extcon can handle the state changes for: > + - Power delivery > + - External displays > + - USB hub connections > + - Ethernet connectivity > + > +3. Wireless charging pad: > + Extcon can manage the state of a wireless charging connection, allowing > + the system to respond appropriately when a device is placed on or removed > + from the charging pad. > + > +4. Smart TV HDMI ports: > + In a smart TV, Extcon can manage multiple HDMI ports, detecting when > + devices are connected or disconnected, and potentially identifying the > + type of device (e.g., gaming console, set-top box, Blu-ray player). > + > +The Extcon framework simplifies the development of drivers for these complex > +scenarios by providing a standardized way to report and query connector > +states, handle mutually exclusive connections, and manage connector > +properties. This allows for more robust and flexible handling of external > +connections in modern devices. > + > +Key Components > +============== > + > +extcon_dev > +---------- > + > +The core structure representing an Extcon device:: > + > + struct extcon_dev { > + const char *name; > + const unsigned int *supported_cable; > + const u32 *mutually_exclusive; > + > + /* Internal data */ > + struct device dev; > + unsigned int id; > + struct raw_notifier_head nh_all; > + struct raw_notifier_head *nh; > + struct list_head entry; > + int max_supported; > + spinlock_t lock; > + u32 state; > + > + /* Sysfs related */ > + struct device_type extcon_dev_type; > + struct extcon_cable *cables; > + struct attribute_group attr_g_muex; > + struct attribute **attrs_muex; > + struct device_attribute *d_attrs_muex; > + }; > + > +Key fields: > + > +- ``name``: Name of the Extcon device > +- ``supported_cable``: Array of supported cable types > +- ``mutually_exclusive``: Array defining mutually exclusive cable types > + This field is crucial for enforcing hardware constraints. It's an array of > + 32-bit unsigned integers, where each element represents a set of mutually > + exclusive cable types. The array should be terminated with a 0. > + > + For example: > + > + :: > + > + static const u32 mutually_exclusive[] = { > + BIT(0) | BIT(1), /* Cable 0 and 1 are mutually exclusive */ > + BIT(2) | BIT(3) | BIT(4), /* Cables 2, 3, and 4 are mutually exclusive */ > + 0 /* Terminator */ > + }; > + > + In this example, cables 0 and 1 cannot be connected simultaneously, and > + cables 2, 3, and 4 are also mutually exclusive. This is useful for > + scenarios like a single port that can either be USB or HDMI, but not both > + at the same time. > + > + The Extcon core uses this information to prevent invalid combinations of > + cable states, ensuring that the reported states are always consistent > + with the hardware capabilities. > + > +- ``state``: Current state of the device (bitmap of connected cables) > + > + > +extcon_cable > +------------ > + > +Represents an individual cable managed by an Extcon device:: > + > + struct extcon_cable { > + struct extcon_dev *edev; > + int cable_index; > + struct attribute_group attr_g; > + struct device_attribute attr_name; > + struct device_attribute attr_state; > + struct attribute *attrs[3]; > + union extcon_property_value usb_propval[EXTCON_PROP_USB_CNT]; > + union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; > + union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; > + union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; > + DECLARE_BITMAP(usb_bits, EXTCON_PROP_USB_CNT); > + DECLARE_BITMAP(chg_bits, EXTCON_PROP_CHG_CNT); > + DECLARE_BITMAP(jack_bits, EXTCON_PROP_JACK_CNT); > + DECLARE_BITMAP(disp_bits, EXTCON_PROP_DISP_CNT); > + }; > + > +Core Functions > +============== > + > +.. kernel-doc:: drivers/extcon/extcon.c > + :identifiers: extcon_get_state > + > +.. kernel-doc:: drivers/extcon/extcon.c > + :identifiers: extcon_set_state > + > +.. kernel-doc:: drivers/extcon/extcon.c > + :identifiers: extcon_set_state_sync > + > +.. kernel-doc:: drivers/extcon/extcon.c > + :identifiers: extcon_get_property > + > + > +Sysfs Interface > +=============== > + > +Extcon devices expose the following sysfs attributes: > + > +- ``name``: Name of the Extcon device > +- ``state``: Current state of all supported cables > +- ``cable.N/name``: Name of the Nth supported cable > +- ``cable.N/state``: State of the Nth supported cable > + > +Usage Example > +------------- > + > +.. code-block:: c > + > + #include <linux/module.h> > + #include <linux/platform_device.h> > + #include <linux/extcon.h> > + > + struct my_extcon_data { > + struct extcon_dev *edev; > + struct device *dev; > + }; > + > + static const unsigned int my_extcon_cable[] = { > + EXTCON_USB, > + EXTCON_USB_HOST, > + EXTCON_NONE, > + }; > + > + static int my_extcon_probe(struct platform_device *pdev) > + { > + struct my_extcon_data *data; > + int ret; > + > + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + data->dev = &pdev->dev; > + > + /* Initialize extcon device */ > + data->edev = devm_extcon_dev_allocate(data->dev, my_extcon_cable); > + if (IS_ERR(data->edev)) { > + dev_err(data->dev, "Failed to allocate extcon device\n"); > + return PTR_ERR(data->edev); > + } > + > + /* Register extcon device */ > + ret = devm_extcon_dev_register(data->dev, data->edev); > + if (ret < 0) { > + dev_err(data->dev, "Failed to register extcon device\n"); > + return ret; > + } > + > + platform_set_drvdata(pdev, data); > + > + /* Example: Set initial state */ > + extcon_set_state_sync(data->edev, EXTCON_USB, true); > + > + dev_info(data->dev, "My extcon driver probed successfully\n"); > + return 0; > + } > + > + static int my_extcon_remove(struct platform_device *pdev) > + { > + struct my_extcon_data *data = platform_get_drvdata(pdev); > + > + /* Example: Clear state before removal */ > + extcon_set_state_sync(data->edev, EXTCON_USB, false); > + > + dev_info(data->dev, "My extcon driver removed\n"); > + return 0; > + } > + > + static const struct of_device_id my_extcon_of_match[] = { > + { .compatible = "my,extcon-device", }, > + { }, > + }; > + MODULE_DEVICE_TABLE(of, my_extcon_of_match); > + > + static struct platform_driver my_extcon_driver = { > + .driver = { > + .name = "my-extcon-driver", > + .of_match_table = my_extcon_of_match, > + }, > + .probe = my_extcon_probe, > + .remove = my_extcon_remove, > + }; > + > + module_platform_driver(my_extcon_driver); > + > +This example demonstrates: > +--------------------------- > + > +- Defining supported cable types (USB and USB Host in this case). > +- Allocating and registering an extcon device. > +- Setting an initial state for a cable (USB connected in this example). > +- Clearing the state when the driver is removed. > diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst > index 7f83e05769b4..16e2c4ec3c01 100644 > --- a/Documentation/driver-api/index.rst > +++ b/Documentation/driver-api/index.rst > @@ -86,6 +86,7 @@ Subsystem-specific APIs > dmaengine/index > dpll > edac > + extcon > firmware/index > fpga/index > frame-buffer > diff --git a/MAINTAINERS b/MAINTAINERS > index c27f3190737f..7a8739ed9d46 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -8572,6 +8572,7 @@ L: linux-kernel@xxxxxxxxxxxxxxx > S: Maintained > T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git > F: Documentation/devicetree/bindings/extcon/ > +F: Documentation/driver-api/extcon.rst > F: Documentation/firmware-guide/acpi/extcon-intel-int3496.rst > F: drivers/extcon/ > F: include/linux/extcon.h > -- > 2.39.3 (Apple Git-146) >