[net-next,01/11] net: dsa: qca8k: add LEDs basic support
Commit Message
Add LEDs basic support for qca8k Switch Family by adding basic
brightness_set() and brightness_get() support.
Since these LEDs refelect port status, the default label is set to
":port". DT binding should describe the color, function and number of
the leds using standard LEDs api.
These LEDs supports only blocking variant of the brightness_set()
function since they can sleep during access of the switch leds to set
the brightness.
While at it add to the qca8k header file each mode defined by the Switch
Documentation for future use.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca/Kconfig | 7 ++
drivers/net/dsa/qca/Makefile | 1 +
drivers/net/dsa/qca/qca8k-8xxx.c | 4 +
drivers/net/dsa/qca/qca8k-leds.c | 200 +++++++++++++++++++++++++++++++
drivers/net/dsa/qca/qca8k.h | 69 +++++++++++
5 files changed, 281 insertions(+)
create mode 100644 drivers/net/dsa/qca/qca8k-leds.c
Comments
On Wed, Mar 08, 2023 at 12:16:13AM +0100, Andrew Lunn wrote:
> > +qca8k_setup_led_ctrl(struct qca8k_priv *priv)
> > +{
> > + struct fwnode_handle *ports, *port;
> > + int port_num;
> > + int ret;
> > +
> > + ports = device_get_named_child_node(priv->dev, "ports");
> > + if (!ports) {
> > + dev_info(priv->dev, "No ports node specified in device tree!\n");
> > + return 0;
> > + }
> > +
> > + fwnode_for_each_child_node(ports, port) {
> > + struct fwnode_handle *phy_node, *reg_port_node = port;
> > +
> > + phy_node = fwnode_find_reference(port, "phy-handle", 0);
> > + if (!IS_ERR(phy_node))
> > + reg_port_node = phy_node;
>
> I don't understand this bit. Why are you looking at the phy-handle?
>
> > +
> > + if (fwnode_property_read_u32(reg_port_node, "reg", &port_num))
> > + continue;
>
> I would of expect port, not reg_port_node. I'm missing something
> here....
>
It's really not to implement ugly things like "reg - 1"
On qca8k the port index goes from 0 to 6.
0 is cpu port 1
1 is port0 at mdio reg 0
2 is port1 at mdio reg 1
...
6 is cpu port 2
Each port have a phy-handle that refer to a phy node with the correct
reg and that reflect the correct port index.
Tell me if this looks wrong, for qca8k we have qca8k_port_to_phy() and
at times we introduced the mdio thing to describe the port - 1 directly
in DT. If needed I can drop the additional fwnode and use this function
but I would love to use what is defined in DT thatn a simple - 1.
On Wed, Mar 08, 2023 at 01:49:55AM +0100, Andrew Lunn wrote:
> On Tue, Mar 07, 2023 at 06:57:10PM +0100, Christian Marangi wrote:
> > On Wed, Mar 08, 2023 at 12:16:13AM +0100, Andrew Lunn wrote:
> > > > +qca8k_setup_led_ctrl(struct qca8k_priv *priv)
> > > > +{
> > > > + struct fwnode_handle *ports, *port;
> > > > + int port_num;
> > > > + int ret;
> > > > +
> > > > + ports = device_get_named_child_node(priv->dev, "ports");
> > > > + if (!ports) {
> > > > + dev_info(priv->dev, "No ports node specified in device tree!\n");
> > > > + return 0;
> > > > + }
> > > > +
> > > > + fwnode_for_each_child_node(ports, port) {
> > > > + struct fwnode_handle *phy_node, *reg_port_node = port;
> > > > +
> > > > + phy_node = fwnode_find_reference(port, "phy-handle", 0);
> > > > + if (!IS_ERR(phy_node))
> > > > + reg_port_node = phy_node;
> > >
> > > I don't understand this bit. Why are you looking at the phy-handle?
> > >
> > > > +
> > > > + if (fwnode_property_read_u32(reg_port_node, "reg", &port_num))
> > > > + continue;
> > >
> > > I would of expect port, not reg_port_node. I'm missing something
> > > here....
> > >
> >
> > It's really not to implement ugly things like "reg - 1"
> >
> > On qca8k the port index goes from 0 to 6.
> > 0 is cpu port 1
> > 1 is port0 at mdio reg 0
> > 2 is port1 at mdio reg 1
> > ...
> > 6 is cpu port 2
> >
> > Each port have a phy-handle that refer to a phy node with the correct
> > reg and that reflect the correct port index.
> >
> > Tell me if this looks wrong, for qca8k we have qca8k_port_to_phy() and
> > at times we introduced the mdio thing to describe the port - 1 directly
> > in DT. If needed I can drop the additional fwnode and use this function
> > but I would love to use what is defined in DT thatn a simple - 1.
>
> This comes back to the off list discussion earlier today. What you
> actually have here are MAC LEDs, not PHY LEDs. They are implemented in
> the MAC, not the PHY. To the end user, it should not matter, they
> blink when you would expect.
>
> So your addressing should be based around the MAC port number, not the
> PHY.
Ok will drop this.
>
> Also, at the moment, all we are adding are a bunch of LEDs. There is
> no link to a netdev at this point. At least, i don't see one. Be once
> we start using ledtrig-netdev we will need that link to a netdev. Take
> a look in my git tree at the last four patch. They add an additional
> call to get the device an LED is attached to.
>
No currently we have no link for netdev, hence we are setting keep and
not setting a default trigger in DT.
Just checked them, interesting concept, guess we can think of something
also for the interval setting. That would effectively make all the
setting of the trigger set. Just my concern is that they may be too much
specific to netdev trigger and may be problematic for other kind of hw
control. (one main argument that was made for this feature was that some
stuff were too much specific and actually not that generic)
> +qca8k_setup_led_ctrl(struct qca8k_priv *priv)
> +{
> + struct fwnode_handle *ports, *port;
> + int port_num;
> + int ret;
> +
> + ports = device_get_named_child_node(priv->dev, "ports");
> + if (!ports) {
> + dev_info(priv->dev, "No ports node specified in device tree!\n");
> + return 0;
> + }
> +
> + fwnode_for_each_child_node(ports, port) {
> + struct fwnode_handle *phy_node, *reg_port_node = port;
> +
> + phy_node = fwnode_find_reference(port, "phy-handle", 0);
> + if (!IS_ERR(phy_node))
> + reg_port_node = phy_node;
I don't understand this bit. Why are you looking at the phy-handle?
> +
> + if (fwnode_property_read_u32(reg_port_node, "reg", &port_num))
> + continue;
I would of expect port, not reg_port_node. I'm missing something
here....
Andrew
On Tue, Mar 07, 2023 at 06:57:10PM +0100, Christian Marangi wrote:
> On Wed, Mar 08, 2023 at 12:16:13AM +0100, Andrew Lunn wrote:
> > > +qca8k_setup_led_ctrl(struct qca8k_priv *priv)
> > > +{
> > > + struct fwnode_handle *ports, *port;
> > > + int port_num;
> > > + int ret;
> > > +
> > > + ports = device_get_named_child_node(priv->dev, "ports");
> > > + if (!ports) {
> > > + dev_info(priv->dev, "No ports node specified in device tree!\n");
> > > + return 0;
> > > + }
> > > +
> > > + fwnode_for_each_child_node(ports, port) {
> > > + struct fwnode_handle *phy_node, *reg_port_node = port;
> > > +
> > > + phy_node = fwnode_find_reference(port, "phy-handle", 0);
> > > + if (!IS_ERR(phy_node))
> > > + reg_port_node = phy_node;
> >
> > I don't understand this bit. Why are you looking at the phy-handle?
> >
> > > +
> > > + if (fwnode_property_read_u32(reg_port_node, "reg", &port_num))
> > > + continue;
> >
> > I would of expect port, not reg_port_node. I'm missing something
> > here....
> >
>
> It's really not to implement ugly things like "reg - 1"
>
> On qca8k the port index goes from 0 to 6.
> 0 is cpu port 1
> 1 is port0 at mdio reg 0
> 2 is port1 at mdio reg 1
> ...
> 6 is cpu port 2
>
> Each port have a phy-handle that refer to a phy node with the correct
> reg and that reflect the correct port index.
>
> Tell me if this looks wrong, for qca8k we have qca8k_port_to_phy() and
> at times we introduced the mdio thing to describe the port - 1 directly
> in DT. If needed I can drop the additional fwnode and use this function
> but I would love to use what is defined in DT thatn a simple - 1.
This comes back to the off list discussion earlier today. What you
actually have here are MAC LEDs, not PHY LEDs. They are implemented in
the MAC, not the PHY. To the end user, it should not matter, they
blink when you would expect.
So your addressing should be based around the MAC port number, not the
PHY.
Also, at the moment, all we are adding are a bunch of LEDs. There is
no link to a netdev at this point. At least, i don't see one. Be once
we start using ledtrig-netdev we will need that link to a netdev. Take
a look in my git tree at the last four patch. They add an additional
call to get the device an LED is attached to.
Andrew
> Just checked them, interesting concept, guess we can think of something
> also for the interval setting. That would effectively make all the
> setting of the trigger set. Just my concern is that they may be too much
> specific to netdev trigger and may be problematic for other kind of hw
> control. (one main argument that was made for this feature was that some
> stuff were too much specific and actually not that generic)
I deliberately made this API return a struct device, not a struct
net_device. That should keep it generic. The LED could then be
attached to an disk device, an mtd device, or a tty device, each of
which have an ledtrig-*.c file.
Andrew
Hi Christian,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/intel-lab-lkp/linux/commits/Christian-Marangi/net-dsa-qca8k-add-LEDs-basic-support/20230308-063832
patch link: https://lore.kernel.org/r/20230307170046.28917-2-ansuelsmth%40gmail.com
patch subject: [net-next PATCH 01/11] net: dsa: qca8k: add LEDs basic support
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20230317/202303170529.8ag9rmM4-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/ce1977c679b8737815636b72f4e65c2de59e8f7d
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Christian-Marangi/net-dsa-qca8k-add-LEDs-basic-support/20230308-063832
git checkout ce1977c679b8737815636b72f4e65c2de59e8f7d
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/net/dsa/qca/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303170529.8ag9rmM4-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/net/dsa/qca/qca8k-leds.c:171:1: error: redefinition of 'qca8k_setup_led_ctrl'
171 | qca8k_setup_led_ctrl(struct qca8k_priv *priv)
| ^~~~~~~~~~~~~~~~~~~~
In file included from drivers/net/dsa/qca/qca8k-leds.c:5:
drivers/net/dsa/qca/qca8k.h:577:19: note: previous definition of 'qca8k_setup_led_ctrl' with type 'int(struct qca8k_priv *)'
577 | static inline int qca8k_setup_led_ctrl(struct qca8k_priv *priv)
| ^~~~~~~~~~~~~~~~~~~~
vim +/qca8k_setup_led_ctrl +171 drivers/net/dsa/qca/qca8k-leds.c
169
170 int
> 171 qca8k_setup_led_ctrl(struct qca8k_priv *priv)
@@ -15,3 +15,10 @@ config NET_DSA_QCA8K
help
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"
+ depends on NET_DSA_QCA8K
+ help
+ This enabled support for LEDs present on the Qualcomm Atheros
+ QCA8K Ethernet switch chips.
@@ -2,3 +2,4 @@
obj-$(CONFIG_NET_DSA_AR9331) += ar9331.o
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
qca8k-y += qca8k-common.o qca8k-8xxx.o
+obj-$(CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT) += qca8k-leds.o
@@ -1742,6 +1742,10 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
+ ret = qca8k_setup_led_ctrl(priv);
+ if (ret)
+ return ret;
+
qca8k_setup_pcs(priv, &priv->pcs_port_0, 0);
qca8k_setup_pcs(priv, &priv->pcs_port_6, 6);
new file mode 100644
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/regmap.h>
+#include <net/dsa.h>
+
+#include "qca8k.h"
+
+static int
+qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
+{
+ switch (port_num) {
+ case 0:
+ reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
+ reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ /* Port 123 are controlled on a different reg */
+ reg_info->reg = QCA8K_LED_CTRL_REG(3);
+ reg_info->shift = QCA8K_LED_PHY123_PATTERN_EN_SHIFT(port_num, led_num);
+ break;
+ case 4:
+ reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
+ reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+qca8k_led_brightness_set(struct qca8k_led *led,
+ enum led_brightness brightness)
+{
+ struct qca8k_led_pattern_en reg_info;
+ struct qca8k_priv *priv = led->priv;
+ u32 mask, val = QCA8K_LED_ALWAYS_OFF;
+
+ qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);
+
+ if (brightness)
+ val = QCA8K_LED_ALWAYS_ON;
+
+ if (led->port_num == 0 || led->port_num == 4) {
+ mask = QCA8K_LED_PATTERN_EN_MASK;
+ val <<= QCA8K_LED_PATTERN_EN_SHIFT;
+ } else {
+ mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
+ }
+
+ return regmap_update_bits(priv->regmap, reg_info.reg,
+ mask << reg_info.shift,
+ val << reg_info.shift);
+}
+
+static int
+qca8k_cled_brightness_set_blocking(struct led_classdev *ldev,
+ enum led_brightness brightness)
+{
+ struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
+
+ return qca8k_led_brightness_set(led, brightness);
+}
+
+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 = regmap_read(priv->regmap, reg_info.reg, &val);
+ if (ret)
+ return 0;
+
+ val >>= reg_info.shift;
+
+ if (led->port_num == 0 || led->port_num == 4) {
+ val &= QCA8K_LED_PATTERN_EN_MASK;
+ val >>= QCA8K_LED_PATTERN_EN_SHIFT;
+ } else {
+ val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
+ }
+
+ 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_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
+{
+ struct fwnode_handle *led = NULL, *leds = NULL;
+ 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 represent 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);
+ }
+ }
+
+ port_led->cdev.max_brightness = 1;
+ port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
+ port_led->cdev.brightness_get = qca8k_cled_brightness_get;
+ 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 *ports, *port;
+ int port_num;
+ int ret;
+
+ ports = device_get_named_child_node(priv->dev, "ports");
+ if (!ports) {
+ dev_info(priv->dev, "No ports node specified in device tree!\n");
+ return 0;
+ }
+
+ fwnode_for_each_child_node(ports, port) {
+ struct fwnode_handle *phy_node, *reg_port_node = port;
+
+ phy_node = fwnode_find_reference(port, "phy-handle", 0);
+ if (!IS_ERR(phy_node))
+ reg_port_node = phy_node;
+
+ if (fwnode_property_read_u32(reg_port_node, "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;
+}
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/gpio.h>
+#include <linux/leds.h>
#include <linux/dsa/tag_qca.h>
#define QCA8K_ETHERNET_MDIO_PRIORITY 7
@@ -85,6 +86,50 @@
#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x)
#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_PHY123_PATTERN_EN_SHIFT(_phy, _led) ((((_phy) - 1) * 6) + 8 + (2 * (_led)))
+#define QCA8K_LED_PHY123_PATTERN_EN_MASK GENMASK(1, 0)
+
+#define QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT 0
+#define QCA8K_LED_PHY4_CONTROL_RULE_SHIFT 16
+
+#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
@@ -383,6 +428,19 @@ struct qca8k_pcs {
int port;
};
+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;
@@ -407,6 +465,7 @@ struct qca8k_priv {
struct qca8k_pcs pcs_port_0;
struct qca8k_pcs pcs_port_6;
const struct qca8k_match_data *info;
+ struct qca8k_led ports_led[QCA8K_LED_COUNT];
};
struct qca8k_mib_desc {
@@ -512,4 +571,14 @@ int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag,
int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
struct dsa_lag lag);
+/* Leds Support function */
+#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 */