xref: /linux/Documentation/driver-api/extcon.rst (revision 9e676a024fa1fa2bd8150c2d2ba85478280353bc)
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