1*f485c8a3SMatt Porter /* 2*f485c8a3SMatt Porter * ET1011C PHY driver 3*f485c8a3SMatt Porter * 4*f485c8a3SMatt Porter * Derived from Linux kernel driver by Chaithrika U S 5*f485c8a3SMatt Porter * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/ 6*f485c8a3SMatt Porter * 7*f485c8a3SMatt Porter * This program is free software; you can redistribute it and/or 8*f485c8a3SMatt Porter * modify it under the terms of the GNU General Public License as 9*f485c8a3SMatt Porter * published by the Free Software Foundation; either version 2 of 10*f485c8a3SMatt Porter * the License, or (at your option) any later version. 11*f485c8a3SMatt Porter * 12*f485c8a3SMatt Porter * This program is distributed in the hope that it will be useful, 13*f485c8a3SMatt Porter * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*f485c8a3SMatt Porter * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*f485c8a3SMatt Porter * GNU General Public License for more details. 16*f485c8a3SMatt Porter * 17*f485c8a3SMatt Porter */ 18*f485c8a3SMatt Porter #include <config.h> 19*f485c8a3SMatt Porter #include <phy.h> 20*f485c8a3SMatt Porter 21*f485c8a3SMatt Porter #define ET1011C_CONFIG_REG (0x16) 22*f485c8a3SMatt Porter #define ET1011C_TX_FIFO_MASK (0x3 << 12) 23*f485c8a3SMatt Porter #define ET1011C_TX_FIFO_DEPTH_8 (0x0 << 12) 24*f485c8a3SMatt Porter #define ET1011C_TX_FIFO_DEPTH_16 (0x1 << 12) 25*f485c8a3SMatt Porter #define ET1011C_INTERFACE_MASK (0x7 << 0) 26*f485c8a3SMatt Porter #define ET1011C_GMII_INTERFACE (0x2 << 0) 27*f485c8a3SMatt Porter #define ET1011C_SYS_CLK_EN (0x1 << 4) 28*f485c8a3SMatt Porter #define ET1011C_TX_CLK_EN (0x1 << 5) 29*f485c8a3SMatt Porter 30*f485c8a3SMatt Porter #define ET1011C_STATUS_REG (0x1A) 31*f485c8a3SMatt Porter #define ET1011C_DUPLEX_STATUS (0x1 << 7) 32*f485c8a3SMatt Porter #define ET1011C_SPEED_MASK (0x3 << 8) 33*f485c8a3SMatt Porter #define ET1011C_SPEED_1000 (0x2 << 8) 34*f485c8a3SMatt Porter #define ET1011C_SPEED_100 (0x1 << 8) 35*f485c8a3SMatt Porter #define ET1011C_SPEED_10 (0x0 << 8) 36*f485c8a3SMatt Porter 37*f485c8a3SMatt Porter static int et1011c_config(struct phy_device *phydev) 38*f485c8a3SMatt Porter { 39*f485c8a3SMatt Porter int ctl = 0; 40*f485c8a3SMatt Porter ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 41*f485c8a3SMatt Porter if (ctl < 0) 42*f485c8a3SMatt Porter return ctl; 43*f485c8a3SMatt Porter ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | 44*f485c8a3SMatt Porter BMCR_ANENABLE); 45*f485c8a3SMatt Porter /* First clear the PHY */ 46*f485c8a3SMatt Porter phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl | BMCR_RESET); 47*f485c8a3SMatt Porter 48*f485c8a3SMatt Porter return genphy_config_aneg(phydev); 49*f485c8a3SMatt Porter } 50*f485c8a3SMatt Porter 51*f485c8a3SMatt Porter static int et1011c_parse_status(struct phy_device *phydev) 52*f485c8a3SMatt Porter { 53*f485c8a3SMatt Porter int mii_reg; 54*f485c8a3SMatt Porter int speed; 55*f485c8a3SMatt Porter 56*f485c8a3SMatt Porter mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_STATUS_REG); 57*f485c8a3SMatt Porter 58*f485c8a3SMatt Porter if (mii_reg & ET1011C_DUPLEX_STATUS) 59*f485c8a3SMatt Porter phydev->duplex = DUPLEX_FULL; 60*f485c8a3SMatt Porter else 61*f485c8a3SMatt Porter phydev->duplex = DUPLEX_HALF; 62*f485c8a3SMatt Porter 63*f485c8a3SMatt Porter speed = mii_reg & ET1011C_SPEED_MASK; 64*f485c8a3SMatt Porter switch (speed) { 65*f485c8a3SMatt Porter case ET1011C_SPEED_1000: 66*f485c8a3SMatt Porter phydev->speed = SPEED_1000; 67*f485c8a3SMatt Porter mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG); 68*f485c8a3SMatt Porter mii_reg &= ~ET1011C_TX_FIFO_MASK; 69*f485c8a3SMatt Porter phy_write(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG, 70*f485c8a3SMatt Porter mii_reg | 71*f485c8a3SMatt Porter ET1011C_GMII_INTERFACE | 72*f485c8a3SMatt Porter ET1011C_SYS_CLK_EN | 73*f485c8a3SMatt Porter #ifdef CONFIG_PHY_ET1011C_TX_CLK_FIX 74*f485c8a3SMatt Porter ET1011C_TX_CLK_EN | 75*f485c8a3SMatt Porter #endif 76*f485c8a3SMatt Porter ET1011C_TX_FIFO_DEPTH_16); 77*f485c8a3SMatt Porter break; 78*f485c8a3SMatt Porter case ET1011C_SPEED_100: 79*f485c8a3SMatt Porter phydev->speed = SPEED_100; 80*f485c8a3SMatt Porter break; 81*f485c8a3SMatt Porter case ET1011C_SPEED_10: 82*f485c8a3SMatt Porter phydev->speed = SPEED_10; 83*f485c8a3SMatt Porter break; 84*f485c8a3SMatt Porter } 85*f485c8a3SMatt Porter 86*f485c8a3SMatt Porter return 0; 87*f485c8a3SMatt Porter } 88*f485c8a3SMatt Porter 89*f485c8a3SMatt Porter static int et1011c_startup(struct phy_device *phydev) 90*f485c8a3SMatt Porter { 91*f485c8a3SMatt Porter genphy_update_link(phydev); 92*f485c8a3SMatt Porter et1011c_parse_status(phydev); 93*f485c8a3SMatt Porter return 0; 94*f485c8a3SMatt Porter } 95*f485c8a3SMatt Porter 96*f485c8a3SMatt Porter static struct phy_driver et1011c_driver = { 97*f485c8a3SMatt Porter .name = "ET1011C", 98*f485c8a3SMatt Porter .uid = 0x0282f014, 99*f485c8a3SMatt Porter .mask = 0xfffffff0, 100*f485c8a3SMatt Porter .features = PHY_GBIT_FEATURES, 101*f485c8a3SMatt Porter .config = &et1011c_config, 102*f485c8a3SMatt Porter .startup = &et1011c_startup, 103*f485c8a3SMatt Porter }; 104*f485c8a3SMatt Porter 105*f485c8a3SMatt Porter int phy_et1011c_init(void) 106*f485c8a3SMatt Porter { 107*f485c8a3SMatt Porter phy_register(&et1011c_driver); 108*f485c8a3SMatt Porter 109*f485c8a3SMatt Porter return 0; 110*f485c8a3SMatt Porter } 111