1*68c84483Sanish kumar======================= 2*68c84483Sanish kumarExtcon Device Subsystem 3*68c84483Sanish kumar======================= 4*68c84483Sanish kumar 5*68c84483Sanish kumarOverview 6*68c84483Sanish kumar======== 7*68c84483Sanish kumar 8*68c84483Sanish kumarThe Extcon (External Connector) subsystem provides a unified framework for 9*68c84483Sanish kumarmanaging external connectors in Linux systems. It allows drivers to report 10*68c84483Sanish kumarthe state of external connectors and provides a standardized interface for 11*68c84483Sanish kumaruserspace to query and monitor these states. 12*68c84483Sanish kumar 13*68c84483Sanish kumarExtcon is particularly useful in modern devices with multiple connectivity 14*68c84483Sanish kumaroptions, such as smartphones, tablets, and laptops. It helps manage various 15*68c84483Sanish kumartypes of connectors, including: 16*68c84483Sanish kumar 17*68c84483Sanish kumar1. USB connectors (e.g., USB-C, micro-USB) 18*68c84483Sanish kumar2. Charging ports (e.g., fast charging, wireless charging) 19*68c84483Sanish kumar3. Audio jacks (e.g., 3.5mm headphone jack) 20*68c84483Sanish kumar4. Video outputs (e.g., HDMI, DisplayPort) 21*68c84483Sanish kumar5. Docking stations 22*68c84483Sanish kumar 23*68c84483Sanish kumarReal-world examples: 24*68c84483Sanish kumar 25*68c84483Sanish kumar1. Smartphone USB-C port: 26*68c84483Sanish kumar A single USB-C port on a smartphone can serve multiple functions. Extcon 27*68c84483Sanish kumar can manage the different states of this port, such as: 28*68c84483Sanish kumar - USB data connection 29*68c84483Sanish kumar - Charging (various types like fast charging, USB Power Delivery) 30*68c84483Sanish kumar - Audio output (USB-C headphones) 31*68c84483Sanish kumar - Video output (USB-C to HDMI adapter) 32*68c84483Sanish kumar 33*68c84483Sanish kumar2. Laptop docking station: 34*68c84483Sanish kumar When a laptop is connected to a docking station, multiple connections are 35*68c84483Sanish kumar made simultaneously. Extcon can handle the state changes for: 36*68c84483Sanish kumar - Power delivery 37*68c84483Sanish kumar - External displays 38*68c84483Sanish kumar - USB hub connections 39*68c84483Sanish kumar - Ethernet connectivity 40*68c84483Sanish kumar 41*68c84483Sanish kumar3. Wireless charging pad: 42*68c84483Sanish kumar Extcon can manage the state of a wireless charging connection, allowing 43*68c84483Sanish kumar the system to respond appropriately when a device is placed on or removed 44*68c84483Sanish kumar from the charging pad. 45*68c84483Sanish kumar 46*68c84483Sanish kumar4. Smart TV HDMI ports: 47*68c84483Sanish kumar In a smart TV, Extcon can manage multiple HDMI ports, detecting when 48*68c84483Sanish kumar devices are connected or disconnected, and potentially identifying the 49*68c84483Sanish kumar type of device (e.g., gaming console, set-top box, Blu-ray player). 50*68c84483Sanish kumar 51*68c84483Sanish kumarThe Extcon framework simplifies the development of drivers for these complex 52*68c84483Sanish kumarscenarios by providing a standardized way to report and query connector 53*68c84483Sanish kumarstates, handle mutually exclusive connections, and manage connector 54*68c84483Sanish kumarproperties. This allows for more robust and flexible handling of external 55*68c84483Sanish kumarconnections in modern devices. 56*68c84483Sanish kumar 57*68c84483Sanish kumarKey Components 58*68c84483Sanish kumar============== 59*68c84483Sanish kumar 60*68c84483Sanish kumarextcon_dev 61*68c84483Sanish kumar---------- 62*68c84483Sanish kumar 63*68c84483Sanish kumarThe core structure representing an Extcon device:: 64*68c84483Sanish kumar 65*68c84483Sanish kumar struct extcon_dev { 66*68c84483Sanish kumar const char *name; 67*68c84483Sanish kumar const unsigned int *supported_cable; 68*68c84483Sanish kumar const u32 *mutually_exclusive; 69*68c84483Sanish kumar 70*68c84483Sanish kumar /* Internal data */ 71*68c84483Sanish kumar struct device dev; 72*68c84483Sanish kumar unsigned int id; 73*68c84483Sanish kumar struct raw_notifier_head nh_all; 74*68c84483Sanish kumar struct raw_notifier_head *nh; 75*68c84483Sanish kumar struct list_head entry; 76*68c84483Sanish kumar int max_supported; 77*68c84483Sanish kumar spinlock_t lock; 78*68c84483Sanish kumar u32 state; 79*68c84483Sanish kumar 80*68c84483Sanish kumar /* Sysfs related */ 81*68c84483Sanish kumar struct device_type extcon_dev_type; 82*68c84483Sanish kumar struct extcon_cable *cables; 83*68c84483Sanish kumar struct attribute_group attr_g_muex; 84*68c84483Sanish kumar struct attribute **attrs_muex; 85*68c84483Sanish kumar struct device_attribute *d_attrs_muex; 86*68c84483Sanish kumar }; 87*68c84483Sanish kumar 88*68c84483Sanish kumarKey fields: 89*68c84483Sanish kumar 90*68c84483Sanish kumar- ``name``: Name of the Extcon device 91*68c84483Sanish kumar- ``supported_cable``: Array of supported cable types 92*68c84483Sanish kumar- ``mutually_exclusive``: Array defining mutually exclusive cable types 93*68c84483Sanish kumar This field is crucial for enforcing hardware constraints. It's an array of 94*68c84483Sanish kumar 32-bit unsigned integers, where each element represents a set of mutually 95*68c84483Sanish kumar exclusive cable types. The array should be terminated with a 0. 96*68c84483Sanish kumar 97*68c84483Sanish kumar For example: 98*68c84483Sanish kumar 99*68c84483Sanish kumar :: 100*68c84483Sanish kumar 101*68c84483Sanish kumar static const u32 mutually_exclusive[] = { 102*68c84483Sanish kumar BIT(0) | BIT(1), /* Cable 0 and 1 are mutually exclusive */ 103*68c84483Sanish kumar BIT(2) | BIT(3) | BIT(4), /* Cables 2, 3, and 4 are mutually exclusive */ 104*68c84483Sanish kumar 0 /* Terminator */ 105*68c84483Sanish kumar }; 106*68c84483Sanish kumar 107*68c84483Sanish kumar In this example, cables 0 and 1 cannot be connected simultaneously, and 108*68c84483Sanish kumar cables 2, 3, and 4 are also mutually exclusive. This is useful for 109*68c84483Sanish kumar scenarios like a single port that can either be USB or HDMI, but not both 110*68c84483Sanish kumar at the same time. 111*68c84483Sanish kumar 112*68c84483Sanish kumar The Extcon core uses this information to prevent invalid combinations of 113*68c84483Sanish kumar cable states, ensuring that the reported states are always consistent 114*68c84483Sanish kumar with the hardware capabilities. 115*68c84483Sanish kumar 116*68c84483Sanish kumar- ``state``: Current state of the device (bitmap of connected cables) 117*68c84483Sanish kumar 118*68c84483Sanish kumar 119*68c84483Sanish kumarextcon_cable 120*68c84483Sanish kumar------------ 121*68c84483Sanish kumar 122*68c84483Sanish kumarRepresents an individual cable managed by an Extcon device:: 123*68c84483Sanish kumar 124*68c84483Sanish kumar struct extcon_cable { 125*68c84483Sanish kumar struct extcon_dev *edev; 126*68c84483Sanish kumar int cable_index; 127*68c84483Sanish kumar struct attribute_group attr_g; 128*68c84483Sanish kumar struct device_attribute attr_name; 129*68c84483Sanish kumar struct device_attribute attr_state; 130*68c84483Sanish kumar struct attribute *attrs[3]; 131*68c84483Sanish kumar union extcon_property_value usb_propval[EXTCON_PROP_USB_CNT]; 132*68c84483Sanish kumar union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; 133*68c84483Sanish kumar union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; 134*68c84483Sanish kumar union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; 135*68c84483Sanish kumar DECLARE_BITMAP(usb_bits, EXTCON_PROP_USB_CNT); 136*68c84483Sanish kumar DECLARE_BITMAP(chg_bits, EXTCON_PROP_CHG_CNT); 137*68c84483Sanish kumar DECLARE_BITMAP(jack_bits, EXTCON_PROP_JACK_CNT); 138*68c84483Sanish kumar DECLARE_BITMAP(disp_bits, EXTCON_PROP_DISP_CNT); 139*68c84483Sanish kumar }; 140*68c84483Sanish kumar 141*68c84483Sanish kumarCore Functions 142*68c84483Sanish kumar============== 143*68c84483Sanish kumar 144*68c84483Sanish kumar.. kernel-doc:: drivers/extcon/extcon.c 145*68c84483Sanish kumar :identifiers: extcon_get_state 146*68c84483Sanish kumar 147*68c84483Sanish kumar.. kernel-doc:: drivers/extcon/extcon.c 148*68c84483Sanish kumar :identifiers: extcon_set_state 149*68c84483Sanish kumar 150*68c84483Sanish kumar.. kernel-doc:: drivers/extcon/extcon.c 151*68c84483Sanish kumar :identifiers: extcon_set_state_sync 152*68c84483Sanish kumar 153*68c84483Sanish kumar.. kernel-doc:: drivers/extcon/extcon.c 154*68c84483Sanish kumar :identifiers: extcon_get_property 155*68c84483Sanish kumar 156*68c84483Sanish kumar 157*68c84483Sanish kumarSysfs Interface 158*68c84483Sanish kumar=============== 159*68c84483Sanish kumar 160*68c84483Sanish kumarExtcon devices expose the following sysfs attributes: 161*68c84483Sanish kumar 162*68c84483Sanish kumar- ``name``: Name of the Extcon device 163*68c84483Sanish kumar- ``state``: Current state of all supported cables 164*68c84483Sanish kumar- ``cable.N/name``: Name of the Nth supported cable 165*68c84483Sanish kumar- ``cable.N/state``: State of the Nth supported cable 166*68c84483Sanish kumar 167*68c84483Sanish kumarUsage Example 168*68c84483Sanish kumar------------- 169*68c84483Sanish kumar 170*68c84483Sanish kumar.. code-block:: c 171*68c84483Sanish kumar 172*68c84483Sanish kumar #include <linux/module.h> 173*68c84483Sanish kumar #include <linux/platform_device.h> 174*68c84483Sanish kumar #include <linux/extcon.h> 175*68c84483Sanish kumar 176*68c84483Sanish kumar struct my_extcon_data { 177*68c84483Sanish kumar struct extcon_dev *edev; 178*68c84483Sanish kumar struct device *dev; 179*68c84483Sanish kumar }; 180*68c84483Sanish kumar 181*68c84483Sanish kumar static const unsigned int my_extcon_cable[] = { 182*68c84483Sanish kumar EXTCON_USB, 183*68c84483Sanish kumar EXTCON_USB_HOST, 184*68c84483Sanish kumar EXTCON_NONE, 185*68c84483Sanish kumar }; 186*68c84483Sanish kumar 187*68c84483Sanish kumar static int my_extcon_probe(struct platform_device *pdev) 188*68c84483Sanish kumar { 189*68c84483Sanish kumar struct my_extcon_data *data; 190*68c84483Sanish kumar int ret; 191*68c84483Sanish kumar 192*68c84483Sanish kumar data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 193*68c84483Sanish kumar if (!data) 194*68c84483Sanish kumar return -ENOMEM; 195*68c84483Sanish kumar 196*68c84483Sanish kumar data->dev = &pdev->dev; 197*68c84483Sanish kumar 198*68c84483Sanish kumar /* Initialize extcon device */ 199*68c84483Sanish kumar data->edev = devm_extcon_dev_allocate(data->dev, my_extcon_cable); 200*68c84483Sanish kumar if (IS_ERR(data->edev)) { 201*68c84483Sanish kumar dev_err(data->dev, "Failed to allocate extcon device\n"); 202*68c84483Sanish kumar return PTR_ERR(data->edev); 203*68c84483Sanish kumar } 204*68c84483Sanish kumar 205*68c84483Sanish kumar /* Register extcon device */ 206*68c84483Sanish kumar ret = devm_extcon_dev_register(data->dev, data->edev); 207*68c84483Sanish kumar if (ret < 0) { 208*68c84483Sanish kumar dev_err(data->dev, "Failed to register extcon device\n"); 209*68c84483Sanish kumar return ret; 210*68c84483Sanish kumar } 211*68c84483Sanish kumar 212*68c84483Sanish kumar platform_set_drvdata(pdev, data); 213*68c84483Sanish kumar 214*68c84483Sanish kumar /* Example: Set initial state */ 215*68c84483Sanish kumar extcon_set_state_sync(data->edev, EXTCON_USB, true); 216*68c84483Sanish kumar 217*68c84483Sanish kumar dev_info(data->dev, "My extcon driver probed successfully\n"); 218*68c84483Sanish kumar return 0; 219*68c84483Sanish kumar } 220*68c84483Sanish kumar 221*68c84483Sanish kumar static int my_extcon_remove(struct platform_device *pdev) 222*68c84483Sanish kumar { 223*68c84483Sanish kumar struct my_extcon_data *data = platform_get_drvdata(pdev); 224*68c84483Sanish kumar 225*68c84483Sanish kumar /* Example: Clear state before removal */ 226*68c84483Sanish kumar extcon_set_state_sync(data->edev, EXTCON_USB, false); 227*68c84483Sanish kumar 228*68c84483Sanish kumar dev_info(data->dev, "My extcon driver removed\n"); 229*68c84483Sanish kumar return 0; 230*68c84483Sanish kumar } 231*68c84483Sanish kumar 232*68c84483Sanish kumar static const struct of_device_id my_extcon_of_match[] = { 233*68c84483Sanish kumar { .compatible = "my,extcon-device", }, 234*68c84483Sanish kumar { }, 235*68c84483Sanish kumar }; 236*68c84483Sanish kumar MODULE_DEVICE_TABLE(of, my_extcon_of_match); 237*68c84483Sanish kumar 238*68c84483Sanish kumar static struct platform_driver my_extcon_driver = { 239*68c84483Sanish kumar .driver = { 240*68c84483Sanish kumar .name = "my-extcon-driver", 241*68c84483Sanish kumar .of_match_table = my_extcon_of_match, 242*68c84483Sanish kumar }, 243*68c84483Sanish kumar .probe = my_extcon_probe, 244*68c84483Sanish kumar .remove = my_extcon_remove, 245*68c84483Sanish kumar }; 246*68c84483Sanish kumar 247*68c84483Sanish kumar module_platform_driver(my_extcon_driver); 248*68c84483Sanish kumar 249*68c84483Sanish kumarThis example demonstrates: 250*68c84483Sanish kumar--------------------------- 251*68c84483Sanish kumar 252*68c84483Sanish kumar- Defining supported cable types (USB and USB Host in this case). 253*68c84483Sanish kumar- Allocating and registering an extcon device. 254*68c84483Sanish kumar- Setting an initial state for a cable (USB connected in this example). 255*68c84483Sanish kumar- Clearing the state when the driver is removed. 256