1*da1af492SCaleb James DeLisle // SPDX-License-Identifier: GPL-2.0+ 2*da1af492SCaleb James DeLisle /* 3*da1af492SCaleb James DeLisle * Author: Caleb James DeLisle <cjd@cjdns.fr> 4*da1af492SCaleb James DeLisle * Ahmed Naseef <naseefkm@gmail.com> 5*da1af492SCaleb James DeLisle */ 6*da1af492SCaleb James DeLisle 7*da1af492SCaleb James DeLisle #include <linux/bitfield.h> 8*da1af492SCaleb James DeLisle #include <linux/module.h> 9*da1af492SCaleb James DeLisle #include <linux/of.h> 10*da1af492SCaleb James DeLisle #include <linux/phy/phy.h> 11*da1af492SCaleb James DeLisle #include <linux/platform_device.h> 12*da1af492SCaleb James DeLisle #include <linux/regmap.h> 13*da1af492SCaleb James DeLisle #include <linux/bits.h> 14*da1af492SCaleb James DeLisle #include <linux/delay.h> 15*da1af492SCaleb James DeLisle 16*da1af492SCaleb James DeLisle /* Rx detection timing for EN751221: 16*8 clock cycles */ 17*da1af492SCaleb James DeLisle #define EN751221_RXDET_VAL 16 18*da1af492SCaleb James DeLisle 19*da1af492SCaleb James DeLisle /* Rx detection timing when in power mode 3 */ 20*da1af492SCaleb James DeLisle #define EN75_RXDET_P3_REG 0xa28 21*da1af492SCaleb James DeLisle #define EN75_RXDET_P3_MASK GENMASK(17, 9) 22*da1af492SCaleb James DeLisle 23*da1af492SCaleb James DeLisle /* Rx detection timing when in power mode 2 */ 24*da1af492SCaleb James DeLisle #define EN75_RXDET_P2_REG 0xa2c 25*da1af492SCaleb James DeLisle #define EN75_RXDET_P2_MASK GENMASK(8, 0) 26*da1af492SCaleb James DeLisle 27*da1af492SCaleb James DeLisle /* Rx impedance */ 28*da1af492SCaleb James DeLisle #define EN75_RX_IMPEDANCE_REG 0xb2c 29*da1af492SCaleb James DeLisle #define EN75_RX_IMPEDANCE_MASK GENMASK(13, 12) 30*da1af492SCaleb James DeLisle enum en75_rx_impedance { 31*da1af492SCaleb James DeLisle EN75_RX_IMPEDANCE_100_OHM = 0, 32*da1af492SCaleb James DeLisle EN75_RX_IMPEDANCE_95_OHM = 1, 33*da1af492SCaleb James DeLisle EN75_RX_IMPEDANCE_90_OHM = 2, 34*da1af492SCaleb James DeLisle }; 35*da1af492SCaleb James DeLisle 36*da1af492SCaleb James DeLisle /* PLL Invert clock */ 37*da1af492SCaleb James DeLisle #define EN75_PLL_PH_INV_REG 0x4a0 38*da1af492SCaleb James DeLisle #define EN75_PLL_PH_INV_MASK BIT(5) 39*da1af492SCaleb James DeLisle 40*da1af492SCaleb James DeLisle struct en75_phy_op { 41*da1af492SCaleb James DeLisle u32 reg; 42*da1af492SCaleb James DeLisle u32 mask; 43*da1af492SCaleb James DeLisle u32 val; 44*da1af492SCaleb James DeLisle }; 45*da1af492SCaleb James DeLisle 46*da1af492SCaleb James DeLisle struct en7528_pcie_phy { 47*da1af492SCaleb James DeLisle struct regmap *regmap; 48*da1af492SCaleb James DeLisle const struct en75_phy_op *data; 49*da1af492SCaleb James DeLisle }; 50*da1af492SCaleb James DeLisle 51*da1af492SCaleb James DeLisle /* Port 0 PHY: set LCDDS_CLK_PH_INV for PLL operation */ 52*da1af492SCaleb James DeLisle static const struct en75_phy_op en7528_phy_gen1[] = { 53*da1af492SCaleb James DeLisle { 54*da1af492SCaleb James DeLisle .reg = EN75_PLL_PH_INV_REG, 55*da1af492SCaleb James DeLisle .mask = EN75_PLL_PH_INV_MASK, 56*da1af492SCaleb James DeLisle .val = 1, 57*da1af492SCaleb James DeLisle }, 58*da1af492SCaleb James DeLisle { /* sentinel */ } 59*da1af492SCaleb James DeLisle }; 60*da1af492SCaleb James DeLisle 61*da1af492SCaleb James DeLisle /* EN7528 Port 1 PHY: Rx impedance tuning, target R -5 Ohm */ 62*da1af492SCaleb James DeLisle static const struct en75_phy_op en7528_phy_gen2[] = { 63*da1af492SCaleb James DeLisle { 64*da1af492SCaleb James DeLisle .reg = EN75_RX_IMPEDANCE_REG, 65*da1af492SCaleb James DeLisle .mask = EN75_RX_IMPEDANCE_MASK, 66*da1af492SCaleb James DeLisle .val = EN75_RX_IMPEDANCE_95_OHM, 67*da1af492SCaleb James DeLisle }, 68*da1af492SCaleb James DeLisle { /* sentinel */ } 69*da1af492SCaleb James DeLisle }; 70*da1af492SCaleb James DeLisle 71*da1af492SCaleb James DeLisle /* EN751221 Port 1 PHY, set RX detect to 16*8 clock cycles */ 72*da1af492SCaleb James DeLisle static const struct en75_phy_op en751221_phy_gen2[] = { 73*da1af492SCaleb James DeLisle { 74*da1af492SCaleb James DeLisle .reg = EN75_RXDET_P3_REG, 75*da1af492SCaleb James DeLisle .mask = EN75_RXDET_P3_MASK, 76*da1af492SCaleb James DeLisle .val = EN751221_RXDET_VAL, 77*da1af492SCaleb James DeLisle }, 78*da1af492SCaleb James DeLisle { 79*da1af492SCaleb James DeLisle .reg = EN75_RXDET_P2_REG, 80*da1af492SCaleb James DeLisle .mask = EN75_RXDET_P2_MASK, 81*da1af492SCaleb James DeLisle .val = EN751221_RXDET_VAL, 82*da1af492SCaleb James DeLisle }, 83*da1af492SCaleb James DeLisle { /* sentinel */ } 84*da1af492SCaleb James DeLisle }; 85*da1af492SCaleb James DeLisle 86*da1af492SCaleb James DeLisle static int en75_pcie_phy_init(struct phy *phy) 87*da1af492SCaleb James DeLisle { 88*da1af492SCaleb James DeLisle struct en7528_pcie_phy *ephy = phy_get_drvdata(phy); 89*da1af492SCaleb James DeLisle const struct en75_phy_op *data = ephy->data; 90*da1af492SCaleb James DeLisle int i, ret; 91*da1af492SCaleb James DeLisle u32 val; 92*da1af492SCaleb James DeLisle 93*da1af492SCaleb James DeLisle for (i = 0; data[i].mask || data[i].val; i++) { 94*da1af492SCaleb James DeLisle if (i) 95*da1af492SCaleb James DeLisle usleep_range(1000, 2000); 96*da1af492SCaleb James DeLisle 97*da1af492SCaleb James DeLisle val = field_prep(data[i].mask, data[i].val); 98*da1af492SCaleb James DeLisle 99*da1af492SCaleb James DeLisle ret = regmap_update_bits(ephy->regmap, data[i].reg, 100*da1af492SCaleb James DeLisle data[i].mask, val); 101*da1af492SCaleb James DeLisle if (ret) 102*da1af492SCaleb James DeLisle return ret; 103*da1af492SCaleb James DeLisle } 104*da1af492SCaleb James DeLisle 105*da1af492SCaleb James DeLisle return 0; 106*da1af492SCaleb James DeLisle } 107*da1af492SCaleb James DeLisle 108*da1af492SCaleb James DeLisle static const struct phy_ops en75_pcie_phy_ops = { 109*da1af492SCaleb James DeLisle .init = en75_pcie_phy_init, 110*da1af492SCaleb James DeLisle .owner = THIS_MODULE, 111*da1af492SCaleb James DeLisle }; 112*da1af492SCaleb James DeLisle 113*da1af492SCaleb James DeLisle static int en75_pcie_phy_probe(struct platform_device *pdev) 114*da1af492SCaleb James DeLisle { 115*da1af492SCaleb James DeLisle struct regmap_config regmap_config = { 116*da1af492SCaleb James DeLisle .reg_bits = 32, 117*da1af492SCaleb James DeLisle .val_bits = 32, 118*da1af492SCaleb James DeLisle .reg_stride = 4, 119*da1af492SCaleb James DeLisle }; 120*da1af492SCaleb James DeLisle struct device *dev = &pdev->dev; 121*da1af492SCaleb James DeLisle const struct en75_phy_op *data; 122*da1af492SCaleb James DeLisle struct phy_provider *provider; 123*da1af492SCaleb James DeLisle struct en7528_pcie_phy *ephy; 124*da1af492SCaleb James DeLisle void __iomem *base; 125*da1af492SCaleb James DeLisle struct phy *phy; 126*da1af492SCaleb James DeLisle int i; 127*da1af492SCaleb James DeLisle 128*da1af492SCaleb James DeLisle data = of_device_get_match_data(dev); 129*da1af492SCaleb James DeLisle if (!data) 130*da1af492SCaleb James DeLisle return -EINVAL; 131*da1af492SCaleb James DeLisle 132*da1af492SCaleb James DeLisle ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL); 133*da1af492SCaleb James DeLisle if (!ephy) 134*da1af492SCaleb James DeLisle return -ENOMEM; 135*da1af492SCaleb James DeLisle 136*da1af492SCaleb James DeLisle ephy->data = data; 137*da1af492SCaleb James DeLisle 138*da1af492SCaleb James DeLisle base = devm_platform_ioremap_resource(pdev, 0); 139*da1af492SCaleb James DeLisle if (IS_ERR(base)) 140*da1af492SCaleb James DeLisle return PTR_ERR(base); 141*da1af492SCaleb James DeLisle 142*da1af492SCaleb James DeLisle /* Set max_register to highest used register */ 143*da1af492SCaleb James DeLisle for (i = 0; data[i].mask || data[i].val; i++) 144*da1af492SCaleb James DeLisle if (data[i].reg > regmap_config.max_register) 145*da1af492SCaleb James DeLisle regmap_config.max_register = data[i].reg; 146*da1af492SCaleb James DeLisle 147*da1af492SCaleb James DeLisle ephy->regmap = devm_regmap_init_mmio(dev, base, ®map_config); 148*da1af492SCaleb James DeLisle if (IS_ERR(ephy->regmap)) 149*da1af492SCaleb James DeLisle return PTR_ERR(ephy->regmap); 150*da1af492SCaleb James DeLisle 151*da1af492SCaleb James DeLisle phy = devm_phy_create(dev, dev->of_node, &en75_pcie_phy_ops); 152*da1af492SCaleb James DeLisle if (IS_ERR(phy)) 153*da1af492SCaleb James DeLisle return PTR_ERR(phy); 154*da1af492SCaleb James DeLisle 155*da1af492SCaleb James DeLisle phy_set_drvdata(phy, ephy); 156*da1af492SCaleb James DeLisle 157*da1af492SCaleb James DeLisle provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 158*da1af492SCaleb James DeLisle 159*da1af492SCaleb James DeLisle return PTR_ERR_OR_ZERO(provider); 160*da1af492SCaleb James DeLisle } 161*da1af492SCaleb James DeLisle 162*da1af492SCaleb James DeLisle static const struct of_device_id en75_pcie_phy_ids[] = { 163*da1af492SCaleb James DeLisle { .compatible = "econet,en7528-pcie-gen1", .data = en7528_phy_gen1 }, 164*da1af492SCaleb James DeLisle { .compatible = "econet,en7528-pcie-gen2", .data = en7528_phy_gen2 }, 165*da1af492SCaleb James DeLisle { .compatible = "econet,en751221-pcie-gen1", .data = en7528_phy_gen1 }, 166*da1af492SCaleb James DeLisle { .compatible = "econet,en751221-pcie-gen2", .data = en751221_phy_gen2 }, 167*da1af492SCaleb James DeLisle { /* sentinel */ } 168*da1af492SCaleb James DeLisle }; 169*da1af492SCaleb James DeLisle MODULE_DEVICE_TABLE(of, en75_pcie_phy_ids); 170*da1af492SCaleb James DeLisle 171*da1af492SCaleb James DeLisle static struct platform_driver en75_pcie_phy_driver = { 172*da1af492SCaleb James DeLisle .probe = en75_pcie_phy_probe, 173*da1af492SCaleb James DeLisle .driver = { 174*da1af492SCaleb James DeLisle .name = "econet-pcie-phy", 175*da1af492SCaleb James DeLisle .of_match_table = en75_pcie_phy_ids, 176*da1af492SCaleb James DeLisle }, 177*da1af492SCaleb James DeLisle }; 178*da1af492SCaleb James DeLisle module_platform_driver(en75_pcie_phy_driver); 179*da1af492SCaleb James DeLisle 180*da1af492SCaleb James DeLisle MODULE_AUTHOR("Caleb James DeLisle <cjd@cjdns.fr>"); 181*da1af492SCaleb James DeLisle MODULE_DESCRIPTION("EcoNet PCIe PHY driver"); 182*da1af492SCaleb James DeLisle MODULE_LICENSE("GPL"); 183