drivers/leds/leds-pca995x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/leds/leds-pca995x.c
Extension
.c
Size
5779 bytes
Lines
219
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 pca995x_chipdef {
	unsigned int num_leds;
	u8 pwm_base;
	u8 irefall;
};

static const struct pca995x_chipdef pca9952_chipdef = {
	.num_leds	= 16,
	.pwm_base	= 0x0a,
	.irefall	= 0x43,
};

static const struct pca995x_chipdef pca9955b_chipdef = {
	.num_leds	= 16,
	.pwm_base	= 0x08,
	.irefall	= 0x45,
};

static const struct pca995x_chipdef pca9956b_chipdef = {
	.num_leds	= 24,
	.pwm_base	= 0x0a,
	.irefall	= 0x40,
};

struct pca995x_led {
	unsigned int led_no;
	struct led_classdev ldev;
	struct pca995x_chip *chip;
};

struct pca995x_chip {
	struct regmap *regmap;
	struct pca995x_led leds[PCA995X_MAX_OUTPUTS];
	const struct pca995x_chipdef *chipdef;
};

static int pca995x_brightness_set(struct led_classdev *led_cdev,
				  enum led_brightness brightness)
{
	struct pca995x_led *led = ldev_to_led(led_cdev);
	struct pca995x_chip *chip = led->chip;
	const struct pca995x_chipdef *chipdef = chip->chipdef;
	u8 ledout_addr, pwmout_addr;
	int shift, ret;

	pwmout_addr = chipdef->pwm_base + led->led_no;
	ledout_addr = PCA995X_LEDOUT0 + (led->led_no / PCA995X_OUTPUTS_PER_REG);
	shift = PCA995X_LDRX_BITS * (led->led_no % PCA995X_OUTPUTS_PER_REG);

	switch (brightness) {
	case LED_FULL:
		return regmap_update_bits(chip->regmap, ledout_addr,
					  PCA995X_LDRX_MASK << shift,
					  PCA995X_LED_ON << shift);
	case LED_OFF:
		return regmap_update_bits(chip->regmap, ledout_addr,
					  PCA995X_LDRX_MASK << shift, 0);
	default:
		/* Adjust brightness as per user input by changing individual PWM */
		ret = regmap_write(chip->regmap, pwmout_addr, brightness);
		if (ret)
			return ret;

		/*
		 * Change LDRx configuration to individual brightness via PWM.
		 * LED will stop blinking if it's doing so.
		 */
		return regmap_update_bits(chip->regmap, ledout_addr,
					  PCA995X_LDRX_MASK << shift,
					  PCA995X_LED_PWM_MODE << shift);
	}
}

static const struct regmap_config pca995x_regmap = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = 0x49,
};

static int pca995x_probe(struct i2c_client *client)
{
	struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 };
	struct device *dev = &client->dev;
	const struct pca995x_chipdef *chipdef;
	struct pca995x_chip *chip;
	struct pca995x_led *led;
	int i, j, reg, ret;

	chipdef = device_get_match_data(&client->dev);

Annotation

Implementation Notes