From patchwork Thu Jul 11 11:57:35 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helmut Schaa X-Patchwork-Id: 258425 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 03EE62C030E for ; Thu, 11 Jul 2013 21:57:52 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755986Ab3GKL5s (ORCPT ); Thu, 11 Jul 2013 07:57:48 -0400 Received: from mail-ee0-f43.google.com ([74.125.83.43]:57621 "EHLO mail-ee0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754132Ab3GKL5r (ORCPT ); Thu, 11 Jul 2013 07:57:47 -0400 Received: by mail-ee0-f43.google.com with SMTP id l10so5470427eei.2 for ; Thu, 11 Jul 2013 04:57:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=5L57Ow6VB5zDCpCPfXXIfXe/PPq6qVfY7sMFBjVvT2k=; b=aVcoSup480uLhCEKDmhY6tJ61K8MaTpDgCoYTlgefpbtqWlgVw5XayNe1qokj206t+ mdLbsk20ZkgSN4EviIl/DEsT8LyB3yiTApdh9gU9EYu4gU2OEM+wOBvq9B1aa8Kqhppu 05oBiXF9qxWGJFZunei3PbPPTnRJReW1wIMnddu8bQeeu7yb/jasiHBPaMc03y2VcQ9I O9yIMptvfediCft4XAPqXZBnGxTXd+H0X081TtDmhgD1kbPHQWy7uAG6LAbjydms652g XPZkFlwqfORO+x+BxbfHyg5wc3Y/HhUTgXqD2yg/7gXBlZzfrtJtvhXq0M1V+bVrgojq o6PA== X-Received: by 10.14.6.198 with SMTP id 46mr29820226een.121.1373543865685; Thu, 11 Jul 2013 04:57:45 -0700 (PDT) Received: from hschaa-desktop.site ([217.8.58.223]) by mx.google.com with ESMTPSA id bj46sm68421316eeb.13.2013.07.11.04.57.44 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 11 Jul 2013 04:57:44 -0700 (PDT) From: Helmut Schaa To: netdev@vger.kernel.org Cc: davem@davemloft.net, Helmut Schaa Subject: [PATCH 2/2] drivers: net: phy: at803x: LED control via led subsystem Date: Thu, 11 Jul 2013 13:57:35 +0200 Message-Id: <1373543855-31670-2-git-send-email-helmut.schaa@googlemail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1373543855-31670-1-git-send-email-helmut.schaa@googlemail.com> References: <1373543855-31670-1-git-send-email-helmut.schaa@googlemail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The AT8035 PHY allows to control the LED PIN behavior from software. Expose this functionality by registering an LED device. Signed-off-by: Helmut Schaa --- drivers/net/phy/Kconfig | 7 ++++ drivers/net/phy/at803x.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 3a316b3..5e855b7 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -19,6 +19,13 @@ config AT803X_PHY ---help--- Currently supports the AT8030 and AT8035 model +config AT803X_LEDS + bool "Enable access to PHY connected LEDs" + depends on AT803X_PHY && LEDS_CLASS + ---help--- + Select this to be able to control LEDs connected to the + PHY from userspace + config AMD_PHY tristate "Drivers for the AMD PHYs" ---help--- diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index ac22283..49ef6306 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -16,6 +16,7 @@ #include #include #include +#include #define AT803X_INTR_ENABLE 0x12 #define AT803X_INTR_STATUS 0x13 @@ -31,6 +32,8 @@ #define AT803X_DEBUG_DATA 0x1E #define AT803X_DEBUG_SYSTEM_MODE_CTRL 0x05 #define AT803X_DEBUG_RGMII_TX_CLK_DLY BIT(8) +#define AT8035_LED_CTRL 0x18 +#define AT8035_LED_CTRL_OFF BIT(15) MODULE_DESCRIPTION("Atheros 803x PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); @@ -152,6 +155,86 @@ static int at803x_config_init(struct phy_device *phydev) return 0; } +#ifdef CONFIG_AT803X_LEDS + +struct at8035_priv { + struct led_classdev led; + struct phy_device *phydev; + struct work_struct led_work; + bool stop; +}; + +static void at8035_led_work(struct work_struct *work) +{ + struct at8035_priv *priv = + container_of(work, struct at8035_priv, led_work); + struct phy_device *phydev = priv->phydev; + int val; + + if (priv->stop) + return; + + val = phy_read(phydev, AT8035_LED_CTRL); + + if (priv->led.brightness > 0) + phy_write(phydev, AT8035_LED_CTRL, val & ~AT8035_LED_CTRL_OFF); + else + phy_write(phydev, AT8035_LED_CTRL, val | AT8035_LED_CTRL_OFF); +} + +static void at8035_led_brightness_set(struct led_classdev *led, + enum led_brightness brightness) +{ + struct at8035_priv *priv = container_of(led, struct at8035_priv, led); + + /* MDIO bus can only be used from process context */ + if (!priv->stop) + schedule_work(&priv->led_work); +} + +static int at8035_probe(struct phy_device *phydev) +{ + struct at8035_priv *priv; + int ret; + + priv = kzalloc(sizeof(struct at8035_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + INIT_WORK(&priv->led_work, at8035_led_work); + + priv->phydev = phydev; + priv->led.brightness_set = at8035_led_brightness_set; + priv->led.max_brightness = 1; + priv->led.name = kasprintf(GFP_KERNEL, "at8035_%u::act", phydev->addr); + + if (!priv->led.name) { + kfree(priv); + return -ENOMEM; + } + + ret = led_classdev_register(&phydev->dev, &priv->led); + if (ret) { + kfree(priv->led.name); + kfree(priv); + return -ENOMEM; + } + + phydev->priv = priv; + return 0; +} + +static void at8035_remove(struct phy_device *phydev) +{ + struct at8035_priv *priv = phydev->priv; + priv->stop = true; + cancel_work_sync(&priv->led_work); + led_classdev_unregister(&priv->led); + kfree(priv->led.name); + kfree(priv); +} +#endif + static struct phy_driver at803x_driver[] = { { /* ATHEROS 8035 */ @@ -163,6 +246,10 @@ static struct phy_driver at803x_driver[] = { .get_wol = at803x_get_wol, .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, +#ifdef CONFIG_AT803X_LEDS + .probe = at8035_probe, + .remove = at8035_remove, +#endif .config_aneg = &genphy_config_aneg, .read_status = &genphy_read_status, .driver = {