drivers/net/dsa/qca/qca8k-leds.c

Source file repositories/reference/linux-study-clean/drivers/net/dsa/qca/qca8k-leds.c

File Facts

System
Linux kernel
Corpus path
drivers/net/dsa/qca/qca8k-leds.c
Extension
.c
Size
13420 bytes
Lines
489
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (led_num >= QCA8K_LED_PORT_COUNT) {
			dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
				 led_num, port_num);
			continue;
		}

		led_index = QCA8K_LED_PORT_INDEX(port_num, led_num);

		port_led = &priv->ports_led[led_index];
		port_led->port_num = port_num;
		port_led->led_num = led_num;
		port_led->priv = priv;

		state = led_init_default_state_get(led);
		switch (state) {
		case LEDS_DEFSTATE_ON:
			port_led->cdev.brightness = 1;
			qca8k_led_brightness_set(port_led, 1);
			break;
		case LEDS_DEFSTATE_KEEP:
			port_led->cdev.brightness =
					qca8k_led_brightness_get(port_led);
			break;
		default:
			port_led->cdev.brightness = 0;
			qca8k_led_brightness_set(port_led, 0);
		}

		port_led->cdev.max_brightness = 1;
		port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
		port_led->cdev.blink_set = qca8k_cled_blink_set;
		port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;
		port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;
		port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;
		port_led->cdev.hw_control_get_device = qca8k_cled_hw_control_get_device;
		port_led->cdev.hw_control_trigger = "netdev";
		init_data.default_label = ":port";
		init_data.fwnode = led;
		init_data.devname_mandatory = true;
		init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d",
						 priv->internal_mdio_bus ?
						 priv->internal_mdio_bus->id : priv->bus->id,
						 port_num);
		if (!init_data.devicename) {
			fwnode_handle_put(led);
			fwnode_handle_put(leds);
			return -ENOMEM;
		}

		ret = devm_led_classdev_register_ext(priv->dev, &port_led->cdev, &init_data);
		if (ret)
			dev_warn(priv->dev, "Failed to init LED %d for port %d", led_num, port_num);

		kfree(init_data.devicename);
	}

	fwnode_handle_put(leds);
	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!");
		return 0;
	}

	fwnode_for_each_child_node(ports, port) {
		if (fwnode_property_read_u32(port, "reg", &port_num))
			continue;

		/* Skip checking for CPU port 0 and CPU port 6 as not supported */
		if (port_num == 0 || port_num == 6)
			continue;

		/* Each port can have at most 3 different leds attached.
		 * Switch port starts from 0 to 6, but port 0 and 6 are CPU
		 * port. The port index needs to be decreased by one to identify
		 * the correct port for LED setup.
		 */
		ret = qca8k_parse_port_leds(priv, port, qca8k_port_to_phy(port_num));
		if (ret) {
			fwnode_handle_put(port);
			fwnode_handle_put(ports);

Annotation

Implementation Notes