18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2017 NXP 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * CORTINA is a registered trademark of Cortina Systems, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/phy.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define PHY_ID_CS4340 0x13e51002 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define VILLA_GLOBAL_CHIP_ID_LSB 0x0 148c2ecf20Sopenharmony_ci#define VILLA_GLOBAL_CHIP_ID_MSB 0x1 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define VILLA_GLOBAL_GPIO_1_INTS 0x017 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int cortina_read_reg(struct phy_device *phydev, u16 regnum) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci return mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr, 0, regnum); 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int cortina_read_status(struct phy_device *phydev) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci int gpio_int_status, ret = 0; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); 288c2ecf20Sopenharmony_ci if (gpio_int_status < 0) { 298c2ecf20Sopenharmony_ci ret = gpio_int_status; 308c2ecf20Sopenharmony_ci goto err; 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (gpio_int_status & 0x8) { 348c2ecf20Sopenharmony_ci /* up when edc_convergedS set */ 358c2ecf20Sopenharmony_ci phydev->speed = SPEED_10000; 368c2ecf20Sopenharmony_ci phydev->duplex = DUPLEX_FULL; 378c2ecf20Sopenharmony_ci phydev->link = 1; 388c2ecf20Sopenharmony_ci } else { 398c2ecf20Sopenharmony_ci phydev->link = 0; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cierr: 438c2ecf20Sopenharmony_ci return ret; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int cortina_probe(struct phy_device *phydev) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci u32 phy_id = 0; 498c2ecf20Sopenharmony_ci int id_lsb = 0, id_msb = 0; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* Read device id from phy registers. */ 528c2ecf20Sopenharmony_ci id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); 538c2ecf20Sopenharmony_ci if (id_lsb < 0) 548c2ecf20Sopenharmony_ci return -ENXIO; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci phy_id = id_lsb << 16; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); 598c2ecf20Sopenharmony_ci if (id_msb < 0) 608c2ecf20Sopenharmony_ci return -ENXIO; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci phy_id |= id_msb; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Make sure the device tree binding matched the driver with the 658c2ecf20Sopenharmony_ci * right device. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci if (phy_id != phydev->drv->phy_id) { 688c2ecf20Sopenharmony_ci phydev_err(phydev, "Error matching phy with %s driver\n", 698c2ecf20Sopenharmony_ci phydev->drv->name); 708c2ecf20Sopenharmony_ci return -ENODEV; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic struct phy_driver cortina_driver[] = { 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci .phy_id = PHY_ID_CS4340, 798c2ecf20Sopenharmony_ci .phy_id_mask = 0xffffffff, 808c2ecf20Sopenharmony_ci .name = "Cortina CS4340", 818c2ecf20Sopenharmony_ci .features = PHY_10GBIT_FEATURES, 828c2ecf20Sopenharmony_ci .config_aneg = gen10g_config_aneg, 838c2ecf20Sopenharmony_ci .read_status = cortina_read_status, 848c2ecf20Sopenharmony_ci .probe = cortina_probe, 858c2ecf20Sopenharmony_ci}, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cimodule_phy_driver(cortina_driver); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic struct mdio_device_id __maybe_unused cortina_tbl[] = { 918c2ecf20Sopenharmony_ci { PHY_ID_CS4340, 0xffffffff}, 928c2ecf20Sopenharmony_ci {}, 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, cortina_tbl); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver"); 988c2ecf20Sopenharmony_ciMODULE_AUTHOR("NXP"); 998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 100