linux/drivers/net/phy/cortina.c
<<
>>
Prefs
   1/*
   2 *    Copyright 2017 NXP
   3 *
   4 *    This program is free software; you can redistribute it and/or modify
   5 *    it under the terms of the GNU General Public License as published by
   6 *    the Free Software Foundation; either version 2 of the License, or
   7 *    (at your option) any later version.
   8 *
   9 *    This program is distributed in the hope that it will be useful,
  10 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 *    GNU General Public License for more details.
  13 *
  14 *    CORTINA is a registered trademark of Cortina Systems, Inc.
  15 *
  16 */
  17#include <linux/module.h>
  18#include <linux/phy.h>
  19
  20#define PHY_ID_CS4340   0x13e51002
  21
  22#define VILLA_GLOBAL_CHIP_ID_LSB                        0x0
  23#define VILLA_GLOBAL_CHIP_ID_MSB                        0x1
  24
  25#define VILLA_GLOBAL_GPIO_1_INTS                        0x017
  26
  27static int cortina_read_reg(struct phy_device *phydev, u16 regnum)
  28{
  29        return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
  30                            MII_ADDR_C45 | regnum);
  31}
  32
  33static int cortina_read_status(struct phy_device *phydev)
  34{
  35        int gpio_int_status, ret = 0;
  36
  37        gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS);
  38        if (gpio_int_status < 0) {
  39                ret = gpio_int_status;
  40                goto err;
  41        }
  42
  43        if (gpio_int_status & 0x8) {
  44                /* up when edc_convergedS set */
  45                phydev->speed = SPEED_10000;
  46                phydev->duplex = DUPLEX_FULL;
  47                phydev->link = 1;
  48        } else {
  49                phydev->link = 0;
  50        }
  51
  52err:
  53        return ret;
  54}
  55
  56static int cortina_probe(struct phy_device *phydev)
  57{
  58        u32 phy_id = 0;
  59        int id_lsb = 0, id_msb = 0;
  60
  61        /* Read device id from phy registers. */
  62        id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB);
  63        if (id_lsb < 0)
  64                return -ENXIO;
  65
  66        phy_id = id_lsb << 16;
  67
  68        id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB);
  69        if (id_msb < 0)
  70                return -ENXIO;
  71
  72        phy_id |= id_msb;
  73
  74        /* Make sure the device tree binding matched the driver with the
  75         * right device.
  76         */
  77        if (phy_id != phydev->drv->phy_id) {
  78                phydev_err(phydev, "Error matching phy with %s driver\n",
  79                           phydev->drv->name);
  80                return -ENODEV;
  81        }
  82
  83        return 0;
  84}
  85
  86static struct phy_driver cortina_driver[] = {
  87{
  88        .phy_id         = PHY_ID_CS4340,
  89        .phy_id_mask    = 0xffffffff,
  90        .name           = "Cortina CS4340",
  91        .features       = PHY_10GBIT_FEATURES,
  92        .config_init    = gen10g_config_init,
  93        .config_aneg    = gen10g_config_aneg,
  94        .read_status    = cortina_read_status,
  95        .soft_reset     = gen10g_no_soft_reset,
  96        .probe          = cortina_probe,
  97},
  98};
  99
 100module_phy_driver(cortina_driver);
 101
 102static struct mdio_device_id __maybe_unused cortina_tbl[] = {
 103        { PHY_ID_CS4340, 0xffffffff},
 104        {},
 105};
 106
 107MODULE_DEVICE_TABLE(mdio, cortina_tbl);
 108
 109MODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver");
 110MODULE_AUTHOR("NXP");
 111MODULE_LICENSE("GPL");
 112