linux/drivers/net/phy/icplus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Driver for ICPlus PHYs
   4 *
   5 * Copyright (c) 2007 Freescale Semiconductor, Inc.
   6 */
   7#include <linux/kernel.h>
   8#include <linux/string.h>
   9#include <linux/errno.h>
  10#include <linux/unistd.h>
  11#include <linux/interrupt.h>
  12#include <linux/init.h>
  13#include <linux/delay.h>
  14#include <linux/netdevice.h>
  15#include <linux/etherdevice.h>
  16#include <linux/skbuff.h>
  17#include <linux/spinlock.h>
  18#include <linux/mm.h>
  19#include <linux/module.h>
  20#include <linux/mii.h>
  21#include <linux/ethtool.h>
  22#include <linux/phy.h>
  23#include <linux/property.h>
  24
  25#include <asm/io.h>
  26#include <asm/irq.h>
  27#include <linux/uaccess.h>
  28
  29MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers");
  30MODULE_AUTHOR("Michael Barkowski");
  31MODULE_LICENSE("GPL");
  32
  33/* IP101A/G - IP1001 */
  34#define IP10XX_SPEC_CTRL_STATUS         16      /* Spec. Control Register */
  35#define IP1001_RXPHASE_SEL              BIT(0)  /* Add delay on RX_CLK */
  36#define IP1001_TXPHASE_SEL              BIT(1)  /* Add delay on TX_CLK */
  37#define IP1001_SPEC_CTRL_STATUS_2       20      /* IP1001 Spec. Control Reg 2 */
  38#define IP1001_APS_ON                   11      /* IP1001 APS Mode  bit */
  39#define IP101A_G_APS_ON                 BIT(1)  /* IP101A/G APS Mode bit */
  40#define IP101A_G_IRQ_CONF_STATUS        0x11    /* Conf Info IRQ & Status Reg */
  41#define IP101A_G_IRQ_PIN_USED           BIT(15) /* INTR pin used */
  42#define IP101A_G_IRQ_ALL_MASK           BIT(11) /* IRQ's inactive */
  43#define IP101A_G_IRQ_SPEED_CHANGE       BIT(2)
  44#define IP101A_G_IRQ_DUPLEX_CHANGE      BIT(1)
  45#define IP101A_G_IRQ_LINK_CHANGE        BIT(0)
  46
  47#define IP101G_DIGITAL_IO_SPEC_CTRL                     0x1d
  48#define IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32          BIT(2)
  49
  50/* The 32-pin IP101GR package can re-configure the mode of the RXER/INTR_32 pin
  51 * (pin number 21). The hardware default is RXER (receive error) mode. But it
  52 * can be configured to interrupt mode manually.
  53 */
  54enum ip101gr_sel_intr32 {
  55        IP101GR_SEL_INTR32_KEEP,
  56        IP101GR_SEL_INTR32_INTR,
  57        IP101GR_SEL_INTR32_RXER,
  58};
  59
  60struct ip101a_g_phy_priv {
  61        enum ip101gr_sel_intr32 sel_intr32;
  62};
  63
  64static int ip175c_config_init(struct phy_device *phydev)
  65{
  66        int err, i;
  67        static int full_reset_performed;
  68
  69        if (full_reset_performed == 0) {
  70
  71                /* master reset */
  72                err = mdiobus_write(phydev->mdio.bus, 30, 0, 0x175c);
  73                if (err < 0)
  74                        return err;
  75
  76                /* ensure no bus delays overlap reset period */
  77                err = mdiobus_read(phydev->mdio.bus, 30, 0);
  78
  79                /* data sheet specifies reset period is 2 msec */
  80                mdelay(2);
  81
  82                /* enable IP175C mode */
  83                err = mdiobus_write(phydev->mdio.bus, 29, 31, 0x175c);
  84                if (err < 0)
  85                        return err;
  86
  87                /* Set MII0 speed and duplex (in PHY mode) */
  88                err = mdiobus_write(phydev->mdio.bus, 29, 22, 0x420);
  89                if (err < 0)
  90                        return err;
  91
  92                /* reset switch ports */
  93                for (i = 0; i < 5; i++) {
  94                        err = mdiobus_write(phydev->mdio.bus, i,
  95                                            MII_BMCR, BMCR_RESET);
  96                        if (err < 0)
  97                                return err;
  98                }
  99
 100                for (i = 0; i < 5; i++)
 101                        err = mdiobus_read(phydev->mdio.bus, i, MII_BMCR);
 102
 103                mdelay(2);
 104
 105                full_reset_performed = 1;
 106        }
 107
 108        if (phydev->mdio.addr != 4) {
 109                phydev->state = PHY_RUNNING;
 110                phydev->speed = SPEED_100;
 111                phydev->duplex = DUPLEX_FULL;
 112                phydev->link = 1;
 113                netif_carrier_on(phydev->attached_dev);
 114        }
 115
 116        return 0;
 117}
 118
 119static int ip1xx_reset(struct phy_device *phydev)
 120{
 121        int bmcr;
 122
 123        /* Software Reset PHY */
 124        bmcr = phy_read(phydev, MII_BMCR);
 125        if (bmcr < 0)
 126                return bmcr;
 127        bmcr |= BMCR_RESET;
 128        bmcr = phy_write(phydev, MII_BMCR, bmcr);
 129        if (bmcr < 0)
 130                return bmcr;
 131
 132        do {
 133                bmcr = phy_read(phydev, MII_BMCR);
 134                if (bmcr < 0)
 135                        return bmcr;
 136        } while (bmcr & BMCR_RESET);
 137
 138        return 0;
 139}
 140
 141static int ip1001_config_init(struct phy_device *phydev)
 142{
 143        int c;
 144
 145        c = ip1xx_reset(phydev);
 146        if (c < 0)
 147                return c;
 148
 149        /* Enable Auto Power Saving mode */
 150        c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2);
 151        if (c < 0)
 152                return c;
 153        c |= IP1001_APS_ON;
 154        c = phy_write(phydev, IP1001_SPEC_CTRL_STATUS_2, c);
 155        if (c < 0)
 156                return c;
 157
 158        if (phy_interface_is_rgmii(phydev)) {
 159
 160                c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
 161                if (c < 0)
 162                        return c;
 163
 164                c &= ~(IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL);
 165
 166                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
 167                        c |= (IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL);
 168                else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
 169                        c |= IP1001_RXPHASE_SEL;
 170                else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
 171                        c |= IP1001_TXPHASE_SEL;
 172
 173                c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
 174                if (c < 0)
 175                        return c;
 176        }
 177
 178        return 0;
 179}
 180
 181static int ip175c_read_status(struct phy_device *phydev)
 182{
 183        if (phydev->mdio.addr == 4) /* WAN port */
 184                genphy_read_status(phydev);
 185        else
 186                /* Don't need to read status for switch ports */
 187                phydev->irq = PHY_IGNORE_INTERRUPT;
 188
 189        return 0;
 190}
 191
 192static int ip175c_config_aneg(struct phy_device *phydev)
 193{
 194        if (phydev->mdio.addr == 4) /* WAN port */
 195                genphy_config_aneg(phydev);
 196
 197        return 0;
 198}
 199
 200static int ip101a_g_probe(struct phy_device *phydev)
 201{
 202        struct device *dev = &phydev->mdio.dev;
 203        struct ip101a_g_phy_priv *priv;
 204
 205        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 206        if (!priv)
 207                return -ENOMEM;
 208
 209        /* Both functions (RX error and interrupt status) are sharing the same
 210         * pin on the 32-pin IP101GR, so this is an exclusive choice.
 211         */
 212        if (device_property_read_bool(dev, "icplus,select-rx-error") &&
 213            device_property_read_bool(dev, "icplus,select-interrupt")) {
 214                dev_err(dev,
 215                        "RXER and INTR mode cannot be selected together\n");
 216                return -EINVAL;
 217        }
 218
 219        if (device_property_read_bool(dev, "icplus,select-rx-error"))
 220                priv->sel_intr32 = IP101GR_SEL_INTR32_RXER;
 221        else if (device_property_read_bool(dev, "icplus,select-interrupt"))
 222                priv->sel_intr32 = IP101GR_SEL_INTR32_INTR;
 223        else
 224                priv->sel_intr32 = IP101GR_SEL_INTR32_KEEP;
 225
 226        phydev->priv = priv;
 227
 228        return 0;
 229}
 230
 231static int ip101a_g_config_init(struct phy_device *phydev)
 232{
 233        struct ip101a_g_phy_priv *priv = phydev->priv;
 234        int err, c;
 235
 236        c = ip1xx_reset(phydev);
 237        if (c < 0)
 238                return c;
 239
 240        /* configure the RXER/INTR_32 pin of the 32-pin IP101GR if needed: */
 241        switch (priv->sel_intr32) {
 242        case IP101GR_SEL_INTR32_RXER:
 243                err = phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL,
 244                                 IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32, 0);
 245                if (err < 0)
 246                        return err;
 247                break;
 248
 249        case IP101GR_SEL_INTR32_INTR:
 250                err = phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL,
 251                                 IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32,
 252                                 IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32);
 253                if (err < 0)
 254                        return err;
 255                break;
 256
 257        default:
 258                /* Don't touch IP101G_DIGITAL_IO_SPEC_CTRL because it's not
 259                 * documented on IP101A and it's not clear whether this would
 260                 * cause problems.
 261                 * For the 32-pin IP101GR we simply keep the SEL_INTR32
 262                 * configuration as set by the bootloader when not configured
 263                 * to one of the special functions.
 264                 */
 265                break;
 266        }
 267
 268        /* Enable Auto Power Saving mode */
 269        c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
 270        c |= IP101A_G_APS_ON;
 271
 272        return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
 273}
 274
 275static int ip101a_g_config_intr(struct phy_device *phydev)
 276{
 277        u16 val;
 278
 279        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 280                /* INTR pin used: Speed/link/duplex will cause an interrupt */
 281                val = IP101A_G_IRQ_PIN_USED;
 282        else
 283                val = IP101A_G_IRQ_ALL_MASK;
 284
 285        return phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, val);
 286}
 287
 288static int ip101a_g_did_interrupt(struct phy_device *phydev)
 289{
 290        int val = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS);
 291
 292        if (val < 0)
 293                return 0;
 294
 295        return val & (IP101A_G_IRQ_SPEED_CHANGE |
 296                      IP101A_G_IRQ_DUPLEX_CHANGE |
 297                      IP101A_G_IRQ_LINK_CHANGE);
 298}
 299
 300static int ip101a_g_ack_interrupt(struct phy_device *phydev)
 301{
 302        int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS);
 303        if (err < 0)
 304                return err;
 305
 306        return 0;
 307}
 308
 309static struct phy_driver icplus_driver[] = {
 310{
 311        .phy_id         = 0x02430d80,
 312        .name           = "ICPlus IP175C",
 313        .phy_id_mask    = 0x0ffffff0,
 314        /* PHY_BASIC_FEATURES */
 315        .config_init    = &ip175c_config_init,
 316        .config_aneg    = &ip175c_config_aneg,
 317        .read_status    = &ip175c_read_status,
 318        .suspend        = genphy_suspend,
 319        .resume         = genphy_resume,
 320}, {
 321        .phy_id         = 0x02430d90,
 322        .name           = "ICPlus IP1001",
 323        .phy_id_mask    = 0x0ffffff0,
 324        /* PHY_GBIT_FEATURES */
 325        .config_init    = &ip1001_config_init,
 326        .suspend        = genphy_suspend,
 327        .resume         = genphy_resume,
 328}, {
 329        .phy_id         = 0x02430c54,
 330        .name           = "ICPlus IP101A/G",
 331        .phy_id_mask    = 0x0ffffff0,
 332        /* PHY_BASIC_FEATURES */
 333        .probe          = ip101a_g_probe,
 334        .config_intr    = ip101a_g_config_intr,
 335        .did_interrupt  = ip101a_g_did_interrupt,
 336        .ack_interrupt  = ip101a_g_ack_interrupt,
 337        .config_init    = &ip101a_g_config_init,
 338        .suspend        = genphy_suspend,
 339        .resume         = genphy_resume,
 340} };
 341
 342module_phy_driver(icplus_driver);
 343
 344static struct mdio_device_id __maybe_unused icplus_tbl[] = {
 345        { 0x02430d80, 0x0ffffff0 },
 346        { 0x02430d90, 0x0ffffff0 },
 347        { 0x02430c54, 0x0ffffff0 },
 348        { }
 349};
 350
 351MODULE_DEVICE_TABLE(mdio, icplus_tbl);
 352