drivers/platform/arm64/acer-aspire1-ec.c

Source file repositories/reference/linux-study-clean/drivers/platform/arm64/acer-aspire1-ec.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/arm64/acer-aspire1-ec.c
Extension
.c
Size
15057 bytes
Lines
563
Domain
Driver Families
Bucket
drivers/platform
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 aspire_ec {
	struct i2c_client *client;
	struct power_supply *bat_psy;
	struct power_supply *adp_psy;
	struct input_dev *idev;

	bool bridge_configured;
	struct drm_bridge bridge;
	struct work_struct work;
};

static int aspire_ec_ram_read(struct i2c_client *client, u8 off, u8 *data, u8 data_len)
{
	i2c_smbus_write_byte_data(client, ASPIRE_EC_RAM_READ, off);
	i2c_smbus_read_i2c_block_data(client, ASPIRE_EC_RAM_READ, data_len, data);
	return 0;
}

static int aspire_ec_ram_write(struct i2c_client *client, u8 off, u8 data)
{
	u8 tmp[2] = {off, data};

	i2c_smbus_write_i2c_block_data(client, ASPIRE_EC_RAM_WRITE, sizeof(tmp), tmp);
	return 0;
}

static irqreturn_t aspire_ec_irq_handler(int irq, void *data)
{
	struct aspire_ec *ec = data;
	int id;
	u8 tmp;

	/*
	 * The original ACPI firmware actually has a small sleep in the handler.
	 *
	 * It seems like in most cases it's not needed but when the device
	 * just exits suspend, our i2c driver has a brief time where data
	 * transfer is not possible yet. So this delay allows us to suppress
	 * quite a bunch of spurious error messages in dmesg. Thus it's kept.
	 */
	usleep_range(15000, 30000);

	id = i2c_smbus_read_byte_data(ec->client, ASPIRE_EC_EVENT);
	if (id < 0) {
		dev_err(&ec->client->dev, "Failed to read event id: %pe\n", ERR_PTR(id));
		return IRQ_HANDLED;
	}

	switch (id) {
	case 0x0: /* No event */
		break;

	case ASPIRE_EC_EVENT_WATCHDOG:
		/*
		 * Here acpi responds to the event and clears some bit.
		 * Notify (\_SB.I2C3.BAT1, 0x81) // Information Change
		 * Notify (\_SB.I2C3.ADP1, 0x80) // Status Change
		 */
		aspire_ec_ram_read(ec->client, ASPIRE_EC_RAM_WATCHDOG, &tmp, sizeof(tmp));
		tmp &= ~ASPIRE_EC_WATCHDOG_BIT;
		aspire_ec_ram_write(ec->client, ASPIRE_EC_RAM_WATCHDOG, tmp);
		break;

	case ASPIRE_EC_EVENT_LID_CLOSE:
		/* Notify (\_SB.LID0, 0x80) // Status Change */
		input_report_switch(ec->idev, SW_LID, 1);
		input_sync(ec->idev);
		break;

	case ASPIRE_EC_EVENT_LID_OPEN:
		/* Notify (\_SB.LID0, 0x80) // Status Change */
		input_report_switch(ec->idev, SW_LID, 0);
		input_sync(ec->idev);
		break;

	case ASPIRE_EC_EVENT_FG_INF_CHG:
		/* Notify (\_SB.I2C3.BAT1, 0x81) // Information Change */
		fallthrough;
	case ASPIRE_EC_EVENT_FG_STA_CHG:
		/* Notify (\_SB.I2C3.BAT1, 0x80) // Status Change */
		power_supply_changed(ec->bat_psy);
		power_supply_changed(ec->adp_psy);
		break;

	case ASPIRE_EC_EVENT_HPD_DIS:
		if (ec->bridge_configured)
			drm_bridge_hpd_notify(&ec->bridge, connector_status_disconnected);
		break;

	case ASPIRE_EC_EVENT_HPD_CON:

Annotation

Implementation Notes