drivers/nfc/st21nfca/i2c.c

Source file repositories/reference/linux-study-clean/drivers/nfc/st21nfca/i2c.c

File Facts

System
Linux kernel
Corpus path
drivers/nfc/st21nfca/i2c.c
Extension
.c
Size
15465 bytes
Lines
607
Domain
Driver Families
Bucket
drivers/nfc
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 st21nfca_i2c_phy {
	struct i2c_client *i2c_dev;
	struct nfc_hci_dev *hdev;

	struct gpio_desc *gpiod_ena;
	struct st21nfca_se_status se_status;

	struct sk_buff *pending_skb;
	int current_read_len;
	/*
	 * crc might have fail because i2c macro
	 * is disable due to other interface activity
	 */
	int crc_trials;

	int powered;
	int run_mode;

	/*
	 * < 0 if hardware error occured (e.g. i2c err)
	 * and prevents normal operation.
	 */
	int hard_fault;
	struct mutex phy_lock;
};

static const u8 len_seq[] = { 16, 24, 12, 29 };
static const u16 wait_tab[] = { 2, 3, 5, 15, 20, 40};

#define I2C_DUMP_SKB(info, skb)					\
do {								\
	pr_debug("%s:\n", info);				\
	print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET,	\
		       16, 1, (skb)->data, (skb)->len, 0);	\
} while (0)

/*
 * In order to get the CLF in a known state we generate an internal reboot
 * using a proprietary command.
 * Once the reboot is completed, we expect to receive a ST21NFCA_SOF_EOF
 * fill buffer.
 */
static int st21nfca_hci_platform_init(struct st21nfca_i2c_phy *phy)
{
	u16 wait_reboot[] = { 50, 300, 1000 };
	char reboot_cmd[] = { 0x7E, 0x66, 0x48, 0xF6, 0x7E };
	u8 tmp[ST21NFCA_HCI_LLC_MAX_SIZE];
	int i, r = -1;

	for (i = 0; i < ARRAY_SIZE(wait_reboot) && r < 0; i++) {
		r = i2c_master_send(phy->i2c_dev, reboot_cmd,
				    sizeof(reboot_cmd));
		if (r < 0)
			msleep(wait_reboot[i]);
	}
	if (r < 0)
		return r;

	/* CLF is spending about 20ms to do an internal reboot */
	msleep(20);
	r = -1;
	for (i = 0; i < ARRAY_SIZE(wait_reboot) && r < 0; i++) {
		r = i2c_master_recv(phy->i2c_dev, tmp,
				    ST21NFCA_HCI_LLC_MAX_SIZE);
		if (r < 0)
			msleep(wait_reboot[i]);
	}
	if (r < 0)
		return r;

	for (i = 0; i < ST21NFCA_HCI_LLC_MAX_SIZE &&
		tmp[i] == ST21NFCA_SOF_EOF; i++)
		;

	if (r != ST21NFCA_HCI_LLC_MAX_SIZE)
		return -ENODEV;

	usleep_range(1000, 1500);
	return 0;
}

static int st21nfca_hci_i2c_enable(void *phy_id)
{
	struct st21nfca_i2c_phy *phy = phy_id;

	gpiod_set_value(phy->gpiod_ena, 1);
	phy->powered = 1;
	phy->run_mode = ST21NFCA_HCI_MODE;

	usleep_range(10000, 15000);

Annotation

Implementation Notes