162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2017 NXP 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * CORTINA is a registered trademark of Cortina Systems, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/phy.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define PHY_ID_CS4340 0x13e51002 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define VILLA_GLOBAL_CHIP_ID_LSB 0x0 1462306a36Sopenharmony_ci#define VILLA_GLOBAL_CHIP_ID_MSB 0x1 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define VILLA_GLOBAL_GPIO_1_INTS 0x017 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int cortina_read_reg(struct phy_device *phydev, u16 regnum) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci return mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr, 0, regnum); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int cortina_read_status(struct phy_device *phydev) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci int gpio_int_status, ret = 0; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); 2862306a36Sopenharmony_ci if (gpio_int_status < 0) { 2962306a36Sopenharmony_ci ret = gpio_int_status; 3062306a36Sopenharmony_ci goto err; 3162306a36Sopenharmony_ci } 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (gpio_int_status & 0x8) { 3462306a36Sopenharmony_ci /* up when edc_convergedS set */ 3562306a36Sopenharmony_ci phydev->speed = SPEED_10000; 3662306a36Sopenharmony_ci phydev->duplex = DUPLEX_FULL; 3762306a36Sopenharmony_ci phydev->link = 1; 3862306a36Sopenharmony_ci } else { 3962306a36Sopenharmony_ci phydev->link = 0; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cierr: 4362306a36Sopenharmony_ci return ret; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int cortina_probe(struct phy_device *phydev) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci u32 phy_id = 0; 4962306a36Sopenharmony_ci int id_lsb = 0, id_msb = 0; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* Read device id from phy registers. */ 5262306a36Sopenharmony_ci id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); 5362306a36Sopenharmony_ci if (id_lsb < 0) 5462306a36Sopenharmony_ci return -ENXIO; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci phy_id = id_lsb << 16; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); 5962306a36Sopenharmony_ci if (id_msb < 0) 6062306a36Sopenharmony_ci return -ENXIO; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci phy_id |= id_msb; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* Make sure the device tree binding matched the driver with the 6562306a36Sopenharmony_ci * right device. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci if (phy_id != phydev->drv->phy_id) { 6862306a36Sopenharmony_ci phydev_err(phydev, "Error matching phy with %s driver\n", 6962306a36Sopenharmony_ci phydev->drv->name); 7062306a36Sopenharmony_ci return -ENODEV; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic struct phy_driver cortina_driver[] = { 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci .phy_id = PHY_ID_CS4340, 7962306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 8062306a36Sopenharmony_ci .name = "Cortina CS4340", 8162306a36Sopenharmony_ci .features = PHY_10GBIT_FEATURES, 8262306a36Sopenharmony_ci .config_aneg = gen10g_config_aneg, 8362306a36Sopenharmony_ci .read_status = cortina_read_status, 8462306a36Sopenharmony_ci .probe = cortina_probe, 8562306a36Sopenharmony_ci}, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cimodule_phy_driver(cortina_driver); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic struct mdio_device_id __maybe_unused cortina_tbl[] = { 9162306a36Sopenharmony_ci { PHY_ID_CS4340, 0xffffffff}, 9262306a36Sopenharmony_ci {}, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, cortina_tbl); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciMODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver"); 9862306a36Sopenharmony_ciMODULE_AUTHOR("NXP"); 9962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 100