1f61687c0SShaohui Xie /* 2f61687c0SShaohui Xie * Driver for Teranetics PHY 3f61687c0SShaohui Xie * 4f61687c0SShaohui Xie * Author: Shaohui Xie <Shaohui.Xie@freescale.com> 5f61687c0SShaohui Xie * 6f61687c0SShaohui Xie * Copyright 2015 Freescale Semiconductor, Inc. 7f61687c0SShaohui Xie * 8f61687c0SShaohui Xie * This file is licensed under the terms of the GNU General Public License 9f61687c0SShaohui Xie * version 2. This program is licensed "as is" without any warranty of any 10f61687c0SShaohui Xie * kind, whether express or implied. 11f61687c0SShaohui Xie */ 12f61687c0SShaohui Xie 13f61687c0SShaohui Xie #include <linux/kernel.h> 14f61687c0SShaohui Xie #include <linux/module.h> 15f61687c0SShaohui Xie #include <linux/mii.h> 16f61687c0SShaohui Xie #include <linux/ethtool.h> 17f61687c0SShaohui Xie #include <linux/mdio.h> 18f61687c0SShaohui Xie #include <linux/phy.h> 19f61687c0SShaohui Xie 20f61687c0SShaohui Xie MODULE_DESCRIPTION("Teranetics PHY driver"); 21f61687c0SShaohui Xie MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>"); 22f61687c0SShaohui Xie MODULE_LICENSE("GPL v2"); 23f61687c0SShaohui Xie 24f61687c0SShaohui Xie #define PHY_ID_TN2020 0x00a19410 25f61687c0SShaohui Xie #define MDIO_PHYXS_LNSTAT_SYNC0 0x0001 26f61687c0SShaohui Xie #define MDIO_PHYXS_LNSTAT_SYNC1 0x0002 27f61687c0SShaohui Xie #define MDIO_PHYXS_LNSTAT_SYNC2 0x0004 28f61687c0SShaohui Xie #define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 29f61687c0SShaohui Xie #define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 30f61687c0SShaohui Xie 31f61687c0SShaohui Xie #define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \ 32f61687c0SShaohui Xie MDIO_PHYXS_LNSTAT_SYNC1 | \ 33f61687c0SShaohui Xie MDIO_PHYXS_LNSTAT_SYNC2 | \ 34f61687c0SShaohui Xie MDIO_PHYXS_LNSTAT_SYNC3 | \ 35f61687c0SShaohui Xie MDIO_PHYXS_LNSTAT_ALIGN) 36f61687c0SShaohui Xie 37f61687c0SShaohui Xie static int teranetics_config_init(struct phy_device *phydev) 38f61687c0SShaohui Xie { 39f61687c0SShaohui Xie phydev->supported = SUPPORTED_10000baseT_Full; 40f61687c0SShaohui Xie phydev->advertising = SUPPORTED_10000baseT_Full; 41f61687c0SShaohui Xie 42f61687c0SShaohui Xie return 0; 43f61687c0SShaohui Xie } 44f61687c0SShaohui Xie 45f61687c0SShaohui Xie static int teranetics_soft_reset(struct phy_device *phydev) 46f61687c0SShaohui Xie { 47f61687c0SShaohui Xie return 0; 48f61687c0SShaohui Xie } 49f61687c0SShaohui Xie 50f61687c0SShaohui Xie static int teranetics_aneg_done(struct phy_device *phydev) 51f61687c0SShaohui Xie { 52f61687c0SShaohui Xie int reg; 53f61687c0SShaohui Xie 54*94724d10SShaohui Xie /* auto negotiation state can only be checked when using copper 55*94724d10SShaohui Xie * port, if using fiber port, just lie it's done. 56*94724d10SShaohui Xie */ 57*94724d10SShaohui Xie if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93)) { 58f61687c0SShaohui Xie reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); 59f61687c0SShaohui Xie return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); 60f61687c0SShaohui Xie } 61f61687c0SShaohui Xie 62*94724d10SShaohui Xie return 1; 63*94724d10SShaohui Xie } 64*94724d10SShaohui Xie 65f61687c0SShaohui Xie static int teranetics_config_aneg(struct phy_device *phydev) 66f61687c0SShaohui Xie { 67f61687c0SShaohui Xie return 0; 68f61687c0SShaohui Xie } 69f61687c0SShaohui Xie 70f61687c0SShaohui Xie static int teranetics_read_status(struct phy_device *phydev) 71f61687c0SShaohui Xie { 72f61687c0SShaohui Xie int reg; 73f61687c0SShaohui Xie 74f61687c0SShaohui Xie phydev->link = 1; 75f61687c0SShaohui Xie 76f61687c0SShaohui Xie phydev->speed = SPEED_10000; 77f61687c0SShaohui Xie phydev->duplex = DUPLEX_FULL; 78f61687c0SShaohui Xie 79f61687c0SShaohui Xie if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93)) { 80f61687c0SShaohui Xie reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT); 81f61687c0SShaohui Xie if (reg < 0 || 82f61687c0SShaohui Xie !((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)) { 83f61687c0SShaohui Xie phydev->link = 0; 84f61687c0SShaohui Xie return 0; 85f61687c0SShaohui Xie } 86f61687c0SShaohui Xie 87f61687c0SShaohui Xie reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); 88f61687c0SShaohui Xie if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) 89f61687c0SShaohui Xie phydev->link = 0; 90f61687c0SShaohui Xie } 91f61687c0SShaohui Xie 92f61687c0SShaohui Xie return 0; 93f61687c0SShaohui Xie } 94f61687c0SShaohui Xie 95f61687c0SShaohui Xie static int teranetics_match_phy_device(struct phy_device *phydev) 96f61687c0SShaohui Xie { 97f61687c0SShaohui Xie return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020; 98f61687c0SShaohui Xie } 99f61687c0SShaohui Xie 100f61687c0SShaohui Xie static struct phy_driver teranetics_driver[] = { 101f61687c0SShaohui Xie { 102f61687c0SShaohui Xie .phy_id = PHY_ID_TN2020, 103f61687c0SShaohui Xie .phy_id_mask = 0xffffffff, 104f61687c0SShaohui Xie .name = "Teranetics TN2020", 105f61687c0SShaohui Xie .soft_reset = teranetics_soft_reset, 106f61687c0SShaohui Xie .aneg_done = teranetics_aneg_done, 107f61687c0SShaohui Xie .config_init = teranetics_config_init, 108f61687c0SShaohui Xie .config_aneg = teranetics_config_aneg, 109f61687c0SShaohui Xie .read_status = teranetics_read_status, 110f61687c0SShaohui Xie .match_phy_device = teranetics_match_phy_device, 111f61687c0SShaohui Xie .driver = { .owner = THIS_MODULE,}, 112f61687c0SShaohui Xie }, 113f61687c0SShaohui Xie }; 114f61687c0SShaohui Xie 115f61687c0SShaohui Xie static int __init teranetics_init(void) 116f61687c0SShaohui Xie { 117f61687c0SShaohui Xie return phy_drivers_register(teranetics_driver, 118f61687c0SShaohui Xie ARRAY_SIZE(teranetics_driver)); 119f61687c0SShaohui Xie } 120f61687c0SShaohui Xie 121f61687c0SShaohui Xie static void __exit teranetics_exit(void) 122f61687c0SShaohui Xie { 123f61687c0SShaohui Xie return phy_drivers_unregister(teranetics_driver, 124f61687c0SShaohui Xie ARRAY_SIZE(teranetics_driver)); 125f61687c0SShaohui Xie } 126f61687c0SShaohui Xie 127f61687c0SShaohui Xie module_init(teranetics_init); 128f61687c0SShaohui Xie module_exit(teranetics_exit); 129f61687c0SShaohui Xie 130f61687c0SShaohui Xie static struct mdio_device_id __maybe_unused teranetics_tbl[] = { 131f61687c0SShaohui Xie { PHY_ID_TN2020, 0xffffffff }, 132f61687c0SShaohui Xie { } 133f61687c0SShaohui Xie }; 134f61687c0SShaohui Xie 135f61687c0SShaohui Xie MODULE_DEVICE_TABLE(mdio, teranetics_tbl); 136