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

MIPS: BCM63XX: Add integrated ethernet PHY support for phylib.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

drivers/net/phy/Kconfig | 6 ++
drivers/net/phy/Makefile | 1
drivers/net/phy/bcm63xx.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 139 insertions(+)
create mode 100644 drivers/net/phy/bcm63xx.c
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Maxime Bizon and committed by
David S. Miller
09bb9aa0 460deefa

+139
+6
drivers/net/phy/Kconfig
··· 56 56 Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481 57 57 and BCM5482 PHYs. 58 58 59 + config BCM63XX_PHY 60 + tristate "Drivers for Broadcom 63xx SOCs internal PHY" 61 + depends on BCM63XX 62 + ---help--- 63 + Currently supports the 6348 and 6358 PHYs. 64 + 59 65 config ICPLUS_PHY 60 66 tristate "Drivers for ICPlus PHYs" 61 67 ---help---
+1
drivers/net/phy/Makefile
··· 11 11 obj-$(CONFIG_SMSC_PHY) += smsc.o 12 12 obj-$(CONFIG_VITESSE_PHY) += vitesse.o 13 13 obj-$(CONFIG_BROADCOM_PHY) += broadcom.o 14 + obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o 14 15 obj-$(CONFIG_ICPLUS_PHY) += icplus.o 15 16 obj-$(CONFIG_REALTEK_PHY) += realtek.o 16 17 obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
+132
drivers/net/phy/bcm63xx.c
··· 1 + /* 2 + * Driver for Broadcom 63xx SOCs integrated PHYs 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 7 + * 2 of the License, or (at your option) any later version. 8 + */ 9 + #include <linux/module.h> 10 + #include <linux/phy.h> 11 + 12 + #define MII_BCM63XX_IR 0x1a /* interrupt register */ 13 + #define MII_BCM63XX_IR_EN 0x4000 /* global interrupt enable */ 14 + #define MII_BCM63XX_IR_DUPLEX 0x0800 /* duplex changed */ 15 + #define MII_BCM63XX_IR_SPEED 0x0400 /* speed changed */ 16 + #define MII_BCM63XX_IR_LINK 0x0200 /* link changed */ 17 + #define MII_BCM63XX_IR_GMASK 0x0100 /* global interrupt mask */ 18 + 19 + MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver"); 20 + MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>"); 21 + MODULE_LICENSE("GPL"); 22 + 23 + static int bcm63xx_config_init(struct phy_device *phydev) 24 + { 25 + int reg, err; 26 + 27 + reg = phy_read(phydev, MII_BCM63XX_IR); 28 + if (reg < 0) 29 + return reg; 30 + 31 + /* Mask interrupts globally. */ 32 + reg |= MII_BCM63XX_IR_GMASK; 33 + err = phy_write(phydev, MII_BCM63XX_IR, reg); 34 + if (err < 0) 35 + return err; 36 + 37 + /* Unmask events we are interested in */ 38 + reg = ~(MII_BCM63XX_IR_DUPLEX | 39 + MII_BCM63XX_IR_SPEED | 40 + MII_BCM63XX_IR_LINK) | 41 + MII_BCM63XX_IR_EN; 42 + err = phy_write(phydev, MII_BCM63XX_IR, reg); 43 + if (err < 0) 44 + return err; 45 + return 0; 46 + } 47 + 48 + static int bcm63xx_ack_interrupt(struct phy_device *phydev) 49 + { 50 + int reg; 51 + 52 + /* Clear pending interrupts. */ 53 + reg = phy_read(phydev, MII_BCM63XX_IR); 54 + if (reg < 0) 55 + return reg; 56 + 57 + return 0; 58 + } 59 + 60 + static int bcm63xx_config_intr(struct phy_device *phydev) 61 + { 62 + int reg, err; 63 + 64 + reg = phy_read(phydev, MII_BCM63XX_IR); 65 + if (reg < 0) 66 + return reg; 67 + 68 + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 69 + reg &= ~MII_BCM63XX_IR_GMASK; 70 + else 71 + reg |= MII_BCM63XX_IR_GMASK; 72 + 73 + err = phy_write(phydev, MII_BCM63XX_IR, reg); 74 + return err; 75 + } 76 + 77 + static struct phy_driver bcm63xx_1_driver = { 78 + .phy_id = 0x00406000, 79 + .phy_id_mask = 0xfffffc00, 80 + .name = "Broadcom BCM63XX (1)", 81 + /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */ 82 + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), 83 + .flags = PHY_HAS_INTERRUPT, 84 + .config_init = bcm63xx_config_init, 85 + .config_aneg = genphy_config_aneg, 86 + .read_status = genphy_read_status, 87 + .ack_interrupt = bcm63xx_ack_interrupt, 88 + .config_intr = bcm63xx_config_intr, 89 + .driver = { .owner = THIS_MODULE }, 90 + }; 91 + 92 + /* same phy as above, with just a different OUI */ 93 + static struct phy_driver bcm63xx_2_driver = { 94 + .phy_id = 0x002bdc00, 95 + .phy_id_mask = 0xfffffc00, 96 + .name = "Broadcom BCM63XX (2)", 97 + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), 98 + .flags = PHY_HAS_INTERRUPT, 99 + .config_init = bcm63xx_config_init, 100 + .config_aneg = genphy_config_aneg, 101 + .read_status = genphy_read_status, 102 + .ack_interrupt = bcm63xx_ack_interrupt, 103 + .config_intr = bcm63xx_config_intr, 104 + .driver = { .owner = THIS_MODULE }, 105 + }; 106 + 107 + static int __init bcm63xx_phy_init(void) 108 + { 109 + int ret; 110 + 111 + ret = phy_driver_register(&bcm63xx_1_driver); 112 + if (ret) 113 + goto out_63xx_1; 114 + ret = phy_driver_register(&bcm63xx_2_driver); 115 + if (ret) 116 + goto out_63xx_2; 117 + return ret; 118 + 119 + out_63xx_2: 120 + phy_driver_unregister(&bcm63xx_1_driver); 121 + out_63xx_1: 122 + return ret; 123 + } 124 + 125 + static void __exit bcm63xx_phy_exit(void) 126 + { 127 + phy_driver_unregister(&bcm63xx_1_driver); 128 + phy_driver_unregister(&bcm63xx_2_driver); 129 + } 130 + 131 + module_init(bcm63xx_phy_init); 132 + module_exit(bcm63xx_phy_exit);