From patchwork Fri Nov 12 15:35:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 517316 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8978BC43219 for ; Fri, 12 Nov 2021 15:36:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7802260F14 for ; Fri, 12 Nov 2021 15:36:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235282AbhKLPi5 (ORCPT ); Fri, 12 Nov 2021 10:38:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56912 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235240AbhKLPiz (ORCPT ); Fri, 12 Nov 2021 10:38:55 -0500 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C9C98C061766; Fri, 12 Nov 2021 07:36:04 -0800 (PST) Received: by mail-wr1-x42b.google.com with SMTP id u1so16147002wru.13; Fri, 12 Nov 2021 07:36:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=IwypWslryGEOUCdwRCWHFfnKAKA1I0ITX6IWEz1PyGA=; b=D+1BNEy+IXKi93+WqRBgBkVgSyRLtOGDBDzI91k6meQQ1OUSSR4cpBQmgb5LUzi5VH W4CwjFcAYd2SFvwOcmt1cvzO9skR3nw3cdgOjfl5Qj48opzDCLMaMxQDd2tQ8/pHTCCN Nhn0tbwLYFWSvHsoe/h6CGkn1nAYx1LPlV/Rzd0sbLGGwNpMAvvL8XoJukJLYvAqdyhh aWgJl5oVzcWPJBeczAKkiQnLCwlCLtSKPIdC4z/K4Pq24h12HYo6fXEqtAoSQvRtt5gI vtTSw8P7HpsM8T89P3kwt9igpsKpwOf1tJtL5s2Q0j630xtIZKOnwk8Kb6WmuMt0g9Y9 bg2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=IwypWslryGEOUCdwRCWHFfnKAKA1I0ITX6IWEz1PyGA=; b=4/HSfbATluuNC3dT4LKccNupqYomusgYznrdb6+kZjs6UzgrFu90iGQIY/fYuslo/q S2UKUjE5C800qQ0W9zz9r6w/FWZqnPo+bTWMb38yzsVMmwLxvpybwZgKuf0ofN0DnIio CROpQjNMT/0W1oaeeXZJEp9pvHFMJDmwKY/HJqOVW2VVPyzsHpulqGGq8f+jIpDfTC11 KzqXZKLKhFFpQuzIyZg8VB+QVaNynAROd/wvYmAc/kM1CaC9AasMP+97FAEQ/WAXMonH pMo+lBT3kFkv3fhKSTu6paJMZTE3Hs+EeKXuU+0U+OnWmmTS6tj0daFM511Dshdq16Vh XKXw== X-Gm-Message-State: AOAM533UrzZ3neZ+7ZbF9sVJpFdzr1WT0cs9yFrhP93MllmTt/Ayq4dx LWaxZZifPCgRhD4SI8vEV1A= X-Google-Smtp-Source: ABdhPJz3ofOdqzNOuVTdKBpaZ3ny1prsA8kyETZphZX+WOFL0Xt3zp8jgoj1yWijqjJJkdYOTWyZkg== X-Received: by 2002:a05:6000:1869:: with SMTP id d9mr19353352wri.416.1636731363138; Fri, 12 Nov 2021 07:36:03 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:02 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 1/8] leds: add support for hardware driven LEDs Date: Fri, 12 Nov 2021 16:35:50 +0100 Message-Id: <20211112153557.26941-2-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Some LEDs can be driven by hardware (for example an LED connected to an ethernet PHY or an ethernet switch can be configured to blink on activity on the network, which in software is done by the netdev trigger). To do such offloading, LED driver must support this and a supported trigger must be used. LED driver should declare the correct control mode supported and should set the LED_SOFTWARE_CONTROLLED or LED_HARDWARE_CONTROLLED bit in the flags parameter. The trigger will check these bits and fail to activate if the control mode is not supported. By default if a LED driver doesn't declare a control mode, bit LED_SOFTWARE_CONTROLLED is assumed and set. The LED must implement 3 main APIs: - hw_control_status(): This asks the LED driver if hardware mode is enabled or not. - hw_control_start(): This will simply enable the hardware mode for the LED and the LED driver should reset any active blink_mode. - hw_control_stop(): This will simply disable the hardware mode for the LED. It's advised for the driver to put the LED in the old state but this is not enforced and putting the LED off is also accepted. If LED_HARDWARE_CONTROLLED bit is the only control mode set (LED_SOFTWARE_CONTROLLED not set) set hw_control_status/start/stop is optional as the LED supports only hardware mode and any software only trigger will reject activation. On init an LED driver that support a hardware mode should reset every blink mode set by default. By setting the config CONFIG_LEDS_TRIGGERS support for LEDs that can be controlled by hardware is also enabled. Cc: Marek BehĂșn Signed-off-by: Ansuel Smith --- Documentation/leds/leds-class.rst | 32 ++++++++++++++++++++++++++++++ drivers/leds/led-class.c | 33 +++++++++++++++++++++++++++++++ drivers/leds/led-triggers.c | 22 +++++++++++++++++++++ drivers/leds/trigger/Kconfig | 10 +++++++++- include/linux/leds.h | 32 +++++++++++++++++++++++++++++- 5 files changed, 127 insertions(+), 2 deletions(-) diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-class.rst index cd155ead8703..e5d266919a19 100644 --- a/Documentation/leds/leds-class.rst +++ b/Documentation/leds/leds-class.rst @@ -169,6 +169,38 @@ Setting the brightness to zero with brightness_set() callback function should completely turn off the LED and cancel the previously programmed hardware blinking function, if any. +Hardware driven LEDs +=================================== + +Some LEDs can be driven by hardware (for example an LED connected to +an ethernet PHY or an ethernet switch can be configured to blink on activity on +the network, which in software is done by the netdev trigger). + +To do such offloading, LED driver must support this and a supported trigger must +be used. + +LED driver should declare the correct control mode supported and should set +the LED_SOFTWARE_CONTROLLED or LED_HARDWARE_CONTROLLED bit in the flags +parameter. +The trigger will check these bits and fail to activate if the control mode +is not supported. By default if a LED driver doesn't declare a control mode, +bit LED_SOFTWARE_CONTROLLED is assumed and set. + +The LED must implement 3 main APIs: +- hw_control_status(): This asks the LED driver if hardware mode is enabled + or not. +- hw_control_start(): This will simply enable the hardware mode for the LED + and the LED driver should reset any active blink_mode. +- hw_control_stop(): This will simply disable the hardware mode for the LED. + It's advised to the driver to put the LED in the old state but this is not + enforced and putting the LED off is also accepted. + +If LED_HARDWARE_CONTROLLED bit is the only control mode set (LED_SOFTWARE_CONTROLLED +not set) set hw_control_status/start/stop is optional as the LED supports only +hardware mode and any software only trigger will reject activation. + +On init an LED driver that support a hardware mode should reset every blink mode +set by default. Known Issues ============ diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index f4bb02f6e042..dbe9840863d0 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -164,6 +164,26 @@ static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev) } #endif +#ifdef CONFIG_LEDS_TRIGGERS +static int led_classdev_check_hw_control_functions(struct led_classdev *led_cdev) +{ + if ((LED_SOFTWARE_CONTROLLED & led_cdev->flags) && + (LED_HARDWARE_CONTROLLED & led_cdev->flags) && + (!led_cdev->hw_control_status || + !led_cdev->hw_control_start || + !led_cdev->hw_control_stop)) + return -EINVAL; + + if ((LED_SOFTWARE_CONTROLLED & led_cdev->flags) && + (led_cdev->hw_control_status || + led_cdev->hw_control_start || + led_cdev->hw_control_stop)) + return -EINVAL; + + return 0; +} +#endif + /** * led_classdev_suspend - suspend an led_classdev. * @led_cdev: the led_classdev to suspend. @@ -367,6 +387,19 @@ int led_classdev_register_ext(struct device *parent, if (ret < 0) return ret; + /* Make sure a control mode is set. + * With no control mode declared, set SOFTWARE_CONTROLLED by default. + */ + if (!(LED_SOFTWARE_CONTROLLED & led_cdev->flags) && + !(LED_HARDWARE_CONTROLLED & led_cdev->flags)) + led_cdev->flags |= LED_SOFTWARE_CONTROLLED; + +#ifdef CONFIG_LEDS_TRIGGERS + ret = led_classdev_check_hw_control_functions(led_cdev); + if (ret < 0) + return ret; +#endif + mutex_init(&led_cdev->led_access); mutex_lock(&led_cdev->led_access); led_cdev->dev = device_create_with_groups(leds_class, parent, 0, diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 072491d3e17b..69dff5a29bea 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -154,6 +154,20 @@ ssize_t led_trigger_read(struct file *filp, struct kobject *kobj, } EXPORT_SYMBOL_GPL(led_trigger_read); +static bool led_trigger_is_supported(struct led_classdev *led_cdev, + struct led_trigger *trigger) +{ + if (trigger->supported_blink_modes == SOFTWARE_ONLY && + !(LED_SOFTWARE_CONTROLLED & led_cdev->flags)) + return 0; + + if (trigger->supported_blink_modes == HARDWARE_ONLY && + !(LED_HARDWARE_CONTROLLED & led_cdev->flags)) + return 0; + + return 1; +} + /* Caller must ensure led_cdev->trigger_lock held */ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) { @@ -179,6 +193,10 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) cancel_work_sync(&led_cdev->set_brightness_work); led_stop_software_blink(led_cdev); + /* Disable hardware mode on trigger change if supported */ + if ((led_cdev->flags & LED_HARDWARE_CONTROLLED) && + led_cdev->hw_control_status(led_cdev)) + led_cdev->hw_control_stop(led_cdev); if (led_cdev->trigger->deactivate) led_cdev->trigger->deactivate(led_cdev); device_remove_groups(led_cdev->dev, led_cdev->trigger->groups); @@ -188,6 +206,10 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) led_set_brightness(led_cdev, LED_OFF); } if (trig) { + /* Make sure the trigger support the LED blink mode */ + if (!led_trigger_is_supported(led_cdev, trig)) + return -EINVAL; + spin_lock(&trig->leddev_list_lock); list_add_tail_rcu(&led_cdev->trig_list, &trig->led_cdevs); spin_unlock(&trig->leddev_list_lock); diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index dc6816d36d06..18a8970bfae6 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -5,7 +5,15 @@ menuconfig LEDS_TRIGGERS help This option enables trigger support for the leds class. These triggers allow kernel events to drive the LEDs and can - be configured via sysfs. If unsure, say Y. + be configured via sysfs. + + This option also enables Hardware control support used by LEDs + that can be driven in hardware by using supported triggers. + + Hardware blink modes will be exposed by sysfs class in + /sys/class/leds based on the trigger currently active. + + If unsure, say Y. if LEDS_TRIGGERS diff --git a/include/linux/leds.h b/include/linux/leds.h index ba4861ec73d3..c8e97fb9252f 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -85,6 +85,11 @@ struct led_classdev { #define LED_BRIGHT_HW_CHANGED BIT(21) #define LED_RETAIN_AT_SHUTDOWN BIT(22) #define LED_INIT_DEFAULT_TRIGGER BIT(23) +/* LED can be controlled by software. This is set by default + * if the LED driver doesn't report SOFTWARE or HARDWARE + */ +#define LED_SOFTWARE_CONTROLLED BIT(24) +#define LED_HARDWARE_CONTROLLED BIT(25) /* set_brightness_work / blink_timer flags, atomic, private. */ unsigned long work_flags; @@ -154,6 +159,18 @@ struct led_classdev { /* LEDs that have private triggers have this set */ struct led_hw_trigger_type *trigger_type; + + /* Ask the LED driver if hardware mode is enabled or not. + * Triggers will check if the hardware mode is active or not. + */ + bool (*hw_control_status)(struct led_classdev *led_cdev); + /* Set LED in hardware mode and reset any blink mode active by default. + */ + int (*hw_control_start)(struct led_classdev *led_cdev); + /* Disable hardware mode for LED. It's advised to the LED driver to put it to + * the old status but that is not mandatory and also putting it off is accepted. + */ + int (*hw_control_stop)(struct led_classdev *led_cdev); #endif #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED @@ -215,7 +232,6 @@ extern struct led_classdev *of_led_get(struct device_node *np, int index); extern void led_put(struct led_classdev *led_cdev); struct led_classdev *__must_check devm_of_led_get(struct device *dev, int index); - /** * led_blink_set - set blinking with software fallback * @led_cdev: the LED to start blinking @@ -350,12 +366,26 @@ static inline bool led_sysfs_is_disabled(struct led_classdev *led_cdev) #define TRIG_NAME_MAX 50 +enum led_trigger_blink_supported_modes { + SOFTWARE_ONLY = BIT(0), + HARDWARE_ONLY = BIT(1), + SOFTWARE_HARDWARE = BIT(2), +}; + struct led_trigger { /* Trigger Properties */ const char *name; int (*activate)(struct led_classdev *led_cdev); void (*deactivate)(struct led_classdev *led_cdev); + /* Declare if the Trigger supports hardware control to + * offload triggers or supports only software control. + * A trigger can also declare support for hardware control + * if is task is only configure LED blink modes and expose + * them in sysfs. + */ + enum led_trigger_blink_supported_modes supported_blink_modes; + /* LED-private triggers have this set */ struct led_hw_trigger_type *trigger_type; From patchwork Fri Nov 12 15:35:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 517315 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6529DC433EF for ; Fri, 12 Nov 2021 15:36:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 54E1161051 for ; Fri, 12 Nov 2021 15:36:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235319AbhKLPjA (ORCPT ); Fri, 12 Nov 2021 10:39:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56924 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235276AbhKLPi5 (ORCPT ); Fri, 12 Nov 2021 10:38:57 -0500 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 13CB5C061767; Fri, 12 Nov 2021 07:36:06 -0800 (PST) Received: by mail-wr1-x430.google.com with SMTP id b12so16224304wrh.4; Fri, 12 Nov 2021 07:36:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=4jGWHLurbyA4/FNcd6iSsivOCVyFz9hIK/N30AnY3g4=; b=dvUVdbRJz8af65msBLml9vdXAaDpZl4VJjWLFvbA/Fn9ZwxgBuyoH+HOAqNGn0ZD6Q GM9NqIMPIv4wC8BT9nXMDb1VX+wNB0/m98lC7HHKtHaJZDcaAfRu+emCsQYdAJAezAec W4sVnAezjgAqSW+b2Qml4ZcoZRQeRInEQs/ctLcRzPtlJxDs9g83+CG85P5RUOifrYDl TcKFyzpe7TAIJ71+6HWc0vPcZpBqd5qu1R1pTe3GS3CVKCi6ZwNfaPwVWoeqCnt4MNDW Fw/779dq+/kqakffVO7+km0P724Ry9mjVnryXOzxBCYD9iLheOen8Zf6Bwa+qdaFrh6b UWdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=4jGWHLurbyA4/FNcd6iSsivOCVyFz9hIK/N30AnY3g4=; b=W8F0G9U/HPg+NzbLqxYcWTs/hJAlcIue+M3ZdlzoMYrdYzq2C4cDyUlIcPhp1ywsYn mXPpGnXjlEqZUyVMU9bGzXgZ0R761qssjbqSXSaCZhGRkEGUsij5HkWrMquwbvBZ+an3 txFQPvG5ZvHJ4nPfr0reJwjIOQiK0KMRrtCE4qNypD4LbJbY64f1+RgpHjpnAMswSbsz 4ZoSXR+GLU2DEX9Y58S8Tb80bgG8/a6DYJKCKqTaP39rOE1V9wFZW+jzc0yjEbOAIjme mYgXDgRjFsMgf02E3vY8EwPQS1xuUl3hN6PxcS0VfPLurENEdIPruAmqL2smWHDn5KH/ Rbpw== X-Gm-Message-State: AOAM533dgxMZ8BiuGIQ9QPTXk4+EUwXBDpk08XaQJJBJUkZ6TWaHL+rU XmUTvvTwn4Rfh5WCeUgRc4U= X-Google-Smtp-Source: ABdhPJxHqBolAxoEFyGpKEC/hKiG0pOutcmXOe9vu935+06JxkMbxCN0idm2sjgonBaATYsVlvRgYA== X-Received: by 2002:a5d:5244:: with SMTP id k4mr20074388wrc.77.1636731364446; Fri, 12 Nov 2021 07:36:04 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:04 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 2/8] leds: document additional use of blink_set for hardware control Date: Fri, 12 Nov 2021 16:35:51 +0100 Message-Id: <20211112153557.26941-3-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org blink_set can now be used also to configure blink modes when hardware control is supported and active. Trigger will try to use blink_set and a LED driver will use the trigger_data to configure the blink_modes once blink_set is called. Setting a brightness to LED_OFF will reset any blink mode and disable hardware control setting the LED off. Signed-off-by: Ansuel Smith --- Documentation/leds/leds-class.rst | 17 +++++++++++++++++ drivers/leds/led-class.c | 7 +++++++ include/linux/leds.h | 9 +++++++++ 3 files changed, 33 insertions(+) diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-class.rst index e5d266919a19..fa6e1cfc4628 100644 --- a/Documentation/leds/leds-class.rst +++ b/Documentation/leds/leds-class.rst @@ -202,6 +202,23 @@ hardware mode and any software only trigger will reject activation. On init an LED driver that support a hardware mode should reset every blink mode set by default. +Once a trigger has declared support for hardware-controlled blinks, it will use +blink_set() to try to offload his trigger on activation/configuration. +blink_set() will return 0 if the requested modes set in trigger_data can be +controlled by hardware or an error if both of the bitmap modes are not supported by +the hardware or there was a problem in the configuration. + +Following blink_set logic, setting brightness to LED_OFF with hardware control active +will reset any active blink mode and disable hardware control setting the LED to off. + +It's in the LED driver's interest to know how to elaborate the trigger data and report support +for a particular set of blink modes. For this exact reason explicit support for the specific +trigger is mandatory or the driver returns -EOPNOTSUPP if asked to enter hardware mode +with a not supported trigger. +If the driver returns -EOPNOTSUPP on hw_control_configure(), the trigger activation will +fail as the driver doesn't support that specific hardware blink mode or doesn't know +how to handle the provided trigger data. + Known Issues ============ diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index dbe9840863d0..ebd023e480ac 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -180,6 +180,13 @@ static int led_classdev_check_hw_control_functions(struct led_classdev *led_cdev led_cdev->hw_control_stop)) return -EINVAL; + /* blink_set is mandatory to configure the blink modes + * in hardware control. + */ + if ((LED_HARDWARE_CONTROLLED & led_cdev->flags) && + !led_cdev->blink_set) + return -EINVAL; + return 0; } #endif diff --git a/include/linux/leds.h b/include/linux/leds.h index c8e97fb9252f..fa929215cdcc 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -76,6 +76,7 @@ struct led_classdev { /* Lower 16 bits reflect status */ #define LED_SUSPENDED BIT(0) #define LED_UNREGISTERING BIT(1) +#define LED_HARDWARE_CONTROL BIT(2) /* Upper 16 bits reflect control information */ #define LED_CORE_SUSPENDRESUME BIT(16) #define LED_SYSFS_DISABLE BIT(17) @@ -123,6 +124,12 @@ struct led_classdev { * match the values specified exactly. * Deactivate blinking again when the brightness is set to LED_OFF * via the brightness_set() callback. + * With LED_HARDWARE_CONTROL set in LED flags blink_set will also + * configure blink modes requested by the current trigger if + * supported by the LED driver. + * Setting brightness to LED_OFF with hardware control active will + * reset any active blink mode and disable hardware control setting + * the LED off. */ int (*blink_set)(struct led_classdev *led_cdev, unsigned long *delay_on, @@ -165,6 +172,8 @@ struct led_classdev { */ bool (*hw_control_status)(struct led_classdev *led_cdev); /* Set LED in hardware mode and reset any blink mode active by default. + * A trigger supporting hardware mode will have to use blink_set to configure + * the modes. */ int (*hw_control_start)(struct led_classdev *led_cdev); /* Disable hardware mode for LED. It's advised to the LED driver to put it to From patchwork Fri Nov 12 15:35:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 518481 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 23F76C433EF for ; Fri, 12 Nov 2021 15:36:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0D76A60F14 for ; Fri, 12 Nov 2021 15:36:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235359AbhKLPjE (ORCPT ); Fri, 12 Nov 2021 10:39:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56932 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235290AbhKLPi6 (ORCPT ); Fri, 12 Nov 2021 10:38:58 -0500 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 391CAC061766; Fri, 12 Nov 2021 07:36:07 -0800 (PST) Received: by mail-wr1-x42c.google.com with SMTP id c4so16151925wrd.9; Fri, 12 Nov 2021 07:36:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=aDae9VxboKRaYt/bmJ4i7DdbNxdsamkoSFhw7jBOT04=; b=Mx+Y+GV2GKATil2tdoypyr/7UxBELXYHV/2UlF4TI/AgAdtRYcyARXmSxew1DUWdTe 6pRUW+Tj9P4xRUTPtxHlkA905GRrYIJDhGm9yR7AOMDuxR2lmlOcd/r2DUa/0aOaR8a3 76K6PtyN04d4/5OnoUenNb/hFOhz/I1FBNelAuYinCXtYmO9+lsOfSlcfG8SQ07DuBrx W13UdO4nJnKXH5VeV89UMRtQjcsPRri5QEToi4d+xiE5d0j4f2ve6Sc+bzWkvuS3E2D2 Srk8qmrBa+wGcmSqkEjFw06slBz1L+nS6vQ+i55r0qW9VeGAJYsdCaOyhpr0eSyQkqMm ZluQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=aDae9VxboKRaYt/bmJ4i7DdbNxdsamkoSFhw7jBOT04=; b=W9SdBOk6iG+LXCOvhIRrAD3X2r8cOFEWNMnHiZOCZpCIWHKs2ODU/pAr1KZuc9ZRB5 QnDFFW8IRwNWt6Isfd4iofOSaVYMYb0JW/6X2/a/oOULou4J/Nc887fkOCKH1/Pw/Dfs T1jq3WDnhGh8FzMReywAXJp3fgj64qQS/ShkgCtT3HgqbLlV2bkpzXxZPPJePF6O6dqN 2WaTq1Rue5aLsiAtoIXbXiorjIJaXn5/sfQ9FkDsp+/MZLG0/B8tDMmrchRz436KHBsL pwC3XvN7SHKEru1pGgCnWbqMrKviS8JU3jonPTmzbuQt8RP3kDFYxeOO3JEg8Z09FWI2 tLww== X-Gm-Message-State: AOAM531lOuTQESRZ94PwPqjb4uQ5ays/Kwm6P9qEuM765pgPCfsc6fMR m+C8s7FOnFmfR9okJV3M/fkt7jMeYvY= X-Google-Smtp-Source: ABdhPJzmvlESmo0uzPUq1oRR9TgG9ZUW5Zqaa7duYCqHfLYbWeQ6PCuFOjeN7412d1HsOs/ZWgo2Gw== X-Received: by 2002:adf:e8c8:: with SMTP id k8mr19192896wrn.135.1636731365698; Fri, 12 Nov 2021 07:36:05 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:05 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 3/8] leds: trigger: netdev: drop NETDEV_LED_MODE_LINKUP from mode Date: Fri, 12 Nov 2021 16:35:52 +0100 Message-Id: <20211112153557.26941-4-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org NETDEV_LED_MODE_LINKUP is not strictly a blink mode but really a status of the current situation of the carrier. It seems wrong to accomunate a link status to the blink mode list and would cause some confusion as someone would think that MODE_LINKUP is a separate mode that provide the netdev trigger with the other 3 LINK, RX and TX. Drop NETDEV_LED_MODE_LINKUP from mode list and convert to a simple bool that will be true or false based on the carrier link. No functional change intended. Signed-off-by: Ansuel Smith --- drivers/leds/trigger/ledtrig-netdev.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index d5e774d83021..66a81cc9b64d 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -50,10 +50,10 @@ struct led_netdev_data { unsigned int last_activity; unsigned long mode; + bool carrier_link_up; #define NETDEV_LED_LINK 0 #define NETDEV_LED_TX 1 #define NETDEV_LED_RX 2 -#define NETDEV_LED_MODE_LINKUP 3 }; enum netdev_led_attr { @@ -73,9 +73,9 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) if (!led_cdev->blink_brightness) led_cdev->blink_brightness = led_cdev->max_brightness; - if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode)) + if (!trigger_data->carrier_link_up) { led_set_brightness(led_cdev, LED_OFF); - else { + } else { if (test_bit(NETDEV_LED_LINK, &trigger_data->mode)) led_set_brightness(led_cdev, led_cdev->blink_brightness); @@ -131,10 +131,9 @@ static ssize_t device_name_store(struct device *dev, trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name); - clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = false; if (trigger_data->net_dev != NULL) - if (netif_carrier_ok(trigger_data->net_dev)) - set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev); trigger_data->last_activity = 0; @@ -315,7 +314,7 @@ static int netdev_trig_notify(struct notifier_block *nb, spin_lock_bh(&trigger_data->lock); - clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = false; switch (evt) { case NETDEV_CHANGENAME: case NETDEV_REGISTER: @@ -330,8 +329,7 @@ static int netdev_trig_notify(struct notifier_block *nb, break; case NETDEV_UP: case NETDEV_CHANGE: - if (netif_carrier_ok(dev)) - set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = netif_carrier_ok(dev); break; } From patchwork Fri Nov 12 15:35:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 517314 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F3A2DC433EF for ; Fri, 12 Nov 2021 15:36:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DE48160F14 for ; Fri, 12 Nov 2021 15:36:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235367AbhKLPjF (ORCPT ); Fri, 12 Nov 2021 10:39:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56938 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235312AbhKLPi7 (ORCPT ); Fri, 12 Nov 2021 10:38:59 -0500 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 961EAC061767; Fri, 12 Nov 2021 07:36:08 -0800 (PST) Received: by mail-wm1-x32e.google.com with SMTP id p3-20020a05600c1d8300b003334fab53afso7273701wms.3; Fri, 12 Nov 2021 07:36:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=9dARbb7WkhVmXUcr3NCB/e51nXglhcyLlTHLejpbidM=; b=XWmrH3IPUYnS+mLIjgNMCfLcimT41UaWMHFcYQCvd8vSFbzflyWY4S2KrsAtcFarSg puPnTXN2PU9+qGn96BDk5yFqFaq7HYixhGe+/n+Q0KlYBDaOIUbhTfZ9T+Mf00O+zkS2 Lag2HnoAj4L2mrMYVHLay0j7zo/Seur7uwHfY8TpDaUrEZvnXSwMIvu637WXPxXf/T4k dm2CHyjaUcAHlI/0OKWgQkzOdMB3O4It3H1DRiVqpXfonT9wmKp9enur0uxqwcX1k9t9 +Z3VWxi2oSsTzyJVbBnPaLKsroWsem0KGyO5m2WNOt9h/6iYZt4BAxzDln6/45qC+4QQ R2Wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9dARbb7WkhVmXUcr3NCB/e51nXglhcyLlTHLejpbidM=; b=szZ/Wfrg7fz1ejeL+0QyWRkPldmFG0blVXeXa9s4LDPHYYoghwe2XVIFyHfhUrX4/R gWIFgb1T0nkgp4W+eKTtBrHWyJmaH/vi66FQ8jk9gD5Quv3rIz/UrkDb7w5zi5eb8kPK 57MN93b9P38KiGt6Fqmz/9RV6CZHlh1iQ3OA/TrnrYFpIPdcqb09E8xj1G6jy1C5mx0o TGLIGzd6pVSwVrloWuaSintFzMPKO5Dyvj2EvGmJ/XcIK728KZcGQsSbo05HlxX+BERN RT2xn9LpFiZdr7KjEF+TaGzCY4RlQ7514GZLZlXH1itbaXxcaCMJHhlp1GW8n35kS/ca 1sJQ== X-Gm-Message-State: AOAM530Ld12ibNNAwJhg7ZWDXAoHRkNc7CdoODbQCck5vngap+SMeOgd 7gpJI4nCItQTcjiG6bHvBCQ= X-Google-Smtp-Source: ABdhPJzaY8AWB+11oUlqioLLTbrfwdAdLNSKtl/Oeo7zYvciPcrK5Qe2Cn6Gio4NMhbF3iS4fOWtnw== X-Received: by 2002:a05:600c:1c13:: with SMTP id j19mr35213711wms.175.1636731366981; Fri, 12 Nov 2021 07:36:06 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:06 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 4/8] leds: trigger: netdev: rename and expose NETDEV trigger enum and struct Date: Fri, 12 Nov 2021 16:35:53 +0100 Message-Id: <20211112153557.26941-5-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org A LED driver, to support hardware control, requires to support a specific trigger and requires to elaborate his trigger_data struct. Move netdev trigger data struct to leds.h to make it accessible by any LED driver that wants to add support for hardware control for the specific netdev trigger. Also rename NETDEV trigger enum modes to a more symbolic and descriptive name. Signed-off-by: Ansuel Smith --- drivers/leds/trigger/ledtrig-netdev.c | 48 ++++++++------------------- include/linux/leds.h | 29 ++++++++++++++++ 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 66a81cc9b64d..01e4544fa7b0 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -36,26 +36,6 @@ * */ -struct led_netdev_data { - spinlock_t lock; - - struct delayed_work work; - struct notifier_block notifier; - - struct led_classdev *led_cdev; - struct net_device *net_dev; - - char device_name[IFNAMSIZ]; - atomic_t interval; - unsigned int last_activity; - - unsigned long mode; - bool carrier_link_up; -#define NETDEV_LED_LINK 0 -#define NETDEV_LED_TX 1 -#define NETDEV_LED_RX 2 -}; - enum netdev_led_attr { NETDEV_ATTR_LINK, NETDEV_ATTR_TX, @@ -76,7 +56,7 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) if (!trigger_data->carrier_link_up) { led_set_brightness(led_cdev, LED_OFF); } else { - if (test_bit(NETDEV_LED_LINK, &trigger_data->mode)) + if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode)) led_set_brightness(led_cdev, led_cdev->blink_brightness); else @@ -85,8 +65,8 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) /* If we are looking for RX/TX start periodically * checking stats */ - if (test_bit(NETDEV_LED_TX, &trigger_data->mode) || - test_bit(NETDEV_LED_RX, &trigger_data->mode)) + if (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode)) schedule_delayed_work(&trigger_data->work, 0); } } @@ -153,13 +133,13 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf, switch (attr) { case NETDEV_ATTR_LINK: - bit = NETDEV_LED_LINK; + bit = TRIGGER_NETDEV_LINK; break; case NETDEV_ATTR_TX: - bit = NETDEV_LED_TX; + bit = TRIGGER_NETDEV_TX; break; case NETDEV_ATTR_RX: - bit = NETDEV_LED_RX; + bit = TRIGGER_NETDEV_RX; break; default: return -EINVAL; @@ -182,13 +162,13 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, switch (attr) { case NETDEV_ATTR_LINK: - bit = NETDEV_LED_LINK; + bit = TRIGGER_NETDEV_LINK; break; case NETDEV_ATTR_TX: - bit = NETDEV_LED_TX; + bit = TRIGGER_NETDEV_TX; break; case NETDEV_ATTR_RX: - bit = NETDEV_LED_RX; + bit = TRIGGER_NETDEV_RX; break; default: return -EINVAL; @@ -358,21 +338,21 @@ static void netdev_trig_work(struct work_struct *work) } /* If we are not looking for RX/TX then return */ - if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) && - !test_bit(NETDEV_LED_RX, &trigger_data->mode)) + if (!test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) && + !test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode)) return; dev_stats = dev_get_stats(trigger_data->net_dev, &temp); new_activity = - (test_bit(NETDEV_LED_TX, &trigger_data->mode) ? + (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ? dev_stats->tx_packets : 0) + - (test_bit(NETDEV_LED_RX, &trigger_data->mode) ? + (test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ? dev_stats->rx_packets : 0); if (trigger_data->last_activity != new_activity) { led_stop_software_blink(trigger_data->led_cdev); - invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode); + invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode); interval = jiffies_to_msecs( atomic_read(&trigger_data->interval)); /* base state is ON (link present) */ diff --git a/include/linux/leds.h b/include/linux/leds.h index fa929215cdcc..89ed009eecad 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -503,6 +503,35 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) #endif /* CONFIG_LEDS_TRIGGERS */ +/* Trigger specific trigger_data used by netdev trigger */ +#ifdef CONFIG_LEDS_TRIGGER_NETDEV +#include + +struct led_netdev_data { + spinlock_t lock; + + struct delayed_work work; + struct notifier_block notifier; + + struct led_classdev *led_cdev; + struct net_device *net_dev; + + char device_name[IFNAMSIZ]; + atomic_t interval; + unsigned int last_activity; + + unsigned long mode; + bool carrier_link_up; +}; + +/* Trigger specific bitmap blink mode used by netdev trigger */ +enum led_trigger_netdev_modes { + TRIGGER_NETDEV_LINK, + TRIGGER_NETDEV_TX, + TRIGGER_NETDEV_RX, +}; +#endif + /* Trigger specific functions */ #ifdef CONFIG_LEDS_TRIGGER_DISK void ledtrig_disk_activity(bool write); From patchwork Fri Nov 12 15:35:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 518480 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 369B6C433FE for ; Fri, 12 Nov 2021 15:36:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2583C610A8 for ; Fri, 12 Nov 2021 15:36:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235455AbhKLPjZ (ORCPT ); Fri, 12 Nov 2021 10:39:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235348AbhKLPjE (ORCPT ); Fri, 12 Nov 2021 10:39:04 -0500 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0B44DC061208; Fri, 12 Nov 2021 07:36:10 -0800 (PST) Received: by mail-wm1-x32a.google.com with SMTP id i8-20020a7bc948000000b0030db7b70b6bso10167567wml.1; Fri, 12 Nov 2021 07:36:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=KUnHZe884NpmCH64YY/DVb8a7ciFakw6u25MaWzmV24=; b=J4SOSH98HHCGQSAVio+ccNj/sbjCKXnOopykrhvOkwB9t6QdKx8I5F29poniW6ibow dSI77+gkoOWdL+S4X5dsKon+WCb7JKRvRoUGcCSAZN7s1EYDiWrtLvCMi5feDc2jNKDX Luk6SADfLrtE/cyPFR+r4Lf/lSietK6AhyPsSpHJCL/6vIS6GsRYjYwQjRrn2m8Cw0pG bYKdKZHwpxg/V3ccm/aqu43Utsa3mMgTNYUjW3hYWfswRyGg2Gorxat+owLR5dZgNBBx HPRxvWEGzYWLPgUL2mECTuFSJAMLKK7wsTOXGiGLVsndwZLdSXx5iAp02/9k2NwJ8sPZ mC7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=KUnHZe884NpmCH64YY/DVb8a7ciFakw6u25MaWzmV24=; b=Q2GN+28e4DFBAaPtKT+Q/y7r6FQm0Dkt1ol7s0ka60DTq9RGP83p6SXHNYVmTAJr24 6Vqj7W5V0cW2lP+zNdpJOLAQumugKfnaVVQlCkEmyxYydE5WIDejkUoqJBk+egt/s2V/ IYA2wnvdCtX+Czv8SSPOSjznsdJSTaWRLHVNHOVymbGuELOYsKsKkAs4R0uUjUi+lvtW Fqjt+C5GVBSTvsUZfkfGcXD0yfvZLuX8s5WfOP2r2Rac5khSpLrgJXmbuGq7zsusH+YT JzNfPDhExOcRHnu0S8r3AwwTVRLjUj38ifHRUwwgsiWz536QpSKIyKMXEFuQ67T5ibr3 AQIw== X-Gm-Message-State: AOAM531Cvc7L4sylJxKYYN7eJsJAtP+dkGddi/OMA47aqtYU1B0XtLeD 83D85UFn6+Xmb+NylJC4QIU= X-Google-Smtp-Source: ABdhPJzeznUt7IW6Dd+vBI87MWnzw5kem9yKH2c0tJEpaBkN69XK7Dic/to0MzcDPI1bajDpo7ahgQ== X-Received: by 2002:a1c:4686:: with SMTP id t128mr17771539wma.194.1636731368420; Fri, 12 Nov 2021 07:36:08 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:08 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 5/8] leds: trigger: netdev: add hardware control support Date: Fri, 12 Nov 2021 16:35:54 +0100 Message-Id: <20211112153557.26941-6-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Add hardware control support for the Netdev trigger. The trigger on config change will check if the requested trigger can set to blink mode using LED hardware mode and if every blink mode is supported, the trigger will enable hardware mode with the requested configuration. If there is at least one trigger that is not supported and can't run in hardware mode, then software mode will be used instead. Signed-off-by: Ansuel Smith --- drivers/leds/trigger/ledtrig-netdev.c | 30 +++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 01e4544fa7b0..74c9a6ecfbbf 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -44,9 +44,31 @@ enum netdev_led_attr { static void set_baseline_state(struct led_netdev_data *trigger_data) { - int current_brightness; + int current_brightness, can_offload; struct led_classdev *led_cdev = trigger_data->led_cdev; + if (LED_HARDWARE_CONTROLLED & led_cdev->flags) { + /* Check if blink mode can he set in hardware mode. + * The LED driver will chose a interval based on the trigger_data + * and its implementation. + */ + can_offload = led_cdev->blink_set(led_cdev, 0, 0); + + /* If blink_set doesn't return error we can run in hardware mode + * So actually activate it. + */ + if (!can_offload) { + led_cdev->hw_control_start(led_cdev); + return; + } + } + + /* If LED supports only hardware mode and we reach this point, + * then skip any software handling. + */ + if (!(LED_SOFTWARE_CONTROLLED & led_cdev->flags)) + return; + current_brightness = led_cdev->brightness; if (current_brightness) led_cdev->blink_brightness = current_brightness; @@ -395,8 +417,11 @@ static int netdev_trig_activate(struct led_classdev *led_cdev) rc = register_netdevice_notifier(&trigger_data->notifier); if (rc) - kfree(trigger_data); + goto err; + return 0; +err: + kfree(trigger_data); return rc; } @@ -416,6 +441,7 @@ static void netdev_trig_deactivate(struct led_classdev *led_cdev) static struct led_trigger netdev_led_trigger = { .name = "netdev", + .supported_blink_modes = SOFTWARE_HARDWARE, .activate = netdev_trig_activate, .deactivate = netdev_trig_deactivate, .groups = netdev_trig_groups, From patchwork Fri Nov 12 15:35:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 517313 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6F5CAC433EF for ; Fri, 12 Nov 2021 15:36:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 56E5061039 for ; Fri, 12 Nov 2021 15:36:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235478AbhKLPj0 (ORCPT ); Fri, 12 Nov 2021 10:39:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56972 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235358AbhKLPjE (ORCPT ); Fri, 12 Nov 2021 10:39:04 -0500 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 84E7EC06120D; Fri, 12 Nov 2021 07:36:11 -0800 (PST) Received: by mail-wm1-x329.google.com with SMTP id b184-20020a1c1bc1000000b0033140bf8dd5so7014525wmb.5; Fri, 12 Nov 2021 07:36:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=oJEpltYphpc/zLEEBz/4uTdZYomePaTobwU7mT3TYiE=; b=iQzYX3VZTmkz4zyTwS5qiIZuUw83l5QMby/hBe3lwC2UxliEcMRAp0XrXSEhCztBlq b7wPbgiyM+S1iA6KBuPSjonD/UHUhKHc9RzgM5o9qJoeQia6KwscSGvCZogY9V98WB21 iYWlZB04GIi9weuswOgoh8gBiHeIL2jcqx//M4pvbbtO8rqpOow42LGqfjVbY9p4blB/ eZeq3R8fDizkmQF8qb7Fo/3n9qrqTQpuKUo0m6suje5rNVtt5+VNoY4esC2zxewroLVp Rls6OIdviFtCmo+Di1DHTXtuGA/OPLE1Pnoc31ba95iz8E61+S1jNnPHurlubv7gOYM+ +o8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=oJEpltYphpc/zLEEBz/4uTdZYomePaTobwU7mT3TYiE=; b=WPcXScwas5EvMwtCnywt8LXO26uZdiuR1FustodYo/ASJCM+r1WgKwkLmF2BI4W11F VOtgjHH+3eF+vK9469HKNaZkJIcX1n0aOfM53GQ7684xY9ouZSIFQHS0yyNq5VtLMHYW joiXu57zbRZhew5fuZs7xCLDpRE9cY1tMnWKma2jR53o153E9h/r+t51KPbfo6M8Zijq dwpI97swksvH+GcNqHnLWw8JJnnFi7EHO8EfT2Wk1LyHth03HinC2fInZAboerRA14uW NSBn+rh4ve9hVDfX8SoH4JIMl6t0DUCuvflvWw/GZLLiYo+R3++ocaA0L0tJKHXYCC5Z WjNg== X-Gm-Message-State: AOAM531SdNXTLcKxC1+wTAkJiDck0GOU9y9mh3eqLRTyjzaMFH+jhDvz Fk6GDIgS3IT773JCc9566kVtIm9dd6E= X-Google-Smtp-Source: ABdhPJwgT9Avjp3XQdfuyfiBR5UKJNF48LLs6Z7YhnWzsX6suW7a9U7A/6S3B3sAJFvLOXu9kl+lJA== X-Received: by 2002:a05:600c:3510:: with SMTP id h16mr34967324wmq.144.1636731369778; Fri, 12 Nov 2021 07:36:09 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:09 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 6/8] leds: trigger: add hardware-phy-activity trigger Date: Fri, 12 Nov 2021 16:35:55 +0100 Message-Id: <20211112153557.26941-7-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Add Hardware Only Trigger for PHY Activity. This special trigger is used to configure and expose the different HW trigger that are provided by the PHY. Each blink mode can be configured by sysfs and on trigger activation the hardware mode is enabled. This currently implement these hw triggers: - blink_tx: Blink LED on tx packet receive - blink_rx: Blink LED on rx packet receive - link_10m: Keep LED on with 10m link speed - link_100m: Keep LED on with 100m link speed - link_1000m: Keep LED on with 1000m link speed - half_duplex: Keep LED on with half duplex link - full_duplex: Keep LED on with full duplex link - option_linkup_over: Ignore blink tx/rx with link keep not active - option_power_on_reset: Keep LED on with switch reset The trigger will check if the LED driver support the various blink modes and will expose the blink modes in sysfs. It will finally enable hw mode for the LED without configuring any rule. It's in the led driver interest the detection and knowing how to elaborate the passed flags and should report -EOPNOTSUPP otherwise. The different hw triggers are exposed in the led sysfs dir under the hardware-phy-activity subdir. Signed-off-by: Ansuel Smith --- drivers/leds/trigger/Kconfig | 27 +++ drivers/leds/trigger/Makefile | 1 + .../trigger/ledtrig-hardware-phy-activity.c | 180 ++++++++++++++++++ include/linux/leds.h | 24 +++ 4 files changed, 232 insertions(+) create mode 100644 drivers/leds/trigger/ledtrig-hardware-phy-activity.c diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 18a8970bfae6..ea7b33995e8d 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -162,4 +162,31 @@ config LEDS_TRIGGER_TTY When build as a module this driver will be called ledtrig-tty. +config LEDS_TRIGGER_HARDWARE_PHY_ACTIVITY + tristate "LED Trigger for PHY Activity for Hardware Controlled LED" + help + This allows LEDs to run by hardware and offloaded based on some + rules. The LED will blink or be on based on the PHY + activity for example on packet receive or based on the link speed. + + The current supported offload triggers are: + - blink_tx: Blink LED on tx packet receive + - blink_rx: Blink LED on rx packet receive + - keep_link_10m: Keep LED on with 10m link speed + - keep_link_100m: Keep LED on with 100m link speed + - keep_link_1000m: Keep LED on with 1000m link speed + - keep_half_duplex: Keep LED on with half duplex link + - keep_full_duplex: Keep LED on with full duplex link + - option_linkup_over: Blink rules are ignored with absent link + - option_power_on_reset: Power ON Led on Switch/PHY reset + - option_blink_2hz: Set blink speed at 2hz for every blink event + - option_blink_4hz: Set blink speed at 4hz for every blink event + - option_blink_8hz: Set blink speed at 8hz for every blink event + + These blink modes are present in the LED sysfs dir under + hardware-phy-activity if supported by the LED driver. + + This trigger can be used only by LEDs that support Hardware mode. + + endif # LEDS_TRIGGERS diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index 25c4db97cdd4..f5d0d0057d2b 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o +obj-$(CONFIG_LEDS_TRIGGER_HARDWARE_PHY_ACTIVITY) += ledtrig-hardware-phy-activity.o diff --git a/drivers/leds/trigger/ledtrig-hardware-phy-activity.c b/drivers/leds/trigger/ledtrig-hardware-phy-activity.c new file mode 100644 index 000000000000..4ac51011d029 --- /dev/null +++ b/drivers/leds/trigger/ledtrig-hardware-phy-activity.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include + +#define PHY_ACTIVITY_MAX_BLINK_MODE 9 + +static ssize_t blink_mode_common_show(int blink_mode, struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + struct hardware_phy_activity_data *trigger_data = led_cdev->trigger_data; + int val; + + val = test_bit(blink_mode, &trigger_data->mode); + return sprintf(buf, "%d\n", val ? 1 : 0); +} + +static ssize_t blink_mode_common_store(int blink_mode, struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + struct hardware_phy_activity_data *trigger_data = led_cdev->trigger_data; + unsigned long state; + int ret; + + ret = kstrtoul(buf, 0, &state); + if (ret) + return ret; + + if (!!state) + set_bit(blink_mode, &trigger_data->mode); + else + clear_bit(blink_mode, &trigger_data->mode); + + /* Update the configuration with every change */ + led_cdev->blink_set(led_cdev, 0, 0); + return size; +} + +#define DEFINE_HW_BLINK_MODE(blink_mode_name, blink_bit) \ + static ssize_t blink_mode_name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ + { \ + return blink_mode_common_show(blink_bit, dev, attr, buf); \ + } \ + static ssize_t blink_mode_name##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t size) \ + { \ + return blink_mode_common_store(blink_bit, dev, attr, buf, size); \ + } \ + DEVICE_ATTR_RW(blink_mode_name) + +/* Expose sysfs for every blink to be configurable from userspace */ +DEFINE_HW_BLINK_MODE(blink_tx, TRIGGER_PHY_ACTIVITY_BLINK_TX); +DEFINE_HW_BLINK_MODE(blink_rx, TRIGGER_PHY_ACTIVITY_BLINK_RX); +DEFINE_HW_BLINK_MODE(link_10M, TRIGGER_PHY_ACTIVITY_LINK_10M); +DEFINE_HW_BLINK_MODE(link_100M, TRIGGER_PHY_ACTIVITY_LINK_100M); +DEFINE_HW_BLINK_MODE(link_1000M, TRIGGER_PHY_ACTIVITY_LINK_1000M); +DEFINE_HW_BLINK_MODE(half_duplex, TRIGGER_PHY_ACTIVITY_HALF_DUPLEX); +DEFINE_HW_BLINK_MODE(full_duplex, TRIGGER_PHY_ACTIVITY_FULL_DUPLEX); +DEFINE_HW_BLINK_MODE(option_linkup_over, TRIGGER_PHY_ACTIVITY_OPTION_LINKUP_OVER); +DEFINE_HW_BLINK_MODE(option_power_on_reset, TRIGGER_PHY_ACTIVITY_OPTION_POWER_ON_RESET); + +static struct attribute *blink_mode_tbl[PHY_ACTIVITY_MAX_BLINK_MODE] = { + &dev_attr_blink_tx.attr, + &dev_attr_blink_rx.attr, + &dev_attr_link_10M.attr, + &dev_attr_link_100M.attr, + &dev_attr_link_1000M.attr, + &dev_attr_half_duplex.attr, + &dev_attr_full_duplex.attr, + &dev_attr_option_linkup_over.attr, + &dev_attr_option_power_on_reset.attr, +}; + +/* The attrs will be placed dynamically based on the supported triggers */ +// static struct attribute *phy_activity_attrs[PHY_ACTIVITY_MAX_TRIGGERS + 1]; + +static int hardware_phy_activity_activate(struct led_classdev *led_cdev) +{ + struct hardware_phy_activity_data *trigger_data; + struct attribute_group *phy_activity_group; + struct attribute **phy_activity_attrs; + unsigned long supported_mode = 0; + int i, j, count = 0, ret; + + trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL); + if (!trigger_data) + return -ENOMEM; + + led_set_trigger_data(led_cdev, trigger_data); + + /* Check supported blink modes + * Request one mode at time and check if it can run in hardware mode + */ + for (i = 0; i < PHY_ACTIVITY_MAX_BLINK_MODE; i++) { + trigger_data->mode = 0; + + set_bit(i, &trigger_data->mode); + + if (!led_cdev->blink_set(led_cdev, 0, 0)) { + set_bit(i, &supported_mode); + count++; + } + } + + if (!count) { + ret = -EINVAL; + goto fail_alloc_driver_data; + } + + phy_activity_group = kzalloc(sizeof(phy_activity_group), GFP_KERNEL); + if (!phy_activity_group) { + ret = -ENOMEM; + goto fail_alloc_driver_data; + } + + phy_activity_attrs = kcalloc(count + 1, sizeof(struct attribute *), GFP_KERNEL); + if (!phy_activity_attrs) + goto fail_alloc_attrs; + + phy_activity_group->name = "hardware-phy-activity"; + phy_activity_group->attrs = phy_activity_attrs; + + for (i = 0, j = 0; i < count; i++) + if (test_bit(i, &supported_mode)) + phy_activity_attrs[j++] = blink_mode_tbl[i]; + + ret = device_add_group(led_cdev->dev, phy_activity_group); + if (ret) + goto fail_alloc_group; + + trigger_data->group = phy_activity_group; + + /* Enable hardware mode. No custom configuration is applied, + * the LED driver will use whatever default configuration is + * currently configured. + */ + ret = led_cdev->hw_control_start(led_cdev); + if (ret) + goto fail_alloc_group; + + return 0; +fail_alloc_driver_data: + kfree(trigger_data); +fail_alloc_group: + kfree(phy_activity_attrs); +fail_alloc_attrs: + kfree(phy_activity_group); + return ret; +} + +static void hardware_phy_activity_deactivate(struct led_classdev *led_cdev) +{ + struct hardware_phy_activity_data *trigger_data = led_get_trigger_data(led_cdev); + + led_cdev->hw_control_stop(led_cdev); + device_remove_group(led_cdev->dev, trigger_data->group); + kfree(trigger_data->group->attrs); + kfree(trigger_data->group); + kfree(trigger_data); +} + +static struct led_trigger hardware_phy_activity_trigger = { + .supported_blink_modes = HARDWARE_ONLY, + .name = "hardware-phy-activity", + .activate = hardware_phy_activity_activate, + .deactivate = hardware_phy_activity_deactivate, +}; + +static int __init hardware_phy_activity_init(void) +{ + return led_trigger_register(&hardware_phy_activity_trigger); +} +device_initcall(hardware_phy_activity_init); diff --git a/include/linux/leds.h b/include/linux/leds.h index 89ed009eecad..f6cdca894c53 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -532,6 +532,30 @@ enum led_trigger_netdev_modes { }; #endif +#ifdef CONFIG_LEDS_TRIGGER_HARDWARE_PHY_ACTIVITY +/* 3 main category for offload trigger: + * - blink: the led will blink on trigger + * - keep: the led will be kept on with condition + * - option: a configuration value internal to the led on how offload works + */ +enum hardware_phy_activity { + TRIGGER_PHY_ACTIVITY_BLINK_TX, /* Blink on TX traffic */ + TRIGGER_PHY_ACTIVITY_BLINK_RX, /* Blink on RX traffic */ + TRIGGER_PHY_ACTIVITY_LINK_10M, /* LED on with 10M link */ + TRIGGER_PHY_ACTIVITY_LINK_100M, /* LED on with 100M link */ + TRIGGER_PHY_ACTIVITY_LINK_1000M, /* LED on with 1000M link */ + TRIGGER_PHY_ACTIVITY_HALF_DUPLEX, /* LED on with Half-Duplex link */ + TRIGGER_PHY_ACTIVITY_FULL_DUPLEX, /* LED on with Full-Duplex link */ + TRIGGER_PHY_ACTIVITY_OPTION_LINKUP_OVER, /* LED will be on with KEEP blink mode and blink on BLINK traffic */ + TRIGGER_PHY_ACTIVITY_OPTION_POWER_ON_RESET, /* LED will be on Switch reset */ +}; + +struct hardware_phy_activity_data { + unsigned long mode; + struct attribute_group *group; +}; +#endif + /* Trigger specific functions */ #ifdef CONFIG_LEDS_TRIGGER_DISK void ledtrig_disk_activity(bool write); From patchwork Fri Nov 12 15:35:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 518479 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6F3D4C433FE for ; Fri, 12 Nov 2021 15:36:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5930060F14 for ; Fri, 12 Nov 2021 15:36:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235494AbhKLPjj (ORCPT ); Fri, 12 Nov 2021 10:39:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56982 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235364AbhKLPjF (ORCPT ); Fri, 12 Nov 2021 10:39:05 -0500 Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D05BCC06121D; Fri, 12 Nov 2021 07:36:12 -0800 (PST) Received: by mail-wm1-x32b.google.com with SMTP id y84-20020a1c7d57000000b00330cb84834fso10180795wmc.2; Fri, 12 Nov 2021 07:36:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=wL7L0zM+ReIseP46K3nvlZUucTcfqTz6dCmuGO1pTzA=; b=OJJb5R49e9R6it/75kGU7nTKchVC0K89cNz5824D5VMHiCJTgNQO7/1dya3l0qOywM lTjt2m0yD/w2bs2oieiOM1Um4gSxjQqwrALsvwTTVFVvoMmeoUAAr8y9Q0YUaRBx3v/I M0vQ2wptS/46D+wt7bXRQ+4W4Vfw80mzH+iNxUhZ1kvi/oEttpXMhVZrP+uHedE/cTZI NC3JFuoNo1g+1CjqKBJGeo3TdyOBRerVkP4r7MqpeTn8F6XChMZ5+vdMQlAJqtRuQyU4 xnmBILvYTC04qnIAXK/at1tWxj6RUe3zcpbS/XBFfC5T0Vy8tUTICgH+WrgXxrb0ULts 01xQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wL7L0zM+ReIseP46K3nvlZUucTcfqTz6dCmuGO1pTzA=; b=BVB3AZG7u1jD8DaKf5zk7Myf8NyYer+W8FHtcjHneZ3hpgD9yMWdgtsBFP+E7QmcOK lLiKdhopF/FbXrhvZBoD0Y1jNCYBcb7BpFUYfyA5cmxCzmpKJTgh88xYvwfxEuYlBkyr tcXtw5e/I2vxY6nTnykIeeo95BFFZwPSP+no+153fywrw9/br8hqfUrfGEAi20Cv+fPy bFWf8/6HdMahoJ98PEWyM5LZoh/HMJ7kkp4cJg3Y5FUfEhoOuZtnuV2lj9ea3dObohRw +rXQe2mMpE6T3sal3+kJpzamLUV9Jaf7LbqVl5W49KNEwD3Up4CZkHwcGXtb1n+sOQXU PPyA== X-Gm-Message-State: AOAM531K79ZWIJyODbicoMYm8+mxPHCHpIZJqtbP0rZCPsaAoeRvcQVG IqWCgW1Y2qKzfd8525S4NQAQlsAMXIU= X-Google-Smtp-Source: ABdhPJz8onwLSFdn5Os0pQ8royLNYvknWj9Qy/pIsXOl1hMo5Nj8dcyiLl9qEJ7xn/QcCeTE8ex6Bg== X-Received: by 2002:a05:600c:21c3:: with SMTP id x3mr17878169wmj.13.1636731371113; Fri, 12 Nov 2021 07:36:11 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:10 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 7/8] net: dsa: qca8k: add LEDs support Date: Fri, 12 Nov 2021 16:35:56 +0100 Message-Id: <20211112153557.26941-8-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Add LEDs support for qca8k Switch Family. This will provide the LEDs hardware API to permit the PHY LED to support hardware mode. Each port have at least 3 LEDs and they can HW blink, set on/off or follow blink modes configured with the LED in hardware mode.. This adds support for 2 hardware trigger netdev and hardware-phy-activity. Signed-off-by: Ansuel Smith --- drivers/net/dsa/Kconfig | 11 + drivers/net/dsa/Makefile | 1 + drivers/net/dsa/qca8k-leds.c | 423 +++++++++++++++++++++++++++++++++++ drivers/net/dsa/qca8k.c | 8 +- drivers/net/dsa/qca8k.h | 65 ++++++ 5 files changed, 506 insertions(+), 2 deletions(-) create mode 100644 drivers/net/dsa/qca8k-leds.c diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 7b1457a6e327..1e59ee50ec92 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -67,6 +67,17 @@ config NET_DSA_QCA8K This enables support for the Qualcomm Atheros QCA8K Ethernet switch chips. +config NET_DSA_QCA8K_LEDS_SUPPORT + tristate "Qualcomm Atheros QCA8K Ethernet switch family LEDs support" + select NET_DSA_QCA8K + select LEDS_TRIGGERS + select LEDS_TRIGGER_NETDEV + select LEDS_TRIGGER_HARDWARE_PHY_ACTIVITY + help + This enables support for LEDs present on the Qualcomm Atheros + QCA8K Ethernet switch chips. This requires the LEDs offload + triggers support as it can run in offload mode. + config NET_DSA_REALTEK_SMI tristate "Realtek SMI Ethernet switch family support" select NET_DSA_TAG_RTL4_A diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index 8da1569a34e6..fb1e7d0cf126 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o +obj-$(CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT) += qca8k-leds.o obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o rtl8365mb.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o diff --git a/drivers/net/dsa/qca8k-leds.c b/drivers/net/dsa/qca8k-leds.c new file mode 100644 index 000000000000..729e55dedc9d --- /dev/null +++ b/drivers/net/dsa/qca8k-leds.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +#include "qca8k.h" + +static int +qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info) +{ + int shift; + + switch (port_num) { + case 0: + reg_info->reg = QCA8K_LED_CTRL_REG(led_num); + reg_info->shift = 14; + break; + case 1: + case 2: + case 3: + reg_info->reg = QCA8K_LED_CTRL_REG(3); + shift = 2 * led_num + (6 * (port_num - 1)); + + reg_info->shift = 8 + shift; + + break; + case 4: + reg_info->reg = QCA8K_LED_CTRL_REG(led_num); + reg_info->shift = 30; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +qca8k_get_control_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info) +{ + reg_info->reg = QCA8K_LED_CTRL_REG(led_num); + + /* 6 total control rule: + * 3 control rules for phy0-3 that applies to all their leds + * 3 control rules for phy4 + */ + if (port_num == 4) + reg_info->shift = 16; + else + reg_info->shift = 0; + + return 0; +} + +static void +qca8k_check_rules(unsigned long *mode, u32 *offload_trigger, + int trigger_bit, int blink_mode, bool read) +{ + if (read) { + if (*offload_trigger & blink_mode) + set_bit(trigger_bit, mode); + } else { + if (test_bit(trigger_bit, mode)) + *offload_trigger |= blink_mode; + } +} + +static int +qca8k_parse_trigger_hardware_phy_activity(struct led_classdev *ldev, u32 *offload_trigger, + u32 *mask, bool read) +{ + struct hardware_phy_activity_data *trigger_data = led_get_trigger_data(ldev); + unsigned long rules = trigger_data->mode; + + /* Parse rule to hardware phy activity trigger */ + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_BLINK_TX, + QCA8K_LED_TX_BLINK_MASK, false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_BLINK_RX, + QCA8K_LED_RX_BLINK_MASK, false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_LINK_10M, + QCA8K_LED_LINK_10M_EN_MASK, false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_LINK_100M, + QCA8K_LED_LINK_100M_EN_MASK, false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_LINK_1000M, + QCA8K_LED_LINK_1000M_EN_MASK, false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_HALF_DUPLEX, + QCA8K_LED_HALF_DUPLEX_MASK, false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_FULL_DUPLEX, + QCA8K_LED_FULL_DUPLEX_MASK, false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_PHY_ACTIVITY_OPTION_LINKUP_OVER, + QCA8K_LED_LINKUP_OVER_MASK, false); + + if (!*offload_trigger) + return -EOPNOTSUPP; + + *mask = *offload_trigger; + + return 0; +} + +static int +qca8k_parse_trigger_netdev(struct led_classdev *ldev, u32 *offload_trigger, + u32 *mask, bool read) +{ + struct led_netdev_data *trigger_data = led_get_trigger_data(ldev); + unsigned long rules = trigger_data->mode; + + /* Parse rule to netdev trigger */ + qca8k_check_rules(&rules, offload_trigger, TRIGGER_NETDEV_TX, QCA8K_LED_TX_BLINK_MASK, + false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_NETDEV_RX, QCA8K_LED_RX_BLINK_MASK, + false); + qca8k_check_rules(&rules, offload_trigger, TRIGGER_NETDEV_LINK, + QCA8K_LED_LINK_10M_EN_MASK | QCA8K_LED_LINK_100M_EN_MASK | + QCA8K_LED_LINK_1000M_EN_MASK, + false); + + if (!*offload_trigger) + return -EOPNOTSUPP; + + *mask = *offload_trigger; + + return 0; +} + +static int +qca8k_parse_trigger(struct led_classdev *ldev, u32 *offload_trigger, u32 *mask, + bool read) +{ + struct led_trigger *trigger = ldev->trigger; + int ret; + + if (strcmp(trigger->name, "hardware-phy-activity") && + strcmp(trigger->name, "netdev")) + return -EINVAL; + + if (!strcmp(trigger->name, "hardware-phy-activity")) + ret = qca8k_parse_trigger_hardware_phy_activity(ldev, offload_trigger, mask, read); + + if (!strcmp(trigger->name, "netdev")) + ret = qca8k_parse_trigger_netdev(ldev, offload_trigger, mask, read); + + return ret; +} + +static int +qca8k_cled_blink_set(struct led_classdev *ldev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 offload_trigger = 0, mask; + int ret; + + /* With no trigger selected, use the blink 4hz mode */ + if (!ldev->trigger) { + if (*delay_on == 0 && *delay_off == 0) { + *delay_on = 125; + *delay_off = 125; + } + + if (*delay_on != 125 || *delay_off != 125) { + /* The hardware only supports blinking at 4Hz. Fall back + * to software implementation in other cases. + */ + return -EINVAL; + } + + qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info); + + return qca8k_rmw(priv, reg_info.reg, + GENMASK(1, 0) << reg_info.shift, + QCA8K_LED_ALWAYS_BLINK_4HZ << reg_info.shift); + } + + /* Check trigger compatibility + * With these trigger blink_set will configure the LED pattern reg + */ + ret = qca8k_parse_trigger(ldev, &offload_trigger, &mask, false); + if (ret) + return ret; + + qca8k_get_control_led_reg(led->port_num, led->led_num, ®_info); + + /* Set 4hz by default */ + if (*delay_on == 0 && *delay_off == 0) + offload_trigger |= QCA8K_LED_BLINK_4HZ; + + if (*delay_on == 250 || *delay_off == 250) + offload_trigger |= QCA8K_LED_BLINK_2HZ; + + if (*delay_on == 125 || *delay_off == 125) + offload_trigger |= QCA8K_LED_BLINK_4HZ; + + if (*delay_on == 62 || *delay_off == 62) + offload_trigger |= QCA8K_LED_BLINK_8HZ; + + return qca8k_rmw(priv, reg_info.reg, + mask << reg_info.shift, + offload_trigger << reg_info.shift); +} + +static void +qca8k_led_brightness_set(struct qca8k_led *led, + enum led_brightness b) +{ + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 val = QCA8K_LED_ALWAYS_OFF; + + qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info); + + if (b) + val = QCA8K_LED_ALWAYS_ON; + + qca8k_rmw(priv, reg_info.reg, + GENMASK(1, 0) << reg_info.shift, + val << reg_info.shift); +} + +static void +qca8k_cled_brightness_set(struct led_classdev *ldev, + enum led_brightness b) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + + return qca8k_led_brightness_set(led, b); +} + +static enum led_brightness +qca8k_led_brightness_get(struct qca8k_led *led) +{ + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 val; + int ret; + + qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info); + + ret = qca8k_read(priv, reg_info.reg, &val); + if (ret) + return 0; + + val >>= reg_info.shift; + val &= GENMASK(1, 0); + + return val > 0 ? 1 : 0; +} + +static enum led_brightness +qca8k_cled_brightness_get(struct led_classdev *ldev) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + + return qca8k_led_brightness_get(led); +} + +static int +qca8k_cled_hw_control(struct led_classdev *ldev, bool enable) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 val = QCA8K_LED_ALWAYS_OFF; + + qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info); + + if (enable) + val = QCA8K_LED_RULE_CONTROLLED; + + return qca8k_rmw(priv, reg_info.reg, + GENMASK(1, 0) << reg_info.shift, + val << reg_info.shift); +} + +static int +qca8k_cled_hw_control_start(struct led_classdev *led_cdev) +{ + return qca8k_cled_hw_control(led_cdev, true); +} + +static int +qca8k_cled_hw_control_stop(struct led_classdev *led_cdev) +{ + return qca8k_cled_hw_control(led_cdev, false); +} + +static bool +qca8k_cled_hw_control_status(struct led_classdev *ldev) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 val; + + qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info); + + qca8k_read(priv, reg_info.reg, &val); + + val >>= reg_info.shift; + val &= GENMASK(1, 0); + + return val == QCA8K_LED_RULE_CONTROLLED; +} + +static int +qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num) +{ + struct fwnode_handle *led = NULL, *leds = NULL; + struct qca8k_led_pattern_en reg_info; + struct led_init_data init_data = { }; + struct qca8k_led *port_led; + int led_num, port_index; + const char *state; + int ret; + + leds = fwnode_get_named_child_node(port, "leds"); + if (!leds) { + dev_dbg(priv->dev, "No Leds node specified in device tree for port %d!\n", + port_num); + return 0; + } + + fwnode_for_each_child_node(leds, led) { + /* Reg rapresent the led number of the port. + * Each port can have at least 3 leds attached + * Commonly: + * 1. is gigabit led + * 2. is mbit led + * 3. additional status led + */ + if (fwnode_property_read_u32(led, "reg", &led_num)) + continue; + + if (led_num >= QCA8K_LED_PORT_COUNT) { + dev_warn(priv->dev, "Invalid LED reg defined %d", port_num); + continue; + } + + port_index = 3 * port_num + led_num; + + port_led = &priv->ports_led[port_index]; + port_led->port_num = port_num; + port_led->led_num = led_num; + port_led->priv = priv; + + ret = fwnode_property_read_string(led, "default-state", &state); + if (!ret) { + if (!strcmp(state, "on")) { + port_led->cdev.brightness = 1; + qca8k_led_brightness_set(port_led, 1); + } else if (!strcmp(state, "off")) { + port_led->cdev.brightness = 0; + qca8k_led_brightness_set(port_led, 0); + } else if (!strcmp(state, "keep")) { + port_led->cdev.brightness = + qca8k_led_brightness_get(port_led); + } + } + + qca8k_get_enable_led_reg(port_led->port_num, port_led->led_num, ®_info); + + /* Reset blink mode set by default */ + ret = qca8k_rmw(priv, reg_info.reg, QCA8K_LED_RULE_MASK << reg_info.shift, + 0 << reg_info.shift); + + /* 3 brightness settings can be applied from Documentation: + * 0 always off + * 1 blink at 4Hz + * 2 always on + * 3 rule controlled + * Suppots only 2 mode: (pcb limitation, with always on and blink + * only the last led is set to this mode) + * 0 always off (sets all leds off) + * 3 rule controlled + */ + port_led->cdev.flags |= LED_SOFTWARE_CONTROLLED; + port_led->cdev.flags |= LED_HARDWARE_CONTROLLED; + port_led->cdev.max_brightness = 1; + port_led->cdev.brightness_set = qca8k_cled_brightness_set; + port_led->cdev.brightness_get = qca8k_cled_brightness_get; + port_led->cdev.blink_set = qca8k_cled_blink_set; + port_led->cdev.hw_control_start = qca8k_cled_hw_control_start; + port_led->cdev.hw_control_stop = qca8k_cled_hw_control_stop; + port_led->cdev.hw_control_status = qca8k_cled_hw_control_status; + init_data.default_label = ":port"; + init_data.devicename = "qca8k"; + init_data.fwnode = led; + + ret = devm_led_classdev_register_ext(priv->dev, &port_led->cdev, &init_data); + if (ret) + dev_warn(priv->dev, "Failed to int led"); + } + + return 0; +} + +int +qca8k_setup_led_ctrl(struct qca8k_priv *priv) +{ + struct fwnode_handle *mdio, *port; + int port_num; + int ret; + + mdio = device_get_named_child_node(priv->dev, "mdio"); + if (!mdio) { + dev_info(priv->dev, "No MDIO node specified in device tree!\n"); + return 0; + } + + fwnode_for_each_child_node(mdio, port) { + if (fwnode_property_read_u32(port, "reg", &port_num)) + continue; + + /* Each port can have at least 3 different leds attached */ + ret = qca8k_parse_port_leds(priv, port, port_num); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index a429c9750add..10b2b47b2156 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -148,7 +148,7 @@ qca8k_set_page(struct mii_bus *bus, u16 page) return 0; } -static int +int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) { struct mii_bus *bus = priv->bus; @@ -192,7 +192,7 @@ qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) return ret; } -static int +int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) { struct mii_bus *bus = priv->bus; @@ -1109,6 +1109,10 @@ qca8k_setup(struct dsa_switch *ds) if (ret) return ret; + ret = qca8k_setup_led_ctrl(priv); + if (ret) + return ret; + /* Make sure MAC06 is disabled */ ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL, QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index 128b8cf85e08..f68f037fe909 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h @@ -11,6 +11,7 @@ #include #include #include +#include #define QCA8K_NUM_PORTS 7 #define QCA8K_NUM_CPU_PORTS 2 @@ -74,6 +75,43 @@ #define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) #define QCA8K_MDIO_MASTER_MAX_PORTS 5 #define QCA8K_MDIO_MASTER_MAX_REG 32 + +/* LED control register */ +#define QCA8K_LED_COUNT 15 +#define QCA8K_LED_PORT_COUNT 3 +#define QCA8K_LED_RULE_COUNT 6 +#define QCA8K_LED_RULE_MAX 11 +#define QCA8K_LED_CTRL_REG(_i) (0x050 + (_i) * 4) +#define QCA8K_LED_CTRL0_REG 0x50 +#define QCA8K_LED_CTRL1_REG 0x54 +#define QCA8K_LED_CTRL2_REG 0x58 +#define QCA8K_LED_CTRL3_REG 0x5C +#define QCA8K_LED_CTRL_SHIFT(_i) (((_i) % 2) * 16) +#define QCA8K_LED_CTRL_MASK GENMASK(15, 0) +#define QCA8K_LED_RULE_MASK GENMASK(13, 0) +#define QCA8K_LED_BLINK_FREQ_MASK GENMASK(1, 0) +#define QCA8K_LED_BLINK_FREQ_SHITF 0 +#define QCA8K_LED_BLINK_2HZ 0 +#define QCA8K_LED_BLINK_4HZ 1 +#define QCA8K_LED_BLINK_8HZ 2 +#define QCA8K_LED_BLINK_AUTO 3 +#define QCA8K_LED_LINKUP_OVER_MASK BIT(2) +#define QCA8K_LED_TX_BLINK_MASK BIT(4) +#define QCA8K_LED_RX_BLINK_MASK BIT(5) +#define QCA8K_LED_COL_BLINK_MASK BIT(7) +#define QCA8K_LED_LINK_10M_EN_MASK BIT(8) +#define QCA8K_LED_LINK_100M_EN_MASK BIT(9) +#define QCA8K_LED_LINK_1000M_EN_MASK BIT(10) +#define QCA8K_LED_POWER_ON_LIGHT_MASK BIT(11) +#define QCA8K_LED_HALF_DUPLEX_MASK BIT(12) +#define QCA8K_LED_FULL_DUPLEX_MASK BIT(13) +#define QCA8K_LED_PATTERN_EN_MASK GENMASK(15, 14) +#define QCA8K_LED_PATTERN_EN_SHIFT 14 +#define QCA8K_LED_ALWAYS_OFF 0 +#define QCA8K_LED_ALWAYS_BLINK_4HZ 1 +#define QCA8K_LED_ALWAYS_ON 2 +#define QCA8K_LED_RULE_CONTROLLED 3 + #define QCA8K_GOL_MAC_ADDR0 0x60 #define QCA8K_GOL_MAC_ADDR1 0x64 #define QCA8K_MAX_FRAME_SIZE 0x78 @@ -279,6 +317,19 @@ struct qca8k_ports_config { u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ }; +struct qca8k_led_pattern_en { + u32 reg; + u8 shift; +}; + +struct qca8k_led { + u8 port_num; + u8 led_num; + u16 old_rule; + struct qca8k_priv *priv; + struct led_classdev cdev; +}; + struct qca8k_priv { u8 switch_id; u8 switch_revision; @@ -293,6 +344,7 @@ struct qca8k_priv { struct dsa_switch_ops ops; struct gpio_desc *reset_gpio; unsigned int port_mtu[QCA8K_NUM_PORTS]; + struct qca8k_led ports_led[QCA8K_LED_COUNT]; }; struct qca8k_mib_desc { @@ -308,4 +360,17 @@ struct qca8k_fdb { u8 mac[6]; }; +/* Common function used by the LEDs module */ +int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); +int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); + +#ifdef CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT +int qca8k_setup_led_ctrl(struct qca8k_priv *priv); +#else +static inline int qca8k_setup_led_ctrl(struct qca8k_priv *priv) +{ + return 0; +} +#endif + #endif /* __QCA8K_H */ From patchwork Fri Nov 12 15:35:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Marangi X-Patchwork-Id: 517312 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6B6FFC433FE for ; Fri, 12 Nov 2021 15:37:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 52DE760F41 for ; Fri, 12 Nov 2021 15:37:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235417AbhKLPj7 (ORCPT ); Fri, 12 Nov 2021 10:39:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235448AbhKLPjY (ORCPT ); Fri, 12 Nov 2021 10:39:24 -0500 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 01078C061766; Fri, 12 Nov 2021 07:36:14 -0800 (PST) Received: by mail-wm1-x32c.google.com with SMTP id p3-20020a05600c1d8300b003334fab53afso7273923wms.3; Fri, 12 Nov 2021 07:36:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=mrT39HXhsvQIv884aQ7FKStKCV5fQEcK++rSuH4MPzo=; b=VYsF1Y9o06tJw68/we3j63O01NDUIboRYOuJ5cVeqsU8EM2wMBCVrDogIoKXRIFFBn EOVgI8mNXXwumFhCDDD6wGDWNmuFTZ5NqHvuezriDmrR0LBkl2zwX3byZJbqzrLEF0ni L3RTA5eXfxsIlcOQuL5iW7hj3Ag4msuBPKg9JFsAGoNhJhjhwfyrdWvq25S6eBN+rREu j2m+4m+vxsCyEA51oOhL1kIIuCl/j6M12s+gKTuX9Tudu+oBouWtg4Qsrln6ltwxpJLM 0btvhD/ad1wvaip9iRICMhQFC6YIQx4CIaiaiZeyNCOvLHVB8EPGnrrG5NWx9LTz4YOt y1OA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=mrT39HXhsvQIv884aQ7FKStKCV5fQEcK++rSuH4MPzo=; b=LG/TTAgAuYLAm068FsqLIHSgGuvrWbPPDTgwA3YHPnBHC4WZ/G+s9qtAVHbVnIgR9l W3OTkjdMYd1i0Wx1nCfYi05cUsBa49kvLb9f8kvyKAw6w5nxAuGSCUWiwPrp/Nfwz6AM U38QyZFpAapJbaMdnbnjG4Gx4yqu6zVrZ6lGjvojzp582nR3CiH0WSgsFQZoKHcdAojt cRXmNoczfCK+SO6vZR2hdjyDgL5bSiLbO7y2h5AqB32FVYVyt6idvSLjWZkmuPl/JrPe Ra3tzk1Y/VZdsyzXmuQXuvWzQTlPfOSAqEa7xzHIR1IZuxEuygNmL4SgSCzXw0koZ/2t zVvA== X-Gm-Message-State: AOAM53316tySoJzt7LtKJCDw4nnct5Z2qQWC9VymfGS+/yndOPme5sw4 1gn5N/0l4NdlMook1G8+VIIh1R/0NCM= X-Google-Smtp-Source: ABdhPJxT2oNv5R2LyXboxFQukgKDLcGexkgECiAkaD2/42/hD7cHOv1OMa4wS1FxvCkTwEMVSa5RaA== X-Received: by 2002:a1c:cc19:: with SMTP id h25mr35813457wmb.57.1636731372432; Fri, 12 Nov 2021 07:36:12 -0800 (PST) Received: from Ansuel-xps.localdomain (93-42-71-246.ip85.fastwebnet.it. [93.42.71.246]) by smtp.googlemail.com with ESMTPSA id az4sm4217543wmb.20.2021.11.12.07.36.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Nov 2021 07:36:12 -0800 (PST) From: Ansuel Smith To: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , "David S. Miller" , Jakub Kicinski , Rob Herring , Jonathan Corbet , Pavel Machek , Ansuel Smith , John Crispin , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-leds@vger.kernel.org, =?utf-8?q?Marek_Beh?= =?utf-8?q?=C3=BAn?= Subject: [PATCH v5 8/8] dt-bindings: net: dsa: qca8k: add LEDs definition example Date: Fri, 12 Nov 2021 16:35:57 +0100 Message-Id: <20211112153557.26941-9-ansuelsmth@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211112153557.26941-1-ansuelsmth@gmail.com> References: <20211112153557.26941-1-ansuelsmth@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Add LEDs definition example for qca8k using the offload trigger as the default trigger and add all the supported offload triggers by the switch. Signed-off-by: Ansuel Smith --- .../devicetree/bindings/net/dsa/qca8k.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/qca8k.yaml b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml index 48de0ace265d..106d95adc1e8 100644 --- a/Documentation/devicetree/bindings/net/dsa/qca8k.yaml +++ b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml @@ -64,6 +64,8 @@ properties: internal mdio access is used. With the legacy mapping the reg corresponding to the internal mdio is the switch reg with an offset of -1. + Each phy have at least 3 LEDs connected and can be declared + using the standard LEDs structure. properties: '#address-cells': @@ -340,6 +342,24 @@ examples: internal_phy_port1: ethernet-phy@0 { reg = <0>; + + leds { + led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_LAN; + function-enumerator = <1>; + linux,default-trigger = "offload-phy-activity"; + }; + + led@1 { + reg = <1>; + color = ; + function = LED_FUNCTION_LAN; + function-enumerator = <1>; + linux,default-trigger = "offload-phy-activity"; + }; + }; }; internal_phy_port2: ethernet-phy@1 {