drivers/leds/leds-pca963x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/leds/leds-pca963x.c
Extension
.c
Size
12123 bytes
Lines
466
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 pca963x_chipdef {
	u8			grppwm;
	u8			grpfreq;
	u8			ledout_base;
	int			n_leds;
	unsigned int		scaling;
};

static struct pca963x_chipdef pca963x_chipdefs[] = {
	[pca9633] = {
		.grppwm		= 0x6,
		.grpfreq	= 0x7,
		.ledout_base	= 0x8,
		.n_leds		= 4,
	},
	[pca9634] = {
		.grppwm		= 0xa,
		.grpfreq	= 0xb,
		.ledout_base	= 0xc,
		.n_leds		= 8,
	},
	[pca9635] = {
		.grppwm		= 0x12,
		.grpfreq	= 0x13,
		.ledout_base	= 0x14,
		.n_leds		= 16,
	},
};

/* Total blink period in milliseconds */
#define PCA963X_BLINK_PERIOD_MIN	42
#define PCA963X_BLINK_PERIOD_MAX	10667

static const struct i2c_device_id pca963x_id[] = {
	{ .name = "pca9632", .driver_data = pca9633 },
	{ .name = "pca9633", .driver_data = pca9633 },
	{ .name = "pca9634", .driver_data = pca9634 },
	{ .name = "pca9635", .driver_data = pca9635 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, pca963x_id);

struct pca963x;

struct pca963x_led {
	struct pca963x *chip;
	struct led_classdev led_cdev;
	int led_num; /* 0 .. 15 potentially */
	bool blinking;
	u8 gdc;
	u8 gfrq;
};

struct pca963x {
	struct pca963x_chipdef *chipdef;
	struct mutex mutex;
	struct i2c_client *client;
	unsigned long leds_on;
	struct pca963x_led leds[];
};

static int pca963x_brightness(struct pca963x_led *led,
			      enum led_brightness brightness)
{
	struct i2c_client *client = led->chip->client;
	struct pca963x_chipdef *chipdef = led->chip->chipdef;
	u8 ledout_addr, ledout, mask, val;
	int shift;
	int ret;

	ledout_addr = chipdef->ledout_base + (led->led_num / 4);
	shift = 2 * (led->led_num % 4);
	mask = 0x3 << shift;
	ledout = i2c_smbus_read_byte_data(client, ledout_addr);

	switch (brightness) {
	case LED_FULL:
		if (led->blinking) {
			val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift);
			ret = i2c_smbus_write_byte_data(client,
						PCA963X_PWM_BASE +
						led->led_num,
						LED_FULL);
		} else {
			val = (ledout & ~mask) | (PCA963X_LED_ON << shift);
		}
		ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
		break;
	case LED_OFF:
		val = ledout & ~mask;

Annotation

Implementation Notes