drivers/leds/flash/leds-qcom-flash.c

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

File Facts

System
Linux kernel
Corpus path
drivers/leds/flash/leds-qcom-flash.c
Extension
.c
Size
28158 bytes
Lines
990
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 qcom_flash_data {
	struct v4l2_flash	**v4l2_flash;
	struct regmap_field     *r_fields[REG_MAX_COUNT];
	struct mutex		lock;
	enum hw_type		hw_type;
	u32			total_ma;
	u8			leds_count;
	u8			max_channels;
	u8			chan_en_bits;
	u8			revision;
	u8			torch_clamp;
};

struct qcom_flash_led {
	struct qcom_flash_data		*flash_data;
	struct led_classdev_flash	flash;
	u32				max_flash_current_ma;
	u32				max_torch_current_ma;
	u32				max_timeout_ms;
	u32				flash_current_ma;
	u32				flash_timeout_ms;
	u32				current_in_use_ma;
	u8				*chan_id;
	u8				chan_count;
	bool				enabled;
};

static int set_flash_module_en(struct qcom_flash_led *led, bool en)
{
	struct qcom_flash_data *flash_data = led->flash_data;
	u8 led_mask = 0, enable;
	int i, rc;

	for (i = 0; i < led->chan_count; i++)
		led_mask |= BIT(led->chan_id[i]);

	mutex_lock(&flash_data->lock);
	if (en)
		flash_data->chan_en_bits |= led_mask;
	else
		flash_data->chan_en_bits &= ~led_mask;

	enable = !!flash_data->chan_en_bits;
	rc = regmap_field_write(flash_data->r_fields[REG_MODULE_EN], enable);
	if (rc)
		dev_err(led->flash.led_cdev.dev, "write module_en failed, rc=%d\n", rc);
	mutex_unlock(&flash_data->lock);

	return rc;
}

static int update_allowed_flash_current(struct qcom_flash_led *led, u32 *current_ma, bool strobe)
{
	struct qcom_flash_data *flash_data = led->flash_data;
	u32 therm_ma, avail_ma, thrsh[3], min_thrsh, sts;
	int rc = 0;

	mutex_lock(&flash_data->lock);
	/*
	 * Put previously allocated current into allowed budget in either of these two cases:
	 * 1) LED is disabled;
	 * 2) LED is enabled repeatedly
	 */
	if (!strobe || led->current_in_use_ma != 0) {
		if (flash_data->total_ma >= led->current_in_use_ma)
			flash_data->total_ma -= led->current_in_use_ma;
		else
			flash_data->total_ma = 0;

		led->current_in_use_ma = 0;
		if (!strobe)
			goto unlock;
	}

	/*
	 * Cache the default thermal threshold settings, and set them to the lowest levels before
	 * reading over-temp real time status. If over-temp has been triggered at the lowest
	 * threshold, it's very likely that it would be triggered at a higher (default) threshold
	 * when more flash current is requested. Prevent device from triggering over-temp condition
	 * by limiting the flash current for the new request.
	 */
	rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH1], &thrsh[0]);
	if (rc < 0)
		goto unlock;

	rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH2], &thrsh[1]);
	if (rc < 0)
		goto unlock;

	if (flash_data->hw_type == QCOM_MVFLASH_3CH) {

Annotation

Implementation Notes