drivers/mfd/tps6594-i2c.c

Source file repositories/reference/linux-study-clean/drivers/mfd/tps6594-i2c.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/tps6594-i2c.c
Extension
.c
Size
6855 bytes
Lines
255
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
/*
 * I2C access driver for the following TI PMICs:
 *  - LP8764
 *  - TPS65224
 *  - TPS652G1
 *  - TPS6593
 *  - TPS6594
 *
 * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
 */

#include <linux/crc8.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of_device.h>
#include <linux/regmap.h>

#include <linux/mfd/tps6594.h>

static bool enable_crc;
module_param(enable_crc, bool, 0444);
MODULE_PARM_DESC(enable_crc, "Enable CRC feature for I2C interface");

DECLARE_CRC8_TABLE(tps6594_i2c_crc_table);

static int tps6594_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	int ret = i2c_transfer(adap, msgs, num);

	if (ret == num)
		return 0;
	else if (ret < 0)
		return ret;
	else
		return -EIO;
}

static int tps6594_i2c_reg_read_with_crc(struct i2c_client *client, u8 page, u8 reg, u8 *val)
{
	struct i2c_msg msgs[2];
	u8 buf_rx[] = { 0, 0 };
	/* I2C address = I2C base address + Page index */
	const u8 addr = client->addr + page;
	/*
	 * CRC is calculated from every bit included in the protocol
	 * except the ACK bits from the target. Byte stream is:
	 * - B0: (I2C_addr_7bits << 1) | WR_bit, with WR_bit = 0
	 * - B1: reg
	 * - B2: (I2C_addr_7bits << 1) | RD_bit, with RD_bit = 1
	 * - B3: val
	 * - B4: CRC from B0-B1-B2-B3
	 */
	u8 crc_data[] = { addr << 1, reg, addr << 1 | 1, 0 };
	int ret;

	/* Write register */
	msgs[0].addr = addr;
	msgs[0].flags = 0;
	msgs[0].len = 1;
	msgs[0].buf = &reg;

	/* Read data and CRC */
	msgs[1].addr = msgs[0].addr;
	msgs[1].flags = I2C_M_RD;
	msgs[1].len = 2;
	msgs[1].buf = buf_rx;

	ret = tps6594_i2c_transfer(client->adapter, msgs, 2);
	if (ret < 0)
		return ret;

	crc_data[sizeof(crc_data) - 1] = *val = buf_rx[0];
	if (buf_rx[1] != crc8(tps6594_i2c_crc_table, crc_data, sizeof(crc_data), CRC8_INIT_VALUE))
		return -EIO;

	return ret;
}

static int tps6594_i2c_reg_write_with_crc(struct i2c_client *client, u8 page, u8 reg, u8 val)
{
	struct i2c_msg msg;
	u8 buf[] = { reg, val, 0 };
	/* I2C address = I2C base address + Page index */
	const u8 addr = client->addr + page;
	/*
	 * CRC is calculated from every bit included in the protocol
	 * except the ACK bits from the target. Byte stream is:
	 * - B0: (I2C_addr_7bits << 1) | WR_bit, with WR_bit = 0

Annotation

Implementation Notes