1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+ 215b9e533SBogdan Purcareata /* 315b9e533SBogdan Purcareata * Copyright 2017 NXP 415b9e533SBogdan Purcareata * 515b9e533SBogdan Purcareata * CORTINA is a registered trademark of Cortina Systems, Inc. 615b9e533SBogdan Purcareata * 715b9e533SBogdan Purcareata */ 815b9e533SBogdan Purcareata #include <linux/module.h> 915b9e533SBogdan Purcareata #include <linux/phy.h> 1015b9e533SBogdan Purcareata 1115b9e533SBogdan Purcareata #define PHY_ID_CS4340 0x13e51002 1215b9e533SBogdan Purcareata 1315b9e533SBogdan Purcareata #define VILLA_GLOBAL_CHIP_ID_LSB 0x0 1415b9e533SBogdan Purcareata #define VILLA_GLOBAL_CHIP_ID_MSB 0x1 1515b9e533SBogdan Purcareata 1615b9e533SBogdan Purcareata #define VILLA_GLOBAL_GPIO_1_INTS 0x017 1715b9e533SBogdan Purcareata 1815b9e533SBogdan Purcareata static int cortina_read_reg(struct phy_device *phydev, u16 regnum) 1915b9e533SBogdan Purcareata { 2015b9e533SBogdan Purcareata return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, 2115b9e533SBogdan Purcareata MII_ADDR_C45 | regnum); 2215b9e533SBogdan Purcareata } 2315b9e533SBogdan Purcareata 2415b9e533SBogdan Purcareata static int cortina_read_status(struct phy_device *phydev) 2515b9e533SBogdan Purcareata { 2615b9e533SBogdan Purcareata int gpio_int_status, ret = 0; 2715b9e533SBogdan Purcareata 2815b9e533SBogdan Purcareata gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); 2915b9e533SBogdan Purcareata if (gpio_int_status < 0) { 3015b9e533SBogdan Purcareata ret = gpio_int_status; 3115b9e533SBogdan Purcareata goto err; 3215b9e533SBogdan Purcareata } 3315b9e533SBogdan Purcareata 3415b9e533SBogdan Purcareata if (gpio_int_status & 0x8) { 3515b9e533SBogdan Purcareata /* up when edc_convergedS set */ 3615b9e533SBogdan Purcareata phydev->speed = SPEED_10000; 3715b9e533SBogdan Purcareata phydev->duplex = DUPLEX_FULL; 3815b9e533SBogdan Purcareata phydev->link = 1; 3915b9e533SBogdan Purcareata } else { 4015b9e533SBogdan Purcareata phydev->link = 0; 4115b9e533SBogdan Purcareata } 4215b9e533SBogdan Purcareata 4315b9e533SBogdan Purcareata err: 4415b9e533SBogdan Purcareata return ret; 4515b9e533SBogdan Purcareata } 4615b9e533SBogdan Purcareata 4715b9e533SBogdan Purcareata static int cortina_probe(struct phy_device *phydev) 4815b9e533SBogdan Purcareata { 4915b9e533SBogdan Purcareata u32 phy_id = 0; 5015b9e533SBogdan Purcareata int id_lsb = 0, id_msb = 0; 5115b9e533SBogdan Purcareata 5215b9e533SBogdan Purcareata /* Read device id from phy registers. */ 5315b9e533SBogdan Purcareata id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); 5415b9e533SBogdan Purcareata if (id_lsb < 0) 5515b9e533SBogdan Purcareata return -ENXIO; 5615b9e533SBogdan Purcareata 5715b9e533SBogdan Purcareata phy_id = id_lsb << 16; 5815b9e533SBogdan Purcareata 5915b9e533SBogdan Purcareata id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); 6015b9e533SBogdan Purcareata if (id_msb < 0) 6115b9e533SBogdan Purcareata return -ENXIO; 6215b9e533SBogdan Purcareata 6315b9e533SBogdan Purcareata phy_id |= id_msb; 6415b9e533SBogdan Purcareata 6515b9e533SBogdan Purcareata /* Make sure the device tree binding matched the driver with the 6615b9e533SBogdan Purcareata * right device. 6715b9e533SBogdan Purcareata */ 6815b9e533SBogdan Purcareata if (phy_id != phydev->drv->phy_id) { 6915b9e533SBogdan Purcareata phydev_err(phydev, "Error matching phy with %s driver\n", 7015b9e533SBogdan Purcareata phydev->drv->name); 7115b9e533SBogdan Purcareata return -ENODEV; 7215b9e533SBogdan Purcareata } 7315b9e533SBogdan Purcareata 7415b9e533SBogdan Purcareata return 0; 7515b9e533SBogdan Purcareata } 7615b9e533SBogdan Purcareata 7715b9e533SBogdan Purcareata static struct phy_driver cortina_driver[] = { 7815b9e533SBogdan Purcareata { 7915b9e533SBogdan Purcareata .phy_id = PHY_ID_CS4340, 8015b9e533SBogdan Purcareata .phy_id_mask = 0xffffffff, 8115b9e533SBogdan Purcareata .name = "Cortina CS4340", 8240f89ebfSCamelia Groza .features = PHY_10GBIT_FEATURES, 830adfdb66SFlorian Fainelli .config_init = gen10g_config_init, 840adfdb66SFlorian Fainelli .config_aneg = gen10g_config_aneg, 8515b9e533SBogdan Purcareata .read_status = cortina_read_status, 860adfdb66SFlorian Fainelli .soft_reset = gen10g_no_soft_reset, 8715b9e533SBogdan Purcareata .probe = cortina_probe, 8815b9e533SBogdan Purcareata }, 8915b9e533SBogdan Purcareata }; 9015b9e533SBogdan Purcareata 9115b9e533SBogdan Purcareata module_phy_driver(cortina_driver); 9215b9e533SBogdan Purcareata 9315b9e533SBogdan Purcareata static struct mdio_device_id __maybe_unused cortina_tbl[] = { 9415b9e533SBogdan Purcareata { PHY_ID_CS4340, 0xffffffff}, 9515b9e533SBogdan Purcareata {}, 9615b9e533SBogdan Purcareata }; 9715b9e533SBogdan Purcareata 9815b9e533SBogdan Purcareata MODULE_DEVICE_TABLE(mdio, cortina_tbl); 990cc03504SJesse Chan 1000cc03504SJesse Chan MODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver"); 1010cc03504SJesse Chan MODULE_AUTHOR("NXP"); 1020cc03504SJesse Chan MODULE_LICENSE("GPL"); 103