linux/drivers/net/phy/realtek.c
<<
>>
Prefs
   1/*
   2 * drivers/net/phy/realtek.c
   3 *
   4 * Driver for Realtek PHYs
   5 *
   6 * Author: Johnson Leung <r58129@freescale.com>
   7 *
   8 * Copyright (c) 2004 Freescale Semiconductor, Inc.
   9 *
  10 * This program is free software; you can redistribute  it and/or modify it
  11 * under  the terms of  the GNU General  Public License as published by the
  12 * Free Software Foundation;  either version 2 of the  License, or (at your
  13 * option) any later version.
  14 *
  15 */
  16#include <linux/phy.h>
  17#include <linux/module.h>
  18
  19#define RTL821x_PHYSR           0x11
  20#define RTL821x_PHYSR_DUPLEX    0x2000
  21#define RTL821x_PHYSR_SPEED     0xc000
  22#define RTL821x_INER            0x12
  23#define RTL821x_INER_INIT       0x6400
  24#define RTL821x_INSR            0x13
  25#define RTL8211E_INER_LINK_STATUS 0x400
  26
  27#define RTL8211F_INER_LINK_STATUS 0x0010
  28#define RTL8211F_INSR           0x1d
  29#define RTL8211F_PAGE_SELECT    0x1f
  30#define RTL8211F_TX_DELAY       0x100
  31
  32MODULE_DESCRIPTION("Realtek PHY driver");
  33MODULE_AUTHOR("Johnson Leung");
  34MODULE_LICENSE("GPL");
  35
  36static int rtl821x_ack_interrupt(struct phy_device *phydev)
  37{
  38        int err;
  39
  40        err = phy_read(phydev, RTL821x_INSR);
  41
  42        return (err < 0) ? err : 0;
  43}
  44
  45static int rtl8211f_ack_interrupt(struct phy_device *phydev)
  46{
  47        int err;
  48
  49        phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43);
  50        err = phy_read(phydev, RTL8211F_INSR);
  51        /* restore to default page 0 */
  52        phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
  53
  54        return (err < 0) ? err : 0;
  55}
  56
  57static int rtl8211b_config_intr(struct phy_device *phydev)
  58{
  59        int err;
  60
  61        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  62                err = phy_write(phydev, RTL821x_INER,
  63                                RTL821x_INER_INIT);
  64        else
  65                err = phy_write(phydev, RTL821x_INER, 0);
  66
  67        return err;
  68}
  69
  70static int rtl8211e_config_intr(struct phy_device *phydev)
  71{
  72        int err;
  73
  74        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  75                err = phy_write(phydev, RTL821x_INER,
  76                                RTL8211E_INER_LINK_STATUS);
  77        else
  78                err = phy_write(phydev, RTL821x_INER, 0);
  79
  80        return err;
  81}
  82
  83static int rtl8211f_config_intr(struct phy_device *phydev)
  84{
  85        int err;
  86
  87        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  88                err = phy_write(phydev, RTL821x_INER,
  89                                RTL8211F_INER_LINK_STATUS);
  90        else
  91                err = phy_write(phydev, RTL821x_INER, 0);
  92
  93        return err;
  94}
  95
  96static int rtl8211f_config_init(struct phy_device *phydev)
  97{
  98        int ret;
  99        u16 reg;
 100
 101        ret = genphy_config_init(phydev);
 102        if (ret < 0)
 103                return ret;
 104
 105        phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
 106        reg = phy_read(phydev, 0x11);
 107
 108        /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
 109        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
 110            phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
 111                reg |= RTL8211F_TX_DELAY;
 112        else
 113                reg &= ~RTL8211F_TX_DELAY;
 114
 115        phy_write(phydev, 0x11, reg);
 116        /* restore to default page 0 */
 117        phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
 118
 119        return 0;
 120}
 121
 122static struct phy_driver realtek_drvs[] = {
 123        {
 124                .phy_id         = 0x00008201,
 125                .name           = "RTL8201CP Ethernet",
 126                .phy_id_mask    = 0x0000ffff,
 127                .features       = PHY_BASIC_FEATURES,
 128                .flags          = PHY_HAS_INTERRUPT,
 129                .config_aneg    = &genphy_config_aneg,
 130                .read_status    = &genphy_read_status,
 131        }, {
 132                .phy_id         = 0x001cc912,
 133                .name           = "RTL8211B Gigabit Ethernet",
 134                .phy_id_mask    = 0x001fffff,
 135                .features       = PHY_GBIT_FEATURES,
 136                .flags          = PHY_HAS_INTERRUPT,
 137                .config_aneg    = &genphy_config_aneg,
 138                .read_status    = &genphy_read_status,
 139                .ack_interrupt  = &rtl821x_ack_interrupt,
 140                .config_intr    = &rtl8211b_config_intr,
 141        }, {
 142                .phy_id         = 0x001cc914,
 143                .name           = "RTL8211DN Gigabit Ethernet",
 144                .phy_id_mask    = 0x001fffff,
 145                .features       = PHY_GBIT_FEATURES,
 146                .flags          = PHY_HAS_INTERRUPT,
 147                .config_aneg    = genphy_config_aneg,
 148                .read_status    = genphy_read_status,
 149                .ack_interrupt  = rtl821x_ack_interrupt,
 150                .config_intr    = rtl8211e_config_intr,
 151                .suspend        = genphy_suspend,
 152                .resume         = genphy_resume,
 153        }, {
 154                .phy_id         = 0x001cc915,
 155                .name           = "RTL8211E Gigabit Ethernet",
 156                .phy_id_mask    = 0x001fffff,
 157                .features       = PHY_GBIT_FEATURES,
 158                .flags          = PHY_HAS_INTERRUPT,
 159                .config_aneg    = &genphy_config_aneg,
 160                .read_status    = &genphy_read_status,
 161                .ack_interrupt  = &rtl821x_ack_interrupt,
 162                .config_intr    = &rtl8211e_config_intr,
 163                .suspend        = genphy_suspend,
 164                .resume         = genphy_resume,
 165        }, {
 166                .phy_id         = 0x001cc916,
 167                .name           = "RTL8211F Gigabit Ethernet",
 168                .phy_id_mask    = 0x001fffff,
 169                .features       = PHY_GBIT_FEATURES,
 170                .flags          = PHY_HAS_INTERRUPT,
 171                .config_aneg    = &genphy_config_aneg,
 172                .config_init    = &rtl8211f_config_init,
 173                .read_status    = &genphy_read_status,
 174                .ack_interrupt  = &rtl8211f_ack_interrupt,
 175                .config_intr    = &rtl8211f_config_intr,
 176                .suspend        = genphy_suspend,
 177                .resume         = genphy_resume,
 178        },
 179};
 180
 181module_phy_driver(realtek_drvs);
 182
 183static struct mdio_device_id __maybe_unused realtek_tbl[] = {
 184        { 0x001cc912, 0x001fffff },
 185        { 0x001cc914, 0x001fffff },
 186        { 0x001cc915, 0x001fffff },
 187        { 0x001cc916, 0x001fffff },
 188        { }
 189};
 190
 191MODULE_DEVICE_TABLE(mdio, realtek_tbl);
 192