From a323a7bf2a131761180a1ffe01928dc2e7804837 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 Apr 2008 02:53:04 +0000 Subject: Add stub driver for ADM6996F switches (configured through MII) The driver currently uses a hardcoded VLAN mapping and has no configuration yet Tested on Accton MR3202a SVN-Revision: 10869 --- .../generic-2.6/files/drivers/net/phy/adm6996.c | 170 +++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 target/linux/generic-2.6/files/drivers/net/phy/adm6996.c (limited to 'target/linux/generic-2.6/files/drivers/net/phy/adm6996.c') diff --git a/target/linux/generic-2.6/files/drivers/net/phy/adm6996.c b/target/linux/generic-2.6/files/drivers/net/phy/adm6996.c new file mode 100644 index 0000000000..3033813ec0 --- /dev/null +++ b/target/linux/generic-2.6/files/drivers/net/phy/adm6996.c @@ -0,0 +1,170 @@ +/* + * ADM6996 switch driver + * + * Copyright (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "adm6996.h" + +MODULE_DESCRIPTION("Infineon ADM6996 Switch"); +MODULE_AUTHOR("Felix Fietkau"); +MODULE_LICENSE("GPL"); + +struct adm6996_priv { + /* use abstraction for regops, we want to add gpio support in the future */ + u16 (*read)(struct phy_device *phydev, enum admreg reg); + void (*write)(struct phy_device *phydev, enum admreg reg, u16 val); +}; + +#define to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) + + +static inline u16 +r16(struct phy_device *pdev, enum admreg reg) +{ + return to_adm(pdev)->read(pdev, reg); +} + +static inline void +w16(struct phy_device *pdev, enum admreg reg, u16 val) +{ + to_adm(pdev)->write(pdev, reg, val); +} + + +static u16 +adm6996_read_mii_reg(struct phy_device *phydev, enum admreg reg) +{ + return phydev->bus->read(phydev->bus, PHYADDR(reg)); +} + +static void +adm6996_write_mii_reg(struct phy_device *phydev, enum admreg reg, u16 val) +{ + phydev->bus->write(phydev->bus, PHYADDR(reg), val); +} + + +static int adm6996_config_init(struct phy_device *pdev) +{ + int i; + + printk("%s: ADM6996 PHY driver attached.\n", pdev->attached_dev->name); + pdev->supported = ADVERTISED_100baseT_Full; + pdev->advertising = ADVERTISED_100baseT_Full; + + /* initialize port and vlan settings */ + for (i = 0; i < ADM_PHY_PORTS; i++) { + w16(pdev, adm_portcfg[i], ADM_PORTCFG_INIT | + ADM_PORTCFG_PVID((i == ADM_WAN_PORT) ? 1 : 0)); + } + w16(pdev, adm_portcfg[5], ADM_PORTCFG_CPU); + + /* reset all ports */ + for (i = 0; i < ADM_PHY_PORTS; i++) { + w16(pdev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); + } + + return 0; +} + +static int adm6996_read_status(struct phy_device *phydev) +{ + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + phydev->state = PHY_UP; + return 0; +} + +static int adm6996_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int adm6996_probe(struct phy_device *pdev) +{ + struct adm6996_priv *priv; + + priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->read = adm6996_read_mii_reg; + priv->write = adm6996_write_mii_reg; + pdev->priv = priv; + return 0; +} + +static void adm6996_remove(struct phy_device *pdev) +{ + kfree(pdev->priv); +} + +static bool adm6996_detect(struct mii_bus *bus, int addr) +{ + u16 reg; + + /* we only attach to phy id 0 */ + if (addr != 0) + return false; + + /* look for the switch on the bus */ + reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; + if (reg != ADM_SIG0_VAL) + return false; + + reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; + if (reg != ADM_SIG1_VAL) + return false; + + return true; +} + +static struct phy_driver adm6996_driver = { + .name = "Infineon ADM6996", + .features = PHY_BASIC_FEATURES, + .detect = adm6996_detect, + .probe = adm6996_probe, + .remove = adm6996_remove, + .config_init = &adm6996_config_init, + .config_aneg = &adm6996_config_aneg, + .read_status = &adm6996_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init adm6996_init(void) +{ + return phy_driver_register(&adm6996_driver); +} + +static void __exit adm6996_exit(void) +{ + phy_driver_unregister(&adm6996_driver); +} + +module_init(adm6996_init); +module_exit(adm6996_exit); -- cgit v1.2.3