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