From patchwork Wed Oct 4 08:40:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 13408400 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F7A5A21 for ; Wed, 4 Oct 2023 08:40:47 +0000 (UTC) Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [IPv6:2a0a:edc0:2:b01:1d::104]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3BC7CBF for ; Wed, 4 Oct 2023 01:40:46 -0700 (PDT) Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1qnxQy-0006e0-4I; Wed, 04 Oct 2023 10:40:44 +0200 Received: from [2a0a:edc0:0:1101:1d::28] (helo=dude02.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qnxQx-00Az7a-AW; Wed, 04 Oct 2023 10:40:43 +0200 Received: from sha by dude02.red.stw.pengutronix.de with local (Exim 4.94.2) (envelope-from ) id 1qnxQx-009I78-1X; Wed, 04 Oct 2023 10:40:43 +0200 From: Sascha Hauer To: netdev@vger.kernel.org Cc: Andrew Lunn , Heiner Kallweit , Russell King , linux-kernel@vger.kernel.org, kernel@pengutronix.de, Michael Riesch , Sascha Hauer , Alexander Stein Subject: [PATCH v2] net: phy: dp83867: Add support for hardware blinking LEDs Date: Wed, 4 Oct 2023 10:40:26 +0200 Message-Id: <20231004084026.2214537-1-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.39.2 Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: netdev@vger.kernel.org X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org This implements the led_hw_* hooks to support hardware blinking LEDs on the DP83867 phy. The driver supports all LED modes that have a corresponding TRIGGER_NETDEV_* define. Error and collision do not have a TRIGGER_NETDEV_* define, so these modes are currently not supported. Reviewed-by: Andrew Lunn Tested-by: Alexander Stein #TQMa8MxML/MBa8Mx Signed-off-by: Sascha Hauer --- Notes: Resending because the last send fell into the merge window. Changes since v1: - Add Reviewed-by/Tested-by tags drivers/net/phy/dp83867.c | 137 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index e397e7d642d92..5f08f9d38bd7a 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -159,6 +159,23 @@ #define DP83867_LED_DRV_EN(x) BIT((x) * 4) #define DP83867_LED_DRV_VAL(x) BIT((x) * 4 + 1) +#define DP83867_LED_FN(idx, val) (((val) & 0xf) << ((idx) * 4)) +#define DP83867_LED_FN_MASK(idx) (0xf << ((idx) * 4)) +#define DP83867_LED_FN_RX_ERR 0xe /* Receive Error */ +#define DP83867_LED_FN_RX_TX_ERR 0xd /* Receive Error or Transmit Error */ +#define DP83867_LED_FN_LINK_RX_TX 0xb /* Link established, blink for rx or tx activity */ +#define DP83867_LED_FN_FULL_DUPLEX 0xa /* Full duplex */ +#define DP83867_LED_FN_LINK_100_1000_BT 0x9 /* 100/1000BT link established */ +#define DP83867_LED_FN_LINK_10_100_BT 0x8 /* 10/100BT link established */ +#define DP83867_LED_FN_LINK_10_BT 0x7 /* 10BT link established */ +#define DP83867_LED_FN_LINK_100_BTX 0x6 /* 100 BTX link established */ +#define DP83867_LED_FN_LINK_1000_BT 0x5 /* 1000 BT link established */ +#define DP83867_LED_FN_COLLISION 0x4 /* Collision detected */ +#define DP83867_LED_FN_RX 0x3 /* Receive activity */ +#define DP83867_LED_FN_TX 0x2 /* Transmit activity */ +#define DP83867_LED_FN_RX_TX 0x1 /* Receive or Transmit activity */ +#define DP83867_LED_FN_LINK 0x0 /* Link established */ + enum { DP83867_PORT_MIRROING_KEEP, DP83867_PORT_MIRROING_EN, @@ -1018,6 +1035,123 @@ dp83867_led_brightness_set(struct phy_device *phydev, val); } +static int dp83867_led_mode(u8 index, unsigned long rules) +{ + if (index >= DP83867_LED_COUNT) + return -EINVAL; + + switch (rules) { + case BIT(TRIGGER_NETDEV_LINK): + return DP83867_LED_FN_LINK; + case BIT(TRIGGER_NETDEV_LINK_10): + return DP83867_LED_FN_LINK_10_BT; + case BIT(TRIGGER_NETDEV_LINK_100): + return DP83867_LED_FN_LINK_100_BTX; + case BIT(TRIGGER_NETDEV_FULL_DUPLEX): + return DP83867_LED_FN_FULL_DUPLEX; + case BIT(TRIGGER_NETDEV_TX): + return DP83867_LED_FN_TX; + case BIT(TRIGGER_NETDEV_RX): + return DP83867_LED_FN_RX; + case BIT(TRIGGER_NETDEV_LINK_1000): + return DP83867_LED_FN_LINK_1000_BT; + case BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX): + return DP83867_LED_FN_RX_TX; + case BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000): + return DP83867_LED_FN_LINK_100_1000_BT; + case BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100): + return DP83867_LED_FN_LINK_10_100_BT; + case BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX): + return DP83867_LED_FN_LINK_RX_TX; + default: + return -EOPNOTSUPP; + } +} + +static int dp83867_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + int ret; + + ret = dp83867_led_mode(index, rules); + if (ret < 0) + return ret; + + return 0; +} + +static int dp83867_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + int mode, ret; + + mode = dp83867_led_mode(index, rules); + if (mode < 0) + return mode; + + ret = phy_modify(phydev, DP83867_LEDCR1, DP83867_LED_FN_MASK(index), + DP83867_LED_FN(index, mode)); + if (ret) + return ret; + + return phy_modify(phydev, DP83867_LEDCR2, DP83867_LED_DRV_EN(index), 0); +} + +static int dp83867_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int val; + + val = phy_read(phydev, DP83867_LEDCR1); + if (val < 0) + return val; + + val &= DP83867_LED_FN_MASK(index); + val >>= index * 4; + + switch (val) { + case DP83867_LED_FN_LINK: + *rules = BIT(TRIGGER_NETDEV_LINK); + break; + case DP83867_LED_FN_LINK_10_BT: + *rules = BIT(TRIGGER_NETDEV_LINK_10); + break; + case DP83867_LED_FN_LINK_100_BTX: + *rules = BIT(TRIGGER_NETDEV_LINK_100); + break; + case DP83867_LED_FN_FULL_DUPLEX: + *rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX); + break; + case DP83867_LED_FN_TX: + *rules = BIT(TRIGGER_NETDEV_TX); + break; + case DP83867_LED_FN_RX: + *rules = BIT(TRIGGER_NETDEV_RX); + break; + case DP83867_LED_FN_LINK_1000_BT: + *rules = BIT(TRIGGER_NETDEV_LINK_1000); + break; + case DP83867_LED_FN_RX_TX: + *rules = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); + break; + case DP83867_LED_FN_LINK_100_1000_BT: + *rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000); + break; + case DP83867_LED_FN_LINK_10_100_BT: + *rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100); + break; + case DP83867_LED_FN_LINK_RX_TX: + *rules = BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) | + BIT(TRIGGER_NETDEV_RX); + break; + default: + *rules = 0; + break; + } + + return 0; +} + static struct phy_driver dp83867_driver[] = { { .phy_id = DP83867_PHY_ID, @@ -1047,6 +1181,9 @@ static struct phy_driver dp83867_driver[] = { .set_loopback = dp83867_loopback, .led_brightness_set = dp83867_led_brightness_set, + .led_hw_is_supported = dp83867_led_hw_is_supported, + .led_hw_control_set = dp83867_led_hw_control_set, + .led_hw_control_get = dp83867_led_hw_control_get, }, }; module_phy_driver(dp83867_driver);