1 /* 2 * Driver for ICPlus PHYs 3 * 4 * Copyright (c) 2007 Freescale Semiconductor, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 * 11 */ 12 #include <linux/kernel.h> 13 #include <linux/string.h> 14 #include <linux/errno.h> 15 #include <linux/unistd.h> 16 #include <linux/interrupt.h> 17 #include <linux/init.h> 18 #include <linux/delay.h> 19 #include <linux/netdevice.h> 20 #include <linux/etherdevice.h> 21 #include <linux/skbuff.h> 22 #include <linux/spinlock.h> 23 #include <linux/mm.h> 24 #include <linux/module.h> 25 #include <linux/mii.h> 26 #include <linux/ethtool.h> 27 #include <linux/phy.h> 28 29 #include <asm/io.h> 30 #include <asm/irq.h> 31 #include <linux/uaccess.h> 32 33 MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers"); 34 MODULE_AUTHOR("Michael Barkowski"); 35 MODULE_LICENSE("GPL"); 36 37 /* IP101A/G - IP1001 */ 38 #define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ 39 #define IP1001_RXPHASE_SEL (1<<0) /* Add delay on RX_CLK */ 40 #define IP1001_TXPHASE_SEL (1<<1) /* Add delay on TX_CLK */ 41 #define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ 42 #define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ 43 #define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */ 44 #define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ 45 #define IP101A_G_IRQ_PIN_USED (1<<15) /* INTR pin used */ 46 #define IP101A_G_IRQ_DEFAULT IP101A_G_IRQ_PIN_USED 47 48 static int ip175c_config_init(struct phy_device *phydev) 49 { 50 int err, i; 51 static int full_reset_performed; 52 53 if (full_reset_performed == 0) { 54 55 /* master reset */ 56 err = mdiobus_write(phydev->mdio.bus, 30, 0, 0x175c); 57 if (err < 0) 58 return err; 59 60 /* ensure no bus delays overlap reset period */ 61 err = mdiobus_read(phydev->mdio.bus, 30, 0); 62 63 /* data sheet specifies reset period is 2 msec */ 64 mdelay(2); 65 66 /* enable IP175C mode */ 67 err = mdiobus_write(phydev->mdio.bus, 29, 31, 0x175c); 68 if (err < 0) 69 return err; 70 71 /* Set MII0 speed and duplex (in PHY mode) */ 72 err = mdiobus_write(phydev->mdio.bus, 29, 22, 0x420); 73 if (err < 0) 74 return err; 75 76 /* reset switch ports */ 77 for (i = 0; i < 5; i++) { 78 err = mdiobus_write(phydev->mdio.bus, i, 79 MII_BMCR, BMCR_RESET); 80 if (err < 0) 81 return err; 82 } 83 84 for (i = 0; i < 5; i++) 85 err = mdiobus_read(phydev->mdio.bus, i, MII_BMCR); 86 87 mdelay(2); 88 89 full_reset_performed = 1; 90 } 91 92 if (phydev->mdio.addr != 4) { 93 phydev->state = PHY_RUNNING; 94 phydev->speed = SPEED_100; 95 phydev->duplex = DUPLEX_FULL; 96 phydev->link = 1; 97 netif_carrier_on(phydev->attached_dev); 98 } 99 100 return 0; 101 } 102 103 static int ip1xx_reset(struct phy_device *phydev) 104 { 105 int bmcr; 106 107 /* Software Reset PHY */ 108 bmcr = phy_read(phydev, MII_BMCR); 109 if (bmcr < 0) 110 return bmcr; 111 bmcr |= BMCR_RESET; 112 bmcr = phy_write(phydev, MII_BMCR, bmcr); 113 if (bmcr < 0) 114 return bmcr; 115 116 do { 117 bmcr = phy_read(phydev, MII_BMCR); 118 if (bmcr < 0) 119 return bmcr; 120 } while (bmcr & BMCR_RESET); 121 122 return 0; 123 } 124 125 static int ip1001_config_init(struct phy_device *phydev) 126 { 127 int c; 128 129 c = ip1xx_reset(phydev); 130 if (c < 0) 131 return c; 132 133 /* Enable Auto Power Saving mode */ 134 c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2); 135 if (c < 0) 136 return c; 137 c |= IP1001_APS_ON; 138 c = phy_write(phydev, IP1001_SPEC_CTRL_STATUS_2, c); 139 if (c < 0) 140 return c; 141 142 if (phy_interface_is_rgmii(phydev)) { 143 144 c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); 145 if (c < 0) 146 return c; 147 148 c &= ~(IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); 149 150 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 151 c |= (IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); 152 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 153 c |= IP1001_RXPHASE_SEL; 154 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 155 c |= IP1001_TXPHASE_SEL; 156 157 c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); 158 if (c < 0) 159 return c; 160 } 161 162 return 0; 163 } 164 165 static int ip101a_g_config_init(struct phy_device *phydev) 166 { 167 int c; 168 169 c = ip1xx_reset(phydev); 170 if (c < 0) 171 return c; 172 173 /* INTR pin used: speed/link/duplex will cause an interrupt */ 174 c = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, IP101A_G_IRQ_DEFAULT); 175 if (c < 0) 176 return c; 177 178 /* Enable Auto Power Saving mode */ 179 c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); 180 c |= IP101A_G_APS_ON; 181 182 return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); 183 } 184 185 static int ip175c_read_status(struct phy_device *phydev) 186 { 187 if (phydev->mdio.addr == 4) /* WAN port */ 188 genphy_read_status(phydev); 189 else 190 /* Don't need to read status for switch ports */ 191 phydev->irq = PHY_IGNORE_INTERRUPT; 192 193 return 0; 194 } 195 196 static int ip175c_config_aneg(struct phy_device *phydev) 197 { 198 if (phydev->mdio.addr == 4) /* WAN port */ 199 genphy_config_aneg(phydev); 200 201 return 0; 202 } 203 204 static int ip101a_g_ack_interrupt(struct phy_device *phydev) 205 { 206 int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); 207 if (err < 0) 208 return err; 209 210 return 0; 211 } 212 213 static struct phy_driver icplus_driver[] = { 214 { 215 .phy_id = 0x02430d80, 216 .name = "ICPlus IP175C", 217 .phy_id_mask = 0x0ffffff0, 218 .features = PHY_BASIC_FEATURES, 219 .config_init = &ip175c_config_init, 220 .config_aneg = &ip175c_config_aneg, 221 .read_status = &ip175c_read_status, 222 .suspend = genphy_suspend, 223 .resume = genphy_resume, 224 }, { 225 .phy_id = 0x02430d90, 226 .name = "ICPlus IP1001", 227 .phy_id_mask = 0x0ffffff0, 228 .features = PHY_GBIT_FEATURES, 229 .config_init = &ip1001_config_init, 230 .suspend = genphy_suspend, 231 .resume = genphy_resume, 232 }, { 233 .phy_id = 0x02430c54, 234 .name = "ICPlus IP101A/G", 235 .phy_id_mask = 0x0ffffff0, 236 .features = PHY_BASIC_FEATURES, 237 .flags = PHY_HAS_INTERRUPT, 238 .ack_interrupt = ip101a_g_ack_interrupt, 239 .config_init = &ip101a_g_config_init, 240 .suspend = genphy_suspend, 241 .resume = genphy_resume, 242 } }; 243 244 module_phy_driver(icplus_driver); 245 246 static struct mdio_device_id __maybe_unused icplus_tbl[] = { 247 { 0x02430d80, 0x0ffffff0 }, 248 { 0x02430d90, 0x0ffffff0 }, 249 { 0x02430c54, 0x0ffffff0 }, 250 { } 251 }; 252 253 MODULE_DEVICE_TABLE(mdio, icplus_tbl); 254