linux/drivers/net/phy/cortina.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *    Copyright 2017 NXP
   4 *
   5 *    CORTINA is a registered trademark of Cortina Systems, Inc.
   6 *
   7 */
   8#include <linux/module.h>
   9#include <linux/phy.h>
  10
  11#define PHY_ID_CS4340   0x13e51002
  12
  13#define VILLA_GLOBAL_CHIP_ID_LSB                        0x0
  14#define VILLA_GLOBAL_CHIP_ID_MSB                        0x1
  15
  16#define VILLA_GLOBAL_GPIO_1_INTS                        0x017
  17
  18static int cortina_read_reg(struct phy_device *phydev, u16 regnum)
  19{
  20        return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
  21                            MII_ADDR_C45 | regnum);
  22}
  23
  24static int cortina_read_status(struct phy_device *phydev)
  25{
  26        int gpio_int_status, ret = 0;
  27
  28        gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS);
  29        if (gpio_int_status < 0) {
  30                ret = gpio_int_status;
  31                goto err;
  32        }
  33
  34        if (gpio_int_status & 0x8) {
  35                /* up when edc_convergedS set */
  36                phydev->speed = SPEED_10000;
  37                phydev->duplex = DUPLEX_FULL;
  38                phydev->link = 1;
  39        } else {
  40                phydev->link = 0;
  41        }
  42
  43err:
  44        return ret;
  45}
  46
  47static int cortina_probe(struct phy_device *phydev)
  48{
  49        u32 phy_id = 0;
  50        int id_lsb = 0, id_msb = 0;
  51
  52        /* Read device id from phy registers. */
  53        id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB);
  54        if (id_lsb < 0)
  55                return -ENXIO;
  56
  57        phy_id = id_lsb << 16;
  58
  59        id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB);
  60        if (id_msb < 0)
  61                return -ENXIO;
  62
  63        phy_id |= id_msb;
  64
  65        /* Make sure the device tree binding matched the driver with the
  66         * right device.
  67         */
  68        if (phy_id != phydev->drv->phy_id) {
  69                phydev_err(phydev, "Error matching phy with %s driver\n",
  70                           phydev->drv->name);
  71                return -ENODEV;
  72        }
  73
  74        return 0;
  75}
  76
  77static struct phy_driver cortina_driver[] = {
  78{
  79        .phy_id         = PHY_ID_CS4340,
  80        .phy_id_mask    = 0xffffffff,
  81        .name           = "Cortina CS4340",
  82        .features       = PHY_10GBIT_FEATURES,
  83        .config_aneg    = gen10g_config_aneg,
  84        .read_status    = cortina_read_status,
  85        .soft_reset     = genphy_no_soft_reset,
  86        .probe          = cortina_probe,
  87},
  88};
  89
  90module_phy_driver(cortina_driver);
  91
  92static struct mdio_device_id __maybe_unused cortina_tbl[] = {
  93        { PHY_ID_CS4340, 0xffffffff},
  94        {},
  95};
  96
  97MODULE_DEVICE_TABLE(mdio, cortina_tbl);
  98
  99MODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver");
 100MODULE_AUTHOR("NXP");
 101MODULE_LICENSE("GPL");
 102