// SPDX-License-Identifier: GPL-2.0-only /* * I2C Link Layer for PN544 HCI based Driver * * Copyright (C) 2012 Intel Corporation. All rights reserved.
*/
/* * Exposed through the 4 most significant bytes * from the HCI SW_VERSION first byte, a.k.a. * SW RomLib.
*/ #define PN544_HW_VARIANT_C2 0xa #define PN544_HW_VARIANT_C3 0xb
/* * Writing a frame must not return the number of written bytes. * It must return either zero for success, or <0 for error. * In addition, it must not alter the skb
*/ staticint pn544_hci_i2c_write(void *phy_id, struct sk_buff *skb)
{ int r; struct pn544_i2c_phy *phy = phy_id; struct i2c_client *client = phy->i2c_dev;
if (phy->hard_fault != 0) return phy->hard_fault;
usleep_range(3000, 6000);
pn544_hci_i2c_add_len_crc(skb);
I2C_DUMP_SKB("i2c frame written", skb);
r = i2c_master_send(client, skb->data, skb->len);
if (r == -EREMOTEIO) { /* Retry, chip was in standby */
usleep_range(6000, 10000);
r = i2c_master_send(client, skb->data, skb->len);
}
if (r >= 0) { if (r != skb->len)
r = -EREMOTEIO; else
r = 0;
}
pn544_hci_i2c_remove_len_crc(skb);
return r;
}
staticint check_crc(u8 *buf, int buflen)
{ int len;
u16 crc;
len = buf[0] + 1;
crc = crc_ccitt(0xffff, buf, len - 2);
crc = ~crc;
/* * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees * that i2c bus will be flushed and that next read will start on a new frame. * returned skb contains only LLC header and payload. * returns: * -EREMOTEIO : i2c read error (fatal) * -EBADMSG : frame was incorrect and discarded * -ENOMEM : cannot allocate skb, frame dropped
*/ staticint pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb)
{ int r;
u8 len;
u8 tmp[PN544_HCI_I2C_LLC_MAX_SIZE - 1]; struct i2c_client *client = phy->i2c_dev;
r = i2c_master_recv(client, &len, 1); if (r != 1) {
nfc_err(&client->dev, "cannot read len byte\n"); return -EREMOTEIO;
}
if ((len < (PN544_HCI_I2C_LLC_MIN_SIZE - 1)) ||
(len > (PN544_HCI_I2C_LLC_MAX_SIZE - 1))) {
nfc_err(&client->dev, "invalid len byte\n");
r = -EBADMSG; goto flush;
}
*skb = alloc_skb(1 + len, GFP_KERNEL); if (*skb == NULL) {
r = -ENOMEM; goto flush;
}
skb_put_u8(*skb, len);
r = i2c_master_recv(client, skb_put(*skb, len), len); if (r != len) {
kfree_skb(*skb); return -EREMOTEIO;
}
I2C_DUMP_SKB("i2c frame read", *skb);
r = check_crc((*skb)->data, (*skb)->len); if (r != 0) {
kfree_skb(*skb);
r = -EBADMSG; goto flush;
}
r = i2c_master_recv(client, (char *) &response, sizeof(response)); if (r != sizeof(response)) {
nfc_err(&client->dev, "cannot read fw status\n"); return -EIO;
}
usleep_range(3000, 6000);
switch (response.status) { case 0: return 0; case PN544_FW_CMD_RESULT_CHUNK_OK: return response.status; case PN544_FW_CMD_RESULT_TIMEOUT: return -ETIMEDOUT; case PN544_FW_CMD_RESULT_BAD_CRC: return -ENODATA; case PN544_FW_CMD_RESULT_ACCESS_DENIED: return -EACCES; case PN544_FW_CMD_RESULT_PROTOCOL_ERROR: return -EPROTO; case PN544_FW_CMD_RESULT_INVALID_PARAMETER: return -EINVAL; case PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND: return -ENOTSUPP; case PN544_FW_CMD_RESULT_INVALID_LENGTH: return -EBADMSG; case PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR: return -ENOKEY; case PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR: return -EINVAL; case PN544_FW_CMD_RESULT_MEMORY_ERROR: return -ENOMEM; case PN544_FW_CMD_RESULT_COMMAND_REJECTED: return -EACCES; case PN544_FW_CMD_RESULT_WRITE_FAILED: case PN544_FW_CMD_RESULT_CHUNK_ERROR: return -EIO; default: return -EIO;
}
}
/* * Reads an shdlc frame from the chip. This is not as straightforward as it * seems. There are cases where we could loose the frame start synchronization. * The frame format is len-data-crc, and corruption can occur anywhere while * transiting on i2c bus, such that we could read an invalid len. * In order to recover synchronization with the next frame, we must be sure * to read the real amount of data without using the len byte. We do this by * assuming the following: * - the chip will always present only one single complete frame on the bus * before triggering the interrupt * - the chip will not present a new frame until we have completely read * the previous one (or until we have handled the interrupt). * The tricky case is when we read a corrupted len that is less than the real * len. We must detect this here in order to determine that we need to flush * the bus. This is the reason why we check the crc here.
*/ static irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id)
{ struct pn544_i2c_phy *phy = phy_id; struct i2c_client *client; struct sk_buff *skb = NULL; int r;
/* Only secure write command can be chunked*/ if (phy->fw_blob_size > PN544_FW_I2C_MAX_PAYLOAD &&
framep->cmd != PN544_FW_CMD_SECURE_WRITE) return -EINVAL;
/* The firmware also have other commands, we just send them directly */ if (phy->fw_blob_size < PN544_FW_I2C_MAX_PAYLOAD) {
r = i2c_master_send(phy->i2c_dev,
(constchar *) phy->fw_blob_data, phy->fw_blob_size);
/* SW reset command will not trig any response from PN544 */ if (framep->cmd == PN544_FW_CMD_RESET) {
pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE);
phy->fw_cmd_result = 0;
schedule_work(&phy->fw_work);
}
r = devm_acpi_dev_add_driver_gpios(dev, acpi_pn544_gpios); if (r)
dev_dbg(dev, "Unable to add GPIO mapping table\n");
/* Get EN GPIO */
phy->gpiod_en = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(phy->gpiod_en)) {
nfc_err(dev, "Unable to get EN GPIO\n"); return PTR_ERR(phy->gpiod_en);
}
/* Get FW GPIO */
phy->gpiod_fw = devm_gpiod_get(dev, "firmware", GPIOD_OUT_LOW); if (IS_ERR(phy->gpiod_fw)) {
nfc_err(dev, "Unable to get FW GPIO\n"); return PTR_ERR(phy->gpiod_fw);
}
pn544_hci_i2c_platform_init(phy);
r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
pn544_hci_i2c_irq_thread_fn,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
PN544_HCI_I2C_DRIVER_NAME, phy); if (r < 0) {
nfc_err(&client->dev, "Unable to register IRQ handler\n"); return r;
}
r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM,
PN544_HCI_I2C_LLC_MAX_PAYLOAD,
pn544_hci_i2c_fw_download, &phy->hdev); if (r < 0) return r;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.