From patchwork Wed Apr 5 08:33:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 96774 Delivered-To: patch@linaro.org Received: by 10.182.246.10 with SMTP id xs10csp150950obc; Wed, 5 Apr 2017 01:35:18 -0700 (PDT) X-Received: by 10.99.164.26 with SMTP id c26mr29022532pgf.89.1491381318361; Wed, 05 Apr 2017 01:35:18 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m21si19917553pgj.395.2017.04.05.01.35.18; Wed, 05 Apr 2017 01:35:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932276AbdDEIel (ORCPT + 14 others); Wed, 5 Apr 2017 04:34:41 -0400 Received: from lelnx194.ext.ti.com ([198.47.27.80]:43397 "EHLO lelnx194.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753484AbdDEIeK (ORCPT ); Wed, 5 Apr 2017 04:34:10 -0400 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by lelnx194.ext.ti.com (8.15.1/8.15.1) with ESMTP id v358Y4oG028333; Wed, 5 Apr 2017 03:34:04 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ti.com; s=ti-com-17Q1; t=1491381244; bh=qpWu9NoBF9JnWEjaMVqDL+k2gRxR9XwJqxOD2ZZIBOU=; h=From:To:CC:Subject:Date; b=J/rNiqsdqYixFSYY71f2euZ+uhihlfroqb2tFLkers6/pDvjhMgRIHS5UeGf9z2zM cKFl+ksaO5MOEQVoJwl0XZ10MN8jHM564M86BPh2QOsBpdHa04y4P/xzQlfww2mpo0 +iTX9C3W7n9lcUfxor9gGWaeghfuoNq7Hrbnc0JI= Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id v358Y4cc000415; Wed, 5 Apr 2017 03:34:04 -0500 Received: from dflp33.itg.ti.com (10.64.6.16) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.294.0; Wed, 5 Apr 2017 03:34:02 -0500 Received: from lta0400828d.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp33.itg.ti.com (8.14.3/8.13.8) with ESMTP id v358Y0NB017088; Wed, 5 Apr 2017 03:34:00 -0500 From: Roger Quadros To: CC: , , , , , , Roger Quadros Subject: [PATCH] net: davinci_mdio: add GPIO reset logic Date: Wed, 5 Apr 2017 11:33:57 +0300 Message-ID: <1491381237-24635-1-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Some boards [1] leave the PHYs at an invalid state during system power-up or reset thus causing unreliability issues with the PHY like not being detected by the mdio bus or link not functional. To work around these boards have a GPIO connected to the PHY's reset pin. Implement GPIO reset handling for such cases. [1] - am572x-idk, am571x-idk, a437x-idk. Signed-off-by: Roger Quadros Signed-off-by: Sekhar Nori --- .../devicetree/bindings/net/davinci-mdio.txt | 2 + drivers/net/ethernet/ti/davinci_mdio.c | 68 +++++++++++++++++++--- 2 files changed, 62 insertions(+), 8 deletions(-) -- 2.7.4 diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt index 621156c..fd6ebe7 100644 --- a/Documentation/devicetree/bindings/net/davinci-mdio.txt +++ b/Documentation/devicetree/bindings/net/davinci-mdio.txt @@ -12,6 +12,8 @@ Required properties: Optional properties: - ti,hwmods : Must be "davinci_mdio" +- reset-gpios : array of GPIO specifier for PHY hardware reset control +- reset-delay-us : reset assertion time [in microseconds] Note: "ti,hwmods" field is used to fetch the base address and irq resources from TI, omap hwmod data base during device registration. diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 33df340..c6f9e55 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -40,6 +40,9 @@ #include #include #include +#include +#include +#include /* * This timeout definition is a worst-case ultra defensive measure against @@ -53,6 +56,8 @@ #define DEF_OUT_FREQ 2200000 /* 2.2 MHz */ +#define DEFAULT_GPIO_RESET_DELAY 10 /* in microseconds */ + struct davinci_mdio_of_param { int autosuspend_delay_ms; }; @@ -104,6 +109,9 @@ struct davinci_mdio_data { */ bool skip_scan; u32 clk_div; + struct gpio_desc **gpio_reset; + int num_gpios; + int reset_delay_us; }; static void davinci_mdio_init_clk(struct davinci_mdio_data *data) @@ -142,6 +150,20 @@ static void davinci_mdio_enable(struct davinci_mdio_data *data) __raw_writel(data->clk_div | CONTROL_ENABLE, &data->regs->control); } +static void __davinci_gpio_reset(struct davinci_mdio_data *data) +{ + int i; + + for (i = 0; i < data->num_gpios; i++) { + if (!data->gpio_reset[i]) + continue; + + gpiod_set_value_cansleep(data->gpio_reset[i], 1); + udelay(data->reset_delay_us); + gpiod_set_value_cansleep(data->gpio_reset[i], 0); + } +} + static int davinci_mdio_reset(struct mii_bus *bus) { struct davinci_mdio_data *data = bus->priv; @@ -317,20 +339,50 @@ static int davinci_mdio_write(struct mii_bus *bus, int phy_id, } #if IS_ENABLED(CONFIG_OF) -static int davinci_mdio_probe_dt(struct mdio_platform_data *data, - struct platform_device *pdev) +static int davinci_mdio_probe_dt(struct davinci_mdio_data *data, + struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; u32 prop; - - if (!node) - return -EINVAL; + int error; + int i; + struct gpio_desc *gpiod; if (of_property_read_u32(node, "bus_freq", &prop)) { dev_err(&pdev->dev, "Missing bus_freq property in the DT.\n"); - return -EINVAL; + data->pdata = default_pdata; + } else { + data->pdata.bus_freq = prop; + } + + i = of_gpio_named_count(node, "reset-gpios"); + if (i > 0) { + data->num_gpios = i; + data->gpio_reset = devm_kcalloc(&pdev->dev, i, + sizeof(struct gpio_desc *), + GFP_KERNEL); + if (!data->gpio_reset) + return -ENOMEM; + + for (i = 0; i < data->num_gpios; i++) { + gpiod = devm_gpiod_get_index(&pdev->dev, "reset", i, + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + error = PTR_ERR(gpiod); + if (error == -ENOENT) + continue; + else + return error; + } + data->gpio_reset[i] = gpiod; + } + + if (of_property_read_u32(node, "reset-delay-us", + &data->reset_delay_us)) + data->reset_delay_us = DEFAULT_GPIO_RESET_DELAY; + + __davinci_gpio_reset(data); } - data->bus_freq = prop; return 0; } @@ -372,7 +424,7 @@ static int davinci_mdio_probe(struct platform_device *pdev) if (dev->of_node) { const struct of_device_id *of_id; - ret = davinci_mdio_probe_dt(&data->pdata, pdev); + ret = davinci_mdio_probe_dt(data, pdev); if (ret) return ret; snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);