115b9e533SBogdan Purcareata /* 215b9e533SBogdan Purcareata * Copyright 2017 NXP 315b9e533SBogdan Purcareata * 415b9e533SBogdan Purcareata * This program is free software; you can redistribute it and/or modify 515b9e533SBogdan Purcareata * it under the terms of the GNU General Public License as published by 615b9e533SBogdan Purcareata * the Free Software Foundation; either version 2 of the License, or 715b9e533SBogdan Purcareata * (at your option) any later version. 815b9e533SBogdan Purcareata * 915b9e533SBogdan Purcareata * This program is distributed in the hope that it will be useful, 1015b9e533SBogdan Purcareata * but WITHOUT ANY WARRANTY; without even the implied warranty of 1115b9e533SBogdan Purcareata * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1215b9e533SBogdan Purcareata * GNU General Public License for more details. 1315b9e533SBogdan Purcareata * 1415b9e533SBogdan Purcareata * CORTINA is a registered trademark of Cortina Systems, Inc. 1515b9e533SBogdan Purcareata * 1615b9e533SBogdan Purcareata */ 1715b9e533SBogdan Purcareata #include <linux/module.h> 1815b9e533SBogdan Purcareata #include <linux/phy.h> 1915b9e533SBogdan Purcareata 2015b9e533SBogdan Purcareata #define PHY_ID_CS4340 0x13e51002 2115b9e533SBogdan Purcareata 2215b9e533SBogdan Purcareata #define VILLA_GLOBAL_CHIP_ID_LSB 0x0 2315b9e533SBogdan Purcareata #define VILLA_GLOBAL_CHIP_ID_MSB 0x1 2415b9e533SBogdan Purcareata 2515b9e533SBogdan Purcareata #define VILLA_GLOBAL_GPIO_1_INTS 0x017 2615b9e533SBogdan Purcareata 2715b9e533SBogdan Purcareata static int cortina_read_reg(struct phy_device *phydev, u16 regnum) 2815b9e533SBogdan Purcareata { 2915b9e533SBogdan Purcareata return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, 3015b9e533SBogdan Purcareata MII_ADDR_C45 | regnum); 3115b9e533SBogdan Purcareata } 3215b9e533SBogdan Purcareata 3315b9e533SBogdan Purcareata static int cortina_read_status(struct phy_device *phydev) 3415b9e533SBogdan Purcareata { 3515b9e533SBogdan Purcareata int gpio_int_status, ret = 0; 3615b9e533SBogdan Purcareata 3715b9e533SBogdan Purcareata gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); 3815b9e533SBogdan Purcareata if (gpio_int_status < 0) { 3915b9e533SBogdan Purcareata ret = gpio_int_status; 4015b9e533SBogdan Purcareata goto err; 4115b9e533SBogdan Purcareata } 4215b9e533SBogdan Purcareata 4315b9e533SBogdan Purcareata if (gpio_int_status & 0x8) { 4415b9e533SBogdan Purcareata /* up when edc_convergedS set */ 4515b9e533SBogdan Purcareata phydev->speed = SPEED_10000; 4615b9e533SBogdan Purcareata phydev->duplex = DUPLEX_FULL; 4715b9e533SBogdan Purcareata phydev->link = 1; 4815b9e533SBogdan Purcareata } else { 4915b9e533SBogdan Purcareata phydev->link = 0; 5015b9e533SBogdan Purcareata } 5115b9e533SBogdan Purcareata 5215b9e533SBogdan Purcareata err: 5315b9e533SBogdan Purcareata return ret; 5415b9e533SBogdan Purcareata } 5515b9e533SBogdan Purcareata 5615b9e533SBogdan Purcareata static int cortina_probe(struct phy_device *phydev) 5715b9e533SBogdan Purcareata { 5815b9e533SBogdan Purcareata u32 phy_id = 0; 5915b9e533SBogdan Purcareata int id_lsb = 0, id_msb = 0; 6015b9e533SBogdan Purcareata 6115b9e533SBogdan Purcareata /* Read device id from phy registers. */ 6215b9e533SBogdan Purcareata id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); 6315b9e533SBogdan Purcareata if (id_lsb < 0) 6415b9e533SBogdan Purcareata return -ENXIO; 6515b9e533SBogdan Purcareata 6615b9e533SBogdan Purcareata phy_id = id_lsb << 16; 6715b9e533SBogdan Purcareata 6815b9e533SBogdan Purcareata id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); 6915b9e533SBogdan Purcareata if (id_msb < 0) 7015b9e533SBogdan Purcareata return -ENXIO; 7115b9e533SBogdan Purcareata 7215b9e533SBogdan Purcareata phy_id |= id_msb; 7315b9e533SBogdan Purcareata 7415b9e533SBogdan Purcareata /* Make sure the device tree binding matched the driver with the 7515b9e533SBogdan Purcareata * right device. 7615b9e533SBogdan Purcareata */ 7715b9e533SBogdan Purcareata if (phy_id != phydev->drv->phy_id) { 7815b9e533SBogdan Purcareata phydev_err(phydev, "Error matching phy with %s driver\n", 7915b9e533SBogdan Purcareata phydev->drv->name); 8015b9e533SBogdan Purcareata return -ENODEV; 8115b9e533SBogdan Purcareata } 8215b9e533SBogdan Purcareata 8315b9e533SBogdan Purcareata return 0; 8415b9e533SBogdan Purcareata } 8515b9e533SBogdan Purcareata 8615b9e533SBogdan Purcareata static struct phy_driver cortina_driver[] = { 8715b9e533SBogdan Purcareata { 8815b9e533SBogdan Purcareata .phy_id = PHY_ID_CS4340, 8915b9e533SBogdan Purcareata .phy_id_mask = 0xffffffff, 9015b9e533SBogdan Purcareata .name = "Cortina CS4340", 91*0adfdb66SFlorian Fainelli .config_init = gen10g_config_init, 92*0adfdb66SFlorian Fainelli .config_aneg = gen10g_config_aneg, 9315b9e533SBogdan Purcareata .read_status = cortina_read_status, 94*0adfdb66SFlorian Fainelli .soft_reset = gen10g_no_soft_reset, 9515b9e533SBogdan Purcareata .probe = cortina_probe, 9615b9e533SBogdan Purcareata }, 9715b9e533SBogdan Purcareata }; 9815b9e533SBogdan Purcareata 9915b9e533SBogdan Purcareata module_phy_driver(cortina_driver); 10015b9e533SBogdan Purcareata 10115b9e533SBogdan Purcareata static struct mdio_device_id __maybe_unused cortina_tbl[] = { 10215b9e533SBogdan Purcareata { PHY_ID_CS4340, 0xffffffff}, 10315b9e533SBogdan Purcareata {}, 10415b9e533SBogdan Purcareata }; 10515b9e533SBogdan Purcareata 10615b9e533SBogdan Purcareata MODULE_DEVICE_TABLE(mdio, cortina_tbl); 1070cc03504SJesse Chan 1080cc03504SJesse Chan MODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver"); 1090cc03504SJesse Chan MODULE_AUTHOR("NXP"); 1100cc03504SJesse Chan MODULE_LICENSE("GPL"); 111