.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd |
---|
3 | 4 | * Author: Chris Zhong <zyw@rock-chips.com> |
---|
4 | 5 | * Kever Yang <kever.yang@rock-chips.com> |
---|
5 | | - * |
---|
6 | | - * This software is licensed under the terms of the GNU General Public |
---|
7 | | - * License version 2, as published by the Free Software Foundation, and |
---|
8 | | - * may be copied, distributed, and modified under those terms. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - * GNU General Public License for more details. |
---|
14 | 6 | * |
---|
15 | 7 | * The ROCKCHIP Type-C PHY has two PLL clocks. The first PLL clock |
---|
16 | 8 | * is used for USB3, the second PLL clock is used for DP. This Type-C PHY has |
---|
.. | .. |
---|
42 | 34 | * This Type-C PHY driver supports normal and flip orientation. The orientation |
---|
43 | 35 | * is reported by the EXTCON_PROP_USB_TYPEC_POLARITY property: true is flip |
---|
44 | 36 | * orientation, false is normal orientation. |
---|
45 | | - * |
---|
46 | 37 | */ |
---|
47 | 38 | |
---|
48 | 39 | #include <linux/clk.h> |
---|
.. | .. |
---|
60 | 51 | #include <linux/platform_device.h> |
---|
61 | 52 | #include <linux/regmap.h> |
---|
62 | 53 | #include <linux/reset.h> |
---|
| 54 | +#include <linux/usb/typec_dp.h> |
---|
| 55 | +#include <linux/usb/typec_mux.h> |
---|
63 | 56 | |
---|
64 | 57 | #include <linux/mfd/syscon.h> |
---|
65 | 58 | #include <linux/phy/phy.h> |
---|
66 | | -#include <linux/phy/phy-rockchip-typec.h> |
---|
| 59 | +#include <linux/usb/typec_mux.h> |
---|
| 60 | +#include <linux/usb/typec_dp.h> |
---|
67 | 61 | |
---|
68 | 62 | #define CMN_SSM_BANDGAP (0x21 << 2) |
---|
69 | 63 | #define CMN_SSM_BIAS (0x22 << 2) |
---|
.. | .. |
---|
393 | 387 | }; |
---|
394 | 388 | |
---|
395 | 389 | /** |
---|
396 | | - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. |
---|
| 390 | + * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration. |
---|
397 | 391 | * @reg: the base address for usb3-phy config. |
---|
398 | 392 | * @typec_conn_dir: the register of type-c connector direction. |
---|
399 | 393 | * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. |
---|
.. | .. |
---|
419 | 413 | int pe; |
---|
420 | 414 | }; |
---|
421 | 415 | |
---|
| 416 | +enum { |
---|
| 417 | + TYPEC_PHY_USB, |
---|
| 418 | + TYPEC_PHY_DP, |
---|
| 419 | + TYPEC_PHY_MAX, |
---|
| 420 | +}; |
---|
| 421 | + |
---|
422 | 422 | struct rockchip_typec_phy { |
---|
423 | 423 | struct device *dev; |
---|
424 | 424 | void __iomem *base; |
---|
425 | | - struct extcon_dev *extcon; |
---|
| 425 | + struct typec_mux *mux; |
---|
| 426 | + struct typec_switch *sw; |
---|
426 | 427 | struct regmap *grf_regs; |
---|
427 | 428 | struct clk *clk_core; |
---|
428 | 429 | struct clk *clk_ref; |
---|
429 | 430 | struct reset_control *uphy_rst; |
---|
430 | 431 | struct reset_control *pipe_rst; |
---|
431 | 432 | struct reset_control *tcphy_rst; |
---|
| 433 | + struct phy *phys[TYPEC_PHY_MAX]; |
---|
432 | 434 | const struct rockchip_usb3phy_port_cfg *port_cfgs; |
---|
433 | 435 | /* mutex to protect access to individual PHYs */ |
---|
434 | 436 | struct mutex lock; |
---|
435 | 437 | |
---|
436 | 438 | bool flip; |
---|
437 | 439 | u8 mode; |
---|
| 440 | + u8 new_mode; |
---|
438 | 441 | struct phy_config config[3][4]; |
---|
439 | 442 | }; |
---|
440 | 443 | |
---|
.. | .. |
---|
635 | 638 | }; |
---|
636 | 639 | |
---|
637 | 640 | enum phy_dp_power_state { |
---|
638 | | - PHY_DP_POWER_STATE_DISABLED = -1, |
---|
639 | 641 | PHY_DP_POWER_STATE_A0, |
---|
640 | 642 | PHY_DP_POWER_STATE_A1, |
---|
641 | 643 | PHY_DP_POWER_STATE_A2, |
---|
.. | .. |
---|
852 | 854 | writel(0x98, tcphy->base + TX_PSC_A3(lane)); |
---|
853 | 855 | } |
---|
854 | 856 | |
---|
855 | | -int tcphy_dp_set_phy_config(struct phy *phy, int link_rate, |
---|
856 | | - int lane_count, u8 swing, u8 pre_emp) |
---|
| 857 | +static int rockchip_dp_phy_set_voltages(struct rockchip_typec_phy *tcphy, |
---|
| 858 | + struct phy_configure_opts_dp *dp) |
---|
857 | 859 | { |
---|
858 | | - struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
---|
859 | 860 | u8 i, j, lane; |
---|
860 | 861 | u32 val; |
---|
861 | 862 | |
---|
862 | | - if (!phy->power_count) |
---|
863 | | - return -EPERM; |
---|
864 | 863 | |
---|
865 | | - if (lane_count == 4) { |
---|
| 864 | + if (dp->lanes == 4) { |
---|
866 | 865 | i = 0; |
---|
867 | 866 | j = 3; |
---|
868 | 867 | } else { |
---|
.. | .. |
---|
876 | 875 | } |
---|
877 | 876 | |
---|
878 | 877 | for (lane = i; lane <= j; lane++) { |
---|
879 | | - writel(tcphy->config[swing][pre_emp].swing, |
---|
| 878 | + writel(tcphy->config[dp->voltage[lane]][dp->pre[lane]].swing, |
---|
880 | 879 | tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); |
---|
881 | | - writel(tcphy->config[swing][pre_emp].pe, |
---|
| 880 | + writel(tcphy->config[dp->voltage[lane]][dp->pre[lane]].pe, |
---|
882 | 881 | tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); |
---|
883 | 882 | |
---|
884 | | - if (swing == 2 && pre_emp == 0 && link_rate != 540000) { |
---|
| 883 | + if (dp->voltage[lane] == 2 && dp->pre[lane] == 0 && dp->link_rate != 540000) { |
---|
885 | 884 | writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane)); |
---|
886 | 885 | writel(0x13c, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); |
---|
887 | 886 | } else { |
---|
.. | .. |
---|
891 | 890 | |
---|
892 | 891 | val = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
---|
893 | 892 | val &= ~GENMASK(14, 12); |
---|
894 | | - val |= ((link_rate == 540000) ? 0x5 : 0x6) << 12; |
---|
| 893 | + val |= ((dp->link_rate == 540000) ? 0x5 : 0x6) << 12; |
---|
895 | 894 | writel(val, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
---|
896 | 895 | } |
---|
897 | 896 | |
---|
898 | 897 | return 0; |
---|
899 | 898 | } |
---|
900 | | -EXPORT_SYMBOL(tcphy_dp_set_phy_config); |
---|
901 | 899 | |
---|
902 | | -int tcphy_dp_set_lane_count(struct phy *phy, u8 lane_count) |
---|
| 900 | +static int rockchip_dp_phy_set_lanes(struct rockchip_typec_phy *tcphy, |
---|
| 901 | + struct phy_configure_opts_dp *dp) |
---|
903 | 902 | { |
---|
904 | | - struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
---|
905 | 903 | u32 reg; |
---|
906 | | - |
---|
907 | | - if (!phy->power_count) |
---|
908 | | - return -EPERM; |
---|
909 | 904 | |
---|
910 | 905 | /* |
---|
911 | 906 | * In cases where fewer than the configured number of DP lanes are |
---|
.. | .. |
---|
917 | 912 | reg = readl(tcphy->base + PHY_DP_MODE_CTL); |
---|
918 | 913 | reg |= PHY_DP_LANE_DISABLE; |
---|
919 | 914 | |
---|
920 | | - switch (lane_count) { |
---|
| 915 | + switch (dp->lanes) { |
---|
921 | 916 | case 4: |
---|
922 | 917 | reg &= ~(PHY_DP_LANE_3_DISABLE | PHY_DP_LANE_2_DISABLE | |
---|
923 | 918 | PHY_DP_LANE_1_DISABLE | PHY_DP_LANE_0_DISABLE); |
---|
.. | .. |
---|
936 | 931 | |
---|
937 | 932 | return 0; |
---|
938 | 933 | } |
---|
939 | | -EXPORT_SYMBOL(tcphy_dp_set_lane_count); |
---|
940 | 934 | |
---|
941 | | -int tcphy_dp_set_link_rate(struct phy *phy, int link_rate, bool ssc_on) |
---|
| 935 | +static int rockchip_dp_phy_set_rate(struct rockchip_typec_phy *tcphy, |
---|
| 936 | + struct phy_configure_opts_dp *dp) |
---|
942 | 937 | { |
---|
943 | | - struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
---|
944 | 938 | const struct phy_reg *phy_cfg; |
---|
945 | 939 | u32 cmn_diag_hsclk_sel, phy_dp_clk_ctl, reg; |
---|
946 | 940 | u32 i, cfg_size; |
---|
947 | 941 | int ret; |
---|
948 | | - |
---|
949 | | - if (!phy->power_count) |
---|
950 | | - return -EPERM; |
---|
951 | 942 | |
---|
952 | 943 | /* Place the PHY lanes in the A3 power state. */ |
---|
953 | 944 | ret = tcphy_dp_set_power_state(tcphy, PHY_DP_POWER_STATE_A3); |
---|
.. | .. |
---|
991 | 982 | phy_dp_clk_ctl = readl(tcphy->base + PHY_DP_CLK_CTL); |
---|
992 | 983 | phy_dp_clk_ctl &= ~(GENMASK(15, 12) | GENMASK(11, 8)); |
---|
993 | 984 | |
---|
994 | | - switch (link_rate) { |
---|
995 | | - case 162000: |
---|
| 985 | + switch (dp->link_rate) { |
---|
| 986 | + case 1620: |
---|
996 | 987 | cmn_diag_hsclk_sel |= (3 << 4) | (0 << 0); |
---|
997 | 988 | phy_dp_clk_ctl |= (2 << 12) | (4 << 8); |
---|
998 | 989 | |
---|
999 | | - phy_cfg = ssc_on ? dp_pll_rbr_ssc_cfg : dp_pll_rbr_cfg; |
---|
1000 | | - cfg_size = ssc_on ? ARRAY_SIZE(dp_pll_rbr_ssc_cfg) : |
---|
| 990 | + phy_cfg = dp->ssc ? dp_pll_rbr_ssc_cfg : dp_pll_rbr_cfg; |
---|
| 991 | + cfg_size = dp->ssc ? ARRAY_SIZE(dp_pll_rbr_ssc_cfg) : |
---|
1001 | 992 | ARRAY_SIZE(dp_pll_rbr_cfg); |
---|
1002 | 993 | break; |
---|
1003 | | - case 270000: |
---|
| 994 | + case 2700: |
---|
1004 | 995 | cmn_diag_hsclk_sel |= (3 << 4) | (0 << 0); |
---|
1005 | 996 | phy_dp_clk_ctl |= (2 << 12) | (4 << 8); |
---|
1006 | 997 | |
---|
1007 | | - phy_cfg = ssc_on ? dp_pll_hbr_ssc_cfg : dp_pll_hbr_cfg; |
---|
1008 | | - cfg_size = ssc_on ? ARRAY_SIZE(dp_pll_hbr_ssc_cfg) : |
---|
| 998 | + phy_cfg = dp->ssc ? dp_pll_hbr_ssc_cfg : dp_pll_hbr_cfg; |
---|
| 999 | + cfg_size = dp->ssc ? ARRAY_SIZE(dp_pll_hbr_ssc_cfg) : |
---|
1009 | 1000 | ARRAY_SIZE(dp_pll_hbr_cfg); |
---|
1010 | 1001 | break; |
---|
1011 | | - case 540000: |
---|
| 1002 | + case 5400: |
---|
1012 | 1003 | cmn_diag_hsclk_sel |= (2 << 4) | (0 << 0); |
---|
1013 | 1004 | phy_dp_clk_ctl |= (1 << 12) | (2 << 8); |
---|
1014 | 1005 | |
---|
1015 | | - phy_cfg = ssc_on ? dp_pll_hbr2_ssc_cfg : dp_pll_hbr2_cfg; |
---|
1016 | | - cfg_size = ssc_on ? ARRAY_SIZE(dp_pll_hbr2_ssc_cfg) : |
---|
| 1006 | + phy_cfg = dp->ssc ? dp_pll_hbr2_ssc_cfg : dp_pll_hbr2_cfg; |
---|
| 1007 | + cfg_size = dp->ssc ? ARRAY_SIZE(dp_pll_hbr2_ssc_cfg) : |
---|
1017 | 1008 | ARRAY_SIZE(dp_pll_hbr2_cfg); |
---|
1018 | 1009 | break; |
---|
1019 | 1010 | default: |
---|
.. | .. |
---|
1071 | 1062 | |
---|
1072 | 1063 | return 0; |
---|
1073 | 1064 | } |
---|
1074 | | -EXPORT_SYMBOL(tcphy_dp_set_link_rate); |
---|
1075 | 1065 | |
---|
1076 | 1066 | static inline int property_enable(struct rockchip_typec_phy *tcphy, |
---|
1077 | 1067 | const struct usb3phy_reg *reg, bool en) |
---|
.. | .. |
---|
1334 | 1324 | |
---|
1335 | 1325 | static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) |
---|
1336 | 1326 | { |
---|
1337 | | - struct extcon_dev *edev = tcphy->extcon; |
---|
1338 | | - union extcon_property_value property; |
---|
1339 | | - unsigned int id; |
---|
1340 | | - bool ufp, dp; |
---|
1341 | | - u8 mode; |
---|
1342 | | - int ret; |
---|
| 1327 | + return tcphy->new_mode; |
---|
| 1328 | +} |
---|
1343 | 1329 | |
---|
1344 | | - if (!edev) |
---|
1345 | | - return MODE_DFP_USB; |
---|
| 1330 | +static int tcphy_orien_sw_set(struct typec_switch *sw, |
---|
| 1331 | + enum typec_orientation orien) |
---|
| 1332 | +{ |
---|
| 1333 | + struct rockchip_typec_phy *tcphy = typec_switch_get_drvdata(sw); |
---|
1346 | 1334 | |
---|
1347 | | - ufp = extcon_get_state(edev, EXTCON_USB); |
---|
1348 | | - dp = extcon_get_state(edev, EXTCON_DISP_DP); |
---|
| 1335 | + mutex_lock(&tcphy->lock); |
---|
1349 | 1336 | |
---|
1350 | | - mode = MODE_DFP_USB; |
---|
1351 | | - id = EXTCON_USB_HOST; |
---|
1352 | | - |
---|
1353 | | - if (ufp) { |
---|
1354 | | - mode = MODE_UFP_USB; |
---|
1355 | | - id = EXTCON_USB; |
---|
1356 | | - } else if (dp) { |
---|
1357 | | - mode = MODE_DFP_DP; |
---|
1358 | | - id = EXTCON_DISP_DP; |
---|
1359 | | - |
---|
1360 | | - ret = extcon_get_property(edev, id, EXTCON_PROP_USB_SS, |
---|
1361 | | - &property); |
---|
1362 | | - if (ret) { |
---|
1363 | | - dev_err(tcphy->dev, "get superspeed property failed\n"); |
---|
1364 | | - return ret; |
---|
1365 | | - } |
---|
1366 | | - |
---|
1367 | | - if (property.intval) |
---|
1368 | | - mode |= MODE_DFP_USB; |
---|
| 1337 | + if (orien == TYPEC_ORIENTATION_NONE) { |
---|
| 1338 | + tcphy->new_mode = MODE_DISCONNECT; |
---|
| 1339 | + goto unlock_ret; |
---|
1369 | 1340 | } |
---|
1370 | 1341 | |
---|
1371 | | - ret = extcon_get_property(edev, id, EXTCON_PROP_USB_TYPEC_POLARITY, |
---|
1372 | | - &property); |
---|
1373 | | - if (ret) { |
---|
1374 | | - dev_err(tcphy->dev, "get polarity property failed\n"); |
---|
1375 | | - return ret; |
---|
| 1342 | + tcphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; |
---|
| 1343 | + tcphy->new_mode = MODE_DFP_USB; |
---|
| 1344 | + |
---|
| 1345 | +unlock_ret: |
---|
| 1346 | + mutex_unlock(&tcphy->lock); |
---|
| 1347 | + return 0; |
---|
| 1348 | +} |
---|
| 1349 | + |
---|
| 1350 | +static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy) |
---|
| 1351 | +{ |
---|
| 1352 | + struct typec_switch_desc sw_desc = { }; |
---|
| 1353 | + |
---|
| 1354 | + sw_desc.drvdata = tcphy; |
---|
| 1355 | + sw_desc.fwnode = dev_fwnode(tcphy->dev); |
---|
| 1356 | + sw_desc.set = tcphy_orien_sw_set; |
---|
| 1357 | + |
---|
| 1358 | + tcphy->sw = typec_switch_register(tcphy->dev, &sw_desc); |
---|
| 1359 | + if (IS_ERR(tcphy->sw)) { |
---|
| 1360 | + dev_err(tcphy->dev, "Error register typec orientation switch: %ld\n", |
---|
| 1361 | + PTR_ERR(tcphy->sw)); |
---|
| 1362 | + return PTR_ERR(tcphy->sw); |
---|
1376 | 1363 | } |
---|
1377 | 1364 | |
---|
1378 | | - tcphy->flip = property.intval ? 1 : 0; |
---|
| 1365 | + return 0; |
---|
| 1366 | +} |
---|
1379 | 1367 | |
---|
1380 | | - return mode; |
---|
| 1368 | +static void udphy_orien_switch_unregister(void *data) |
---|
| 1369 | +{ |
---|
| 1370 | + struct rockchip_typec_phy *tcphy = data; |
---|
| 1371 | + |
---|
| 1372 | + typec_switch_unregister(tcphy->sw); |
---|
1381 | 1373 | } |
---|
1382 | 1374 | |
---|
1383 | 1375 | static int _rockchip_usb3_phy_power_on(struct rockchip_typec_phy *tcphy) |
---|
.. | .. |
---|
1415 | 1407 | regmap_read(tcphy->grf_regs, reg->offset, &val); |
---|
1416 | 1408 | if (!(val & BIT(reg->enable_bit))) { |
---|
1417 | 1409 | tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); |
---|
1418 | | - |
---|
1419 | 1410 | /* enable usb3 host */ |
---|
1420 | 1411 | tcphy_cfg_usb3_to_usb2_only(tcphy, false); |
---|
1421 | 1412 | goto unlock_ret; |
---|
.. | .. |
---|
1567 | 1558 | return 0; |
---|
1568 | 1559 | } |
---|
1569 | 1560 | |
---|
| 1561 | +static int rockchip_dp_phy_verify_config(struct rockchip_typec_phy *tcphy, |
---|
| 1562 | + struct phy_configure_opts_dp *dp) |
---|
| 1563 | +{ |
---|
| 1564 | + u8 i; |
---|
| 1565 | + |
---|
| 1566 | + /* If changing link rate was required, verify it's supported. */ |
---|
| 1567 | + if (dp->set_rate) { |
---|
| 1568 | + switch (dp->link_rate) { |
---|
| 1569 | + case 1620: |
---|
| 1570 | + case 2700: |
---|
| 1571 | + case 5400: |
---|
| 1572 | + /* valid bit rate */ |
---|
| 1573 | + break; |
---|
| 1574 | + default: |
---|
| 1575 | + return -EINVAL; |
---|
| 1576 | + } |
---|
| 1577 | + } |
---|
| 1578 | + |
---|
| 1579 | + /* Verify lane count. */ |
---|
| 1580 | + switch (dp->lanes) { |
---|
| 1581 | + case 1: |
---|
| 1582 | + case 2: |
---|
| 1583 | + case 4: |
---|
| 1584 | + /* valid lane count. */ |
---|
| 1585 | + break; |
---|
| 1586 | + default: |
---|
| 1587 | + return -EINVAL; |
---|
| 1588 | + } |
---|
| 1589 | + |
---|
| 1590 | + /* |
---|
| 1591 | + * If changing voltages is required, check swing and pre-emphasis |
---|
| 1592 | + * levels, per-lane. |
---|
| 1593 | + */ |
---|
| 1594 | + if (dp->set_voltages) { |
---|
| 1595 | + /* Lane count verified previously. */ |
---|
| 1596 | + for (i = 0; i < dp->lanes; i++) { |
---|
| 1597 | + if (dp->voltage[i] > 3 || dp->pre[i] > 3) |
---|
| 1598 | + return -EINVAL; |
---|
| 1599 | + |
---|
| 1600 | + /* Sum of voltage swing and pre-emphasis levels cannot |
---|
| 1601 | + * exceed 3. |
---|
| 1602 | + */ |
---|
| 1603 | + if (dp->voltage[i] + dp->pre[i] > 3) |
---|
| 1604 | + return -EINVAL; |
---|
| 1605 | + } |
---|
| 1606 | + } |
---|
| 1607 | + |
---|
| 1608 | + return 0; |
---|
| 1609 | +} |
---|
| 1610 | + |
---|
| 1611 | +static int rockchip_dp_phy_configure(struct phy *phy, |
---|
| 1612 | + union phy_configure_opts *opts) |
---|
| 1613 | +{ |
---|
| 1614 | + struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
---|
| 1615 | + int ret; |
---|
| 1616 | + |
---|
| 1617 | + if (!phy->power_count) |
---|
| 1618 | + return -EPERM; |
---|
| 1619 | + |
---|
| 1620 | + ret = rockchip_dp_phy_verify_config(tcphy, &opts->dp); |
---|
| 1621 | + if (ret) { |
---|
| 1622 | + dev_err(&phy->dev, "invalid params for phy configure\n"); |
---|
| 1623 | + return ret; |
---|
| 1624 | + } |
---|
| 1625 | + |
---|
| 1626 | + if (opts->dp.set_lanes) { |
---|
| 1627 | + ret = rockchip_dp_phy_set_lanes(tcphy, &opts->dp); |
---|
| 1628 | + if (ret) { |
---|
| 1629 | + dev_err(&phy->dev, "rockchip_dp_phy_set_lanes failed\n"); |
---|
| 1630 | + return ret; |
---|
| 1631 | + } |
---|
| 1632 | + } |
---|
| 1633 | + |
---|
| 1634 | + if (opts->dp.set_rate) { |
---|
| 1635 | + ret = rockchip_dp_phy_set_rate(tcphy, &opts->dp); |
---|
| 1636 | + if (ret) { |
---|
| 1637 | + dev_err(&phy->dev, "rockchip_dp_phy_set_rate failed\n"); |
---|
| 1638 | + return ret; |
---|
| 1639 | + } |
---|
| 1640 | + } |
---|
| 1641 | + |
---|
| 1642 | + if (opts->dp.set_voltages) { |
---|
| 1643 | + ret = rockchip_dp_phy_set_voltages(tcphy, &opts->dp); |
---|
| 1644 | + if (ret) { |
---|
| 1645 | + dev_err(&phy->dev, "rockchip_dp_phy_set_voltages failed\n"); |
---|
| 1646 | + return ret; |
---|
| 1647 | + } |
---|
| 1648 | + } |
---|
| 1649 | + |
---|
| 1650 | + return 0; |
---|
| 1651 | +} |
---|
| 1652 | + |
---|
1570 | 1653 | static const struct phy_ops rockchip_dp_phy_ops = { |
---|
1571 | 1654 | .power_on = rockchip_dp_phy_power_on, |
---|
1572 | 1655 | .power_off = rockchip_dp_phy_power_off, |
---|
| 1656 | + .configure = rockchip_dp_phy_configure, |
---|
1573 | 1657 | .owner = THIS_MODULE, |
---|
1574 | 1658 | }; |
---|
| 1659 | + |
---|
| 1660 | +static int tcphy_typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) |
---|
| 1661 | +{ |
---|
| 1662 | + struct rockchip_typec_phy *tcphy = typec_mux_get_drvdata(mux); |
---|
| 1663 | + struct typec_displayport_data *data; |
---|
| 1664 | + int hpd = 0; |
---|
| 1665 | + |
---|
| 1666 | + mutex_lock(&tcphy->lock); |
---|
| 1667 | + |
---|
| 1668 | + switch (state->mode) { |
---|
| 1669 | + case TYPEC_STATE_SAFE: |
---|
| 1670 | + fallthrough; |
---|
| 1671 | + case TYPEC_STATE_USB: |
---|
| 1672 | + tcphy->new_mode = MODE_DFP_USB; |
---|
| 1673 | + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], 0); |
---|
| 1674 | + break; |
---|
| 1675 | + case TYPEC_DP_STATE_C: |
---|
| 1676 | + case TYPEC_DP_STATE_E: |
---|
| 1677 | + tcphy->new_mode = MODE_DFP_DP; |
---|
| 1678 | + data = state->data; |
---|
| 1679 | + hpd = !!(data->status & DP_STATUS_HPD_STATE); |
---|
| 1680 | + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 4 : 0); |
---|
| 1681 | + break; |
---|
| 1682 | + case TYPEC_DP_STATE_D: |
---|
| 1683 | + tcphy->new_mode = MODE_DFP_DP | MODE_DFP_USB; |
---|
| 1684 | + data = state->data; |
---|
| 1685 | + hpd = !!(data->status & DP_STATUS_HPD_STATE); |
---|
| 1686 | + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 2 : 0); |
---|
| 1687 | + break; |
---|
| 1688 | + default: |
---|
| 1689 | + break; |
---|
| 1690 | + } |
---|
| 1691 | + |
---|
| 1692 | + mutex_unlock(&tcphy->lock); |
---|
| 1693 | + |
---|
| 1694 | + return 0; |
---|
| 1695 | +} |
---|
| 1696 | + |
---|
| 1697 | +static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy) |
---|
| 1698 | +{ |
---|
| 1699 | + struct typec_mux_desc mux_desc = {}; |
---|
| 1700 | + |
---|
| 1701 | + mux_desc.drvdata = tcphy; |
---|
| 1702 | + mux_desc.fwnode = dev_fwnode(tcphy->dev); |
---|
| 1703 | + mux_desc.set = tcphy_typec_mux_set; |
---|
| 1704 | + |
---|
| 1705 | + tcphy->mux = typec_mux_register(tcphy->dev, &mux_desc); |
---|
| 1706 | + if (IS_ERR(tcphy->mux)) { |
---|
| 1707 | + dev_err(tcphy->dev, "Error register typec mux: %ld\n", |
---|
| 1708 | + PTR_ERR(tcphy->mux)); |
---|
| 1709 | + return PTR_ERR(tcphy->mux); |
---|
| 1710 | + } |
---|
| 1711 | + |
---|
| 1712 | + return 0; |
---|
| 1713 | +} |
---|
| 1714 | + |
---|
| 1715 | +static void tcphy_typec_mux_unregister(void *data) |
---|
| 1716 | +{ |
---|
| 1717 | + struct rockchip_typec_phy *tcphy = data; |
---|
| 1718 | + |
---|
| 1719 | + typec_mux_unregister(tcphy->mux); |
---|
| 1720 | +} |
---|
1575 | 1721 | |
---|
1576 | 1722 | static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, |
---|
1577 | 1723 | struct device *dev) |
---|
.. | .. |
---|
1683 | 1829 | } |
---|
1684 | 1830 | |
---|
1685 | 1831 | if (!tcphy->port_cfgs) { |
---|
1686 | | - dev_err(dev, "no phy-config can be matched with %s node\n", |
---|
1687 | | - np->name); |
---|
| 1832 | + dev_err(dev, "no phy-config can be matched with %pOFn node\n", |
---|
| 1833 | + np); |
---|
1688 | 1834 | return -EINVAL; |
---|
1689 | 1835 | } |
---|
1690 | 1836 | |
---|
.. | .. |
---|
1693 | 1839 | return ret; |
---|
1694 | 1840 | |
---|
1695 | 1841 | tcphy->dev = dev; |
---|
| 1842 | + tcphy->new_mode = MODE_DFP_USB; |
---|
1696 | 1843 | platform_set_drvdata(pdev, tcphy); |
---|
1697 | 1844 | mutex_init(&tcphy->lock); |
---|
1698 | 1845 | |
---|
1699 | 1846 | typec_phy_pre_init(tcphy); |
---|
1700 | 1847 | |
---|
1701 | | - tcphy->extcon = extcon_get_edev_by_phandle(dev, 0); |
---|
1702 | | - if (IS_ERR(tcphy->extcon)) { |
---|
1703 | | - if (PTR_ERR(tcphy->extcon) == -ENODEV) { |
---|
1704 | | - tcphy->extcon = NULL; |
---|
1705 | | - } else { |
---|
1706 | | - if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER) |
---|
1707 | | - dev_err(dev, "Invalid or missing extcon\n"); |
---|
1708 | | - return PTR_ERR(tcphy->extcon); |
---|
1709 | | - } |
---|
| 1848 | + if (device_property_present(dev, "orientation-switch")) { |
---|
| 1849 | + ret = tcphy_setup_orien_switch(tcphy); |
---|
| 1850 | + if (ret) |
---|
| 1851 | + return ret; |
---|
| 1852 | + ret = devm_add_action_or_reset(dev, udphy_orien_switch_unregister, |
---|
| 1853 | + tcphy); |
---|
| 1854 | + if (ret) |
---|
| 1855 | + return ret; |
---|
| 1856 | + } |
---|
| 1857 | + |
---|
| 1858 | + if (device_property_present(dev, "svid")) { |
---|
| 1859 | + ret = tcphy_setup_typec_mux(tcphy); |
---|
| 1860 | + if (ret) |
---|
| 1861 | + return ret; |
---|
| 1862 | + |
---|
| 1863 | + ret = devm_add_action_or_reset(dev, tcphy_typec_mux_unregister, tcphy); |
---|
| 1864 | + if (ret) |
---|
| 1865 | + return ret; |
---|
1710 | 1866 | } |
---|
1711 | 1867 | |
---|
1712 | 1868 | pm_runtime_enable(dev); |
---|
.. | .. |
---|
1714 | 1870 | for_each_available_child_of_node(np, child_np) { |
---|
1715 | 1871 | struct phy *phy; |
---|
1716 | 1872 | |
---|
1717 | | - if (!of_node_cmp(child_np->name, "dp-port")) |
---|
| 1873 | + if (!of_node_cmp(child_np->name, "dp-port")) { |
---|
1718 | 1874 | phy = devm_phy_create(dev, child_np, |
---|
1719 | 1875 | &rockchip_dp_phy_ops); |
---|
1720 | | - else if (!of_node_cmp(child_np->name, "usb3-port")) |
---|
| 1876 | + if (IS_ERR(phy)) { |
---|
| 1877 | + dev_err(dev, "failed to create phy: %s\n", |
---|
| 1878 | + child_np->name); |
---|
| 1879 | + of_node_put(child_np); |
---|
| 1880 | + ret = PTR_ERR(phy); |
---|
| 1881 | + goto error; |
---|
| 1882 | + } |
---|
| 1883 | + tcphy->phys[TYPEC_PHY_DP] = phy; |
---|
| 1884 | + } else if (!of_node_cmp(child_np->name, "usb3-port")) { |
---|
1721 | 1885 | phy = devm_phy_create(dev, child_np, |
---|
1722 | 1886 | &rockchip_usb3_phy_ops); |
---|
1723 | | - else |
---|
| 1887 | + if (IS_ERR(phy)) { |
---|
| 1888 | + dev_err(dev, "failed to create phy: %s\n", |
---|
| 1889 | + child_np->name); |
---|
| 1890 | + of_node_put(child_np); |
---|
| 1891 | + ret = PTR_ERR(phy); |
---|
| 1892 | + goto error; |
---|
| 1893 | + } |
---|
| 1894 | + tcphy->phys[TYPEC_PHY_USB] = phy; |
---|
| 1895 | + } else { |
---|
1724 | 1896 | continue; |
---|
1725 | 1897 | |
---|
1726 | | - if (IS_ERR(phy)) { |
---|
1727 | | - dev_err(dev, "failed to create phy: %s\n", |
---|
1728 | | - child_np->name); |
---|
1729 | | - pm_runtime_disable(dev); |
---|
1730 | | - return PTR_ERR(phy); |
---|
1731 | 1898 | } |
---|
1732 | 1899 | |
---|
1733 | 1900 | phy_set_drvdata(phy, tcphy); |
---|
.. | .. |
---|
1736 | 1903 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
---|
1737 | 1904 | if (IS_ERR(phy_provider)) { |
---|
1738 | 1905 | dev_err(dev, "Failed to register phy provider\n"); |
---|
1739 | | - pm_runtime_disable(dev); |
---|
1740 | | - return PTR_ERR(phy_provider); |
---|
| 1906 | + ret = PTR_ERR(phy_provider); |
---|
| 1907 | + goto error; |
---|
1741 | 1908 | } |
---|
1742 | 1909 | |
---|
1743 | 1910 | return 0; |
---|
| 1911 | + |
---|
| 1912 | +error: |
---|
| 1913 | + pm_runtime_disable(dev); |
---|
| 1914 | + return ret; |
---|
1744 | 1915 | } |
---|
1745 | 1916 | |
---|
1746 | 1917 | static int rockchip_typec_phy_remove(struct platform_device *pdev) |
---|