at v4.13-rc2 257 lines 6.2 kB view raw
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 33MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers"); 34MODULE_AUTHOR("Michael Barkowski"); 35MODULE_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 48static 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 103static 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 125static 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 165static 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 185static 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 196static 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 204static 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 213static 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 .config_aneg = &genphy_config_aneg, 231 .read_status = &genphy_read_status, 232 .suspend = genphy_suspend, 233 .resume = genphy_resume, 234}, { 235 .phy_id = 0x02430c54, 236 .name = "ICPlus IP101A/G", 237 .phy_id_mask = 0x0ffffff0, 238 .features = PHY_BASIC_FEATURES, 239 .flags = PHY_HAS_INTERRUPT, 240 .ack_interrupt = ip101a_g_ack_interrupt, 241 .config_init = &ip101a_g_config_init, 242 .config_aneg = &genphy_config_aneg, 243 .read_status = &genphy_read_status, 244 .suspend = genphy_suspend, 245 .resume = genphy_resume, 246} }; 247 248module_phy_driver(icplus_driver); 249 250static struct mdio_device_id __maybe_unused icplus_tbl[] = { 251 { 0x02430d80, 0x0ffffff0 }, 252 { 0x02430d90, 0x0ffffff0 }, 253 { 0x02430c54, 0x0ffffff0 }, 254 { } 255}; 256 257MODULE_DEVICE_TABLE(mdio, icplus_tbl);