From patchwork Mon Apr 29 19:36:54 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 2501991 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork1.kernel.org (Postfix) with ESMTP id 0D7CA3FD1A for ; Mon, 29 Apr 2013 19:39:49 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UWtuA-0005S7-Ek; Mon, 29 Apr 2013 19:38:31 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UWttk-0002TG-QJ; Mon, 29 Apr 2013 19:38:04 +0000 Received: from mail.free-electrons.com ([94.23.35.102]) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UWtt7-0002OQ-CD for linux-arm-kernel@lists.infradead.org; Mon, 29 Apr 2013 19:37:30 +0000 Received: by mail.free-electrons.com (Postfix, from userid 106) id D19B577A; Mon, 29 Apr 2013 21:37:05 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.3.2 Received: from localhost (189.58.26.109.rev.sfr.net [109.26.58.189]) by mail.free-electrons.com (Postfix) with ESMTPSA id 911AD754; Mon, 29 Apr 2013 21:37:05 +0200 (CEST) From: Maxime Ripard To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 2/6] net: Add MDIO bus driver for the Allwinner EMAC Date: Mon, 29 Apr 2013 21:36:54 +0200 Message-Id: <1367264218-15235-3-git-send-email-maxime.ripard@free-electrons.com> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1367264218-15235-1-git-send-email-maxime.ripard@free-electrons.com> References: <1367264218-15235-1-git-send-email-maxime.ripard@free-electrons.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130429_153725_747784_F7C8FBE1 X-CRM114-Status: GOOD ( 22.74 ) X-Spam-Score: -4.3 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -2.4 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-doc@vger.kernel.org, Emilio Lopez , netdev@vger.kernel.org, devicetree-discuss@lists.ozlabs.org, linux-kernel@vger.kernel.org, Rob Herring , Florian Fainelly , Grant Likely , Alejandro Mery , Rob Landley , sunny@allwinnertech.com, shuge@allwinnertech.com, Maxime Ripard , Stefan Roese , kevin@allwinnertech.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This patch adds a separate driver for the MDIO interface of the Allwinner ethernet controllers. Signed-off-by: Maxime Ripard --- .../bindings/net/allwinner,sun4i-mdio.txt | 26 +++ drivers/net/ethernet/allwinner/Kconfig | 8 + drivers/net/ethernet/allwinner/Makefile | 1 + drivers/net/ethernet/allwinner/sun4i-mdio.c | 191 +++++++++++++++++++++ 4 files changed, 226 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt create mode 100644 drivers/net/ethernet/allwinner/sun4i-mdio.c diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt new file mode 100644 index 0000000..00b9f9a --- /dev/null +++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt @@ -0,0 +1,26 @@ +* Allwinner A10 MDIO Ethernet Controller interface + +Required properties: +- compatible: should be "allwinner,sun4i-mdio". +- reg: address and length of the register set for the device. + +Optional properties: +- phy-supply: phandle to a regulator if the PHY needs one + +Example at the SoC level: +mdio@01c0b080 { + compatible = "allwinner,sun4i-mdio"; + reg = <0x01c0b080 0x14>; + #address-cells = <1>; + #size-cells = <0>; +}; + +And at the board level: + +mdio@01c0b080 { + phy-supply = <®_emac_3v3>; + + phy0: ethernet-phy@0 { + reg = <0>; + }; +}; diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig index 5d20fb0..7bbd500 100644 --- a/drivers/net/ethernet/allwinner/Kconfig +++ b/drivers/net/ethernet/allwinner/Kconfig @@ -27,10 +27,18 @@ config SUN4I_EMAC select NET_CORE select MII select REGULATOR_FIXED_VOLTAGE + select PHYLIB ---help--- Support for Allwinner A10 EMAC ethernet driver. To compile this driver as a module, choose M here. The module will be called sun4i-emac. +config SUN4I_MDIO + tristate "Allwinner sun4i MDIO interface support" + ---help--- + This driver supports the MDIO interface found in the network + interface units of the Allwinner SoC that have an EMAC (A10, + A12, A10s, etc.) + endif # NET_VENDOR_ALLWINNER diff --git a/drivers/net/ethernet/allwinner/Makefile b/drivers/net/ethernet/allwinner/Makefile index 03129f7..95eaa31 100644 --- a/drivers/net/ethernet/allwinner/Makefile +++ b/drivers/net/ethernet/allwinner/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_SUN4I_EMAC) += sun4i-emac.o +obj-$(CONFIG_SUN4I_MDIO) += sun4i-mdio.o \ No newline at end of file diff --git a/drivers/net/ethernet/allwinner/sun4i-mdio.c b/drivers/net/ethernet/allwinner/sun4i-mdio.c new file mode 100644 index 0000000..00e432c --- /dev/null +++ b/drivers/net/ethernet/allwinner/sun4i-mdio.c @@ -0,0 +1,191 @@ +/* + * Allwinner EMAC MDIO interface driver + * + * Copyright 2012-2013 Stefan Roese + * Copyright 2013 Maxime Ripard + * + * Based on the Linux driver provided by Allwinner: + * Copyright (C) 1997 Sten Wang + * + * 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 EMAC_MAC_MCMD_REG (0x00) +#define EMAC_MAC_MADR_REG (0x04) +#define EMAC_MAC_MWTD_REG (0x08) +#define EMAC_MAC_MRDD_REG (0x0c) +#define EMAC_MAC_MIND_REG (0x10) +#define EMAC_MAC_SSRR_REG (0x14) + +#define MDIO_TIMEOUT (msecs_to_jiffies(100)) + +struct sun4i_mdio_data { + void __iomem *membase; + struct regulator *regulator; +}; + +static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct sun4i_mdio_data *data = bus->priv; + unsigned long start_jiffies; + int value; + + /* issue the phy address and reg */ + writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG); + /* pull up the phy io line */ + writel(0x1, data->membase + EMAC_MAC_MCMD_REG); + + /* Wait read complete */ + start_jiffies = jiffies; + while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { + if (time_after(start_jiffies, + start_jiffies + MDIO_TIMEOUT)) + return -ETIMEDOUT; + msleep(1); + } + + /* push down the phy io line */ + writel(0x0, data->membase + EMAC_MAC_MCMD_REG); + /* and read data */ + value = readl(data->membase + EMAC_MAC_MRDD_REG); + + return value; +} + +static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum, + u16 value) +{ + struct sun4i_mdio_data *data = bus->priv; + unsigned long start_jiffies; + + /* issue the phy address and reg */ + writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG); + /* pull up the phy io line */ + writel(0x1, data->membase + EMAC_MAC_MCMD_REG); + + /* Wait read complete */ + start_jiffies = jiffies; + while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { + if (time_after(start_jiffies, + start_jiffies + MDIO_TIMEOUT)) + return -ETIMEDOUT; + msleep(1); + } + + /* push down the phy io line */ + writel(0x0, data->membase + EMAC_MAC_MCMD_REG); + /* and write data */ + writel(value, data->membase + EMAC_MAC_MWTD_REG); + + return 0; +} + +static int sun4i_mdio_reset(struct mii_bus *bus) +{ + return 0; +} + +static int sun4i_mdio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct mii_bus *bus; + struct sun4i_mdio_data *data; + int ret, i; + + bus = mdiobus_alloc_size(sizeof(*data)); + if (!bus) + return -ENOMEM; + + bus->name = "sun4i_mii_bus"; + bus->read = &sun4i_mdio_read; + bus->write = &sun4i_mdio_write; + bus->reset = &sun4i_mdio_reset; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); + bus->parent = &pdev->dev; + + bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!bus->irq) { + ret = -ENOMEM; + goto err_out_free_mdiobus; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + bus->irq[i] = PHY_POLL; + + data = bus->priv; + data->membase = of_iomap(np, 0); + if (!data->membase) { + ret = -ENOMEM; + goto err_out_free_mdio_irq; + } + + data->regulator = devm_regulator_get(&pdev->dev, "phy"); + if (IS_ERR(data->regulator)) { + if (PTR_ERR(data->regulator) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_info(&pdev->dev, "no regulator found\n"); + } else + regulator_enable(data->regulator); + + ret = of_mdiobus_register(bus, np); + if (ret < 0) + goto err_out_disable_regulator; + + platform_set_drvdata(pdev, bus); + + return 0; + +err_out_disable_regulator: + regulator_disable(data->regulator); +err_out_free_mdio_irq: + kfree(bus->irq); +err_out_free_mdiobus: + mdiobus_free(bus); + return ret; +} + +static int sun4i_mdio_remove(struct platform_device *pdev) +{ + struct mii_bus *bus = platform_get_drvdata(pdev); + + mdiobus_unregister(bus); + kfree(bus->irq); + mdiobus_free(bus); + + return 0; +} + +static const struct of_device_id sun4i_mdio_dt_ids[] = { + { .compatible = "allwinner,sun4i-mdio" }, + { } +}; +MODULE_DEVICE_TABLE(of, sun4i_mdio_dt_ids); + +static struct platform_driver sun4i_mdio_driver = { + .probe = sun4i_mdio_probe, + .remove = sun4i_mdio_remove, + .driver = { + .name = "sun4i-mdio", + .of_match_table = sun4i_mdio_dt_ids, + }, +}; + +module_platform_driver(sun4i_mdio_driver); + +MODULE_DESCRIPTION("Allwinner EMAC MDIO interface driver"); +MODULE_AUTHOR("Maxime Ripard "); +MODULE_LICENSE("GPL");