drivers/leds/leds-bcm6328.c

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

File Facts

System
Linux kernel
Corpus path
drivers/leds/leds-bcm6328.c
Extension
.c
Size
12938 bytes
Lines
484
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 bcm6328_led {
	struct led_classdev cdev;
	void __iomem *mem;
	spinlock_t *lock;
	unsigned long pin;
	unsigned long *blink_leds;
	unsigned long *blink_delay;
	bool active_low;
};

static void bcm6328_led_write(void __iomem *reg, unsigned long data)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
	iowrite32be(data, reg);
#else
	writel(data, reg);
#endif
}

static unsigned long bcm6328_led_read(void __iomem *reg)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
	return ioread32be(reg);
#else
	return readl(reg);
#endif
}

/*
 * LEDMode 64 bits / 24 LEDs
 * bits [31:0] -> LEDs 8-23
 * bits [47:32] -> LEDs 0-7
 * bits [63:48] -> unused
 */
static unsigned long bcm6328_pin2shift(unsigned long pin)
{
	if (pin < 8)
		return pin + 16; /* LEDs 0-7 (bits 47:32) */
	else
		return pin - 8; /* LEDs 8-23 (bits 31:0) */
}

static void bcm6328_led_mode(struct bcm6328_led *led, unsigned long value)
{
	void __iomem *mode;
	unsigned long val, shift;

	shift = bcm6328_pin2shift(led->pin);
	if (shift >= 16)
		mode = led->mem + BCM6328_REG_MODE_HI;
	else
		mode = led->mem + BCM6328_REG_MODE_LO;

	val = bcm6328_led_read(mode);
	val &= ~(BCM6328_LED_MODE_MASK << BCM6328_LED_SHIFT(shift % 16));
	val |= (value << BCM6328_LED_SHIFT(shift % 16));
	bcm6328_led_write(mode, val);
}

static void bcm6328_led_set(struct led_classdev *led_cdev,
			    enum led_brightness value)
{
	struct bcm6328_led *led =
		container_of(led_cdev, struct bcm6328_led, cdev);
	unsigned long flags;

	spin_lock_irqsave(led->lock, flags);

	/* Remove LED from cached HW blinking intervals */
	led->blink_leds[0] &= ~BIT(led->pin);
	led->blink_leds[1] &= ~BIT(led->pin);

	/* Set LED on/off */
	if ((led->active_low && value == LED_OFF) ||
	    (!led->active_low && value != LED_OFF))
		bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
	else
		bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);

	spin_unlock_irqrestore(led->lock, flags);
}

static unsigned long bcm6328_blink_delay(unsigned long delay)
{
	unsigned long bcm6328_delay;

	bcm6328_delay = delay + BCM6328_LED_BLINK_MS / 2;
	bcm6328_delay = bcm6328_delay / BCM6328_LED_BLINK_MS;
	if (bcm6328_delay == 0)
		bcm6328_delay = 1;

Annotation

Implementation Notes