18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Salvo PHY is a 28nm PHY, it is a legacy PHY, and only 48c2ecf20Sopenharmony_ci * for USB3 and USB2. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 NXP 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* PHY register definition */ 198c2ecf20Sopenharmony_ci#define PHY_PMA_CMN_CTRL1 0xC800 208c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_HSCLK_SEL 0x01e0 218c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR 0x0084 228c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR 0x0085 238c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_INTDIV 0x0094 248c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_FRACDIV 0x0095 258c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_HIGH_THR 0x0096 268c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_SS_CTRL1 0x0098 278c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_SS_CTRL2 0x0099 288c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PLL0_DSM_DIAG 0x0097 298c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_PLL0_OVRD 0x01c2 308c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD 0x01c0 318c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD 0x01c1 328c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE 0x01C5 338c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_PLL0_CP_TUNE 0x01C6 348c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_PLL0_LF_PROG 0x01C7 358c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_DIAG_PLL0_TEST_MODE 0x01c4 368c2ecf20Sopenharmony_ci#define TB_ADDR_CMN_PSM_CLK_CTRL 0x0061 378c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR 0x40ea 388c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_RCTRL 0x4001 398c2ecf20Sopenharmony_ci#define TB_ADDR_TX_PSC_A0 0x4100 408c2ecf20Sopenharmony_ci#define TB_ADDR_TX_PSC_A1 0x4101 418c2ecf20Sopenharmony_ci#define TB_ADDR_TX_PSC_A2 0x4102 428c2ecf20Sopenharmony_ci#define TB_ADDR_TX_PSC_A3 0x4103 438c2ecf20Sopenharmony_ci#define TB_ADDR_TX_DIAG_ECTRL_OVRD 0x41f5 448c2ecf20Sopenharmony_ci#define TB_ADDR_TX_PSC_CAL 0x4106 458c2ecf20Sopenharmony_ci#define TB_ADDR_TX_PSC_RDY 0x4107 468c2ecf20Sopenharmony_ci#define TB_ADDR_RX_PSC_A0 0x8000 478c2ecf20Sopenharmony_ci#define TB_ADDR_RX_PSC_A1 0x8001 488c2ecf20Sopenharmony_ci#define TB_ADDR_RX_PSC_A2 0x8002 498c2ecf20Sopenharmony_ci#define TB_ADDR_RX_PSC_A3 0x8003 508c2ecf20Sopenharmony_ci#define TB_ADDR_RX_PSC_CAL 0x8006 518c2ecf20Sopenharmony_ci#define TB_ADDR_RX_PSC_RDY 0x8007 528c2ecf20Sopenharmony_ci#define TB_ADDR_TX_TXCC_MGNLS_MULT_000 0x4058 538c2ecf20Sopenharmony_ci#define TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY 0x41e7 548c2ecf20Sopenharmony_ci#define TB_ADDR_RX_SLC_CU_ITER_TMR 0x80e3 558c2ecf20Sopenharmony_ci#define TB_ADDR_RX_SIGDET_HL_FILT_TMR 0x8090 568c2ecf20Sopenharmony_ci#define TB_ADDR_RX_SAMP_DAC_CTRL 0x8058 578c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_SIGDET_TUNE 0x81dc 588c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_LFPSDET_TUNE2 0x81df 598c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_BS_TM 0x81f5 608c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_DFE_CTRL1 0x81d3 618c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM4 0x81c7 628c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_ILL_E_TRIM0 0x81c2 638c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_ILL_IQ_TRIM0 0x81c1 648c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM6 0x81c9 658c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_RXFE_TM3 0x81f8 668c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_RXFE_TM4 0x81f9 678c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_LFPSDET_TUNE 0x81dd 688c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_DFE_CTRL3 0x81d5 698c2ecf20Sopenharmony_ci#define TB_ADDR_RX_DIAG_SC2C_DELAY 0x81e1 708c2ecf20Sopenharmony_ci#define TB_ADDR_RX_REE_VGA_GAIN_NODFE 0x81bf 718c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_CAL_TMR 0x4002 728c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A0BYP_TMR 0x4004 738c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A0IN_TMR 0x4003 748c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A1IN_TMR 0x4005 758c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A2IN_TMR 0x4006 768c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A3IN_TMR 0x4007 778c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A4IN_TMR 0x4008 788c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A5IN_TMR 0x4009 798c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A0OUT_TMR 0x400a 808c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A1OUT_TMR 0x400b 818c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A2OUT_TMR 0x400c 828c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A3OUT_TMR 0x400d 838c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A4OUT_TMR 0x400e 848c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_PSM_A5OUT_TMR 0x400f 858c2ecf20Sopenharmony_ci#define TB_ADDR_TX_RCVDET_EN_TMR 0x4122 868c2ecf20Sopenharmony_ci#define TB_ADDR_TX_RCVDET_ST_TMR 0x4123 878c2ecf20Sopenharmony_ci#define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40f2 888c2ecf20Sopenharmony_ci#define TB_ADDR_TX_RCVDETSC_CTRL 0x4124 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* TB_ADDR_TX_RCVDETSC_CTRL */ 918c2ecf20Sopenharmony_ci#define RXDET_IN_P3_32KHZ BIT(0) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistruct cdns_reg_pairs { 948c2ecf20Sopenharmony_ci u16 val; 958c2ecf20Sopenharmony_ci u32 off; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistruct cdns_salvo_data { 998c2ecf20Sopenharmony_ci u8 reg_offset_shift; 1008c2ecf20Sopenharmony_ci const struct cdns_reg_pairs *init_sequence_val; 1018c2ecf20Sopenharmony_ci u8 init_sequence_length; 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistruct cdns_salvo_phy { 1058c2ecf20Sopenharmony_ci struct phy *phy; 1068c2ecf20Sopenharmony_ci struct clk *clk; 1078c2ecf20Sopenharmony_ci void __iomem *base; 1088c2ecf20Sopenharmony_ci struct cdns_salvo_data *data; 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct of_device_id cdns_salvo_phy_of_match[]; 1128c2ecf20Sopenharmony_cistatic u16 cdns_salvo_read(struct cdns_salvo_phy *salvo_phy, u32 reg) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci return (u16)readl(salvo_phy->base + 1158c2ecf20Sopenharmony_ci reg * (1 << salvo_phy->data->reg_offset_shift)); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void cdns_salvo_write(struct cdns_salvo_phy *salvo_phy, 1198c2ecf20Sopenharmony_ci u32 reg, u16 val) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci writel(val, salvo_phy->base + 1228c2ecf20Sopenharmony_ci reg * (1 << salvo_phy->data->reg_offset_shift)); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* 1268c2ecf20Sopenharmony_ci * Below bringup sequence pair are from Cadence PHY's User Guide 1278c2ecf20Sopenharmony_ci * and NXP platform tuning results. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_cistatic const struct cdns_reg_pairs cdns_nxp_sequence_pair[] = { 1308c2ecf20Sopenharmony_ci {0x0830, PHY_PMA_CMN_CTRL1}, 1318c2ecf20Sopenharmony_ci {0x0010, TB_ADDR_CMN_DIAG_HSCLK_SEL}, 1328c2ecf20Sopenharmony_ci {0x00f0, TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR}, 1338c2ecf20Sopenharmony_ci {0x0018, TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR}, 1348c2ecf20Sopenharmony_ci {0x00d0, TB_ADDR_CMN_PLL0_INTDIV}, 1358c2ecf20Sopenharmony_ci {0x4aaa, TB_ADDR_CMN_PLL0_FRACDIV}, 1368c2ecf20Sopenharmony_ci {0x0034, TB_ADDR_CMN_PLL0_HIGH_THR}, 1378c2ecf20Sopenharmony_ci {0x01ee, TB_ADDR_CMN_PLL0_SS_CTRL1}, 1388c2ecf20Sopenharmony_ci {0x7f03, TB_ADDR_CMN_PLL0_SS_CTRL2}, 1398c2ecf20Sopenharmony_ci {0x0020, TB_ADDR_CMN_PLL0_DSM_DIAG}, 1408c2ecf20Sopenharmony_ci {0x0000, TB_ADDR_CMN_DIAG_PLL0_OVRD}, 1418c2ecf20Sopenharmony_ci {0x0000, TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD}, 1428c2ecf20Sopenharmony_ci {0x0000, TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD}, 1438c2ecf20Sopenharmony_ci {0x0007, TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE}, 1448c2ecf20Sopenharmony_ci {0x0027, TB_ADDR_CMN_DIAG_PLL0_CP_TUNE}, 1458c2ecf20Sopenharmony_ci {0x0008, TB_ADDR_CMN_DIAG_PLL0_LF_PROG}, 1468c2ecf20Sopenharmony_ci {0x0022, TB_ADDR_CMN_DIAG_PLL0_TEST_MODE}, 1478c2ecf20Sopenharmony_ci {0x000a, TB_ADDR_CMN_PSM_CLK_CTRL}, 1488c2ecf20Sopenharmony_ci {0x0139, TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR}, 1498c2ecf20Sopenharmony_ci {0xbefc, TB_ADDR_XCVR_PSM_RCTRL}, 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci {0x7799, TB_ADDR_TX_PSC_A0}, 1528c2ecf20Sopenharmony_ci {0x7798, TB_ADDR_TX_PSC_A1}, 1538c2ecf20Sopenharmony_ci {0x509b, TB_ADDR_TX_PSC_A2}, 1548c2ecf20Sopenharmony_ci {0x0003, TB_ADDR_TX_DIAG_ECTRL_OVRD}, 1558c2ecf20Sopenharmony_ci {0x509b, TB_ADDR_TX_PSC_A3}, 1568c2ecf20Sopenharmony_ci {0x2090, TB_ADDR_TX_PSC_CAL}, 1578c2ecf20Sopenharmony_ci {0x2090, TB_ADDR_TX_PSC_RDY}, 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci {0xA6FD, TB_ADDR_RX_PSC_A0}, 1608c2ecf20Sopenharmony_ci {0xA6FD, TB_ADDR_RX_PSC_A1}, 1618c2ecf20Sopenharmony_ci {0xA410, TB_ADDR_RX_PSC_A2}, 1628c2ecf20Sopenharmony_ci {0x2410, TB_ADDR_RX_PSC_A3}, 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci {0x23FF, TB_ADDR_RX_PSC_CAL}, 1658c2ecf20Sopenharmony_ci {0x2010, TB_ADDR_RX_PSC_RDY}, 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci {0x0020, TB_ADDR_TX_TXCC_MGNLS_MULT_000}, 1688c2ecf20Sopenharmony_ci {0x00ff, TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY}, 1698c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_RX_SLC_CU_ITER_TMR}, 1708c2ecf20Sopenharmony_ci {0x0013, TB_ADDR_RX_SIGDET_HL_FILT_TMR}, 1718c2ecf20Sopenharmony_ci {0x0000, TB_ADDR_RX_SAMP_DAC_CTRL}, 1728c2ecf20Sopenharmony_ci {0x1004, TB_ADDR_RX_DIAG_SIGDET_TUNE}, 1738c2ecf20Sopenharmony_ci {0x4041, TB_ADDR_RX_DIAG_LFPSDET_TUNE2}, 1748c2ecf20Sopenharmony_ci {0x0480, TB_ADDR_RX_DIAG_BS_TM}, 1758c2ecf20Sopenharmony_ci {0x8006, TB_ADDR_RX_DIAG_DFE_CTRL1}, 1768c2ecf20Sopenharmony_ci {0x003f, TB_ADDR_RX_DIAG_ILL_IQE_TRIM4}, 1778c2ecf20Sopenharmony_ci {0x543f, TB_ADDR_RX_DIAG_ILL_E_TRIM0}, 1788c2ecf20Sopenharmony_ci {0x543f, TB_ADDR_RX_DIAG_ILL_IQ_TRIM0}, 1798c2ecf20Sopenharmony_ci {0x0000, TB_ADDR_RX_DIAG_ILL_IQE_TRIM6}, 1808c2ecf20Sopenharmony_ci {0x8000, TB_ADDR_RX_DIAG_RXFE_TM3}, 1818c2ecf20Sopenharmony_ci {0x0003, TB_ADDR_RX_DIAG_RXFE_TM4}, 1828c2ecf20Sopenharmony_ci {0x2408, TB_ADDR_RX_DIAG_LFPSDET_TUNE}, 1838c2ecf20Sopenharmony_ci {0x05ca, TB_ADDR_RX_DIAG_DFE_CTRL3}, 1848c2ecf20Sopenharmony_ci {0x0258, TB_ADDR_RX_DIAG_SC2C_DELAY}, 1858c2ecf20Sopenharmony_ci {0x1fff, TB_ADDR_RX_REE_VGA_GAIN_NODFE}, 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci {0x02c6, TB_ADDR_XCVR_PSM_CAL_TMR}, 1888c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_XCVR_PSM_A0BYP_TMR}, 1898c2ecf20Sopenharmony_ci {0x02c6, TB_ADDR_XCVR_PSM_A0IN_TMR}, 1908c2ecf20Sopenharmony_ci {0x0010, TB_ADDR_XCVR_PSM_A1IN_TMR}, 1918c2ecf20Sopenharmony_ci {0x0010, TB_ADDR_XCVR_PSM_A2IN_TMR}, 1928c2ecf20Sopenharmony_ci {0x0010, TB_ADDR_XCVR_PSM_A3IN_TMR}, 1938c2ecf20Sopenharmony_ci {0x0010, TB_ADDR_XCVR_PSM_A4IN_TMR}, 1948c2ecf20Sopenharmony_ci {0x0010, TB_ADDR_XCVR_PSM_A5IN_TMR}, 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_XCVR_PSM_A0OUT_TMR}, 1978c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_XCVR_PSM_A1OUT_TMR}, 1988c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_XCVR_PSM_A2OUT_TMR}, 1998c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_XCVR_PSM_A3OUT_TMR}, 2008c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_XCVR_PSM_A4OUT_TMR}, 2018c2ecf20Sopenharmony_ci {0x0002, TB_ADDR_XCVR_PSM_A5OUT_TMR}, 2028c2ecf20Sopenharmony_ci /* Change rx detect parameter */ 2038c2ecf20Sopenharmony_ci {0x0960, TB_ADDR_TX_RCVDET_EN_TMR}, 2048c2ecf20Sopenharmony_ci {0x01e0, TB_ADDR_TX_RCVDET_ST_TMR}, 2058c2ecf20Sopenharmony_ci {0x0090, TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR}, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int cdns_salvo_phy_init(struct phy *phy) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy); 2118c2ecf20Sopenharmony_ci struct cdns_salvo_data *data = salvo_phy->data; 2128c2ecf20Sopenharmony_ci int ret, i; 2138c2ecf20Sopenharmony_ci u16 value; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = clk_prepare_enable(salvo_phy->clk); 2168c2ecf20Sopenharmony_ci if (ret) 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci for (i = 0; i < data->init_sequence_length; i++) { 2208c2ecf20Sopenharmony_ci const struct cdns_reg_pairs *reg_pair = data->init_sequence_val + i; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci cdns_salvo_write(salvo_phy, reg_pair->off, reg_pair->val); 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */ 2268c2ecf20Sopenharmony_ci value = cdns_salvo_read(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL); 2278c2ecf20Sopenharmony_ci value |= RXDET_IN_P3_32KHZ; 2288c2ecf20Sopenharmony_ci cdns_salvo_write(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL, 2298c2ecf20Sopenharmony_ci RXDET_IN_P3_32KHZ); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci udelay(10); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci clk_disable_unprepare(salvo_phy->clk); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int cdns_salvo_phy_power_on(struct phy *phy) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return clk_prepare_enable(salvo_phy->clk); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int cdns_salvo_phy_power_off(struct phy *phy) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci clk_disable_unprepare(salvo_phy->clk); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic const struct phy_ops cdns_salvo_phy_ops = { 2558c2ecf20Sopenharmony_ci .init = cdns_salvo_phy_init, 2568c2ecf20Sopenharmony_ci .power_on = cdns_salvo_phy_power_on, 2578c2ecf20Sopenharmony_ci .power_off = cdns_salvo_phy_power_off, 2588c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int cdns_salvo_phy_probe(struct platform_device *pdev) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct phy_provider *phy_provider; 2648c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2658c2ecf20Sopenharmony_ci struct cdns_salvo_phy *salvo_phy; 2668c2ecf20Sopenharmony_ci struct resource *res; 2678c2ecf20Sopenharmony_ci const struct of_device_id *match; 2688c2ecf20Sopenharmony_ci struct cdns_salvo_data *data; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci match = of_match_device(cdns_salvo_phy_of_match, dev); 2718c2ecf20Sopenharmony_ci if (!match) 2728c2ecf20Sopenharmony_ci return -EINVAL; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci data = (struct cdns_salvo_data *)match->data; 2758c2ecf20Sopenharmony_ci salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL); 2768c2ecf20Sopenharmony_ci if (!salvo_phy) 2778c2ecf20Sopenharmony_ci return -ENOMEM; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci salvo_phy->data = data; 2808c2ecf20Sopenharmony_ci salvo_phy->clk = devm_clk_get_optional(dev, "salvo_phy_clk"); 2818c2ecf20Sopenharmony_ci if (IS_ERR(salvo_phy->clk)) 2828c2ecf20Sopenharmony_ci return PTR_ERR(salvo_phy->clk); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2858c2ecf20Sopenharmony_ci salvo_phy->base = devm_ioremap_resource(dev, res); 2868c2ecf20Sopenharmony_ci if (IS_ERR(salvo_phy->base)) 2878c2ecf20Sopenharmony_ci return PTR_ERR(salvo_phy->base); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci salvo_phy->phy = devm_phy_create(dev, NULL, &cdns_salvo_phy_ops); 2908c2ecf20Sopenharmony_ci if (IS_ERR(salvo_phy->phy)) 2918c2ecf20Sopenharmony_ci return PTR_ERR(salvo_phy->phy); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci phy_set_drvdata(salvo_phy->phy, salvo_phy); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 2968c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(phy_provider); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic const struct cdns_salvo_data cdns_nxp_salvo_data = { 3008c2ecf20Sopenharmony_ci 2, 3018c2ecf20Sopenharmony_ci cdns_nxp_sequence_pair, 3028c2ecf20Sopenharmony_ci ARRAY_SIZE(cdns_nxp_sequence_pair), 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic const struct of_device_id cdns_salvo_phy_of_match[] = { 3068c2ecf20Sopenharmony_ci { 3078c2ecf20Sopenharmony_ci .compatible = "nxp,salvo-phy", 3088c2ecf20Sopenharmony_ci .data = &cdns_nxp_salvo_data, 3098c2ecf20Sopenharmony_ci }, 3108c2ecf20Sopenharmony_ci {} 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cdns_salvo_phy_of_match); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic struct platform_driver cdns_salvo_phy_driver = { 3158c2ecf20Sopenharmony_ci .probe = cdns_salvo_phy_probe, 3168c2ecf20Sopenharmony_ci .driver = { 3178c2ecf20Sopenharmony_ci .name = "cdns-salvo-phy", 3188c2ecf20Sopenharmony_ci .of_match_table = cdns_salvo_phy_of_match, 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci}; 3218c2ecf20Sopenharmony_cimodule_platform_driver(cdns_salvo_phy_driver); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>"); 3248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cadence SALVO PHY Driver"); 326