drivers/leds/leds-ns2.c

Source file repositories/reference/linux-study-clean/drivers/leds/leds-ns2.c

File Facts

System
Linux kernel
Corpus path
drivers/leds/leds-ns2.c
Extension
.c
Size
6624 bytes
Lines
282
Domain
Driver Families
Bucket
drivers/leds
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

struct ns2_led_modval {
	u32			mode;
	u32			cmd_level;
	u32			slow_level;
} __packed;

/*
 * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED
 * modes are available: off, on and SATA activity blinking. The LED modes are
 * controlled through two GPIOs (command and slow): each combination of values
 * for the command/slow GPIOs corresponds to a LED mode.
 */

struct ns2_led {
	struct led_classdev	cdev;
	struct gpio_desc	*cmd;
	struct gpio_desc	*slow;
	bool			can_sleep;
	unsigned char		sata; /* True when SATA mode active. */
	rwlock_t		rw_lock; /* Lock GPIOs. */
	int			num_modes;
	struct ns2_led_modval	*modval;
};

static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode)
{
	int i;
	int cmd_level;
	int slow_level;

	cmd_level = gpiod_get_value_cansleep(led->cmd);
	slow_level = gpiod_get_value_cansleep(led->slow);

	for (i = 0; i < led->num_modes; i++) {
		if (cmd_level == led->modval[i].cmd_level &&
		    slow_level == led->modval[i].slow_level) {
			*mode = led->modval[i].mode;
			return 0;
		}
	}

	return -EINVAL;
}

static void ns2_led_set_mode(struct ns2_led *led, enum ns2_led_modes mode)
{
	int i;
	unsigned long flags;

	for (i = 0; i < led->num_modes; i++)
		if (mode == led->modval[i].mode)
			break;

	if (i == led->num_modes)
		return;

	write_lock_irqsave(&led->rw_lock, flags);

	if (!led->can_sleep) {
		gpiod_set_value(led->cmd, led->modval[i].cmd_level);
		gpiod_set_value(led->slow, led->modval[i].slow_level);
		goto exit_unlock;
	}

	gpiod_set_value_cansleep(led->cmd, led->modval[i].cmd_level);
	gpiod_set_value_cansleep(led->slow, led->modval[i].slow_level);

exit_unlock:
	write_unlock_irqrestore(&led->rw_lock, flags);
}

static void ns2_led_set(struct led_classdev *led_cdev,
			enum led_brightness value)
{
	struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
	enum ns2_led_modes mode;

	if (value == LED_OFF)
		mode = NS_V2_LED_OFF;
	else if (led->sata)
		mode = NS_V2_LED_SATA;
	else
		mode = NS_V2_LED_ON;

	ns2_led_set_mode(led, mode);
}

static int ns2_led_set_blocking(struct led_classdev *led_cdev,
			enum led_brightness value)
{

Annotation

Implementation Notes