drivers/hid/i2c-hid/i2c-hid-of-elan.c

Source file repositories/reference/linux-study-clean/drivers/hid/i2c-hid/i2c-hid-of-elan.c

File Facts

System
Linux kernel
Corpus path
drivers/hid/i2c-hid/i2c-hid-of-elan.c
Extension
.c
Size
6613 bytes
Lines
232
Domain
Driver Families
Bucket
drivers/hid
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 elan_i2c_hid_chip_data {
	unsigned int post_gpio_reset_on_delay_ms;
	unsigned int post_gpio_reset_off_delay_ms;
	unsigned int post_power_delay_ms;
	u16 hid_descriptor_address;
	const char *main_supply_name;
	bool power_after_backlight;
};

struct i2c_hid_of_elan {
	struct i2chid_ops ops;

	struct regulator *vcc33;
	struct regulator *vccio;
	struct gpio_desc *reset_gpio;
	bool no_reset_on_power_off;
	const struct elan_i2c_hid_chip_data *chip_data;
};

static int elan_i2c_hid_power_up(struct i2chid_ops *ops)
{
	struct i2c_hid_of_elan *ihid_elan =
		container_of(ops, struct i2c_hid_of_elan, ops);
	int ret;

	gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);

	if (ihid_elan->vcc33) {
		ret = regulator_enable(ihid_elan->vcc33);
		if (ret)
			goto err_deassert_reset;
	}

	ret = regulator_enable(ihid_elan->vccio);
	if (ret)
		goto err_disable_vcc33;

	if (ihid_elan->chip_data->post_power_delay_ms)
		msleep(ihid_elan->chip_data->post_power_delay_ms);

	gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0);
	if (ihid_elan->chip_data->post_gpio_reset_on_delay_ms)
		msleep(ihid_elan->chip_data->post_gpio_reset_on_delay_ms);

	return 0;

err_disable_vcc33:
	if (ihid_elan->vcc33)
		regulator_disable(ihid_elan->vcc33);
err_deassert_reset:
	if (ihid_elan->no_reset_on_power_off)
		gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0);

	return ret;
}

static void elan_i2c_hid_power_down(struct i2chid_ops *ops)
{
	struct i2c_hid_of_elan *ihid_elan =
		container_of(ops, struct i2c_hid_of_elan, ops);

	/*
	 * Do not assert reset when the hardware allows for it to remain
	 * deasserted regardless of the state of the (shared) power supply to
	 * avoid wasting power when the supply is left on.
	 */
	if (!ihid_elan->no_reset_on_power_off)
		gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);

	if (ihid_elan->chip_data->post_gpio_reset_off_delay_ms)
		msleep(ihid_elan->chip_data->post_gpio_reset_off_delay_ms);

	regulator_disable(ihid_elan->vccio);
	if (ihid_elan->vcc33)
		regulator_disable(ihid_elan->vcc33);
}

static int i2c_hid_of_elan_probe(struct i2c_client *client)
{
	struct i2c_hid_of_elan *ihid_elan;
	int ret;
	u32 quirks = 0;

	ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL);
	if (!ihid_elan)
		return -ENOMEM;

	ihid_elan->ops.power_up = elan_i2c_hid_power_up;
	ihid_elan->ops.power_down = elan_i2c_hid_power_down;

Annotation

Implementation Notes