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