linux/drivers/net/phy/qsemi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * drivers/net/phy/qsemi.c
   4 *
   5 * Driver for Quality Semiconductor PHYs
   6 *
   7 * Author: Andy Fleming
   8 *
   9 * Copyright (c) 2004 Freescale Semiconductor, Inc.
  10 */
  11#include <linux/kernel.h>
  12#include <linux/string.h>
  13#include <linux/errno.h>
  14#include <linux/unistd.h>
  15#include <linux/interrupt.h>
  16#include <linux/init.h>
  17#include <linux/delay.h>
  18#include <linux/netdevice.h>
  19#include <linux/etherdevice.h>
  20#include <linux/skbuff.h>
  21#include <linux/spinlock.h>
  22#include <linux/mm.h>
  23#include <linux/module.h>
  24#include <linux/mii.h>
  25#include <linux/ethtool.h>
  26#include <linux/phy.h>
  27
  28#include <asm/io.h>
  29#include <asm/irq.h>
  30#include <linux/uaccess.h>
  31
  32/* ------------------------------------------------------------------------- */
  33/* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */
  34
  35/* register definitions */
  36
  37#define MII_QS6612_MCR          17  /* Mode Control Register      */
  38#define MII_QS6612_FTR          27  /* Factory Test Register      */
  39#define MII_QS6612_MCO          28  /* Misc. Control Register     */
  40#define MII_QS6612_ISR          29  /* Interrupt Source Register  */
  41#define MII_QS6612_IMR          30  /* Interrupt Mask Register    */
  42#define MII_QS6612_IMR_INIT     0x003a
  43#define MII_QS6612_PCR          31  /* 100BaseTx PHY Control Reg. */
  44
  45#define QS6612_PCR_AN_COMPLETE  0x1000
  46#define QS6612_PCR_RLBEN        0x0200
  47#define QS6612_PCR_DCREN        0x0100
  48#define QS6612_PCR_4B5BEN       0x0040
  49#define QS6612_PCR_TX_ISOLATE   0x0020
  50#define QS6612_PCR_MLT3_DIS     0x0002
  51#define QS6612_PCR_SCRM_DESCRM  0x0001
  52
  53MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
  54MODULE_AUTHOR("Andy Fleming");
  55MODULE_LICENSE("GPL");
  56
  57/* Returns 0, unless there's a write error */
  58static int qs6612_config_init(struct phy_device *phydev)
  59{
  60        /* The PHY powers up isolated on the RPX,
  61         * so send a command to allow operation.
  62         * XXX - My docs indicate this should be 0x0940
  63         * ...or something.  The current value sets three
  64         * reserved bits, bit 11, which specifies it should be
  65         * set to one, bit 10, which specifies it should be set
  66         * to 0, and bit 7, which doesn't specify.  However, my
  67         * docs are preliminary, and I will leave it like this
  68         * until someone more knowledgable corrects me or it.
  69         * -- Andy Fleming
  70         */
  71        return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
  72}
  73
  74static int qs6612_ack_interrupt(struct phy_device *phydev)
  75{
  76        int err;
  77
  78        /* The Interrupt Source register is not self-clearing, bits 4 and 5 are
  79         * cleared when MII_BMSR is read and bits 1 and 3 are cleared when
  80         * MII_EXPANSION is read
  81         */
  82        err = phy_read(phydev, MII_QS6612_ISR);
  83
  84        if (err < 0)
  85                return err;
  86
  87        err = phy_read(phydev, MII_BMSR);
  88
  89        if (err < 0)
  90                return err;
  91
  92        err = phy_read(phydev, MII_EXPANSION);
  93
  94        if (err < 0)
  95                return err;
  96
  97        return 0;
  98}
  99
 100static int qs6612_config_intr(struct phy_device *phydev)
 101{
 102        int err;
 103        if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 104                /* clear any interrupts before enabling them */
 105                err = qs6612_ack_interrupt(phydev);
 106                if (err)
 107                        return err;
 108
 109                err = phy_write(phydev, MII_QS6612_IMR,
 110                                MII_QS6612_IMR_INIT);
 111        } else {
 112                err = phy_write(phydev, MII_QS6612_IMR, 0);
 113                if (err)
 114                        return err;
 115
 116                /* clear any leftover interrupts */
 117                err = qs6612_ack_interrupt(phydev);
 118        }
 119
 120        return err;
 121
 122}
 123
 124static irqreturn_t qs6612_handle_interrupt(struct phy_device *phydev)
 125{
 126        int irq_status;
 127
 128        irq_status = phy_read(phydev, MII_QS6612_ISR);
 129        if (irq_status < 0) {
 130                phy_error(phydev);
 131                return IRQ_NONE;
 132        }
 133
 134        if (!(irq_status & MII_QS6612_IMR_INIT))
 135                return IRQ_NONE;
 136
 137        /* the interrupt source register is not self-clearing */
 138        qs6612_ack_interrupt(phydev);
 139
 140        phy_trigger_machine(phydev);
 141
 142        return IRQ_HANDLED;
 143}
 144
 145static struct phy_driver qs6612_driver[] = { {
 146        .phy_id         = 0x00181440,
 147        .name           = "QS6612",
 148        .phy_id_mask    = 0xfffffff0,
 149        /* PHY_BASIC_FEATURES */
 150        .config_init    = qs6612_config_init,
 151        .config_intr    = qs6612_config_intr,
 152        .handle_interrupt = qs6612_handle_interrupt,
 153} };
 154
 155module_phy_driver(qs6612_driver);
 156
 157static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
 158        { 0x00181440, 0xfffffff0 },
 159        { }
 160};
 161
 162MODULE_DEVICE_TABLE(mdio, qs6612_tbl);
 163