diff mbox series

[net-next,2/2] net: dsa: mv88e6xxx: Add LED support for 6393X

Message ID 20240103103351.1188835-3-tobias@waldekranz.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net: dsa: mv88e6xxx: Add LED support for 6393X | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 1115 this patch: 1118
netdev/cc_maintainers warning 3 maintainers not CCed: edumazet@google.com pabeni@redhat.com linux@armlinux.org.uk
netdev/build_clang fail Errors and warnings before: 1142 this patch: 1143
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 1142 this patch: 1145
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Tobias Waldekranz Jan. 3, 2024, 10:33 a.m. UTC
Trigger support:
- "none"
- "timer"
- "netdev"

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c |   1 +
 drivers/net/dsa/mv88e6xxx/leds.c | 227 +++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/leds.h |   2 +
 drivers/net/dsa/mv88e6xxx/port.c |  33 +++++
 drivers/net/dsa/mv88e6xxx/port.h |   7 +
 5 files changed, 270 insertions(+)

Comments

kernel test robot Jan. 4, 2024, 3:16 a.m. UTC | #1
Hi Tobias,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Tobias-Waldekranz/net-dsa-mv88e6xxx-Add-LED-infrastructure/20240103-183726
base:   net-next/main
patch link:    https://lore.kernel.org/r/20240103103351.1188835-3-tobias%40waldekranz.com
patch subject: [PATCH net-next 2/2] net: dsa: mv88e6xxx: Add LED support for 6393X
config: arm64-randconfig-001-20240104 (https://download.01.org/0day-ci/archive/20240104/202401041120.UXiohfGq-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240104/202401041120.UXiohfGq-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401041120.UXiohfGq-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/net/dsa/mv88e6xxx/leds.c:77:22: warning: no previous prototype for 'mv88e6393x_led_map' [-Wmissing-prototypes]
      77 | const unsigned long *mv88e6393x_led_map(struct mv88e6xxx_led *led)
         |                      ^~~~~~~~~~~~~~~~~~
   drivers/net/dsa/mv88e6xxx/leds.c:398:5: warning: no previous prototype for 'mv88e6xxx_port_setup_leds' [-Wmissing-prototypes]
     398 | int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port)
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~


vim +/mv88e6393x_led_map +77 drivers/net/dsa/mv88e6xxx/leds.c

    76	
  > 77	const unsigned long *mv88e6393x_led_map(struct mv88e6xxx_led *led)
    78	{
    79		switch (led->port) {
    80		case 1:
    81		case 2:
    82		case 3:
    83		case 4:
    84		case 5:
    85		case 6:
    86		case 7:
    87		case 8:
    88			return mv88e6393x_led_map_p1_p8[led->index];
    89		case 9:
    90		case 10:
    91			return mv88e6393x_led_map_p9_p10[led->index];
    92		}
    93	
    94		return NULL;
    95	}
    96
