.. | .. |
---|
| 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> |
---|
.. | .. |
---|
393 | 386 | }; |
---|
394 | 387 | |
---|
395 | 388 | /** |
---|
396 | | - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. |
---|
| 389 | + * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration. |
---|
397 | 390 | * @reg: the base address for usb3-phy config. |
---|
398 | 391 | * @typec_conn_dir: the register of type-c connector direction. |
---|
399 | 392 | * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. |
---|
.. | .. |
---|
419 | 412 | int pe; |
---|
420 | 413 | }; |
---|
421 | 414 | |
---|
| 415 | +enum { |
---|
| 416 | + TYPEC_PHY_USB, |
---|
| 417 | + TYPEC_PHY_DP, |
---|
| 418 | + TYPEC_PHY_MAX, |
---|
| 419 | +}; |
---|
| 420 | + |
---|
422 | 421 | struct rockchip_typec_phy { |
---|
423 | 422 | struct device *dev; |
---|
424 | 423 | void __iomem *base; |
---|
425 | | - struct extcon_dev *extcon; |
---|
| 424 | + struct typec_mux *mux; |
---|
| 425 | + struct typec_switch *sw; |
---|
426 | 426 | struct regmap *grf_regs; |
---|
427 | 427 | struct clk *clk_core; |
---|
428 | 428 | struct clk *clk_ref; |
---|
429 | 429 | struct reset_control *uphy_rst; |
---|
430 | 430 | struct reset_control *pipe_rst; |
---|
431 | 431 | struct reset_control *tcphy_rst; |
---|
| 432 | + struct phy *phys[TYPEC_PHY_MAX]; |
---|
432 | 433 | const struct rockchip_usb3phy_port_cfg *port_cfgs; |
---|
433 | 434 | /* mutex to protect access to individual PHYs */ |
---|
434 | 435 | struct mutex lock; |
---|
435 | 436 | |
---|
436 | 437 | bool flip; |
---|
437 | 438 | u8 mode; |
---|
| 439 | + u8 new_mode; |
---|
438 | 440 | struct phy_config config[3][4]; |
---|
439 | 441 | }; |
---|
440 | 442 | |
---|
.. | .. |
---|
635 | 637 | }; |
---|
636 | 638 | |
---|
637 | 639 | enum phy_dp_power_state { |
---|
638 | | - PHY_DP_POWER_STATE_DISABLED = -1, |
---|
639 | 640 | PHY_DP_POWER_STATE_A0, |
---|
640 | 641 | PHY_DP_POWER_STATE_A1, |
---|
641 | 642 | PHY_DP_POWER_STATE_A2, |
---|
.. | .. |
---|
843 | 844 | writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); |
---|
844 | 845 | } |
---|
845 | 846 | |
---|
846 | | -static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) |
---|
| 847 | +static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, int link_rate, |
---|
| 848 | + u8 swing, u8 pre_emp, u32 lane) |
---|
847 | 849 | { |
---|
| 850 | + u16 val; |
---|
| 851 | + |
---|
848 | 852 | writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane)); |
---|
849 | 853 | writel(0x6799, tcphy->base + TX_PSC_A0(lane)); |
---|
850 | 854 | writel(0x6798, tcphy->base + TX_PSC_A1(lane)); |
---|
851 | 855 | writel(0x98, tcphy->base + TX_PSC_A2(lane)); |
---|
852 | 856 | writel(0x98, tcphy->base + TX_PSC_A3(lane)); |
---|
| 857 | + |
---|
| 858 | + writel(tcphy->config[swing][pre_emp].swing, |
---|
| 859 | + tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); |
---|
| 860 | + writel(tcphy->config[swing][pre_emp].pe, |
---|
| 861 | + tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); |
---|
| 862 | + |
---|
| 863 | + if (swing == 2 && pre_emp == 0 && link_rate != 540000) { |
---|
| 864 | + writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane)); |
---|
| 865 | + writel(0x13c, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); |
---|
| 866 | + } else { |
---|
| 867 | + writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); |
---|
| 868 | + writel(0x0400, tcphy->base + TX_DIAG_TX_DRV(lane)); |
---|
| 869 | + } |
---|
| 870 | + |
---|
| 871 | + val = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
---|
| 872 | + val = val & 0x8fff; |
---|
| 873 | + switch (link_rate) { |
---|
| 874 | + case 540000: |
---|
| 875 | + val |= (5 << 12); |
---|
| 876 | + break; |
---|
| 877 | + case 162000: |
---|
| 878 | + case 270000: |
---|
| 879 | + default: |
---|
| 880 | + val |= (6 << 12); |
---|
| 881 | + break; |
---|
| 882 | + } |
---|
| 883 | + writel(val, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
---|
853 | 884 | } |
---|
854 | 885 | |
---|
855 | 886 | int tcphy_dp_set_phy_config(struct phy *phy, int link_rate, |
---|
856 | 887 | int lane_count, u8 swing, u8 pre_emp) |
---|
857 | 888 | { |
---|
858 | 889 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
---|
859 | | - u8 i, j, lane; |
---|
860 | | - u32 val; |
---|
| 890 | + u8 i; |
---|
861 | 891 | |
---|
862 | 892 | if (!phy->power_count) |
---|
863 | 893 | return -EPERM; |
---|
864 | 894 | |
---|
865 | | - if (lane_count == 4) { |
---|
866 | | - i = 0; |
---|
867 | | - j = 3; |
---|
| 895 | + if (tcphy->mode == MODE_DFP_DP) { |
---|
| 896 | + for (i = 0; i < 4; i++) |
---|
| 897 | + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, i); |
---|
868 | 898 | } else { |
---|
869 | 899 | if (tcphy->flip) { |
---|
870 | | - i = 0; |
---|
871 | | - j = 1; |
---|
| 900 | + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 0); |
---|
| 901 | + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 1); |
---|
872 | 902 | } else { |
---|
873 | | - i = 2; |
---|
874 | | - j = 3; |
---|
| 903 | + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 2); |
---|
| 904 | + tcphy_dp_cfg_lane(tcphy, link_rate, swing, pre_emp, 3); |
---|
875 | 905 | } |
---|
876 | | - } |
---|
877 | | - |
---|
878 | | - for (lane = i; lane <= j; lane++) { |
---|
879 | | - writel(tcphy->config[swing][pre_emp].swing, |
---|
880 | | - tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); |
---|
881 | | - writel(tcphy->config[swing][pre_emp].pe, |
---|
882 | | - tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); |
---|
883 | | - |
---|
884 | | - if (swing == 2 && pre_emp == 0 && link_rate != 540000) { |
---|
885 | | - writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane)); |
---|
886 | | - writel(0x13c, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); |
---|
887 | | - } else { |
---|
888 | | - writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); |
---|
889 | | - writel(0x0400, tcphy->base + TX_DIAG_TX_DRV(lane)); |
---|
890 | | - } |
---|
891 | | - |
---|
892 | | - val = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
---|
893 | | - val &= ~GENMASK(14, 12); |
---|
894 | | - val |= ((link_rate == 540000) ? 0x5 : 0x6) << 12; |
---|
895 | | - writel(val, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
---|
896 | 906 | } |
---|
897 | 907 | |
---|
898 | 908 | return 0; |
---|
.. | .. |
---|
1277 | 1287 | tcphy_cfg_usb3_to_usb2_only(tcphy, true); |
---|
1278 | 1288 | tcphy_cfg_dp_pll(tcphy, DP_DEFAULT_RATE); |
---|
1279 | 1289 | for (i = 0; i < 4; i++) |
---|
1280 | | - tcphy_dp_cfg_lane(tcphy, i); |
---|
| 1290 | + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, i); |
---|
1281 | 1291 | } else { |
---|
1282 | 1292 | tcphy_cfg_usb3_pll(tcphy); |
---|
1283 | 1293 | tcphy_cfg_dp_pll(tcphy, DP_DEFAULT_RATE); |
---|
1284 | 1294 | if (tcphy->flip) { |
---|
1285 | 1295 | tcphy_tx_usb3_cfg_lane(tcphy, 3); |
---|
1286 | 1296 | tcphy_rx_usb3_cfg_lane(tcphy, 2); |
---|
1287 | | - tcphy_dp_cfg_lane(tcphy, 0); |
---|
1288 | | - tcphy_dp_cfg_lane(tcphy, 1); |
---|
| 1297 | + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 0); |
---|
| 1298 | + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 1); |
---|
1289 | 1299 | } else { |
---|
1290 | 1300 | tcphy_tx_usb3_cfg_lane(tcphy, 0); |
---|
1291 | 1301 | tcphy_rx_usb3_cfg_lane(tcphy, 1); |
---|
1292 | | - tcphy_dp_cfg_lane(tcphy, 2); |
---|
1293 | | - tcphy_dp_cfg_lane(tcphy, 3); |
---|
| 1302 | + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 2); |
---|
| 1303 | + tcphy_dp_cfg_lane(tcphy, DP_DEFAULT_RATE, 0, 0, 3); |
---|
1294 | 1304 | } |
---|
1295 | 1305 | } |
---|
1296 | 1306 | |
---|
.. | .. |
---|
1334 | 1344 | |
---|
1335 | 1345 | static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) |
---|
1336 | 1346 | { |
---|
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; |
---|
| 1347 | + return tcphy->new_mode; |
---|
| 1348 | +} |
---|
1343 | 1349 | |
---|
1344 | | - if (!edev) |
---|
1345 | | - return MODE_DFP_USB; |
---|
| 1350 | +static int tcphy_orien_sw_set(struct typec_switch *sw, |
---|
| 1351 | + enum typec_orientation orien) |
---|
| 1352 | +{ |
---|
| 1353 | + struct rockchip_typec_phy *tcphy = typec_switch_get_drvdata(sw); |
---|
1346 | 1354 | |
---|
1347 | | - ufp = extcon_get_state(edev, EXTCON_USB); |
---|
1348 | | - dp = extcon_get_state(edev, EXTCON_DISP_DP); |
---|
| 1355 | + mutex_lock(&tcphy->lock); |
---|
1349 | 1356 | |
---|
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; |
---|
| 1357 | + if (orien == TYPEC_ORIENTATION_NONE) { |
---|
| 1358 | + tcphy->new_mode = MODE_DISCONNECT; |
---|
| 1359 | + goto unlock_ret; |
---|
1369 | 1360 | } |
---|
1370 | 1361 | |
---|
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; |
---|
| 1362 | + tcphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; |
---|
| 1363 | + tcphy->new_mode = MODE_DFP_USB; |
---|
| 1364 | + |
---|
| 1365 | +unlock_ret: |
---|
| 1366 | + mutex_unlock(&tcphy->lock); |
---|
| 1367 | + return 0; |
---|
| 1368 | +} |
---|
| 1369 | + |
---|
| 1370 | +static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy) |
---|
| 1371 | +{ |
---|
| 1372 | + struct typec_switch_desc sw_desc = { }; |
---|
| 1373 | + |
---|
| 1374 | + sw_desc.drvdata = tcphy; |
---|
| 1375 | + sw_desc.fwnode = dev_fwnode(tcphy->dev); |
---|
| 1376 | + sw_desc.set = tcphy_orien_sw_set; |
---|
| 1377 | + |
---|
| 1378 | + tcphy->sw = typec_switch_register(tcphy->dev, &sw_desc); |
---|
| 1379 | + if (IS_ERR(tcphy->sw)) { |
---|
| 1380 | + dev_err(tcphy->dev, "Error register typec orientation switch: %ld\n", |
---|
| 1381 | + PTR_ERR(tcphy->sw)); |
---|
| 1382 | + return PTR_ERR(tcphy->sw); |
---|
1376 | 1383 | } |
---|
1377 | 1384 | |
---|
1378 | | - tcphy->flip = property.intval ? 1 : 0; |
---|
| 1385 | + return 0; |
---|
| 1386 | +} |
---|
1379 | 1387 | |
---|
1380 | | - return mode; |
---|
| 1388 | +static void udphy_orien_switch_unregister(void *data) |
---|
| 1389 | +{ |
---|
| 1390 | + struct rockchip_typec_phy *tcphy = data; |
---|
| 1391 | + |
---|
| 1392 | + typec_switch_unregister(tcphy->sw); |
---|
1381 | 1393 | } |
---|
1382 | 1394 | |
---|
1383 | 1395 | static int _rockchip_usb3_phy_power_on(struct rockchip_typec_phy *tcphy) |
---|
.. | .. |
---|
1415 | 1427 | regmap_read(tcphy->grf_regs, reg->offset, &val); |
---|
1416 | 1428 | if (!(val & BIT(reg->enable_bit))) { |
---|
1417 | 1429 | tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); |
---|
1418 | | - |
---|
1419 | 1430 | /* enable usb3 host */ |
---|
1420 | 1431 | tcphy_cfg_usb3_to_usb2_only(tcphy, false); |
---|
1421 | 1432 | goto unlock_ret; |
---|
.. | .. |
---|
1573 | 1584 | .owner = THIS_MODULE, |
---|
1574 | 1585 | }; |
---|
1575 | 1586 | |
---|
| 1587 | +static int tcphy_typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) |
---|
| 1588 | +{ |
---|
| 1589 | + struct rockchip_typec_phy *tcphy = typec_mux_get_drvdata(mux); |
---|
| 1590 | + struct typec_displayport_data *data; |
---|
| 1591 | + int hpd = 0; |
---|
| 1592 | + |
---|
| 1593 | + mutex_lock(&tcphy->lock); |
---|
| 1594 | + |
---|
| 1595 | + switch (state->mode) { |
---|
| 1596 | + case TYPEC_STATE_SAFE: |
---|
| 1597 | + fallthrough; |
---|
| 1598 | + case TYPEC_STATE_USB: |
---|
| 1599 | + tcphy->new_mode = MODE_DFP_USB; |
---|
| 1600 | + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], 0); |
---|
| 1601 | + break; |
---|
| 1602 | + case TYPEC_DP_STATE_C: |
---|
| 1603 | + case TYPEC_DP_STATE_E: |
---|
| 1604 | + tcphy->new_mode = MODE_DFP_DP; |
---|
| 1605 | + data = state->data; |
---|
| 1606 | + hpd = !!(data->status & DP_STATUS_HPD_STATE); |
---|
| 1607 | + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 4 : 0); |
---|
| 1608 | + break; |
---|
| 1609 | + case TYPEC_DP_STATE_D: |
---|
| 1610 | + tcphy->new_mode = MODE_DFP_DP | MODE_DFP_USB; |
---|
| 1611 | + data = state->data; |
---|
| 1612 | + hpd = !!(data->status & DP_STATUS_HPD_STATE); |
---|
| 1613 | + phy_set_bus_width(tcphy->phys[TYPEC_PHY_DP], hpd ? 2 : 0); |
---|
| 1614 | + break; |
---|
| 1615 | + default: |
---|
| 1616 | + break; |
---|
| 1617 | + } |
---|
| 1618 | + |
---|
| 1619 | + mutex_unlock(&tcphy->lock); |
---|
| 1620 | + |
---|
| 1621 | + return 0; |
---|
| 1622 | +} |
---|
| 1623 | + |
---|
| 1624 | +static int tcphy_setup_typec_mux(struct rockchip_typec_phy *tcphy) |
---|
| 1625 | +{ |
---|
| 1626 | + struct typec_mux_desc mux_desc = {}; |
---|
| 1627 | + |
---|
| 1628 | + mux_desc.drvdata = tcphy; |
---|
| 1629 | + mux_desc.fwnode = dev_fwnode(tcphy->dev); |
---|
| 1630 | + mux_desc.set = tcphy_typec_mux_set; |
---|
| 1631 | + |
---|
| 1632 | + tcphy->mux = typec_mux_register(tcphy->dev, &mux_desc); |
---|
| 1633 | + if (IS_ERR(tcphy->mux)) { |
---|
| 1634 | + dev_err(tcphy->dev, "Error register typec mux: %ld\n", |
---|
| 1635 | + PTR_ERR(tcphy->mux)); |
---|
| 1636 | + return PTR_ERR(tcphy->mux); |
---|
| 1637 | + } |
---|
| 1638 | + |
---|
| 1639 | + return 0; |
---|
| 1640 | +} |
---|
| 1641 | + |
---|
| 1642 | +static void tcphy_typec_mux_unregister(void *data) |
---|
| 1643 | +{ |
---|
| 1644 | + struct rockchip_typec_phy *tcphy = data; |
---|
| 1645 | + |
---|
| 1646 | + typec_mux_unregister(tcphy->mux); |
---|
| 1647 | +} |
---|
| 1648 | + |
---|
1576 | 1649 | static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, |
---|
1577 | 1650 | struct device *dev) |
---|
1578 | 1651 | { |
---|
.. | .. |
---|
1683 | 1756 | } |
---|
1684 | 1757 | |
---|
1685 | 1758 | if (!tcphy->port_cfgs) { |
---|
1686 | | - dev_err(dev, "no phy-config can be matched with %s node\n", |
---|
1687 | | - np->name); |
---|
| 1759 | + dev_err(dev, "no phy-config can be matched with %pOFn node\n", |
---|
| 1760 | + np); |
---|
1688 | 1761 | return -EINVAL; |
---|
1689 | 1762 | } |
---|
1690 | 1763 | |
---|
.. | .. |
---|
1693 | 1766 | return ret; |
---|
1694 | 1767 | |
---|
1695 | 1768 | tcphy->dev = dev; |
---|
| 1769 | + tcphy->new_mode = MODE_DFP_USB; |
---|
1696 | 1770 | platform_set_drvdata(pdev, tcphy); |
---|
1697 | 1771 | mutex_init(&tcphy->lock); |
---|
1698 | 1772 | |
---|
1699 | 1773 | typec_phy_pre_init(tcphy); |
---|
1700 | 1774 | |
---|
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 | | - } |
---|
| 1775 | + if (device_property_present(dev, "orientation-switch")) { |
---|
| 1776 | + ret = tcphy_setup_orien_switch(tcphy); |
---|
| 1777 | + if (ret) |
---|
| 1778 | + return ret; |
---|
| 1779 | + ret = devm_add_action_or_reset(dev, udphy_orien_switch_unregister, |
---|
| 1780 | + tcphy); |
---|
| 1781 | + if (ret) |
---|
| 1782 | + return ret; |
---|
| 1783 | + } |
---|
| 1784 | + |
---|
| 1785 | + if (device_property_present(dev, "svid")) { |
---|
| 1786 | + ret = tcphy_setup_typec_mux(tcphy); |
---|
| 1787 | + if (ret) |
---|
| 1788 | + return ret; |
---|
| 1789 | + |
---|
| 1790 | + ret = devm_add_action_or_reset(dev, tcphy_typec_mux_unregister, tcphy); |
---|
| 1791 | + if (ret) |
---|
| 1792 | + return ret; |
---|
1710 | 1793 | } |
---|
1711 | 1794 | |
---|
1712 | 1795 | pm_runtime_enable(dev); |
---|
.. | .. |
---|
1714 | 1797 | for_each_available_child_of_node(np, child_np) { |
---|
1715 | 1798 | struct phy *phy; |
---|
1716 | 1799 | |
---|
1717 | | - if (!of_node_cmp(child_np->name, "dp-port")) |
---|
| 1800 | + if (!of_node_cmp(child_np->name, "dp-port")) { |
---|
1718 | 1801 | phy = devm_phy_create(dev, child_np, |
---|
1719 | 1802 | &rockchip_dp_phy_ops); |
---|
1720 | | - else if (!of_node_cmp(child_np->name, "usb3-port")) |
---|
| 1803 | + if (IS_ERR(phy)) { |
---|
| 1804 | + dev_err(dev, "failed to create phy: %s\n", |
---|
| 1805 | + child_np->name); |
---|
| 1806 | + of_node_put(child_np); |
---|
| 1807 | + ret = PTR_ERR(phy); |
---|
| 1808 | + goto error; |
---|
| 1809 | + } |
---|
| 1810 | + tcphy->phys[TYPEC_PHY_DP] = phy; |
---|
| 1811 | + } else if (!of_node_cmp(child_np->name, "usb3-port")) { |
---|
1721 | 1812 | phy = devm_phy_create(dev, child_np, |
---|
1722 | 1813 | &rockchip_usb3_phy_ops); |
---|
1723 | | - else |
---|
| 1814 | + if (IS_ERR(phy)) { |
---|
| 1815 | + dev_err(dev, "failed to create phy: %s\n", |
---|
| 1816 | + child_np->name); |
---|
| 1817 | + of_node_put(child_np); |
---|
| 1818 | + ret = PTR_ERR(phy); |
---|
| 1819 | + goto error; |
---|
| 1820 | + } |
---|
| 1821 | + tcphy->phys[TYPEC_PHY_USB] = phy; |
---|
| 1822 | + } else { |
---|
1724 | 1823 | continue; |
---|
1725 | 1824 | |
---|
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 | 1825 | } |
---|
1732 | 1826 | |
---|
1733 | 1827 | phy_set_drvdata(phy, tcphy); |
---|
.. | .. |
---|
1736 | 1830 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
---|
1737 | 1831 | if (IS_ERR(phy_provider)) { |
---|
1738 | 1832 | dev_err(dev, "Failed to register phy provider\n"); |
---|
1739 | | - pm_runtime_disable(dev); |
---|
1740 | | - return PTR_ERR(phy_provider); |
---|
| 1833 | + ret = PTR_ERR(phy_provider); |
---|
| 1834 | + goto error; |
---|
1741 | 1835 | } |
---|
1742 | 1836 | |
---|
1743 | 1837 | return 0; |
---|
| 1838 | + |
---|
| 1839 | +error: |
---|
| 1840 | + pm_runtime_disable(dev); |
---|
| 1841 | + return ret; |
---|
1744 | 1842 | } |
---|
1745 | 1843 | |
---|
1746 | 1844 | static int rockchip_typec_phy_remove(struct platform_device *pdev) |
---|