0001
0002
0003
0004
0005
0006
0007
0008
0009
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 <asm/io.h>
0029 #include <asm/irq.h>
0030 #include <linux/uaccess.h>
0031
0032
0033
0034
0035
0036
0037 #define MII_QS6612_MCR 17
0038 #define MII_QS6612_FTR 27
0039 #define MII_QS6612_MCO 28
0040 #define MII_QS6612_ISR 29
0041 #define MII_QS6612_IMR 30
0042 #define MII_QS6612_IMR_INIT 0x003a
0043 #define MII_QS6612_PCR 31
0044
0045 #define QS6612_PCR_AN_COMPLETE 0x1000
0046 #define QS6612_PCR_RLBEN 0x0200
0047 #define QS6612_PCR_DCREN 0x0100
0048 #define QS6612_PCR_4B5BEN 0x0040
0049 #define QS6612_PCR_TX_ISOLATE 0x0020
0050 #define QS6612_PCR_MLT3_DIS 0x0002
0051 #define QS6612_PCR_SCRM_DESCRM 0x0001
0052
0053 MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
0054 MODULE_AUTHOR("Andy Fleming");
0055 MODULE_LICENSE("GPL");
0056
0057
0058 static int qs6612_config_init(struct phy_device *phydev)
0059 {
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
0072 }
0073
0074 static int qs6612_ack_interrupt(struct phy_device *phydev)
0075 {
0076 int err;
0077
0078
0079
0080
0081
0082 err = phy_read(phydev, MII_QS6612_ISR);
0083
0084 if (err < 0)
0085 return err;
0086
0087 err = phy_read(phydev, MII_BMSR);
0088
0089 if (err < 0)
0090 return err;
0091
0092 err = phy_read(phydev, MII_EXPANSION);
0093
0094 if (err < 0)
0095 return err;
0096
0097 return 0;
0098 }
0099
0100 static int qs6612_config_intr(struct phy_device *phydev)
0101 {
0102 int err;
0103
0104 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0105
0106 err = qs6612_ack_interrupt(phydev);
0107 if (err)
0108 return err;
0109
0110 err = phy_write(phydev, MII_QS6612_IMR,
0111 MII_QS6612_IMR_INIT);
0112 } else {
0113 err = phy_write(phydev, MII_QS6612_IMR, 0);
0114 if (err)
0115 return err;
0116
0117
0118 err = qs6612_ack_interrupt(phydev);
0119 }
0120
0121 return err;
0122
0123 }
0124
0125 static irqreturn_t qs6612_handle_interrupt(struct phy_device *phydev)
0126 {
0127 int irq_status;
0128
0129 irq_status = phy_read(phydev, MII_QS6612_ISR);
0130 if (irq_status < 0) {
0131 phy_error(phydev);
0132 return IRQ_NONE;
0133 }
0134
0135 if (!(irq_status & MII_QS6612_IMR_INIT))
0136 return IRQ_NONE;
0137
0138
0139 qs6612_ack_interrupt(phydev);
0140
0141 phy_trigger_machine(phydev);
0142
0143 return IRQ_HANDLED;
0144 }
0145
0146 static struct phy_driver qs6612_driver[] = { {
0147 .phy_id = 0x00181440,
0148 .name = "QS6612",
0149 .phy_id_mask = 0xfffffff0,
0150
0151 .config_init = qs6612_config_init,
0152 .config_intr = qs6612_config_intr,
0153 .handle_interrupt = qs6612_handle_interrupt,
0154 } };
0155
0156 module_phy_driver(qs6612_driver);
0157
0158 static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
0159 { 0x00181440, 0xfffffff0 },
0160 { }
0161 };
0162
0163 MODULE_DEVICE_TABLE(mdio, qs6612_tbl);