Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ib-extcon-drm-dt-v4.17' into extcon-next

+258 -13
+49
Documentation/devicetree/bindings/connector/samsung,usb-connector-11pin.txt
··· 1 + Samsung micro-USB 11-pin connector 2 + ================================== 3 + 4 + Samsung micro-USB 11-pin connector is an extension of micro-USB connector. 5 + It is present in multiple Samsung mobile devices. 6 + It has additional pins to route MHL traffic simultanously with USB. 7 + 8 + The bindings are superset of usb-connector bindings for micro-USB connector[1]. 9 + 10 + Required properties: 11 + - compatible: must be: "samsung,usb-connector-11pin", "usb-b-connector", 12 + - type: must be "micro". 13 + 14 + Required nodes: 15 + - any data bus to the connector should be modeled using the OF graph bindings 16 + specified in bindings/graph.txt, unless the bus is between parent node and 17 + the connector. Since single connector can have multpile data buses every bus 18 + has assigned OF graph port number as follows: 19 + 0: High Speed (HS), 20 + 3: Mobile High-Definition Link (MHL), specific to 11-pin Samsung micro-USB. 21 + 22 + [1]: bindings/connector/usb-connector.txt 23 + 24 + Example 25 + ------- 26 + 27 + Micro-USB connector with HS lines routed via controller (MUIC) and MHL lines 28 + connected to HDMI-MHL bridge (sii8620): 29 + 30 + muic-max77843@66 { 31 + ... 32 + usb_con: connector { 33 + compatible = "samsung,usb-connector-11pin", "usb-b-connector"; 34 + label = "micro-USB"; 35 + type = "micro"; 36 + 37 + ports { 38 + #address-cells = <1>; 39 + #size-cells = <0>; 40 + 41 + port@3 { 42 + reg = <3>; 43 + usb_con_mhl: endpoint { 44 + remote-endpoint = <&sii8620_mhl>; 45 + }; 46 + }; 47 + }; 48 + }; 49 + };
+75
Documentation/devicetree/bindings/connector/usb-connector.txt
··· 1 + USB Connector 2 + ============= 3 + 4 + USB connector node represents physical USB connector. It should be 5 + a child of USB interface controller. 6 + 7 + Required properties: 8 + - compatible: describes type of the connector, must be one of: 9 + "usb-a-connector", 10 + "usb-b-connector", 11 + "usb-c-connector". 12 + 13 + Optional properties: 14 + - label: symbolic name for the connector, 15 + - type: size of the connector, should be specified in case of USB-A, USB-B 16 + non-fullsize connectors: "mini", "micro". 17 + 18 + Required nodes: 19 + - any data bus to the connector should be modeled using the OF graph bindings 20 + specified in bindings/graph.txt, unless the bus is between parent node and 21 + the connector. Since single connector can have multpile data buses every bus 22 + has assigned OF graph port number as follows: 23 + 0: High Speed (HS), present in all connectors, 24 + 1: Super Speed (SS), present in SS capable connectors, 25 + 2: Sideband use (SBU), present in USB-C. 26 + 27 + Examples 28 + -------- 29 + 30 + 1. Micro-USB connector with HS lines routed via controller (MUIC): 31 + 32 + muic-max77843@66 { 33 + ... 34 + usb_con: connector { 35 + compatible = "usb-b-connector"; 36 + label = "micro-USB"; 37 + type = "micro"; 38 + }; 39 + }; 40 + 41 + 2. USB-C connector attached to CC controller (s2mm005), HS lines routed 42 + to companion PMIC (max77865), SS lines to USB3 PHY and SBU to DisplayPort. 43 + DisplayPort video lines are routed to the connector via SS mux in USB3 PHY. 44 + 45 + ccic: s2mm005@33 { 46 + ... 47 + usb_con: connector { 48 + compatible = "usb-c-connector"; 49 + label = "USB-C"; 50 + 51 + ports { 52 + #address-cells = <1>; 53 + #size-cells = <0>; 54 + 55 + port@0 { 56 + reg = <0>; 57 + usb_con_hs: endpoint { 58 + remote-endpoint = <&max77865_usbc_hs>; 59 + }; 60 + }; 61 + port@1 { 62 + reg = <1>; 63 + usb_con_ss: endpoint { 64 + remote-endpoint = <&usbdrd_phy_ss>; 65 + }; 66 + }; 67 + port@2 { 68 + reg = <2>; 69 + usb_con_sbu: endpoint { 70 + remote-endpoint = <&dp_aux>; 71 + }; 72 + }; 73 + }; 74 + }; 75 + };
+34 -10
drivers/extcon/extcon.c
··· 1336 1336 EXPORT_SYMBOL_GPL(extcon_dev_unregister); 1337 1337 1338 1338 #ifdef CONFIG_OF 1339 + 1340 + /* 1341 + * extcon_find_edev_by_node - Find the extcon device from devicetree. 1342 + * @node : OF node identifying edev 1343 + * 1344 + * Return the pointer of extcon device if success or ERR_PTR(err) if fail. 1345 + */ 1346 + struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) 1347 + { 1348 + struct extcon_dev *edev; 1349 + 1350 + mutex_lock(&extcon_dev_list_lock); 1351 + list_for_each_entry(edev, &extcon_dev_list, entry) 1352 + if (edev->dev.parent && edev->dev.parent->of_node == node) 1353 + goto out; 1354 + edev = ERR_PTR(-EPROBE_DEFER); 1355 + out: 1356 + mutex_unlock(&extcon_dev_list_lock); 1357 + 1358 + return edev; 1359 + } 1360 + 1339 1361 /* 1340 1362 * extcon_get_edev_by_phandle - Get the extcon device from devicetree. 1341 1363 * @dev : the instance to the given device ··· 1385 1363 return ERR_PTR(-ENODEV); 1386 1364 } 1387 1365 1388 - mutex_lock(&extcon_dev_list_lock); 1389 - list_for_each_entry(edev, &extcon_dev_list, entry) { 1390 - if (edev->dev.parent && edev->dev.parent->of_node == node) { 1391 - mutex_unlock(&extcon_dev_list_lock); 1392 - of_node_put(node); 1393 - return edev; 1394 - } 1395 - } 1396 - mutex_unlock(&extcon_dev_list_lock); 1366 + edev = extcon_find_edev_by_node(node); 1397 1367 of_node_put(node); 1398 1368 1399 - return ERR_PTR(-EPROBE_DEFER); 1369 + return edev; 1400 1370 } 1371 + 1401 1372 #else 1373 + 1374 + struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) 1375 + { 1376 + return ERR_PTR(-ENOSYS); 1377 + } 1378 + 1402 1379 struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) 1403 1380 { 1404 1381 return ERR_PTR(-ENOSYS); 1405 1382 } 1383 + 1406 1384 #endif /* CONFIG_OF */ 1385 + 1386 + EXPORT_SYMBOL_GPL(extcon_find_edev_by_node); 1407 1387 EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle); 1408 1388 1409 1389 /**
+94 -3
drivers/gpu/drm/bridge/sil-sii8620.c
··· 17 17 18 18 #include <linux/clk.h> 19 19 #include <linux/delay.h> 20 + #include <linux/extcon.h> 20 21 #include <linux/gpio/consumer.h> 21 22 #include <linux/i2c.h> 22 23 #include <linux/interrupt.h> ··· 26 25 #include <linux/list.h> 27 26 #include <linux/module.h> 28 27 #include <linux/mutex.h> 28 + #include <linux/of_graph.h> 29 29 #include <linux/regulator/consumer.h> 30 30 #include <linux/slab.h> 31 31 ··· 83 81 struct edid *edid; 84 82 unsigned int gen2_write_burst:1; 85 83 enum sii8620_mt_state mt_state; 84 + struct extcon_dev *extcon; 85 + struct notifier_block extcon_nb; 86 + struct work_struct extcon_wq; 87 + int cable_state; 86 88 struct list_head mt_queue; 87 89 struct { 88 90 int r_size; ··· 2176 2170 ctx->rc_dev = rc_dev; 2177 2171 } 2178 2172 2173 + static void sii8620_cable_out(struct sii8620 *ctx) 2174 + { 2175 + disable_irq(to_i2c_client(ctx->dev)->irq); 2176 + sii8620_hw_off(ctx); 2177 + } 2178 + 2179 + static void sii8620_extcon_work(struct work_struct *work) 2180 + { 2181 + struct sii8620 *ctx = 2182 + container_of(work, struct sii8620, extcon_wq); 2183 + int state = extcon_get_state(ctx->extcon, EXTCON_DISP_MHL); 2184 + 2185 + if (state == ctx->cable_state) 2186 + return; 2187 + 2188 + ctx->cable_state = state; 2189 + 2190 + if (state > 0) 2191 + sii8620_cable_in(ctx); 2192 + else 2193 + sii8620_cable_out(ctx); 2194 + } 2195 + 2196 + static int sii8620_extcon_notifier(struct notifier_block *self, 2197 + unsigned long event, void *ptr) 2198 + { 2199 + struct sii8620 *ctx = 2200 + container_of(self, struct sii8620, extcon_nb); 2201 + 2202 + schedule_work(&ctx->extcon_wq); 2203 + 2204 + return NOTIFY_DONE; 2205 + } 2206 + 2207 + static int sii8620_extcon_init(struct sii8620 *ctx) 2208 + { 2209 + struct extcon_dev *edev; 2210 + struct device_node *musb, *muic; 2211 + int ret; 2212 + 2213 + /* get micro-USB connector node */ 2214 + musb = of_graph_get_remote_node(ctx->dev->of_node, 1, -1); 2215 + /* next get micro-USB Interface Controller node */ 2216 + muic = of_get_next_parent(musb); 2217 + 2218 + if (!muic) { 2219 + dev_info(ctx->dev, "no extcon found, switching to 'always on' mode\n"); 2220 + return 0; 2221 + } 2222 + 2223 + edev = extcon_find_edev_by_node(muic); 2224 + of_node_put(muic); 2225 + if (IS_ERR(edev)) { 2226 + if (PTR_ERR(edev) == -EPROBE_DEFER) 2227 + return -EPROBE_DEFER; 2228 + dev_err(ctx->dev, "Invalid or missing extcon\n"); 2229 + return PTR_ERR(edev); 2230 + } 2231 + 2232 + ctx->extcon = edev; 2233 + ctx->extcon_nb.notifier_call = sii8620_extcon_notifier; 2234 + INIT_WORK(&ctx->extcon_wq, sii8620_extcon_work); 2235 + ret = extcon_register_notifier(edev, EXTCON_DISP_MHL, &ctx->extcon_nb); 2236 + if (ret) { 2237 + dev_err(ctx->dev, "failed to register notifier for MHL\n"); 2238 + return ret; 2239 + } 2240 + 2241 + return 0; 2242 + } 2243 + 2179 2244 static inline struct sii8620 *bridge_to_sii8620(struct drm_bridge *bridge) 2180 2245 { 2181 2246 return container_of(bridge, struct sii8620, bridge); ··· 2379 2302 if (ret) 2380 2303 return ret; 2381 2304 2305 + ret = sii8620_extcon_init(ctx); 2306 + if (ret < 0) { 2307 + dev_err(ctx->dev, "failed to initialize EXTCON\n"); 2308 + return ret; 2309 + } 2310 + 2382 2311 i2c_set_clientdata(client, ctx); 2383 2312 2384 2313 ctx->bridge.funcs = &sii8620_bridge_funcs; 2385 2314 ctx->bridge.of_node = dev->of_node; 2386 2315 drm_bridge_add(&ctx->bridge); 2387 2316 2388 - sii8620_cable_in(ctx); 2317 + if (!ctx->extcon) 2318 + sii8620_cable_in(ctx); 2389 2319 2390 2320 return 0; 2391 2321 } ··· 2401 2317 { 2402 2318 struct sii8620 *ctx = i2c_get_clientdata(client); 2403 2319 2404 - disable_irq(to_i2c_client(ctx->dev)->irq); 2405 - sii8620_hw_off(ctx); 2320 + if (ctx->extcon) { 2321 + extcon_unregister_notifier(ctx->extcon, EXTCON_DISP_MHL, 2322 + &ctx->extcon_nb); 2323 + flush_work(&ctx->extcon_wq); 2324 + if (ctx->cable_state > 0) 2325 + sii8620_cable_out(ctx); 2326 + } else { 2327 + sii8620_cable_out(ctx); 2328 + } 2406 2329 drm_bridge_remove(&ctx->bridge); 2407 2330 2408 2331 return 0;
+6
include/linux/extcon.h
··· 230 230 * Following APIs get the extcon_dev from devicetree or by through extcon name. 231 231 */ 232 232 extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name); 233 + extern struct extcon_dev *extcon_find_edev_by_node(struct device_node *node); 233 234 extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, 234 235 int index); 235 236 ··· 280 279 struct notifier_block *nb) { } 281 280 282 281 static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) 282 + { 283 + return ERR_PTR(-ENODEV); 284 + } 285 + 286 + static inline struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) 283 287 { 284 288 return ERR_PTR(-ENODEV); 285 289 }