drivers/mfd/acer-ec-a500.c

Source file repositories/reference/linux-study-clean/drivers/mfd/acer-ec-a500.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/acer-ec-a500.c
Extension
.c
Size
4517 bytes
Lines
201
Domain
Driver Families
Bucket
drivers/mfd
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

// SPDX-License-Identifier: GPL-2.0+
/*
 * Acer Iconia Tab A500 Embedded Controller Driver
 *
 * Copyright 2020 GRATE-driver project
 */

#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/reboot.h>
#include <linux/regmap.h>

#define A500_EC_I2C_ERR_TIMEOUT		500
#define A500_EC_POWER_CMD_TIMEOUT	1000

/*
 * Controller's firmware expects specific command opcodes to be used for the
 * corresponding registers. Unsupported commands are skipped by the firmware.
 */
#define CMD_SHUTDOWN			0x0
#define CMD_WARM_REBOOT			0x0
#define CMD_COLD_REBOOT			0x1

enum {
	REG_CURRENT_NOW = 0x03,
	REG_SHUTDOWN = 0x52,
	REG_WARM_REBOOT = 0x54,
	REG_COLD_REBOOT = 0x55,
};

static struct i2c_client *a500_ec_client_pm_off;

static int a500_ec_read(void *context, const void *reg_buf, size_t reg_size,
			void *val_buf, size_t val_sizel)
{
	struct i2c_client *client = context;
	unsigned int reg, retries = 5;
	u16 *ret_val = val_buf;
	s32 ret = 0;

	reg = *(u8 *)reg_buf;

	while (retries-- > 0) {
		ret = i2c_smbus_read_word_data(client, reg);
		if (ret >= 0)
			break;

		msleep(A500_EC_I2C_ERR_TIMEOUT);
	}

	if (ret < 0) {
		dev_err(&client->dev, "read 0x%x failed: %d\n", reg, ret);
		return ret;
	}

	*ret_val = ret;

	if (reg == REG_CURRENT_NOW)
		fsleep(10000);

	return 0;
}

static int a500_ec_write(void *context, const void *data, size_t count)
{
	struct i2c_client *client = context;
	unsigned int reg, val, retries = 5;
	s32 ret = 0;

	reg = *(u8  *)(data + 0);
	val = *(u16 *)(data + 1);

	while (retries-- > 0) {
		ret = i2c_smbus_write_word_data(client, reg, val);
		if (ret >= 0)
			break;

		msleep(A500_EC_I2C_ERR_TIMEOUT);
	}

	if (ret < 0) {
		dev_err(&client->dev, "write 0x%x failed: %d\n", reg, ret);
		return ret;
	}

	return 0;
}

Annotation

Implementation Notes