kernel test robot Jan. 4, 2024, 10:01 p.m. UTC | #2
Hi Tobias,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Tobias-Waldekranz/net-dsa-mv88e6xxx-Add-LED-infrastructure/20240103-183726
base:   net-next/main
patch link:    https://lore.kernel.org/r/20240103103351.1188835-3-tobias%40waldekranz.com
patch subject: [PATCH net-next 2/2] net: dsa: mv88e6xxx: Add LED support for 6393X
config: loongarch-randconfig-r113-20240104 (https://download.01.org/0day-ci/archive/20240105/202401050539.Y9LYQsgz-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20240105/202401050539.Y9LYQsgz-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401050539.Y9LYQsgz-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/net/dsa/mv88e6xxx/leds.c:77:21: sparse: sparse: symbol 'mv88e6393x_led_map' was not declared. Should it be static?

vim +/mv88e6393x_led_map +77 drivers/net/dsa/mv88e6xxx/leds.c

    76	
  > 77	const unsigned long *mv88e6393x_led_map(struct mv88e6xxx_led *led)
    78	{
    79		switch (led->port) {
    80		case 1:
    81		case 2:
    82		case 3:
    83		case 4:
    84		case 5:
    85		case 6:
    86		case 7:
    87		case 8:
    88			return mv88e6393x_led_map_p1_p8[led->index];
    89		case 9:
    90		case 10:
    91			return mv88e6393x_led_map_p9_p10[led->index];
    92		}
    93	
    94		return NULL;
    95	}
    96
diff mbox series

Patch

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 8fab16badc9e..f43dc863999a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -5495,6 +5495,7 @@  static const struct mv88e6xxx_ops mv88e6393x_ops = {
 	.gpio_ops = &mv88e6352_gpio_ops,
 	.avb_ops = &mv88e6390_avb_ops,
 	.ptp_ops = &mv88e6352_ptp_ops,
+	.led_ops = &mv88e6393x_led_ops,
 	.phylink_get_caps = mv88e6393x_phylink_get_caps,
 	.pcs_ops = &mv88e6393x_pcs_ops,
 };
diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c
index 1f331a632065..f964b3a7a3e7 100644
--- a/drivers/net/dsa/mv88e6xxx/leds.c
+++ b/drivers/net/dsa/mv88e6xxx/leds.c
@@ -4,6 +4,13 @@ 
 #include "chip.h"
 #include "port.h"
 
+#define FLAG_ACT      (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX))
+#define FLAG_LINK     BIT(TRIGGER_NETDEV_LINK)
+#define FLAG_LINK_10  BIT(TRIGGER_NETDEV_LINK_10)
+#define FLAG_LINK_100 BIT(TRIGGER_NETDEV_LINK_100)
+#define FLAG_LINK_1G  BIT(TRIGGER_NETDEV_LINK_1000)
+#define FLAG_FULL     BIT(TRIGGER_NETDEV_FULL_DUPLEX)
+
 struct mv88e6xxx_led {
 	struct mv88e6xxx_chip *chip;
 	int port;
@@ -23,6 +30,226 @@  struct mv88e6xxx_led_ops {
 	int (*hw_control_get)(struct mv88e6xxx_led *led, unsigned long *flags);
 };
 
+enum mv88e6393x_led_mode {
+	MV88E6393X_LED_MODE_BLINK = 0xd,
+	MV88E6393X_LED_MODE_OFF = 0xe,
+	MV88E6393X_LED_MODE_ON = 0xf,
+
+	MV88E6393X_LED_MODES = 0x10
+};
+
+static const unsigned long mv88e6393x_led_map_p1_p8[2][MV88E6393X_LED_MODES] = {
+	{
+		[0x1] = FLAG_ACT | FLAG_LINK_100 | FLAG_LINK_1G,
+		[0x2] = FLAG_ACT | FLAG_LINK_1G,
+		[0x3] = FLAG_ACT | FLAG_LINK,
+		[0x6] = FLAG_FULL,
+		[0x7] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_1G,
+		[0x8] = FLAG_LINK,
+		[0x9] = FLAG_LINK_10,
+		[0xa] = FLAG_ACT | FLAG_LINK_10,
+		[0xb] = FLAG_LINK_100 | FLAG_LINK_1G,
+	},
+	{
+		[0x1] = FLAG_ACT,
+		[0x2] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_100,
+		[0x3] = FLAG_LINK_1G,
+		[0x5] = FLAG_ACT | FLAG_LINK,
+		[0x6] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_1G,
+		[0x7] = FLAG_LINK_10 | FLAG_LINK_1G,
+		[0x9] = FLAG_LINK_100,
+		[0xa] = FLAG_ACT | FLAG_LINK_100,
+		[0xb] = FLAG_LINK_10 | FLAG_LINK_100,
+	}
+};
+
+static const unsigned long mv88e6393x_led_map_p9_p10[2][MV88E6393X_LED_MODES] = {
+	{
+		[0x1] = FLAG_ACT | FLAG_LINK,
+	},
+	{
+		[0x6] = FLAG_FULL,
+		[0x7] = FLAG_ACT | FLAG_LINK,
+		[0x8] = FLAG_LINK,
+	}
+};
+
+const unsigned long *mv88e6393x_led_map(struct mv88e6xxx_led *led)
+{
+	switch (led->port) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+	case 8:
+		return mv88e6393x_led_map_p1_p8[led->index];
+	case 9:
+	case 10:
+		return mv88e6393x_led_map_p9_p10[led->index];
+	}
+
+	return NULL;
+}
+
+static int mv88e6393x_led_flags_to_mode(struct mv88e6xxx_led *led, unsigned long flags)
+{
+	const unsigned long *map = mv88e6393x_led_map(led);
+	int i;
+
+	if (!map)
+		return -ENODEV;
+
+	if (!flags)
+		return MV88E6393X_LED_MODE_OFF;
+
+	for (i = 0; i < MV88E6393X_LED_MODES; i++) {
+		if (map[i] == flags)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int mv88e6393x_led_mode_to_flags(struct mv88e6xxx_led *led, u8 mode,
+					unsigned long *flags)
+{
+	const unsigned long *map = mv88e6393x_led_map(led);
+
+	if (!map)
+		return -ENODEV;
+
+	if (mode == MV88E6393X_LED_MODE_OFF) {
+		*flags = 0;
+		return 0;
+	}
+
+	if (map[mode]) {
+		*flags = map[mode];
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int mv88e6393x_led_set(struct mv88e6xxx_led *led, int mode)
+{
+	u16 ctrl;
+	int err;
+
+	if (mode < 0)
+		return mode;
+
+	mv88e6xxx_reg_lock(led->chip);
+
+	err = mv88e6393x_port_led_read(led->chip, led->port, 0, &ctrl);
+	if (err)
+		goto out;
+
+	switch (led->index) {
+	case 0:
+		ctrl &= ~0x0f;
+		ctrl |= mode;
+		break;
+	case 1:
+		ctrl &= ~0xf0;
+		ctrl |= mode << 4;
+	}
+
+	err = mv88e6393x_port_led_write(led->chip, led->port, 0, ctrl);
+out:
+	mv88e6xxx_reg_unlock(led->chip);
+	return err;
+}
+
+static int mv88e6393x_led_get(struct mv88e6xxx_led *led)
+{
+	u16 ctrl;
+	int err;
+
+	mv88e6xxx_reg_lock(led->chip);
+	err = mv88e6393x_port_led_read(led->chip, led->port, 0, &ctrl);
+	mv88e6xxx_reg_unlock(led->chip);
+	if (err)
+		return err;
+
+	switch (led->index) {
+	case 0:
+		return ctrl & 0xf;
+	case 1:
+		return (ctrl >> 4) & 0xf;
+	}
+
+	return -EINVAL;
+}
+
+static int mv88e6393x_led_brightness_set(struct mv88e6xxx_led *led,
+					 enum led_brightness brightness)
+{
+	if (brightness == LED_OFF)
+		return mv88e6393x_led_set(led, MV88E6393X_LED_MODE_OFF);
+
+	return mv88e6393x_led_set(led, MV88E6393X_LED_MODE_ON);
+}
+
+static int mv88e6393x_led_blink_set(struct mv88e6xxx_led *led,
+				    unsigned long *delay_on,
+				    unsigned long *delay_off)
+{
+	int err;
+
+	/* Defer anything other than 50% duty cycles to software */
+	if (*delay_on != *delay_off)
+		return -EINVAL;
+
+	/* Reject values outside ~20% of our default rate (84ms) */
+	if (*delay_on && ((*delay_on < 30) || (*delay_on > 50)))
+		return -EINVAL;
+
+	err = mv88e6393x_led_set(led, MV88E6393X_LED_MODE_BLINK);
+	if (!err)
+		*delay_on = *delay_off = 42;
+
+	return err;
+}
+
+static int mv88e6393x_led_hw_control_is_supported(struct mv88e6xxx_led *led,
+						  unsigned long flags)
+{
+	int mode = mv88e6393x_led_flags_to_mode(led, flags);
+
+	return (mode < 0) ? mode : 0;
+}
+
+static int mv88e6393x_led_hw_control_set(struct mv88e6xxx_led *led,
+					 unsigned long flags)
+{
+	int mode = mv88e6393x_led_flags_to_mode(led, flags);
+
+	return mv88e6393x_led_set(led, mode);
+}
+
+static int mv88e6393x_led_hw_control_get(struct mv88e6xxx_led *led,
+					 unsigned long *flags)
+{
+	int mode = mv88e6393x_led_get(led);
+
+	if (mode < 0)
+		return mode;
+
+	return mv88e6393x_led_mode_to_flags(led, mode, flags);
+}
+
+const struct mv88e6xxx_led_ops mv88e6393x_led_ops = {
+	.brightness_set = mv88e6393x_led_brightness_set,
+	.blink_set = mv88e6393x_led_blink_set,
+	.hw_control_is_supported = mv88e6393x_led_hw_control_is_supported,
+	.hw_control_set = mv88e6393x_led_hw_control_set,
+	.hw_control_get = mv88e6393x_led_hw_control_get,
+};
+
 static int mv88e6xxx_led_brightness_set(struct led_classdev *ldev,
 					enum led_brightness brightness)
 {
diff --git a/drivers/net/dsa/mv88e6xxx/leds.h b/drivers/net/dsa/mv88e6xxx/leds.h
index a99d7a5ebc6d..c7de16ce4dde 100644
--- a/drivers/net/dsa/mv88e6xxx/leds.h
+++ b/drivers/net/dsa/mv88e6xxx/leds.h
@@ -7,6 +7,8 @@ 
 
 #include "chip.h"
 
+extern const struct mv88e6xxx_led_ops mv88e6393x_led_ops;
+
 int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port);
 
 #endif /* _MV88E6XXX_LEDS_H */
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 5394a8cf7bf1..66073a1ef260 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1539,6 +1539,39 @@  int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
 }
 
+/* Offset 0x16: LED Control Register */
+
+int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port,
+			      unsigned int pointer, u16 data)
+{
+	u16 cmd = BIT(15) | ((pointer & 0x7) << 12) | (data & 0x7ff);
+	int err;
+
+	err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_LED_CONTROL, cmd);
+	if (err)
+		return err;
+
+	return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_LED_CONTROL, 15, 0);
+}
+
+int mv88e6393x_port_led_read(struct mv88e6xxx_chip *chip, int port,
+			     unsigned int pointer, u16 *data)
+{
+	u16 cmd = (pointer & 0x7) << 12;
+	int err;
+
+	err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_LED_CONTROL, cmd);
+	if (err)
+		return err;
+
+	err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_LED_CONTROL, &cmd);
+	if (err)
+		return err;
+
+	*data = cmd & 0x7ff;
+	return 0;
+}
+
 /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
  * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
  */
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 86deeb347cbc..3605a59d1399 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -294,6 +294,9 @@ 
 /* Offset 0x13: OutFiltered Counter */
 #define MV88E6XXX_PORT_OUT_FILTERED	0x13
 
+/* Offset 0x16: LED Control Register */
+#define MV88E6393X_PORT_LED_CONTROL	0x16
+
 /* Offset 0x18: IEEE Priority Mapping Table */
 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE			0x18
 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE		0x8000
@@ -410,6 +413,10 @@  int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,
 			       enum mv88e6xxx_policy_action action);
 int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
 				  u16 etype);
+int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port,
+			      unsigned int pointer, u16 data);
+int mv88e6393x_port_led_read(struct mv88e6xxx_chip *chip, int port,
+			     unsigned int pointer, u16 *data);
 int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
 			       enum mv88e6xxx_egress_direction direction,
 			       int port);