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 #define MII_DM9161_SCR 0x10
0033 #define MII_DM9161_SCR_INIT 0x0610
0034 #define MII_DM9161_SCR_RMII 0x0100
0035
0036
0037 #define MII_DM9161_INTR 0x15
0038 #define MII_DM9161_INTR_PEND 0x8000
0039 #define MII_DM9161_INTR_DPLX_MASK 0x0800
0040 #define MII_DM9161_INTR_SPD_MASK 0x0400
0041 #define MII_DM9161_INTR_LINK_MASK 0x0200
0042 #define MII_DM9161_INTR_MASK 0x0100
0043 #define MII_DM9161_INTR_DPLX_CHANGE 0x0010
0044 #define MII_DM9161_INTR_SPD_CHANGE 0x0008
0045 #define MII_DM9161_INTR_LINK_CHANGE 0x0004
0046 #define MII_DM9161_INTR_INIT 0x0000
0047 #define MII_DM9161_INTR_STOP \
0048 (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK | \
0049 MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
0050 #define MII_DM9161_INTR_CHANGE \
0051 (MII_DM9161_INTR_DPLX_CHANGE | \
0052 MII_DM9161_INTR_SPD_CHANGE | \
0053 MII_DM9161_INTR_LINK_CHANGE)
0054
0055
0056 #define MII_DM9161_10BTCSR 0x12
0057 #define MII_DM9161_10BTCSR_INIT 0x7800
0058
0059 MODULE_DESCRIPTION("Davicom PHY driver");
0060 MODULE_AUTHOR("Andy Fleming");
0061 MODULE_LICENSE("GPL");
0062
0063
0064 static int dm9161_ack_interrupt(struct phy_device *phydev)
0065 {
0066 int err = phy_read(phydev, MII_DM9161_INTR);
0067
0068 return (err < 0) ? err : 0;
0069 }
0070
0071 #define DM9161_DELAY 1
0072 static int dm9161_config_intr(struct phy_device *phydev)
0073 {
0074 int temp, err;
0075
0076 temp = phy_read(phydev, MII_DM9161_INTR);
0077
0078 if (temp < 0)
0079 return temp;
0080
0081 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0082 err = dm9161_ack_interrupt(phydev);
0083 if (err)
0084 return err;
0085
0086 temp &= ~(MII_DM9161_INTR_STOP);
0087 err = phy_write(phydev, MII_DM9161_INTR, temp);
0088 } else {
0089 temp |= MII_DM9161_INTR_STOP;
0090 err = phy_write(phydev, MII_DM9161_INTR, temp);
0091 if (err)
0092 return err;
0093
0094 err = dm9161_ack_interrupt(phydev);
0095 }
0096
0097 return err;
0098 }
0099
0100 static irqreturn_t dm9161_handle_interrupt(struct phy_device *phydev)
0101 {
0102 int irq_status;
0103
0104 irq_status = phy_read(phydev, MII_DM9161_INTR);
0105 if (irq_status < 0) {
0106 phy_error(phydev);
0107 return IRQ_NONE;
0108 }
0109
0110 if (!(irq_status & MII_DM9161_INTR_CHANGE))
0111 return IRQ_NONE;
0112
0113 phy_trigger_machine(phydev);
0114
0115 return IRQ_HANDLED;
0116 }
0117
0118 static int dm9161_config_aneg(struct phy_device *phydev)
0119 {
0120 int err;
0121
0122
0123 err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
0124
0125 if (err < 0)
0126 return err;
0127
0128
0129 err = genphy_config_aneg(phydev);
0130
0131 if (err < 0)
0132 return err;
0133
0134 return 0;
0135 }
0136
0137 static int dm9161_config_init(struct phy_device *phydev)
0138 {
0139 int err, temp;
0140
0141
0142 err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
0143
0144 if (err < 0)
0145 return err;
0146
0147 switch (phydev->interface) {
0148 case PHY_INTERFACE_MODE_MII:
0149 temp = MII_DM9161_SCR_INIT;
0150 break;
0151 case PHY_INTERFACE_MODE_RMII:
0152 temp = MII_DM9161_SCR_INIT | MII_DM9161_SCR_RMII;
0153 break;
0154 default:
0155 return -EINVAL;
0156 }
0157
0158
0159 err = phy_write(phydev, MII_DM9161_SCR, temp);
0160 if (err < 0)
0161 return err;
0162
0163
0164 err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT);
0165
0166 if (err < 0)
0167 return err;
0168
0169
0170 return phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
0171 }
0172
0173 static struct phy_driver dm91xx_driver[] = {
0174 {
0175 .phy_id = 0x0181b880,
0176 .name = "Davicom DM9161E",
0177 .phy_id_mask = 0x0ffffff0,
0178
0179 .config_init = dm9161_config_init,
0180 .config_aneg = dm9161_config_aneg,
0181 .config_intr = dm9161_config_intr,
0182 .handle_interrupt = dm9161_handle_interrupt,
0183 }, {
0184 .phy_id = 0x0181b8b0,
0185 .name = "Davicom DM9161B/C",
0186 .phy_id_mask = 0x0ffffff0,
0187
0188 .config_init = dm9161_config_init,
0189 .config_aneg = dm9161_config_aneg,
0190 .config_intr = dm9161_config_intr,
0191 .handle_interrupt = dm9161_handle_interrupt,
0192 }, {
0193 .phy_id = 0x0181b8a0,
0194 .name = "Davicom DM9161A",
0195 .phy_id_mask = 0x0ffffff0,
0196
0197 .config_init = dm9161_config_init,
0198 .config_aneg = dm9161_config_aneg,
0199 .config_intr = dm9161_config_intr,
0200 .handle_interrupt = dm9161_handle_interrupt,
0201 }, {
0202 .phy_id = 0x00181b80,
0203 .name = "Davicom DM9131",
0204 .phy_id_mask = 0x0ffffff0,
0205
0206 .config_intr = dm9161_config_intr,
0207 .handle_interrupt = dm9161_handle_interrupt,
0208 } };
0209
0210 module_phy_driver(dm91xx_driver);
0211
0212 static struct mdio_device_id __maybe_unused davicom_tbl[] = {
0213 { 0x0181b880, 0x0ffffff0 },
0214 { 0x0181b8b0, 0x0ffffff0 },
0215 { 0x0181b8a0, 0x0ffffff0 },
0216 { 0x00181b80, 0x0ffffff0 },
0217 { }
0218 };
0219
0220 MODULE_DEVICE_TABLE(mdio, davicom_tbl);