diff --git a/Documentation/devicetree/bindings/net/cortina.txt b/Documentation/devicetree/bindings/net/cortina.txt new file mode 100644 index 0000000000000000000000000000000000000000..40d0bd984113de4acf867654a01a057f04aa3dc0 --- /dev/null +++ b/Documentation/devicetree/bindings/net/cortina.txt @@ -0,0 +1,21 @@ +Cortina Phy Driver Device Tree Bindings +--------------------------------------- + +CORTINA is a registered trademark of Cortina Systems, Inc. + +The driver supports the Cortina Electronic Dispersion Compensation (EDC) +devices, equipped with clock and data recovery (CDR) circuits. These +devices make use of registers that are not compatible with Clause 45 or +Clause 22, therefore they need to be described using the +"ethernet-phy-id" compatible. + +Since the driver only implements polling mode support, interrupts info +can be skipped. + +Example (CS4340 phy): + mdio { + cs4340_phy@10 { + compatible = "ethernet-phy-id13e5.1002"; + reg = <0x10>; + }; + }; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index c360dd6ead2213b112282ff508b963354cf15d72..0c516d3229d0b8aa98064a8796cbeea6797f0752 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -234,6 +234,11 @@ config CICADA_PHY ---help--- Currently supports the cis8204 +config CORTINA_PHY + tristate "Cortina EDC CDR 10G Ethernet PHY" + ---help--- + Currently supports the CS4340 phy. + config DAVICOM_PHY tristate "Davicom PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e36db9a2ba3814330277ea21980689c2d88c4018..e2fde094f63db5f9da9f326860768a3bd5d54a87 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_CICADA_PHY) += cicada.o +obj-$(CONFIG_CORTINA_PHY) += cortina.o obj-$(CONFIG_DAVICOM_PHY) += davicom.o obj-$(CONFIG_DP83640_PHY) += dp83640.o obj-$(CONFIG_DP83848_PHY) += dp83848.o diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c new file mode 100644 index 0000000000000000000000000000000000000000..72f4228a63bb0a9fb0f3baa993fa85fc8ad6f823 --- /dev/null +++ b/drivers/net/phy/cortina.c @@ -0,0 +1,118 @@ +/* + * Copyright 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * CORTINA is a registered trademark of Cortina Systems, Inc. + * + */ +#include +#include + +#define PHY_ID_CS4340 0x13e51002 + +#define VILLA_GLOBAL_CHIP_ID_LSB 0x0 +#define VILLA_GLOBAL_CHIP_ID_MSB 0x1 + +#define VILLA_GLOBAL_GPIO_1_INTS 0x017 + +static int cortina_read_reg(struct phy_device *phydev, u16 regnum) +{ + return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, + MII_ADDR_C45 | regnum); +} + +static int cortina_config_aneg(struct phy_device *phydev) +{ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + +static int cortina_read_status(struct phy_device *phydev) +{ + int gpio_int_status, ret = 0; + + gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); + if (gpio_int_status < 0) { + ret = gpio_int_status; + goto err; + } + + if (gpio_int_status & 0x8) { + /* up when edc_convergedS set */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + } else { + phydev->link = 0; + } + +err: + return ret; +} + +static int cortina_soft_reset(struct phy_device *phydev) +{ + return 0; +} + +static int cortina_probe(struct phy_device *phydev) +{ + u32 phy_id = 0; + int id_lsb = 0, id_msb = 0; + + /* Read device id from phy registers. */ + id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); + if (id_lsb < 0) + return -ENXIO; + + phy_id = id_lsb << 16; + + id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); + if (id_msb < 0) + return -ENXIO; + + phy_id |= id_msb; + + /* Make sure the device tree binding matched the driver with the + * right device. + */ + if (phy_id != phydev->drv->phy_id) { + phydev_err(phydev, "Error matching phy with %s driver\n", + phydev->drv->name); + return -ENODEV; + } + + return 0; +} + +static struct phy_driver cortina_driver[] = { +{ + .phy_id = PHY_ID_CS4340, + .phy_id_mask = 0xffffffff, + .name = "Cortina CS4340", + .config_aneg = cortina_config_aneg, + .read_status = cortina_read_status, + .soft_reset = cortina_soft_reset, + .probe = cortina_probe, +}, +}; + +module_phy_driver(cortina_driver); + +static struct mdio_device_id __maybe_unused cortina_tbl[] = { + { PHY_ID_CS4340, 0xffffffff}, + {}, +}; + +MODULE_DEVICE_TABLE(mdio, cortina_tbl);