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