Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * drivers/net/phy/cicada.c
0004  *
0005  * Driver for Cicada PHYs
0006  *
0007  * Author: Andy Fleming
0008  *
0009  * Copyright (c) 2004 Freescale Semiconductor, Inc.
0010  */
0011 #include <linux/kernel.h>
0012 #include <linux/string.h>
0013 #include <linux/errno.h>
0014 #include <linux/unistd.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/init.h>
0017 #include <linux/delay.h>
0018 #include <linux/netdevice.h>
0019 #include <linux/etherdevice.h>
0020 #include <linux/skbuff.h>
0021 #include <linux/spinlock.h>
0022 #include <linux/mm.h>
0023 #include <linux/module.h>
0024 #include <linux/mii.h>
0025 #include <linux/ethtool.h>
0026 #include <linux/phy.h>
0027 
0028 #include <linux/io.h>
0029 #include <asm/irq.h>
0030 #include <linux/uaccess.h>
0031 
0032 /* Cicada Extended Control Register 1 */
0033 #define MII_CIS8201_EXT_CON1           0x17
0034 #define MII_CIS8201_EXTCON1_INIT       0x0000
0035 
0036 /* Cicada Interrupt Mask Register */
0037 #define MII_CIS8201_IMASK       0x19
0038 #define MII_CIS8201_IMASK_IEN       0x8000
0039 #define MII_CIS8201_IMASK_SPEED 0x4000
0040 #define MII_CIS8201_IMASK_LINK      0x2000
0041 #define MII_CIS8201_IMASK_DUPLEX    0x1000
0042 #define MII_CIS8201_IMASK_MASK      0xf000
0043 
0044 /* Cicada Interrupt Status Register */
0045 #define MII_CIS8201_ISTAT       0x1a
0046 #define MII_CIS8201_ISTAT_STATUS    0x8000
0047 #define MII_CIS8201_ISTAT_SPEED 0x4000
0048 #define MII_CIS8201_ISTAT_LINK      0x2000
0049 #define MII_CIS8201_ISTAT_DUPLEX    0x1000
0050 
0051 /* Cicada Auxiliary Control/Status Register */
0052 #define MII_CIS8201_AUX_CONSTAT        0x1c
0053 #define MII_CIS8201_AUXCONSTAT_INIT    0x0004
0054 #define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020
0055 #define MII_CIS8201_AUXCONSTAT_SPEED   0x0018
0056 #define MII_CIS8201_AUXCONSTAT_GBIT    0x0010
0057 #define MII_CIS8201_AUXCONSTAT_100     0x0008
0058 
0059 MODULE_DESCRIPTION("Cicadia PHY driver");
0060 MODULE_AUTHOR("Andy Fleming");
0061 MODULE_LICENSE("GPL");
0062 
0063 static int cis820x_config_init(struct phy_device *phydev)
0064 {
0065     int err;
0066 
0067     err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT,
0068             MII_CIS8201_AUXCONSTAT_INIT);
0069 
0070     if (err < 0)
0071         return err;
0072 
0073     err = phy_write(phydev, MII_CIS8201_EXT_CON1,
0074             MII_CIS8201_EXTCON1_INIT);
0075 
0076     return err;
0077 }
0078 
0079 static int cis820x_ack_interrupt(struct phy_device *phydev)
0080 {
0081     int err = phy_read(phydev, MII_CIS8201_ISTAT);
0082 
0083     return (err < 0) ? err : 0;
0084 }
0085 
0086 static int cis820x_config_intr(struct phy_device *phydev)
0087 {
0088     int err;
0089 
0090     if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0091         err = cis820x_ack_interrupt(phydev);
0092         if (err)
0093             return err;
0094 
0095         err = phy_write(phydev, MII_CIS8201_IMASK,
0096                 MII_CIS8201_IMASK_MASK);
0097     } else {
0098         err = phy_write(phydev, MII_CIS8201_IMASK, 0);
0099         if (err)
0100             return err;
0101 
0102         err = cis820x_ack_interrupt(phydev);
0103     }
0104 
0105     return err;
0106 }
0107 
0108 static irqreturn_t cis820x_handle_interrupt(struct phy_device *phydev)
0109 {
0110     int irq_status;
0111 
0112     irq_status = phy_read(phydev, MII_CIS8201_ISTAT);
0113     if (irq_status < 0) {
0114         phy_error(phydev);
0115         return IRQ_NONE;
0116     }
0117 
0118     if (!(irq_status & MII_CIS8201_IMASK_MASK))
0119         return IRQ_NONE;
0120 
0121     phy_trigger_machine(phydev);
0122 
0123     return IRQ_HANDLED;
0124 }
0125 
0126 /* Cicada 8201, a.k.a Vitesse VSC8201 */
0127 static struct phy_driver cis820x_driver[] = {
0128 {
0129     .phy_id     = 0x000fc410,
0130     .name       = "Cicada Cis8201",
0131     .phy_id_mask    = 0x000ffff0,
0132     /* PHY_GBIT_FEATURES */
0133     .config_init    = &cis820x_config_init,
0134     .config_intr    = &cis820x_config_intr,
0135     .handle_interrupt = &cis820x_handle_interrupt,
0136 }, {
0137     .phy_id     = 0x000fc440,
0138     .name       = "Cicada Cis8204",
0139     .phy_id_mask    = 0x000fffc0,
0140     /* PHY_GBIT_FEATURES */
0141     .config_init    = &cis820x_config_init,
0142     .config_intr    = &cis820x_config_intr,
0143     .handle_interrupt = &cis820x_handle_interrupt,
0144 } };
0145 
0146 module_phy_driver(cis820x_driver);
0147 
0148 static struct mdio_device_id __maybe_unused cicada_tbl[] = {
0149     { 0x000fc410, 0x000ffff0 },
0150     { 0x000fc440, 0x000fffc0 },
0151     { }
0152 };
0153 
0154 MODULE_DEVICE_TABLE(mdio, cicada_tbl);