Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.10-rc4 360 lines 10 kB view raw
1/* 2 * drivers/net/phy/micrel.c 3 * 4 * Driver for Micrel PHYs 5 * 6 * Author: David J. Choi 7 * 8 * Copyright (c) 2010-2013 Micrel, Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 * Support : Micrel Phys: 16 * Giga phys: ksz9021, ksz9031 17 * 100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041 18 * ksz8021, ksz8031, ksz8051, 19 * ksz8081, ksz8091, 20 * ksz8061, 21 * Switch : ksz8873, ksz886x 22 */ 23 24#include <linux/kernel.h> 25#include <linux/module.h> 26#include <linux/phy.h> 27#include <linux/micrel_phy.h> 28 29/* Operation Mode Strap Override */ 30#define MII_KSZPHY_OMSO 0x16 31#define KSZPHY_OMSO_B_CAST_OFF (1 << 9) 32#define KSZPHY_OMSO_RMII_OVERRIDE (1 << 1) 33#define KSZPHY_OMSO_MII_OVERRIDE (1 << 0) 34 35/* general Interrupt control/status reg in vendor specific block. */ 36#define MII_KSZPHY_INTCS 0x1B 37#define KSZPHY_INTCS_JABBER (1 << 15) 38#define KSZPHY_INTCS_RECEIVE_ERR (1 << 14) 39#define KSZPHY_INTCS_PAGE_RECEIVE (1 << 13) 40#define KSZPHY_INTCS_PARELLEL (1 << 12) 41#define KSZPHY_INTCS_LINK_PARTNER_ACK (1 << 11) 42#define KSZPHY_INTCS_LINK_DOWN (1 << 10) 43#define KSZPHY_INTCS_REMOTE_FAULT (1 << 9) 44#define KSZPHY_INTCS_LINK_UP (1 << 8) 45#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\ 46 KSZPHY_INTCS_LINK_DOWN) 47 48/* general PHY control reg in vendor specific block. */ 49#define MII_KSZPHY_CTRL 0x1F 50/* bitmap of PHY register to set interrupt mode */ 51#define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9) 52#define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14) 53#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14) 54#define KSZ8051_RMII_50MHZ_CLK (1 << 7) 55 56static int ksz_config_flags(struct phy_device *phydev) 57{ 58 int regval; 59 60 if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) { 61 regval = phy_read(phydev, MII_KSZPHY_CTRL); 62 regval |= KSZ8051_RMII_50MHZ_CLK; 63 return phy_write(phydev, MII_KSZPHY_CTRL, regval); 64 } 65 return 0; 66} 67 68static int kszphy_ack_interrupt(struct phy_device *phydev) 69{ 70 /* bit[7..0] int status, which is a read and clear register. */ 71 int rc; 72 73 rc = phy_read(phydev, MII_KSZPHY_INTCS); 74 75 return (rc < 0) ? rc : 0; 76} 77 78static int kszphy_set_interrupt(struct phy_device *phydev) 79{ 80 int temp; 81 temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ? 82 KSZPHY_INTCS_ALL : 0; 83 return phy_write(phydev, MII_KSZPHY_INTCS, temp); 84} 85 86static int kszphy_config_intr(struct phy_device *phydev) 87{ 88 int temp, rc; 89 90 /* set the interrupt pin active low */ 91 temp = phy_read(phydev, MII_KSZPHY_CTRL); 92 temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; 93 phy_write(phydev, MII_KSZPHY_CTRL, temp); 94 rc = kszphy_set_interrupt(phydev); 95 return rc < 0 ? rc : 0; 96} 97 98static int ksz9021_config_intr(struct phy_device *phydev) 99{ 100 int temp, rc; 101 102 /* set the interrupt pin active low */ 103 temp = phy_read(phydev, MII_KSZPHY_CTRL); 104 temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH; 105 phy_write(phydev, MII_KSZPHY_CTRL, temp); 106 rc = kszphy_set_interrupt(phydev); 107 return rc < 0 ? rc : 0; 108} 109 110static int ks8737_config_intr(struct phy_device *phydev) 111{ 112 int temp, rc; 113 114 /* set the interrupt pin active low */ 115 temp = phy_read(phydev, MII_KSZPHY_CTRL); 116 temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH; 117 phy_write(phydev, MII_KSZPHY_CTRL, temp); 118 rc = kszphy_set_interrupt(phydev); 119 return rc < 0 ? rc : 0; 120} 121 122static int kszphy_config_init(struct phy_device *phydev) 123{ 124 return 0; 125} 126 127static int ksz8021_config_init(struct phy_device *phydev) 128{ 129 int rc; 130 const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE; 131 phy_write(phydev, MII_KSZPHY_OMSO, val); 132 rc = ksz_config_flags(phydev); 133 return rc < 0 ? rc : 0; 134} 135 136static int ks8051_config_init(struct phy_device *phydev) 137{ 138 int rc; 139 140 rc = ksz_config_flags(phydev); 141 return rc < 0 ? rc : 0; 142} 143 144#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06 145#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6) 146#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4) 147int ksz8873mll_read_status(struct phy_device *phydev) 148{ 149 int regval; 150 151 /* dummy read */ 152 regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4); 153 154 regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4); 155 156 if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX) 157 phydev->duplex = DUPLEX_HALF; 158 else 159 phydev->duplex = DUPLEX_FULL; 160 161 if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_SPEED) 162 phydev->speed = SPEED_10; 163 else 164 phydev->speed = SPEED_100; 165 166 phydev->link = 1; 167 phydev->pause = phydev->asym_pause = 0; 168 169 return 0; 170} 171 172static int ksz8873mll_config_aneg(struct phy_device *phydev) 173{ 174 return 0; 175} 176 177static struct phy_driver ksphy_driver[] = { 178{ 179 .phy_id = PHY_ID_KS8737, 180 .phy_id_mask = 0x00fffff0, 181 .name = "Micrel KS8737", 182 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), 183 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 184 .config_init = kszphy_config_init, 185 .config_aneg = genphy_config_aneg, 186 .read_status = genphy_read_status, 187 .ack_interrupt = kszphy_ack_interrupt, 188 .config_intr = ks8737_config_intr, 189 .driver = { .owner = THIS_MODULE,}, 190}, { 191 .phy_id = PHY_ID_KSZ8021, 192 .phy_id_mask = 0x00ffffff, 193 .name = "Micrel KSZ8021 or KSZ8031", 194 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | 195 SUPPORTED_Asym_Pause), 196 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 197 .config_init = ksz8021_config_init, 198 .config_aneg = genphy_config_aneg, 199 .read_status = genphy_read_status, 200 .ack_interrupt = kszphy_ack_interrupt, 201 .config_intr = kszphy_config_intr, 202 .driver = { .owner = THIS_MODULE,}, 203}, { 204 .phy_id = PHY_ID_KSZ8031, 205 .phy_id_mask = 0x00ffffff, 206 .name = "Micrel KSZ8031", 207 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | 208 SUPPORTED_Asym_Pause), 209 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 210 .config_init = ksz8021_config_init, 211 .config_aneg = genphy_config_aneg, 212 .read_status = genphy_read_status, 213 .ack_interrupt = kszphy_ack_interrupt, 214 .config_intr = kszphy_config_intr, 215 .driver = { .owner = THIS_MODULE,}, 216}, { 217 .phy_id = PHY_ID_KSZ8041, 218 .phy_id_mask = 0x00fffff0, 219 .name = "Micrel KSZ8041", 220 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause 221 | SUPPORTED_Asym_Pause), 222 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 223 .config_init = kszphy_config_init, 224 .config_aneg = genphy_config_aneg, 225 .read_status = genphy_read_status, 226 .ack_interrupt = kszphy_ack_interrupt, 227 .config_intr = kszphy_config_intr, 228 .driver = { .owner = THIS_MODULE,}, 229}, { 230 .phy_id = PHY_ID_KSZ8051, 231 .phy_id_mask = 0x00fffff0, 232 .name = "Micrel KSZ8051", 233 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause 234 | SUPPORTED_Asym_Pause), 235 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 236 .config_init = ks8051_config_init, 237 .config_aneg = genphy_config_aneg, 238 .read_status = genphy_read_status, 239 .ack_interrupt = kszphy_ack_interrupt, 240 .config_intr = kszphy_config_intr, 241 .driver = { .owner = THIS_MODULE,}, 242}, { 243 .phy_id = PHY_ID_KSZ8001, 244 .name = "Micrel KSZ8001 or KS8721", 245 .phy_id_mask = 0x00ffffff, 246 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), 247 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 248 .config_init = kszphy_config_init, 249 .config_aneg = genphy_config_aneg, 250 .read_status = genphy_read_status, 251 .ack_interrupt = kszphy_ack_interrupt, 252 .config_intr = kszphy_config_intr, 253 .driver = { .owner = THIS_MODULE,}, 254}, { 255 .phy_id = PHY_ID_KSZ8081, 256 .name = "Micrel KSZ8081 or KSZ8091", 257 .phy_id_mask = 0x00fffff0, 258 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), 259 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 260 .config_init = kszphy_config_init, 261 .config_aneg = genphy_config_aneg, 262 .read_status = genphy_read_status, 263 .ack_interrupt = kszphy_ack_interrupt, 264 .config_intr = kszphy_config_intr, 265 .driver = { .owner = THIS_MODULE,}, 266}, { 267 .phy_id = PHY_ID_KSZ8061, 268 .name = "Micrel KSZ8061", 269 .phy_id_mask = 0x00fffff0, 270 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), 271 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 272 .config_init = kszphy_config_init, 273 .config_aneg = genphy_config_aneg, 274 .read_status = genphy_read_status, 275 .ack_interrupt = kszphy_ack_interrupt, 276 .config_intr = kszphy_config_intr, 277 .driver = { .owner = THIS_MODULE,}, 278}, { 279 .phy_id = PHY_ID_KSZ9021, 280 .phy_id_mask = 0x000ffffe, 281 .name = "Micrel KSZ9021 Gigabit PHY", 282 .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause), 283 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 284 .config_init = kszphy_config_init, 285 .config_aneg = genphy_config_aneg, 286 .read_status = genphy_read_status, 287 .ack_interrupt = kszphy_ack_interrupt, 288 .config_intr = ksz9021_config_intr, 289 .driver = { .owner = THIS_MODULE, }, 290}, { 291 .phy_id = PHY_ID_KSZ9031, 292 .phy_id_mask = 0x00fffff0, 293 .name = "Micrel KSZ9031 Gigabit PHY", 294 .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause 295 | SUPPORTED_Asym_Pause), 296 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 297 .config_init = kszphy_config_init, 298 .config_aneg = genphy_config_aneg, 299 .read_status = genphy_read_status, 300 .ack_interrupt = kszphy_ack_interrupt, 301 .config_intr = ksz9021_config_intr, 302 .driver = { .owner = THIS_MODULE, }, 303}, { 304 .phy_id = PHY_ID_KSZ8873MLL, 305 .phy_id_mask = 0x00fffff0, 306 .name = "Micrel KSZ8873MLL Switch", 307 .features = (SUPPORTED_Pause | SUPPORTED_Asym_Pause), 308 .flags = PHY_HAS_MAGICANEG, 309 .config_init = kszphy_config_init, 310 .config_aneg = ksz8873mll_config_aneg, 311 .read_status = ksz8873mll_read_status, 312 .driver = { .owner = THIS_MODULE, }, 313}, { 314 .phy_id = PHY_ID_KSZ886X, 315 .phy_id_mask = 0x00fffff0, 316 .name = "Micrel KSZ886X Switch", 317 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), 318 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 319 .config_init = kszphy_config_init, 320 .config_aneg = genphy_config_aneg, 321 .read_status = genphy_read_status, 322 .driver = { .owner = THIS_MODULE, }, 323} }; 324 325static int __init ksphy_init(void) 326{ 327 return phy_drivers_register(ksphy_driver, 328 ARRAY_SIZE(ksphy_driver)); 329} 330 331static void __exit ksphy_exit(void) 332{ 333 phy_drivers_unregister(ksphy_driver, 334 ARRAY_SIZE(ksphy_driver)); 335} 336 337module_init(ksphy_init); 338module_exit(ksphy_exit); 339 340MODULE_DESCRIPTION("Micrel PHY driver"); 341MODULE_AUTHOR("David J. Choi"); 342MODULE_LICENSE("GPL"); 343 344static struct mdio_device_id __maybe_unused micrel_tbl[] = { 345 { PHY_ID_KSZ9021, 0x000ffffe }, 346 { PHY_ID_KSZ9031, 0x00fffff0 }, 347 { PHY_ID_KSZ8001, 0x00ffffff }, 348 { PHY_ID_KS8737, 0x00fffff0 }, 349 { PHY_ID_KSZ8021, 0x00ffffff }, 350 { PHY_ID_KSZ8031, 0x00ffffff }, 351 { PHY_ID_KSZ8041, 0x00fffff0 }, 352 { PHY_ID_KSZ8051, 0x00fffff0 }, 353 { PHY_ID_KSZ8061, 0x00fffff0 }, 354 { PHY_ID_KSZ8081, 0x00fffff0 }, 355 { PHY_ID_KSZ8873MLL, 0x00fffff0 }, 356 { PHY_ID_KSZ886X, 0x00fffff0 }, 357 { } 358}; 359 360MODULE_DEVICE_TABLE(mdio, micrel_tbl);