Signed-off-by: Bernd Edlinger <bernd.edlin...@hotmail.de> --- drivers/net/phy/Kconfig | 5 + drivers/net/phy/Makefile | 1 + drivers/net/phy/uPD60620.c | 226 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 drivers/net/phy/uPD60620.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a9d16a3..25089f0 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -287,6 +287,11 @@ config DP83867_PHY ---help--- Currently supports the DP83867 PHY. +config RENESAS_PHY + tristate "Driver for Renesas PHYs" + ---help--- + Supports the uPD60620 and uPD60620A PHYs. + config FIXED_PHY tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs" depends on PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 416df92..1404ad3 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_MICROSEMI_PHY) += mscc.o obj-$(CONFIG_NATIONAL_PHY) += national.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek.o +obj-$(CONFIG_RENESAS_PHY) += uPD60620.o obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_STE10XP) += ste10Xp.o diff --git a/drivers/net/phy/uPD60620.c b/drivers/net/phy/uPD60620.c new file mode 100644 index 0000000..b3d900c --- /dev/null +++ b/drivers/net/phy/uPD60620.c @@ -0,0 +1,226 @@ +/* + * Driver for the Renesas PHY uPD60620. + * + * Copyright (C) 2015 Softing Industrial Automation GmbH + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/phy.h> + +#define UPD60620_PHY_ID 0xb8242824 + +/* Extended Registers and values */ +/* PHY Special Control/Status */ +#define PHY_PHYSCR 0x1F /* PHY.31 */ +#define PHY_PHYSCR_10MB 0x0004 /* PHY speed = 10mb */ +#define PHY_PHYSCR_100MB 0x0008 /* PHY speed = 100mb */ +#define PHY_PHYSCR_DUPLEX 0x0010 /* PHY Duplex */ +#define PHY_PHYSCR_RSVD5 0x0020 /* Reserved Bit 5 */ +#define PHY_PHYSCR_MIIMOD 0x0040 /* Enable 4B5B MII mode */ +#define PHY_PHYSCR_RSVD7 0x0080 /* Reserved Bit 7 */ +#define PHY_PHYSCR_RSVD8 0x0100 /* Reserved Bit 8 */ +#define PHY_PHYSCR_RSVD9 0x0200 /* Reserved Bit 9 */ +#define PHY_PHYSCR_RSVD10 0x0400 /* Reserved Bit 10 */ +#define PHY_PHYSCR_RSVD11 0x0800 /* Reserved Bit 11 */ +#define PHY_PHYSCR_ANDONE 0x1000 /* Auto negotiation done */ +#define PHY_PHYSCR_RSVD13 0x2000 /* Reserved Bit 13 */ +#define PHY_PHYSCR_RSVD14 0x4000 /* Reserved Bit 14 */ +#define PHY_PHYSCR_RSVD15 0x8000 /* Reserved Bit 15 */ + +/* PHY Global Config Mapping */ +#define PHY_GLOBAL_CONFIG 0x07 +/* PHY GPIO Config Register 1 */ +#define PHY_GPIO_CONFIG1 0x01 /* PHY 7.1 */ +#define PHY_GPIO4_INT0 0x000d /* GPIO4 configuration */ +#define PHY_GPIO5_INT1 0x00d0 /* GPIO5 configuration */ + +/* PHY Interrupt Control Register */ +#define PHY_ICR 0x1e /* PHY.30 */ +#define PHY_ICR_RSVD0 0x0001 /* Reserved bit 0 */ +#define PHY_ICR_ANCPRRN 0x0002 /* Auto negotiation paged received */ +#define PHY_ICR_PDFEN 0x0004 /* Parallel detection fault */ +#define PHY_ICR_ANCLPAEN 0x0008 /* Auto negotiation last page ack */ +#define PHY_ICR_LNKINTEN 0x0010 /* Link down */ +#define PHY_ICR_REMFD 0x0020 /* Remote fault detected */ +#define PHY_ICR_ANCINTEN 0x0040 /* Auto negotiation complete */ +#define PHY_ICR_EOEN 0x0080 /* Energy on generated */ +#define PHY_ICR_RSVD8 0x0100 /* Reserved bit 8 */ +#define PHY_ICR_FEQTRGEN 0x0200 /* FEQ Trigger */ +#define PHY_ICR_BERTRGEN 0x0400 /* BER Counter Trigger */ +#define PHY_ICR_MLINTEN 0x0800 /* Maxlvl */ +#define PHY_ICR_CLPINTEN 0x1000 /* Clipping */ +#define PHY_ICR_RSVD13 0x2000 /* Reserved bit 13 */ +#define PHY_ICR_RSVD14 0x4000 /* Reserved bit 14 */ +#define PHY_ICR_RSVD15 0x8000 /* Reserved bit 15 */ + +/* PHY Interrupt Status Register */ +#define PHY_ISR 0x1d /* PHY.29 */ +#define PHY_ISR_DUPINT 0x0000 /* Placeholder for Duplex/Speed intr */ +#define PHY_ISR_RSVD0 0x0001 /* Reserved bit 0 */ +#define PHY_ISR_ANCPR 0x0002 /* Auto negotiation paged received */ +#define PHY_ISR_PDF 0x0004 /* Parallel detection fault */ +#define PHY_ISR_ANCLPA 0x0008 /* Auto negotiation last page ack */ +#define PHY_ISR_LNKINT 0x0010 /* Link down */ +#define PHY_ISR_REMFD 0x0020 /* Remote fault detected */ +#define PHY_ISR_ANCINT 0x0040 /* Auto negotiation complete */ +#define PHY_ISR_EO 0x0080 /* Energy on generated */ +#define PHY_ISR_RSVD8 0x0100 /* Reserved bit 8 */ +#define PHY_ISR_FEQTRG 0x0200 /* FEQ Trigger */ +#define PHY_ISR_BERTRG 0x0400 /* BER Counter Trigger */ +#define PHY_ISR_MLINT 0x0800 /* Maxlvl */ +#define PHY_ISR_CLPINT 0x1000 /* Clipping */ +#define PHY_ISR_RSVD13 0x2000 /* Reserved bit 13 */ +#define PHY_ISR_RSVD14 0x4000 /* Reserved bit 14 */ +#define PHY_ISR_RSVD15 0x8000 /* Reserved bit 15 */ + +/* PHY Diagnosis Control/Status Register*/ +#define PHY_DCS 0x19 /* PHY.25 */ +#define PHY_DCS_PWDIAG1 0x0001 /* Pulse Width Diagnosis -- 8ns */ +#define PHY_DCS_DIAGSEL 0x0020 /* Diagnosis select Tx or Rx */ +#define PHY_DCS_DIAGPOL 0x0040 /* Diagnosis stop polarity */ +#define PHY_DCS_DIAGDONE 0x0080 /* Diagnosis done */ +#define PHY_DCS_ADCTRIG05 0x0700 /* ADC Trigger level 0.5V for cable len */ +#define PHY_DCS_ADCMAX 0x3F00 /* ADC Max value */ +#define PHY_DCS_DIAGINIT 0x4000 /* Init TDR test */ + +/* PHY Diagnosis Counter Register */ +#define PHY_DCR 0x1a /* PHY.26 */ +#define PHY_DCR_DIGNCNT 0x00ff /* Diagnosis Count */ +#define PHY_DCR_CNTWIN 0xff00 /* Diagnosis Count Window */ + +/* PHY Mode Control/Status Register */ +#define PHY_MCS 0x11 /* PHY.17 */ +#define PHY_MCS_RSVD0 0x0001 /* Reserved bit 0 */ +#define PHY_MCS_ENERGYON 0x0002 /* Energy on the Line status */ +#define PHY_MCS_FGLS 0x0004 /* Force Good Link Status */ +#define PHY_MCS_RSVD3 0x0008 /* Reserved bit 3 */ +#define PHY_MCS_DCDPATGEN 0x0010 /* DCD measuring pattern generation */ +#define PHY_MCS_RSVD5 0x0020 /* Reserved bit 5 */ +#define PHY_MCS_MDIMODE 0x0040 /* Force MDIX or MDI */ +#define PHY_MCS_AUTOMDIX 0x0080 /* Auto MDIX enable */ +#define PHY_MCS_FASTEST 0x0100 /* Auto negotiation test mode */ +#define PHY_MCS_FARLOOP 0x0200 /* Remote loopback enable */ +#define PHY_MCS_RSVD10 0x0400 /* Reserved bit 10 */ +#define PHY_MCS_LOWSQEN 0x0800 /* Squelch Threshold */ +#define PHY_MCS_RSVD12 0x1000 /* Reserved bit 12 */ +#define PHY_MCS_EPWRDOWN 0x2000 /* Power down mode enable */ +#define PHY_MCS_FASTRIP 0x4000 /* 10Base-T Fast mode */ +#define PHY_MCS_RSVD15 0x8000 /* Reserved bit 15 */ + +/* PHY Special Modes */ +#define PHY_SPM 0x12 /* PHY.18 */ +#define PHY_SPM_FX_MODE 0x400 /* Enable 100BASE-FX mode */ +#define PHY_SPM_PHYMODE 0x1E0 /* PHY mode of operation */ +#define PHY_SPM_PHYADD 0x01F /* PHY address of device */ + +/* PHY BER Counter Register */ +#define PHY_BER 0x17 /* PHY.23 */ +#define PHY_BER_COUNT 0x007f /* BER Count Bits 6-0 */ +#define PHY_BER_WINDOW 0x0780 /* BER Window Bits 10-7 */ +#define PHY_BER_CNT_TRIG 0x3800 /* BER count trigger bits 13-11 */ +#define PHY_BER_CNT_LNK_EN 0x4000 /* BER count link enable */ +#define PHY_BER_LNK_OK 0x8000 /* BER link OK */ + +/* Init PHY */ + +static int upd60620_config_init(struct phy_device *phydev) +{ + /* Enable support for passive HUBs (could be a strap option) */ + /* PHYMODE: All speeds, HD in parallel detect */ + return phy_write(phydev, PHY_SPM, 0x0180 | phydev->mdio.addr); +} + +/* Get PHY status from common registers */ + +static int upd60620_read_status(struct phy_device *phydev) +{ + int phy_state; + + /* Read negotiated state */ + phy_state = phy_read(phydev, MII_BMSR); + if (phy_state < 0) + return phy_state; + + phydev->link = 0; + phydev->lp_advertising = 0; + phydev->pause = 0; + phydev->asym_pause = 0; + + if (phy_state & BMSR_ANEGCOMPLETE) { + phy_state = phy_read(phydev, PHY_PHYSCR); + if (phy_state < 0) + return phy_state; + + if (phy_state & (PHY_PHYSCR_10MB | PHY_PHYSCR_100MB)) { + phydev->link = 1; + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + + if (phy_state & PHY_PHYSCR_100MB) + phydev->speed = SPEED_100; + if (phy_state & PHY_PHYSCR_DUPLEX) + phydev->duplex = DUPLEX_FULL; + + phy_state = phy_read(phydev, MII_LPA); + if (phy_state < 0) + return phy_state; + + phydev->lp_advertising + = mii_lpa_to_ethtool_lpa_t(phy_state); + + if (phydev->duplex == DUPLEX_FULL) { + if (phy_state & LPA_PAUSE_CAP) + phydev->pause = 1; + if (phy_state & LPA_PAUSE_ASYM) + phydev->asym_pause = 1; + } + } + } else if (phy_state & BMSR_LSTATUS) { + phy_state = phy_read(phydev, MII_BMCR); + if (phy_state < 0) + return phy_state; + + if (!(phy_state & BMCR_ANENABLE)) { + phydev->link = 1; + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + + if (phy_state & BMCR_SPEED100) + phydev->speed = SPEED_100; + if (phy_state & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + } + } + return 0; +} + +MODULE_DESCRIPTION("Renesas uPD60620 PHY driver"); +MODULE_AUTHOR("Bernd Edlinger <bernd.edlin...@hotmail.de>"); +MODULE_LICENSE("GPL"); + +static struct phy_driver upd60620_driver[1] = { { + .phy_id = UPD60620_PHY_ID, + .phy_id_mask = 0xfffffffe, + .name = "Renesas uPD60620", + .features = PHY_BASIC_FEATURES, + .flags = 0, + .config_init = upd60620_config_init, + .config_aneg = genphy_config_aneg, + .read_status = upd60620_read_status, +} }; + +module_phy_driver(upd60620_driver); + +static struct mdio_device_id __maybe_unused upd60620_tbl[] = { + { UPD60620_PHY_ID, 0xfffffffe }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, upd60620_tbl); -- 2.7.4