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

Configure Feed

Select the types of activity you want to include in your feed.

drm: bridge: anx7625: implement minimal Type-C support

ANX7625 can be used as a USB-C controller, handling USB and DP data
streams. Provide minimal Type-C support necessary for ANX7625 to
register the Type-C port device and properly respond to data / power
role events from the Type-C partner.

While ANX7625 provides TCPCI interface, using it would circumvent the
on-chip running firmware. Analogix recommended using the higher-level
interface instead of TCPCI.

Reviewed-by: Xin Ji <xji@analogixsemi.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://patch.msgid.link/20260121-anx7625-typec-v2-2-d14f31256a17@oss.qualcomm.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>

+168 -10
+1
drivers/gpu/drm/bridge/analogix/Kconfig
··· 34 34 tristate "Analogix Anx7625 MIPI to DP interface support" 35 35 depends on DRM 36 36 depends on OF 37 + depends on TYPEC || !TYPEC 37 38 select DRM_DISPLAY_DP_HELPER 38 39 select DRM_DISPLAY_HDCP_HELPER 39 40 select DRM_DISPLAY_HELPER
+147 -8
drivers/gpu/drm/bridge/analogix/anx7625.c
··· 3 3 * Copyright(c) 2020, Analogix Semiconductor. All rights reserved. 4 4 * 5 5 */ 6 + #include <linux/cleanup.h> 6 7 #include <linux/gcd.h> 7 8 #include <linux/gpio/consumer.h> 8 9 #include <linux/i2c.h> ··· 16 15 #include <linux/regulator/consumer.h> 17 16 #include <linux/slab.h> 18 17 #include <linux/types.h> 18 + #include <linux/usb.h> 19 + #include <linux/usb/pd.h> 20 + #include <linux/usb/role.h> 19 21 #include <linux/workqueue.h> 20 22 21 23 #include <linux/of_graph.h> ··· 1329 1325 static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) 1330 1326 { 1331 1327 struct device *dev = ctx->dev; 1332 - int ret, val; 1328 + int ret; 1333 1329 1334 1330 /* Reset main ocm */ 1335 1331 ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, 0x88, 0x40); ··· 1343 1339 DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature fail.\n"); 1344 1340 else 1345 1341 DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature succeeded.\n"); 1342 + } 1343 + 1344 + static void anx7625_configure_hpd(struct anx7625_data *ctx) 1345 + { 1346 + int val; 1346 1347 1347 1348 /* 1348 1349 * Make sure the HPD GPIO already be configured after OCM release before ··· 1378 1369 if ((ret & FLASH_LOAD_STA_CHK) != FLASH_LOAD_STA_CHK) 1379 1370 return -ENODEV; 1380 1371 1381 - anx7625_disable_pd_protocol(ctx); 1372 + if (!ctx->typec_port) 1373 + anx7625_disable_pd_protocol(ctx); 1374 + anx7625_configure_hpd(ctx); 1382 1375 1383 1376 DRM_DEV_DEBUG_DRIVER(dev, "Firmware ver %02x%02x,", 1384 1377 anx7625_reg_read(ctx, ··· 1483 1472 DRM_DEV_DEBUG_DRIVER(dev, "Secure OCM version=%02x\n", ret); 1484 1473 } 1485 1474 1475 + #if IS_REACHABLE(CONFIG_TYPEC) 1476 + static void anx7625_typec_set_orientation(struct anx7625_data *ctx) 1477 + { 1478 + u32 val = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS); 1479 + 1480 + if (val & (CC1_RP | CC1_RD)) 1481 + typec_set_orientation(ctx->typec_port, TYPEC_ORIENTATION_NORMAL); 1482 + else if (val & (CC2_RP | CC2_RD)) 1483 + typec_set_orientation(ctx->typec_port, TYPEC_ORIENTATION_REVERSE); 1484 + else 1485 + typec_set_orientation(ctx->typec_port, TYPEC_ORIENTATION_NONE); 1486 + } 1487 + 1488 + static void anx7625_typec_set_status(struct anx7625_data *ctx, 1489 + unsigned int intr_status, 1490 + unsigned int intr_vector) 1491 + { 1492 + if (intr_vector & CC_STATUS) 1493 + anx7625_typec_set_orientation(ctx); 1494 + if (intr_vector & DATA_ROLE_STATUS) { 1495 + enum typec_data_role data_role = (intr_status & DATA_ROLE_STATUS) ? 1496 + TYPEC_HOST : TYPEC_DEVICE; 1497 + usb_role_switch_set_role(ctx->role_sw, 1498 + (intr_status & DATA_ROLE_STATUS) ? 1499 + USB_ROLE_HOST : USB_ROLE_DEVICE); 1500 + typec_set_data_role(ctx->typec_port, data_role); 1501 + ctx->typec_data_role = data_role; 1502 + } 1503 + if (intr_vector & VBUS_STATUS) 1504 + typec_set_pwr_role(ctx->typec_port, 1505 + (intr_status & VBUS_STATUS) ? 1506 + TYPEC_SOURCE : TYPEC_SINK); 1507 + if (intr_vector & VCONN_STATUS) 1508 + typec_set_vconn_role(ctx->typec_port, 1509 + (intr_status & VCONN_STATUS) ? 1510 + TYPEC_SOURCE : TYPEC_SINK); 1511 + } 1512 + 1513 + static int anx7625_typec_register(struct anx7625_data *ctx) 1514 + { 1515 + struct typec_capability typec_cap = { }; 1516 + struct fwnode_handle *fwnode __free(fwnode_handle) = 1517 + device_get_named_child_node(ctx->dev, "connector"); 1518 + u32 val; 1519 + int ret; 1520 + 1521 + if (!fwnode) 1522 + return 0; 1523 + 1524 + ret = typec_get_fw_cap(&typec_cap, fwnode); 1525 + if (ret < 0) 1526 + return ret; 1527 + 1528 + typec_cap.revision = 0x0120; 1529 + typec_cap.pd_revision = 0x0300; 1530 + typec_cap.usb_capability = USB_CAPABILITY_USB2 | USB_CAPABILITY_USB3; 1531 + typec_cap.orientation_aware = true; 1532 + 1533 + typec_cap.driver_data = ctx; 1534 + 1535 + ctx->typec_port = typec_register_port(ctx->dev, &typec_cap); 1536 + if (IS_ERR(ctx->typec_port)) 1537 + return PTR_ERR(ctx->typec_port); 1538 + 1539 + ctx->role_sw = fwnode_usb_role_switch_get(fwnode); 1540 + if (IS_ERR(ctx->role_sw)) { 1541 + typec_unregister_port(ctx->typec_port); 1542 + return PTR_ERR(ctx->role_sw); 1543 + } 1544 + 1545 + val = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS); 1546 + 1547 + anx7625_typec_set_status(ctx, val, 1548 + CC_STATUS | DATA_ROLE_STATUS | 1549 + VBUS_STATUS | VCONN_STATUS); 1550 + 1551 + return 0; 1552 + } 1553 + 1554 + static void anx7625_typec_unregister(struct anx7625_data *ctx) 1555 + { 1556 + usb_role_switch_put(ctx->role_sw); 1557 + typec_unregister_port(ctx->typec_port); 1558 + } 1559 + #else 1560 + static void anx7625_typec_set_status(struct anx7625_data *ctx, 1561 + unsigned int intr_status, 1562 + unsigned int intr_vector) 1563 + { 1564 + } 1565 + 1566 + static int anx7625_typec_register(struct anx7625_data *ctx) 1567 + { 1568 + return 0; 1569 + } 1570 + 1571 + static void anx7625_typec_unregister(struct anx7625_data *ctx) 1572 + { 1573 + } 1574 + #endif 1575 + 1486 1576 static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx) 1487 1577 { 1488 1578 return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS); ··· 1678 1566 } 1679 1567 } 1680 1568 1681 - static int anx7625_hpd_change_detect(struct anx7625_data *ctx) 1569 + static int anx7625_intr_status(struct anx7625_data *ctx) 1682 1570 { 1683 1571 int intr_vector, status; 1684 1572 struct device *dev = ctx->dev; ··· 1705 1593 return status; 1706 1594 } 1707 1595 1708 - if (!(intr_vector & HPD_STATUS_CHANGE)) 1709 - return -ENOENT; 1710 - 1711 1596 status = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, 1712 1597 SYSTEM_STSTUS); 1713 1598 if (status < 0) { ··· 1713 1604 } 1714 1605 1715 1606 DRM_DEV_DEBUG_DRIVER(dev, "0x7e:0x45=%x\n", status); 1607 + 1608 + anx7625_typec_set_status(ctx, status, intr_vector); 1609 + 1610 + if (!(intr_vector & HPD_STATUS)) 1611 + return -ENOENT; 1612 + 1716 1613 dp_hpd_change_handler(ctx, status & HPD_STATUS); 1717 1614 1718 1615 return 0; ··· 1737 1622 return; 1738 1623 } 1739 1624 1740 - event = anx7625_hpd_change_detect(ctx); 1625 + event = anx7625_intr_status(ctx); 1741 1626 1742 1627 mutex_unlock(&ctx->lock); 1743 1628 ··· 2856 2741 } 2857 2742 2858 2743 if (!platform->pdata.low_power_mode) { 2859 - anx7625_disable_pd_protocol(platform); 2744 + struct fwnode_handle *fwnode; 2745 + 2746 + fwnode = device_get_named_child_node(dev, "connector"); 2747 + if (fwnode) 2748 + fwnode_handle_put(fwnode); 2749 + else 2750 + anx7625_disable_pd_protocol(platform); 2751 + 2752 + anx7625_configure_hpd(platform); 2753 + 2860 2754 pm_runtime_get_sync(dev); 2861 2755 _anx7625_hpd_polling(platform, 5000 * 100); 2862 2756 } 2757 + 2758 + if (platform->pdata.intp_irq) 2759 + anx7625_reg_write(platform, platform->i2c.rx_p0_client, 2760 + INTERFACE_CHANGE_INT_MASK, 0); 2761 + 2762 + /* After getting runtime handle */ 2763 + ret = anx7625_typec_register(platform); 2764 + if (ret) 2765 + goto pm_suspend; 2863 2766 2864 2767 /* Add work function */ 2865 2768 if (platform->pdata.intp_irq) { ··· 2891 2758 DRM_DEV_DEBUG_DRIVER(dev, "probe done\n"); 2892 2759 2893 2760 return 0; 2761 + 2762 + pm_suspend: 2763 + if (!platform->pdata.low_power_mode) 2764 + pm_runtime_put_sync_suspend(&client->dev); 2894 2765 2895 2766 free_wq: 2896 2767 if (platform->workqueue) ··· 2910 2773 static void anx7625_i2c_remove(struct i2c_client *client) 2911 2774 { 2912 2775 struct anx7625_data *platform = i2c_get_clientdata(client); 2776 + 2777 + anx7625_typec_unregister(platform); 2913 2778 2914 2779 drm_bridge_remove(&platform->bridge); 2915 2780
+20 -2
drivers/gpu/drm/bridge/analogix/anx7625.h
··· 51 51 #define INTR_RECEIVED_MSG BIT(5) 52 52 53 53 #define SYSTEM_STSTUS 0x45 54 + #define INTERFACE_CHANGE_INT_MASK 0x43 54 55 #define INTERFACE_CHANGE_INT 0x44 55 - #define HPD_STATUS_CHANGE 0x80 56 - #define HPD_STATUS 0x80 56 + #define VCONN_STATUS BIT(2) 57 + #define VBUS_STATUS BIT(3) 58 + #define CC_STATUS BIT(4) 59 + #define DATA_ROLE_STATUS BIT(5) 60 + #define HPD_STATUS BIT(7) 61 + 62 + #define NEW_CC_STATUS 0x46 63 + #define CC1_RD BIT(0) 64 + #define CC1_RA BIT(1) 65 + #define CC1_RP (BIT(2) | BIT(3)) 66 + #define CC2_RD BIT(4) 67 + #define CC2_RA BIT(5) 68 + #define CC2_RP (BIT(6) | BIT(7)) 57 69 58 70 /******** END of I2C Address 0x58 ********/ 59 71 ··· 459 447 struct i2c_client *tcpc_client; 460 448 }; 461 449 450 + struct typec_port; 451 + struct usb_role_switch; 452 + 462 453 struct anx7625_data { 463 454 struct anx7625_platform_data pdata; 464 455 struct platform_device *audio_pdev; 456 + struct typec_port *typec_port; 457 + struct usb_role_switch *role_sw; 458 + int typec_data_role; 465 459 int hpd_status; 466 460 int hpd_high_cnt; 467 461 int dp_en;