// SPDX-License-Identifier: GPL-2.0-only
/*
* HCI based Driver for NXP PN544 NFC Chip
*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/nfc.h>
#include <net/nfc/hci.h>
#include <net/nfc/llc.h>
#include "pn544.h"
/* Timing restrictions (ms) */
#define PN544_HCI_RESETVEN_TIME 30
enum pn544_state {
PN544_ST_COLD,
PN544_ST_FW_READY,
PN544_ST_READY,
};
#define FULL_VERSION_LEN 11
/* Proprietary commands */
#define PN544_WRITE 0x3f
#define PN544_TEST_SWP 0x21
/* Proprietary gates, events, commands and registers */
/* NFC_HCI_RF_READER_A_GATE additional registers and commands */
#define PN544_RF_READER_A_AUTO_ACTIVATION 0x10
#define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12
#define PN544_MIFARE_CMD 0x21
/* Commands that apply to all RF readers */
#define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30
#define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32
/* NFC_HCI_ID_MGMT_GATE additional registers */
#define PN544_ID_MGMT_FULL_VERSION_SW 0x10
#define PN544_RF_READER_ISO15693_GATE 0x12
#define PN544_RF_READER_F_GATE 0x14
#define PN544_FELICA_ID 0x04
#define PN544_FELICA_RAW 0x20
#define PN544_RF_READER_JEWEL_GATE 0x15
#define PN544_JEWEL_RAW_CMD 0x23
#define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30
#define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31
#define PN544_SYS_MGMT_GATE 0x90
#define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02
#define PN544_POLLING_LOOP_MGMT_GATE 0x94
#define PN544_DEP_MODE 0x01
#define PN544_DEP_ATR_REQ 0x02
#define PN544_DEP_ATR_RES 0x03
#define PN544_DEP_MERGE 0x0D
#define PN544_PL_RDPHASES 0x06
#define PN544_PL_EMULATION 0x07
#define PN544_PL_NFCT_DEACTIVATED 0x09
#define PN544_SWP_MGMT_GATE 0xA0
#define PN544_SWP_DEFAULT_MODE 0x01
#define PN544_NFC_WI_MGMT_GATE 0xA1
#define PN544_NFC_ESE_DEFAULT_MODE 0x01
#define PN544_HCI_EVT_SND_DATA 0x01
#define PN544_HCI_EVT_ACTIVATED 0x02
#define PN544_HCI_EVT_DEACTIVATED 0x03
#define PN544_HCI_EVT_RCV_DATA 0x04
#define PN544_HCI_EVT_CONTINUE_MI 0x05
#define PN544_HCI_EVT_SWITCH_MODE 0x03
#define PN544_HCI_CMD_ATTREQUEST 0x12
#define PN544_HCI_CMD_CONTINUE_ACTIVATION 0x13
static struct nfc_hci_gate pn544_gates[] = {
{NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE},
{PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE},
{PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
{PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
{PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE},
{PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
{PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE},
{PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
{PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE},
{PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE}
};
/* Largest headroom needed for outgoing custom commands */
#define PN544_CMDS_HEADROOM 2
struct pn544_hci_info {
struct nfc_phy_ops *phy_ops;
void *phy_id;
struct nfc_hci_dev *hdev;
enum pn544_state state;
struct mutex info_lock;
int async_cb_type;
data_exchange_cb_t async_cb;
void *async_cb_context;
fw_download_t fw_download;
};
static int pn544_hci_open(struct nfc_hci_dev *hdev)
{
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
int r = 0;
mutex_lock(&info->info_lock);
if (info->state != PN544_ST_COLD) {
r = -EBUSY;
goto out;
}
r = info->phy_ops->enable(info->phy_id);
if (r == 0)
info->state = PN544_ST_READY;
out:
mutex_unlock(&info->info_lock);
return r;
}
static void pn544_hci_close(struct nfc_hci_dev *hdev)
{
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
mutex_lock(&info->info_lock);
if (info->state == PN544_ST_COLD)
goto out;
info->phy_ops->disable(info->phy_id);
info->state = PN544_ST_COLD;
out:
mutex_unlock(&info->info_lock);
}
static int pn544_hci_ready(struct nfc_hci_dev *hdev)
{
struct sk_buff *skb;
static struct hw_config {
u8 adr[2];
u8 value;
} hw_config[] = {
{{0x9f, 0x9a}, 0x00},
{{0x98, 0x10}, 0xbc},
{{0x9e, 0x71}, 0x00},
{{0x98, 0x09}, 0x00},
{{0x9e, 0xb4}, 0x00},
{{0x9c, 0x01}, 0x08},
{{0x9e, 0xaa}, 0x01},
{{0x9b, 0xd1}, 0x17},
{{0x9b, 0xd2}, 0x58},
{{0x9b, 0xd3}, 0x10},
{{0x9b, 0xd4}, 0x47},
{{0x9b, 0xd5}, 0x0c},
{{0x9b, 0xd6}, 0x37},
{{0x9b, 0xdd}, 0x33},
{{0x9b, 0x84}, 0x00},
{{0x99, 0x81}, 0x79},
{{0x99, 0x31}, 0x79},
{{0x98, 0x00}, 0x3f},
{{0x9f, 0x09}, 0x02},
{{0x9f, 0x0a}, 0x05},
{{0x9e, 0xd1}, 0xa1},
{{0x99, 0x23}, 0x01},
{{0x9e, 0x74}, 0x00},
{{0x9e, 0x90}, 0x00},
{{0x9f, 0x28}, 0x10},
{{0x9f, 0x35}, 0x04},
{{0x9f,<