From 1a5465f5d6a23e84ef5c06cb32f3d8c26632f42a Mon Sep 17 00:00:00 2001 From: Patrice Vilchez Date: Thu, 19 Sep 2013 19:40:48 +0200 Subject: phy/micrel: Add suspend/resume support to Micrel PHYs All supported Micrel PHYs implement the standard "power down" bit 11 of BMCR, so this patch adds support using the generic genphy_{suspend,resume} functions. Signed-off-by: Patrice Vilchez [b.brezillon@overkiz.com: adapt to newer kernel and generalize to other phys] Signed-off-by: Boris BREZILLON [nicolas.ferre@atmel.com: commit message modification] Signed-off-by: Nicolas Ferre Cc: David J. Choi Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c31aad0004cb..3ae28f420868 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -287,6 +287,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = ks8737_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ8021, @@ -300,6 +302,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ8031, @@ -313,6 +317,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ8041, @@ -326,6 +332,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ8051, @@ -339,6 +347,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ8001, @@ -351,6 +361,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ8081, @@ -363,6 +375,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ8061, @@ -375,6 +389,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { .phy_id = PHY_ID_KSZ9021, @@ -387,6 +403,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = ksz9021_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE, }, }, { .phy_id = PHY_ID_KSZ9031, @@ -400,6 +418,8 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = ksz9021_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE, }, }, { .phy_id = PHY_ID_KSZ8873MLL, @@ -410,6 +430,8 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE, }, }, { .phy_id = PHY_ID_KSZ886X, @@ -420,6 +442,8 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE, }, } }; -- cgit v1.2.2 From 0197ffed8690751b027253b97f68df6304aaa6a1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sat, 21 Sep 2013 16:53:01 +0200 Subject: net: phy: at803x: don't pass function pointers with & Just a cosmetic cleanup. Signed-off-by: Daniel Mack Acked-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index ac22283aaf23..417922810c79 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -163,8 +163,8 @@ static struct phy_driver at803x_driver[] = { .get_wol = at803x_get_wol, .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, - .config_aneg = &genphy_config_aneg, - .read_status = &genphy_read_status, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, .driver = { .owner = THIS_MODULE, }, @@ -178,8 +178,8 @@ static struct phy_driver at803x_driver[] = { .get_wol = at803x_get_wol, .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, - .config_aneg = &genphy_config_aneg, - .read_status = &genphy_read_status, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, .driver = { .owner = THIS_MODULE, }, @@ -193,8 +193,8 @@ static struct phy_driver at803x_driver[] = { .get_wol = at803x_get_wol, .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, - .config_aneg = &genphy_config_aneg, - .read_status = &genphy_read_status, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, .driver = { .owner = THIS_MODULE, }, -- cgit v1.2.2 From 6229ed1f22592d5ee8360a638cb965fef88b080f Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sat, 21 Sep 2013 16:53:02 +0200 Subject: net: phy: at803x: add suspend/resume callbacks When WOL is enabled, the chip can't be put into power-down (BMCR_PDOWN) mode, as that will also switch off the MAC, which consequently leads to a link loss. Use BMCR_ISOLATE in that case, which will at least save us some milliamperes in comparison to normal operation mode. Signed-off-by: Daniel Mack Acked-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 417922810c79..bc71947b1ec3 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -100,6 +100,45 @@ static void at803x_get_wol(struct phy_device *phydev, wol->wolopts |= WAKE_MAGIC; } +static int at803x_suspend(struct phy_device *phydev) +{ + int value; + int wol_enabled; + + mutex_lock(&phydev->lock); + + value = phy_read(phydev, AT803X_INTR_ENABLE); + wol_enabled = value & AT803X_WOL_ENABLE; + + value = phy_read(phydev, MII_BMCR); + + if (wol_enabled) + value |= BMCR_ISOLATE; + else + value |= BMCR_PDOWN; + + phy_write(phydev, MII_BMCR, value); + + mutex_unlock(&phydev->lock); + + return 0; +} + +static int at803x_resume(struct phy_device *phydev) +{ + int value; + + mutex_lock(&phydev->lock); + + value = phy_read(phydev, MII_BMCR); + value &= ~(BMCR_PDOWN | BMCR_ISOLATE); + phy_write(phydev, MII_BMCR, value); + + mutex_unlock(&phydev->lock); + + return 0; +} + static int at803x_config_init(struct phy_device *phydev) { int val; @@ -161,6 +200,8 @@ static struct phy_driver at803x_driver[] = { .config_init = at803x_config_init, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, .config_aneg = genphy_config_aneg, @@ -176,6 +217,8 @@ static struct phy_driver at803x_driver[] = { .config_init = at803x_config_init, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, .config_aneg = genphy_config_aneg, @@ -191,6 +234,8 @@ static struct phy_driver at803x_driver[] = { .config_init = at803x_config_init, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, .config_aneg = genphy_config_aneg, -- cgit v1.2.2 From eea3b201970b4025baa04a83ff674b1b7e5d0802 Mon Sep 17 00:00:00 2001 From: Avinash Kumar Date: Mon, 30 Sep 2013 09:36:44 +0530 Subject: drivers: net: phy: marvell.c: removed checkpatch.pl warnings removes following warnings- drivers/net/phy/marvell.c:37: WARNING: Use #include instead of drivers/net/phy/marvell.c:39: WARNING: Use #include instead of Signed-off-by: Avinash Kumar Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 2e91477362d4..2e3c778ea9bf 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -34,9 +34,9 @@ #include #include -#include +#include #include -#include +#include #define MII_MARVELL_PHY_PAGE 22 -- cgit v1.2.2 From b0db7b0c21a014d01be1018db68e78ebf7d4f0d7 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 5 Nov 2013 16:55:01 +0100 Subject: phy: Add MOXA MDIO driver The MOXA UC-711X hardware(s) has an ethernet controller that seem to be developed internally. The IC used is "RTL8201CP". This patch adds an MDIO driver which handles the MII bus. Signed-off-by: Jonas Jensen Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 7 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/mdio-moxart.c | 201 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 drivers/net/phy/mdio-moxart.c (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 342561ad3158..9b5d46c03eed 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -154,6 +154,13 @@ config MDIO_SUN4I interface units of the Allwinner SoC that have an EMAC (A10, A12, A10s, etc.) +config MDIO_MOXART + tristate "MOXA ART MDIO interface support" + depends on ARCH_MOXART + help + This driver supports the MDIO interface found in the network + interface units of the MOXA ART SoC + config MDIO_BUS_MUX tristate depends on OF_MDIO diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 23a2ab2e847e..9013dfa12aa3 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o +obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o diff --git a/drivers/net/phy/mdio-moxart.c b/drivers/net/phy/mdio-moxart.c new file mode 100644 index 000000000000..a5741cb0304e --- /dev/null +++ b/drivers/net/phy/mdio-moxart.c @@ -0,0 +1,201 @@ +/* MOXA ART Ethernet (RTL8201CP) MDIO interface driver + * + * Copyright (C) 2013 Jonas Jensen + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_PHY_CTRL 0 +#define REG_PHY_WRITE_DATA 4 + +/* REG_PHY_CTRL */ +#define MIIWR BIT(27) /* init write sequence (auto cleared)*/ +#define MIIRD BIT(26) +#define REGAD_MASK 0x3e00000 +#define PHYAD_MASK 0x1f0000 +#define MIIRDATA_MASK 0xffff + +/* REG_PHY_WRITE_DATA */ +#define MIIWDATA_MASK 0xffff + +struct moxart_mdio_data { + void __iomem *base; +}; + +static int moxart_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct moxart_mdio_data *data = bus->priv; + u32 ctrl = 0; + unsigned int count = 5; + + dev_dbg(&bus->dev, "%s\n", __func__); + + ctrl |= MIIRD | ((mii_id << 16) & PHYAD_MASK) | + ((regnum << 21) & REGAD_MASK); + + writel(ctrl, data->base + REG_PHY_CTRL); + + do { + ctrl = readl(data->base + REG_PHY_CTRL); + + if (!(ctrl & MIIRD)) + return ctrl & MIIRDATA_MASK; + + mdelay(10); + count--; + } while (count > 0); + + dev_dbg(&bus->dev, "%s timed out\n", __func__); + + return -ETIMEDOUT; +} + +static int moxart_mdio_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) +{ + struct moxart_mdio_data *data = bus->priv; + u32 ctrl = 0; + unsigned int count = 5; + + dev_dbg(&bus->dev, "%s\n", __func__); + + ctrl |= MIIWR | ((mii_id << 16) & PHYAD_MASK) | + ((regnum << 21) & REGAD_MASK); + + value &= MIIWDATA_MASK; + + writel(value, data->base + REG_PHY_WRITE_DATA); + writel(ctrl, data->base + REG_PHY_CTRL); + + do { + ctrl = readl(data->base + REG_PHY_CTRL); + + if (!(ctrl & MIIWR)) + return 0; + + mdelay(10); + count--; + } while (count > 0); + + dev_dbg(&bus->dev, "%s timed out\n", __func__); + + return -ETIMEDOUT; +} + +static int moxart_mdio_reset(struct mii_bus *bus) +{ + int data, i; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + data = moxart_mdio_read(bus, i, MII_BMCR); + if (data < 0) + continue; + + data |= BMCR_RESET; + if (moxart_mdio_write(bus, i, MII_BMCR, data) < 0) + continue; + } + + return 0; +} + +static int moxart_mdio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct mii_bus *bus; + struct moxart_mdio_data *data; + struct resource *res; + int ret, i; + + bus = mdiobus_alloc_size(sizeof(*data)); + if (!bus) + return -ENOMEM; + + bus->name = "MOXA ART Ethernet MII"; + bus->read = &moxart_mdio_read; + bus->write = &moxart_mdio_write; + bus->reset = &moxart_mdio_reset; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d-mii", pdev->name, pdev->id); + bus->parent = &pdev->dev; + + bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR, + GFP_KERNEL); + if (!bus->irq) { + ret = -ENOMEM; + goto err_out_free_mdiobus; + } + + /* Setting PHY_IGNORE_INTERRUPT here even if it has no effect, + * of_mdiobus_register() sets these PHY_POLL. + * Ideally, the interrupt from MAC controller could be used to + * detect link state changes, not polling, i.e. if there was + * a way phy_driver could set PHY_HAS_INTERRUPT but have that + * interrupt handled in ethernet drivercode. + */ + for (i = 0; i < PHY_MAX_ADDR; i++) + bus->irq[i] = PHY_IGNORE_INTERRUPT; + + data = bus->priv; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) { + ret = PTR_ERR(data->base); + goto err_out_free_mdiobus; + } + + ret = of_mdiobus_register(bus, np); + if (ret < 0) + goto err_out_free_mdiobus; + + platform_set_drvdata(pdev, bus); + + return 0; + +err_out_free_mdiobus: + mdiobus_free(bus); + return ret; +} + +static int moxart_mdio_remove(struct platform_device *pdev) +{ + struct mii_bus *bus = platform_get_drvdata(pdev); + + mdiobus_unregister(bus); + mdiobus_free(bus); + + return 0; +} + +static const struct of_device_id moxart_mdio_dt_ids[] = { + { .compatible = "moxa,moxart-mdio" }, + { } +}; +MODULE_DEVICE_TABLE(of, moxart_mdio_dt_ids); + +static struct platform_driver moxart_mdio_driver = { + .probe = moxart_mdio_probe, + .remove = moxart_mdio_remove, + .driver = { + .name = "moxart-mdio", + .of_match_table = moxart_mdio_dt_ids, + }, +}; + +module_platform_driver(moxart_mdio_driver); + +MODULE_DESCRIPTION("MOXA ART MDIO interface driver"); +MODULE_AUTHOR("Jonas Jensen "); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 129596674c00352cbbb1efaf36db50726fd374ef Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 11 Nov 2013 15:46:06 +0100 Subject: PHY: Add RTL8201CP phy_driver to realtek Add RTL8201CP phy_driver. Signed-off-by: Jonas Jensen Signed-off-by: David S. Miller --- drivers/net/phy/realtek.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 138de837977f..fa1d69a38ccf 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -64,6 +64,18 @@ static int rtl8211e_config_intr(struct phy_device *phydev) return err; } +/* RTL8201CP */ +static struct phy_driver rtl8201cp_driver = { + .phy_id = 0x00008201, + .name = "RTL8201CP Ethernet", + .phy_id_mask = 0x0000ffff, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + /* RTL8211B */ static struct phy_driver rtl8211b_driver = { .phy_id = 0x001cc912, @@ -98,6 +110,9 @@ static int __init realtek_init(void) { int ret; + ret = phy_driver_register(&rtl8201cp_driver); + if (ret < 0) + return -ENODEV; ret = phy_driver_register(&rtl8211b_driver); if (ret < 0) return -ENODEV; -- cgit v1.2.2