146fe7771SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
297f18414SEric Lapuyade /*
397f18414SEric Lapuyade * HCI based Driver for NXP PN544 NFC Chip
497f18414SEric Lapuyade *
597f18414SEric Lapuyade * Copyright (C) 2012 Intel Corporation. All rights reserved.
697f18414SEric Lapuyade */
797f18414SEric Lapuyade
817936b43SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
917936b43SJoe Perches
1097f18414SEric Lapuyade #include <linux/delay.h>
1197f18414SEric Lapuyade #include <linux/slab.h>
12aa741030SSamuel Ortiz #include <linux/module.h>
1397f18414SEric Lapuyade
1497f18414SEric Lapuyade #include <linux/nfc.h>
1597f18414SEric Lapuyade #include <net/nfc/hci.h>
1697f18414SEric Lapuyade
1797f18414SEric Lapuyade #include "pn544.h"
1897f18414SEric Lapuyade
1997f18414SEric Lapuyade /* Timing restrictions (ms) */
2097f18414SEric Lapuyade #define PN544_HCI_RESETVEN_TIME 30
2197f18414SEric Lapuyade
2297f18414SEric Lapuyade enum pn544_state {
2397f18414SEric Lapuyade PN544_ST_COLD,
2497f18414SEric Lapuyade PN544_ST_FW_READY,
2597f18414SEric Lapuyade PN544_ST_READY,
2697f18414SEric Lapuyade };
2797f18414SEric Lapuyade
2897f18414SEric Lapuyade #define FULL_VERSION_LEN 11
2997f18414SEric Lapuyade
3097f18414SEric Lapuyade /* Proprietary commands */
3197f18414SEric Lapuyade #define PN544_WRITE 0x3f
325faba2fdSArron Wang #define PN544_TEST_SWP 0x21
3397f18414SEric Lapuyade
3497f18414SEric Lapuyade /* Proprietary gates, events, commands and registers */
3597f18414SEric Lapuyade
3697f18414SEric Lapuyade /* NFC_HCI_RF_READER_A_GATE additional registers and commands */
3797f18414SEric Lapuyade #define PN544_RF_READER_A_AUTO_ACTIVATION 0x10
3897f18414SEric Lapuyade #define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12
3997f18414SEric Lapuyade #define PN544_MIFARE_CMD 0x21
4097f18414SEric Lapuyade
4197f18414SEric Lapuyade /* Commands that apply to all RF readers */
4297f18414SEric Lapuyade #define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30
4397f18414SEric Lapuyade #define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32
4497f18414SEric Lapuyade
4597f18414SEric Lapuyade /* NFC_HCI_ID_MGMT_GATE additional registers */
4697f18414SEric Lapuyade #define PN544_ID_MGMT_FULL_VERSION_SW 0x10
4797f18414SEric Lapuyade
4897f18414SEric Lapuyade #define PN544_RF_READER_ISO15693_GATE 0x12
4997f18414SEric Lapuyade
5097f18414SEric Lapuyade #define PN544_RF_READER_F_GATE 0x14
5197f18414SEric Lapuyade #define PN544_FELICA_ID 0x04
5297f18414SEric Lapuyade #define PN544_FELICA_RAW 0x20
5397f18414SEric Lapuyade
5497f18414SEric Lapuyade #define PN544_RF_READER_JEWEL_GATE 0x15
5597f18414SEric Lapuyade #define PN544_JEWEL_RAW_CMD 0x23
5697f18414SEric Lapuyade
5797f18414SEric Lapuyade #define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30
5897f18414SEric Lapuyade #define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31
5997f18414SEric Lapuyade
6097f18414SEric Lapuyade #define PN544_SYS_MGMT_GATE 0x90
6197f18414SEric Lapuyade #define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02
6297f18414SEric Lapuyade
6397f18414SEric Lapuyade #define PN544_POLLING_LOOP_MGMT_GATE 0x94
6497f18414SEric Lapuyade #define PN544_DEP_MODE 0x01
6597f18414SEric Lapuyade #define PN544_DEP_ATR_REQ 0x02
6697f18414SEric Lapuyade #define PN544_DEP_ATR_RES 0x03
6797f18414SEric Lapuyade #define PN544_DEP_MERGE 0x0D
6897f18414SEric Lapuyade #define PN544_PL_RDPHASES 0x06
6997f18414SEric Lapuyade #define PN544_PL_EMULATION 0x07
7097f18414SEric Lapuyade #define PN544_PL_NFCT_DEACTIVATED 0x09
7197f18414SEric Lapuyade
7297f18414SEric Lapuyade #define PN544_SWP_MGMT_GATE 0xA0
7339438261SArron Wang #define PN544_SWP_DEFAULT_MODE 0x01
7497f18414SEric Lapuyade
7597f18414SEric Lapuyade #define PN544_NFC_WI_MGMT_GATE 0xA1
765faba2fdSArron Wang #define PN544_NFC_ESE_DEFAULT_MODE 0x01
7797f18414SEric Lapuyade
7897f18414SEric Lapuyade #define PN544_HCI_EVT_SND_DATA 0x01
7997f18414SEric Lapuyade #define PN544_HCI_EVT_ACTIVATED 0x02
8097f18414SEric Lapuyade #define PN544_HCI_EVT_DEACTIVATED 0x03
8197f18414SEric Lapuyade #define PN544_HCI_EVT_RCV_DATA 0x04
8297f18414SEric Lapuyade #define PN544_HCI_EVT_CONTINUE_MI 0x05
835faba2fdSArron Wang #define PN544_HCI_EVT_SWITCH_MODE 0x03
8497f18414SEric Lapuyade
8597f18414SEric Lapuyade #define PN544_HCI_CMD_ATTREQUEST 0x12
8697f18414SEric Lapuyade #define PN544_HCI_CMD_CONTINUE_ACTIVATION 0x13
8797f18414SEric Lapuyade
885f3e6393SKrzysztof Kozlowski static const struct nfc_hci_gate pn544_gates[] = {
8997f18414SEric Lapuyade {NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE},
9097f18414SEric Lapuyade {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
9197f18414SEric Lapuyade {NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9297f18414SEric Lapuyade {NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9397f18414SEric Lapuyade {NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE},
9497f18414SEric Lapuyade {NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE},
9597f18414SEric Lapuyade {PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9697f18414SEric Lapuyade {PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9797f18414SEric Lapuyade {PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9897f18414SEric Lapuyade {PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9997f18414SEric Lapuyade {PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
10097f18414SEric Lapuyade {PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE},
10197f18414SEric Lapuyade {PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
10297f18414SEric Lapuyade {PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE},
10397f18414SEric Lapuyade {PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE}
10497f18414SEric Lapuyade };
10597f18414SEric Lapuyade
10697f18414SEric Lapuyade /* Largest headroom needed for outgoing custom commands */
10797f18414SEric Lapuyade #define PN544_CMDS_HEADROOM 2
10897f18414SEric Lapuyade
10997f18414SEric Lapuyade struct pn544_hci_info {
1107a5e98daSKrzysztof Kozlowski const struct nfc_phy_ops *phy_ops;
11197f18414SEric Lapuyade void *phy_id;
11297f18414SEric Lapuyade
11397f18414SEric Lapuyade struct nfc_hci_dev *hdev;
11497f18414SEric Lapuyade
11597f18414SEric Lapuyade enum pn544_state state;
11697f18414SEric Lapuyade
11797f18414SEric Lapuyade struct mutex info_lock;
11897f18414SEric Lapuyade
11997f18414SEric Lapuyade int async_cb_type;
12097f18414SEric Lapuyade data_exchange_cb_t async_cb;
12197f18414SEric Lapuyade void *async_cb_context;
1228bd7fc89SEric Lapuyade
1238bd7fc89SEric Lapuyade fw_download_t fw_download;
12497f18414SEric Lapuyade };
12597f18414SEric Lapuyade
pn544_hci_open(struct nfc_hci_dev * hdev)12697f18414SEric Lapuyade static int pn544_hci_open(struct nfc_hci_dev *hdev)
12797f18414SEric Lapuyade {
12897f18414SEric Lapuyade struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
12997f18414SEric Lapuyade int r = 0;
13097f18414SEric Lapuyade
13197f18414SEric Lapuyade mutex_lock(&info->info_lock);
13297f18414SEric Lapuyade
13397f18414SEric Lapuyade if (info->state != PN544_ST_COLD) {
13497f18414SEric Lapuyade r = -EBUSY;
13597f18414SEric Lapuyade goto out;
13697f18414SEric Lapuyade }
13797f18414SEric Lapuyade
13897f18414SEric Lapuyade r = info->phy_ops->enable(info->phy_id);
13997f18414SEric Lapuyade
14097f18414SEric Lapuyade if (r == 0)
14197f18414SEric Lapuyade info->state = PN544_ST_READY;
14297f18414SEric Lapuyade
14397f18414SEric Lapuyade out:
14497f18414SEric Lapuyade mutex_unlock(&info->info_lock);
14597f18414SEric Lapuyade return r;
14697f18414SEric Lapuyade }
14797f18414SEric Lapuyade
pn544_hci_close(struct nfc_hci_dev * hdev)14897f18414SEric Lapuyade static void pn544_hci_close(struct nfc_hci_dev *hdev)
14997f18414SEric Lapuyade {
15097f18414SEric Lapuyade struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
15197f18414SEric Lapuyade
15297f18414SEric Lapuyade mutex_lock(&info->info_lock);
15397f18414SEric Lapuyade
15497f18414SEric Lapuyade if (info->state == PN544_ST_COLD)
15597f18414SEric Lapuyade goto out;
15697f18414SEric Lapuyade
15797f18414SEric Lapuyade info->phy_ops->disable(info->phy_id);
15897f18414SEric Lapuyade
15997f18414SEric Lapuyade info->state = PN544_ST_COLD;
16097f18414SEric Lapuyade
16197f18414SEric Lapuyade out:
16297f18414SEric Lapuyade mutex_unlock(&info->info_lock);
16397f18414SEric Lapuyade }
16497f18414SEric Lapuyade
pn544_hci_ready(struct nfc_hci_dev * hdev)16597f18414SEric Lapuyade static int pn544_hci_ready(struct nfc_hci_dev *hdev)
16697f18414SEric Lapuyade {
16797f18414SEric Lapuyade struct sk_buff *skb;
16897f18414SEric Lapuyade static struct hw_config {
16997f18414SEric Lapuyade u8 adr[2];
17097f18414SEric Lapuyade u8 value;
17197f18414SEric Lapuyade } hw_config[] = {
17297f18414SEric Lapuyade {{0x9f, 0x9a}, 0x00},
17397f18414SEric Lapuyade
17497f18414SEric Lapuyade {{0x98, 0x10}, 0xbc},
17597f18414SEric Lapuyade
17697f18414SEric Lapuyade {{0x9e, 0x71}, 0x00},
17797f18414SEric Lapuyade
17897f18414SEric Lapuyade {{0x98, 0x09}, 0x00},
17997f18414SEric Lapuyade
18097f18414SEric Lapuyade {{0x9e, 0xb4}, 0x00},
18197f18414SEric Lapuyade
18297f18414SEric Lapuyade {{0x9c, 0x01}, 0x08},
18397f18414SEric Lapuyade
18497f18414SEric Lapuyade {{0x9e, 0xaa}, 0x01},
18597f18414SEric Lapuyade
18634f7e57bSArman Uguray {{0x9b, 0xd1}, 0x17},
18734f7e57bSArman Uguray {{0x9b, 0xd2}, 0x58},
18834f7e57bSArman Uguray {{0x9b, 0xd3}, 0x10},
18934f7e57bSArman Uguray {{0x9b, 0xd4}, 0x47},
19034f7e57bSArman Uguray {{0x9b, 0xd5}, 0x0c},
19134f7e57bSArman Uguray {{0x9b, 0xd6}, 0x37},
19234f7e57bSArman Uguray {{0x9b, 0xdd}, 0x33},
19397f18414SEric Lapuyade
19434f7e57bSArman Uguray {{0x9b, 0x84}, 0x00},
19534f7e57bSArman Uguray {{0x99, 0x81}, 0x79},
19634f7e57bSArman Uguray {{0x99, 0x31}, 0x79},
19797f18414SEric Lapuyade
19897f18414SEric Lapuyade {{0x98, 0x00}, 0x3f},
19997f18414SEric Lapuyade
20034f7e57bSArman Uguray {{0x9f, 0x09}, 0x02},
20197f18414SEric Lapuyade
20297f18414SEric Lapuyade {{0x9f, 0x0a}, 0x05},
20397f18414SEric Lapuyade
20497f18414SEric Lapuyade {{0x9e, 0xd1}, 0xa1},
20534f7e57bSArman Uguray {{0x99, 0x23}, 0x01},
20697f18414SEric Lapuyade
20734f7e57bSArman Uguray {{0x9e, 0x74}, 0x00},
20834f7e57bSArman Uguray {{0x9e, 0x90}, 0x00},
20997f18414SEric Lapuyade {{0x9f, 0x28}, 0x10},
21097f18414SEric Lapuyade
21134f7e57bSArman Uguray {{0x9f, 0x35}, 0x04},
21297f18414SEric Lapuyade
21334f7e57bSArman Uguray {{0x9f, 0x36}, 0x11},
21497f18414SEric Lapuyade
21597f18414SEric Lapuyade {{0x9c, 0x31}, 0x00},
21697f18414SEric Lapuyade
21734f7e57bSArman Uguray {{0x9c, 0x32}, 0x00},
21897f18414SEric Lapuyade
21934f7e57bSArman Uguray {{0x9c, 0x19}, 0x0a},
22097f18414SEric Lapuyade
22134f7e57bSArman Uguray {{0x9c, 0x1a}, 0x0a},
22297f18414SEric Lapuyade
22397f18414SEric Lapuyade {{0x9c, 0x0c}, 0x00},
22497f18414SEric Lapuyade
22597f18414SEric Lapuyade {{0x9c, 0x0d}, 0x00},
22697f18414SEric Lapuyade
22797f18414SEric Lapuyade {{0x9c, 0x12}, 0x00},
22897f18414SEric Lapuyade
22997f18414SEric Lapuyade {{0x9c, 0x13}, 0x00},
23097f18414SEric Lapuyade
23134f7e57bSArman Uguray {{0x98, 0xa2}, 0x09},
23297f18414SEric Lapuyade
23334f7e57bSArman Uguray {{0x98, 0x93}, 0x00},
23497f18414SEric Lapuyade
23534f7e57bSArman Uguray {{0x98, 0x7d}, 0x08},
23697f18414SEric Lapuyade {{0x98, 0x7e}, 0x00},
23734f7e57bSArman Uguray {{0x9f, 0xc8}, 0x00},
23897f18414SEric Lapuyade };
23997f18414SEric Lapuyade struct hw_config *p = hw_config;
24097f18414SEric Lapuyade int count = ARRAY_SIZE(hw_config);
24197f18414SEric Lapuyade struct sk_buff *res_skb;
24297f18414SEric Lapuyade u8 param[4];
24397f18414SEric Lapuyade int r;
24497f18414SEric Lapuyade
24597f18414SEric Lapuyade param[0] = 0;
24697f18414SEric Lapuyade while (count--) {
24797f18414SEric Lapuyade param[1] = p->adr[0];
24897f18414SEric Lapuyade param[2] = p->adr[1];
24997f18414SEric Lapuyade param[3] = p->value;
25097f18414SEric Lapuyade
25197f18414SEric Lapuyade r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE,
25297f18414SEric Lapuyade param, 4, &res_skb);
25397f18414SEric Lapuyade if (r < 0)
25497f18414SEric Lapuyade return r;
25597f18414SEric Lapuyade
25697f18414SEric Lapuyade if (res_skb->len != 1) {
25797f18414SEric Lapuyade kfree_skb(res_skb);
25897f18414SEric Lapuyade return -EPROTO;
25997f18414SEric Lapuyade }
26097f18414SEric Lapuyade
26197f18414SEric Lapuyade if (res_skb->data[0] != p->value) {
26297f18414SEric Lapuyade kfree_skb(res_skb);
26397f18414SEric Lapuyade return -EIO;
26497f18414SEric Lapuyade }
26597f18414SEric Lapuyade
26697f18414SEric Lapuyade kfree_skb(res_skb);
26797f18414SEric Lapuyade
26897f18414SEric Lapuyade p++;
26997f18414SEric Lapuyade }
27097f18414SEric Lapuyade
27197f18414SEric Lapuyade param[0] = NFC_HCI_UICC_HOST_ID;
27297f18414SEric Lapuyade r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
27397f18414SEric Lapuyade NFC_HCI_ADMIN_WHITELIST, param, 1);
27497f18414SEric Lapuyade if (r < 0)
27597f18414SEric Lapuyade return r;
27697f18414SEric Lapuyade
27797f18414SEric Lapuyade param[0] = 0x3d;
27897f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE,
27997f18414SEric Lapuyade PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1);
28097f18414SEric Lapuyade if (r < 0)
28197f18414SEric Lapuyade return r;
28297f18414SEric Lapuyade
28397f18414SEric Lapuyade param[0] = 0x0;
28497f18414SEric Lapuyade r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE,
28597f18414SEric Lapuyade PN544_RF_READER_A_AUTO_ACTIVATION, param, 1);
28697f18414SEric Lapuyade if (r < 0)
28797f18414SEric Lapuyade return r;
28897f18414SEric Lapuyade
28997f18414SEric Lapuyade r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
29097f18414SEric Lapuyade NFC_HCI_EVT_END_OPERATION, NULL, 0);
29197f18414SEric Lapuyade if (r < 0)
29297f18414SEric Lapuyade return r;
29397f18414SEric Lapuyade
29497f18414SEric Lapuyade param[0] = 0x1;
29597f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
29697f18414SEric Lapuyade PN544_PL_NFCT_DEACTIVATED, param, 1);
29797f18414SEric Lapuyade if (r < 0)
29897f18414SEric Lapuyade return r;
29997f18414SEric Lapuyade
30097f18414SEric Lapuyade param[0] = 0x0;
30197f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
30297f18414SEric Lapuyade PN544_PL_RDPHASES, param, 1);
30397f18414SEric Lapuyade if (r < 0)
30497f18414SEric Lapuyade return r;
30597f18414SEric Lapuyade
30697f18414SEric Lapuyade r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
30797f18414SEric Lapuyade PN544_ID_MGMT_FULL_VERSION_SW, &skb);
30897f18414SEric Lapuyade if (r < 0)
30997f18414SEric Lapuyade return r;
31097f18414SEric Lapuyade
31197f18414SEric Lapuyade if (skb->len != FULL_VERSION_LEN) {
31297f18414SEric Lapuyade kfree_skb(skb);
31397f18414SEric Lapuyade return -EINVAL;
31497f18414SEric Lapuyade }
31597f18414SEric Lapuyade
31697f18414SEric Lapuyade print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ",
31797f18414SEric Lapuyade DUMP_PREFIX_NONE, 16, 1,
31897f18414SEric Lapuyade skb->data, FULL_VERSION_LEN, false);
31997f18414SEric Lapuyade
32097f18414SEric Lapuyade kfree_skb(skb);
32197f18414SEric Lapuyade
32297f18414SEric Lapuyade return 0;
32397f18414SEric Lapuyade }
32497f18414SEric Lapuyade
pn544_hci_xmit(struct nfc_hci_dev * hdev,struct sk_buff * skb)32597f18414SEric Lapuyade static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
32697f18414SEric Lapuyade {
32797f18414SEric Lapuyade struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
32897f18414SEric Lapuyade
32997f18414SEric Lapuyade return info->phy_ops->write(info->phy_id, skb);
33097f18414SEric Lapuyade }
33197f18414SEric Lapuyade
pn544_hci_start_poll(struct nfc_hci_dev * hdev,u32 im_protocols,u32 tm_protocols)33297f18414SEric Lapuyade static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
33397f18414SEric Lapuyade u32 im_protocols, u32 tm_protocols)
33497f18414SEric Lapuyade {
33597f18414SEric Lapuyade u8 phases = 0;
33697f18414SEric Lapuyade int r;
33797f18414SEric Lapuyade u8 duration[2];
33897f18414SEric Lapuyade u8 activated;
33997f18414SEric Lapuyade u8 i_mode = 0x3f; /* Enable all supported modes */
34097f18414SEric Lapuyade u8 t_mode = 0x0f;
34197f18414SEric Lapuyade u8 t_merge = 0x01; /* Enable merge by default */
34297f18414SEric Lapuyade
34397f18414SEric Lapuyade pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
34497f18414SEric Lapuyade __func__, im_protocols, tm_protocols);
34597f18414SEric Lapuyade
34697f18414SEric Lapuyade r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
34797f18414SEric Lapuyade NFC_HCI_EVT_END_OPERATION, NULL, 0);
34897f18414SEric Lapuyade if (r < 0)
34997f18414SEric Lapuyade return r;
35097f18414SEric Lapuyade
35197f18414SEric Lapuyade duration[0] = 0x18;
35297f18414SEric Lapuyade duration[1] = 0x6a;
35397f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
35497f18414SEric Lapuyade PN544_PL_EMULATION, duration, 2);
35597f18414SEric Lapuyade if (r < 0)
35697f18414SEric Lapuyade return r;
35797f18414SEric Lapuyade
35897f18414SEric Lapuyade activated = 0;
35997f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
36097f18414SEric Lapuyade PN544_PL_NFCT_DEACTIVATED, &activated, 1);
36197f18414SEric Lapuyade if (r < 0)
36297f18414SEric Lapuyade return r;
36397f18414SEric Lapuyade
36497f18414SEric Lapuyade if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
36597f18414SEric Lapuyade NFC_PROTO_JEWEL_MASK))
36697f18414SEric Lapuyade phases |= 1; /* Type A */
36797f18414SEric Lapuyade if (im_protocols & NFC_PROTO_FELICA_MASK) {
36897f18414SEric Lapuyade phases |= (1 << 2); /* Type F 212 */
36997f18414SEric Lapuyade phases |= (1 << 3); /* Type F 424 */
37097f18414SEric Lapuyade }
37197f18414SEric Lapuyade
37297f18414SEric Lapuyade phases |= (1 << 5); /* NFC active */
37397f18414SEric Lapuyade
37497f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
37597f18414SEric Lapuyade PN544_PL_RDPHASES, &phases, 1);
37697f18414SEric Lapuyade if (r < 0)
37797f18414SEric Lapuyade return r;
37897f18414SEric Lapuyade
37997f18414SEric Lapuyade if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
38097f18414SEric Lapuyade hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
38197f18414SEric Lapuyade &hdev->gb_len);
38217936b43SJoe Perches pr_debug("generate local bytes %p\n", hdev->gb);
38397f18414SEric Lapuyade if (hdev->gb == NULL || hdev->gb_len == 0) {
38497f18414SEric Lapuyade im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
38597f18414SEric Lapuyade tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
38697f18414SEric Lapuyade }
38797f18414SEric Lapuyade }
38897f18414SEric Lapuyade
38997f18414SEric Lapuyade if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
39097f18414SEric Lapuyade r = nfc_hci_send_event(hdev,
39197f18414SEric Lapuyade PN544_RF_READER_NFCIP1_INITIATOR_GATE,
39297f18414SEric Lapuyade NFC_HCI_EVT_END_OPERATION, NULL, 0);
39397f18414SEric Lapuyade if (r < 0)
39497f18414SEric Lapuyade return r;
39597f18414SEric Lapuyade
39697f18414SEric Lapuyade r = nfc_hci_set_param(hdev,
39797f18414SEric Lapuyade PN544_RF_READER_NFCIP1_INITIATOR_GATE,
39897f18414SEric Lapuyade PN544_DEP_MODE, &i_mode, 1);
39997f18414SEric Lapuyade if (r < 0)
40097f18414SEric Lapuyade return r;
40197f18414SEric Lapuyade
40297f18414SEric Lapuyade r = nfc_hci_set_param(hdev,
40397f18414SEric Lapuyade PN544_RF_READER_NFCIP1_INITIATOR_GATE,
40497f18414SEric Lapuyade PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len);
40597f18414SEric Lapuyade if (r < 0)
40697f18414SEric Lapuyade return r;
40797f18414SEric Lapuyade
40897f18414SEric Lapuyade r = nfc_hci_send_event(hdev,
40997f18414SEric Lapuyade PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41097f18414SEric Lapuyade NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
41197f18414SEric Lapuyade if (r < 0)
41297f18414SEric Lapuyade nfc_hci_send_event(hdev,
41397f18414SEric Lapuyade PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41497f18414SEric Lapuyade NFC_HCI_EVT_END_OPERATION, NULL, 0);
41597f18414SEric Lapuyade }
41697f18414SEric Lapuyade
41797f18414SEric Lapuyade if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
41897f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
41997f18414SEric Lapuyade PN544_DEP_MODE, &t_mode, 1);
42097f18414SEric Lapuyade if (r < 0)
42197f18414SEric Lapuyade return r;
42297f18414SEric Lapuyade
42397f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
42497f18414SEric Lapuyade PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len);
42597f18414SEric Lapuyade if (r < 0)
42697f18414SEric Lapuyade return r;
42797f18414SEric Lapuyade
42897f18414SEric Lapuyade r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
42997f18414SEric Lapuyade PN544_DEP_MERGE, &t_merge, 1);
43097f18414SEric Lapuyade if (r < 0)
43197f18414SEric Lapuyade return r;
43297f18414SEric Lapuyade }
43397f18414SEric Lapuyade
43497f18414SEric Lapuyade r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
43597f18414SEric Lapuyade NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
43697f18414SEric Lapuyade if (r < 0)
43797f18414SEric Lapuyade nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
43897f18414SEric Lapuyade NFC_HCI_EVT_END_OPERATION, NULL, 0);
43997f18414SEric Lapuyade
44097f18414SEric Lapuyade return r;
44197f18414SEric Lapuyade }
44297f18414SEric Lapuyade
pn544_hci_dep_link_up(struct nfc_hci_dev * hdev,struct nfc_target * target,u8 comm_mode,u8 * gb,size_t gb_len)44397f18414SEric Lapuyade static int pn544_hci_dep_link_up(struct nfc_hci_dev *hdev,
44497f18414SEric Lapuyade struct nfc_target *target, u8 comm_mode,
44597f18414SEric Lapuyade u8 *gb, size_t gb_len)
44697f18414SEric Lapuyade {
44797f18414SEric Lapuyade struct sk_buff *rgb_skb = NULL;
44897f18414SEric Lapuyade int r;
44997f18414SEric Lapuyade
45097f18414SEric Lapuyade r = nfc_hci_get_param(hdev, target->hci_reader_gate,
45197f18414SEric Lapuyade PN544_DEP_ATR_RES, &rgb_skb);
45297f18414SEric Lapuyade if (r < 0)
45397f18414SEric Lapuyade return r;
45497f18414SEric Lapuyade
45597f18414SEric Lapuyade if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
45697f18414SEric Lapuyade r = -EPROTO;
45797f18414SEric Lapuyade goto exit;
45897f18414SEric Lapuyade }
45997f18414SEric Lapuyade print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET,
46097f18414SEric Lapuyade 16, 1, rgb_skb->data, rgb_skb->len, true);
46197f18414SEric Lapuyade
46297f18414SEric Lapuyade r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
46397f18414SEric Lapuyade rgb_skb->len);
46497f18414SEric Lapuyade
46597f18414SEric Lapuyade if (r == 0)
46697f18414SEric Lapuyade r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
46797f18414SEric Lapuyade NFC_RF_INITIATOR);
46897f18414SEric Lapuyade exit:
46997f18414SEric Lapuyade kfree_skb(rgb_skb);
47097f18414SEric Lapuyade return r;
47197f18414SEric Lapuyade }
47297f18414SEric Lapuyade
pn544_hci_dep_link_down(struct nfc_hci_dev * hdev)47397f18414SEric Lapuyade static int pn544_hci_dep_link_down(struct nfc_hci_dev *hdev)
47497f18414SEric Lapuyade {
47597f18414SEric Lapuyade
47697f18414SEric Lapuyade return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE,
47797f18414SEric Lapuyade NFC_HCI_EVT_END_OPERATION, NULL, 0);
47897f18414SEric Lapuyade }
47997f18414SEric Lapuyade
pn544_hci_target_from_gate(struct nfc_hci_dev * hdev,u8 gate,struct nfc_target * target)48097f18414SEric Lapuyade static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
48197f18414SEric Lapuyade struct nfc_target *target)
48297f18414SEric Lapuyade {
48397f18414SEric Lapuyade switch (gate) {
48497f18414SEric Lapuyade case PN544_RF_READER_F_GATE:
48597f18414SEric Lapuyade target->supported_protocols = NFC_PROTO_FELICA_MASK;
48697f18414SEric Lapuyade break;
48797f18414SEric Lapuyade case PN544_RF_READER_JEWEL_GATE:
48897f18414SEric Lapuyade target->supported_protocols = NFC_PROTO_JEWEL_MASK;
48997f18414SEric Lapuyade target->sens_res = 0x0c00;
49097f18414SEric Lapuyade break;
49197f18414SEric Lapuyade case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
49297f18414SEric Lapuyade target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
49397f18414SEric Lapuyade break;
49497f18414SEric Lapuyade default:
49597f18414SEric Lapuyade return -EPROTO;
49697f18414SEric Lapuyade }
49797f18414SEric Lapuyade
49897f18414SEric Lapuyade return 0;
49997f18414SEric Lapuyade }
50097f18414SEric Lapuyade
pn544_hci_complete_target_discovered(struct nfc_hci_dev * hdev,u8 gate,struct nfc_target * target)50197f18414SEric Lapuyade static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
50297f18414SEric Lapuyade u8 gate,
50397f18414SEric Lapuyade struct nfc_target *target)
50497f18414SEric Lapuyade {
50597f18414SEric Lapuyade struct sk_buff *uid_skb;
50697f18414SEric Lapuyade int r = 0;
50797f18414SEric Lapuyade
50897f18414SEric Lapuyade if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
50997f18414SEric Lapuyade return r;
51097f18414SEric Lapuyade
51197f18414SEric Lapuyade if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
51297f18414SEric Lapuyade r = nfc_hci_send_cmd(hdev,
51397f18414SEric Lapuyade PN544_RF_READER_NFCIP1_INITIATOR_GATE,
51497f18414SEric Lapuyade PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL);
51597f18414SEric Lapuyade if (r < 0)
51697f18414SEric Lapuyade return r;
51797f18414SEric Lapuyade
51897f18414SEric Lapuyade target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
51997f18414SEric Lapuyade } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
52097f18414SEric Lapuyade if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
52197f18414SEric Lapuyade target->nfcid1_len != 10)
52297f18414SEric Lapuyade return -EPROTO;
52397f18414SEric Lapuyade
52497f18414SEric Lapuyade r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
52597f18414SEric Lapuyade PN544_RF_READER_CMD_ACTIVATE_NEXT,
52697f18414SEric Lapuyade target->nfcid1, target->nfcid1_len, NULL);
52797f18414SEric Lapuyade } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
52897f18414SEric Lapuyade r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE,
52997f18414SEric Lapuyade PN544_FELICA_ID, &uid_skb);
53097f18414SEric Lapuyade if (r < 0)
53197f18414SEric Lapuyade return r;
53297f18414SEric Lapuyade
53397f18414SEric Lapuyade if (uid_skb->len != 8) {
53497f18414SEric Lapuyade kfree_skb(uid_skb);
53597f18414SEric Lapuyade return -EPROTO;
53697f18414SEric Lapuyade }
53797f18414SEric Lapuyade
5389c598440SArron Wang /* Type F NFC-DEP IDm has prefix 0x01FE */
5399c598440SArron Wang if ((uid_skb->data[0] == 0x01) && (uid_skb->data[1] == 0xfe)) {
54097f18414SEric Lapuyade kfree_skb(uid_skb);
54197f18414SEric Lapuyade r = nfc_hci_send_cmd(hdev,
54297f18414SEric Lapuyade PN544_RF_READER_NFCIP1_INITIATOR_GATE,
54397f18414SEric Lapuyade PN544_HCI_CMD_CONTINUE_ACTIVATION,
54497f18414SEric Lapuyade NULL, 0, NULL);
54597f18414SEric Lapuyade if (r < 0)
54697f18414SEric Lapuyade return r;
54797f18414SEric Lapuyade
54897f18414SEric Lapuyade target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
5499c598440SArron Wang target->hci_reader_gate =
5509c598440SArron Wang PN544_RF_READER_NFCIP1_INITIATOR_GATE;
5519c598440SArron Wang } else {
5529c598440SArron Wang r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
5539c598440SArron Wang PN544_RF_READER_CMD_ACTIVATE_NEXT,
5549c598440SArron Wang uid_skb->data, uid_skb->len, NULL);
5559c598440SArron Wang kfree_skb(uid_skb);
5569c598440SArron Wang }
55797f18414SEric Lapuyade } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {
55897f18414SEric Lapuyade /*
55997f18414SEric Lapuyade * TODO: maybe other ISO 14443 require some kind of continue
56097f18414SEric Lapuyade * activation, but for now we've seen only this one below.
56197f18414SEric Lapuyade */
56297f18414SEric Lapuyade if (target->sens_res == 0x4403) /* Type 4 Mifare DESFire */
56397f18414SEric Lapuyade r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
56497f18414SEric Lapuyade PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION,
56597f18414SEric Lapuyade NULL, 0, NULL);
56697f18414SEric Lapuyade }
56797f18414SEric Lapuyade
56897f18414SEric Lapuyade return r;
56997f18414SEric Lapuyade }
57097f18414SEric Lapuyade
57197f18414SEric Lapuyade #define PN544_CB_TYPE_READER_F 1
57297f18414SEric Lapuyade
pn544_hci_data_exchange_cb(void * context,struct sk_buff * skb,int err)57397f18414SEric Lapuyade static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
57497f18414SEric Lapuyade int err)
57597f18414SEric Lapuyade {
57697f18414SEric Lapuyade struct pn544_hci_info *info = context;
57797f18414SEric Lapuyade
57897f18414SEric Lapuyade switch (info->async_cb_type) {
57997f18414SEric Lapuyade case PN544_CB_TYPE_READER_F:
58097f18414SEric Lapuyade if (err == 0)
58197f18414SEric Lapuyade skb_pull(skb, 1);
58297f18414SEric Lapuyade info->async_cb(info->async_cb_context, skb, err);
58397f18414SEric Lapuyade break;
58497f18414SEric Lapuyade default:
58597f18414SEric Lapuyade if (err == 0)
58697f18414SEric Lapuyade kfree_skb(skb);
58797f18414SEric Lapuyade break;
58897f18414SEric Lapuyade }
58997f18414SEric Lapuyade }
59097f18414SEric Lapuyade
59197f18414SEric Lapuyade #define MIFARE_CMD_AUTH_KEY_A 0x60
59297f18414SEric Lapuyade #define MIFARE_CMD_AUTH_KEY_B 0x61
59397f18414SEric Lapuyade #define MIFARE_CMD_HEADER 2
59497f18414SEric Lapuyade #define MIFARE_UID_LEN 4
59597f18414SEric Lapuyade #define MIFARE_KEY_LEN 6
59697f18414SEric Lapuyade #define MIFARE_CMD_LEN 12
59797f18414SEric Lapuyade /*
59897f18414SEric Lapuyade * Returns:
59997f18414SEric Lapuyade * <= 0: driver handled the data exchange
60097f18414SEric Lapuyade * 1: driver doesn't especially handle, please do standard processing
60197f18414SEric Lapuyade */
pn544_hci_im_transceive(struct nfc_hci_dev * hdev,struct nfc_target * target,struct sk_buff * skb,data_exchange_cb_t cb,void * cb_context)60297f18414SEric Lapuyade static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
60397f18414SEric Lapuyade struct nfc_target *target,
60497f18414SEric Lapuyade struct sk_buff *skb, data_exchange_cb_t cb,
60597f18414SEric Lapuyade void *cb_context)
60697f18414SEric Lapuyade {
60797f18414SEric Lapuyade struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
60897f18414SEric Lapuyade
60997f18414SEric Lapuyade pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
61097f18414SEric Lapuyade target->hci_reader_gate);
61197f18414SEric Lapuyade
61297f18414SEric Lapuyade switch (target->hci_reader_gate) {
61397f18414SEric Lapuyade case NFC_HCI_RF_READER_A_GATE:
61497f18414SEric Lapuyade if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
61597f18414SEric Lapuyade /*
61697f18414SEric Lapuyade * It seems that pn544 is inverting key and UID for
61797f18414SEric Lapuyade * MIFARE authentication commands.
61897f18414SEric Lapuyade */
61997f18414SEric Lapuyade if (skb->len == MIFARE_CMD_LEN &&
62097f18414SEric Lapuyade (skb->data[0] == MIFARE_CMD_AUTH_KEY_A ||
62197f18414SEric Lapuyade skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) {
62297f18414SEric Lapuyade u8 uid[MIFARE_UID_LEN];
62397f18414SEric Lapuyade u8 *data = skb->data + MIFARE_CMD_HEADER;
62497f18414SEric Lapuyade
62597f18414SEric Lapuyade memcpy(uid, data + MIFARE_KEY_LEN,
62697f18414SEric Lapuyade MIFARE_UID_LEN);
62797f18414SEric Lapuyade memmove(data + MIFARE_UID_LEN, data,
62897f18414SEric Lapuyade MIFARE_KEY_LEN);
62997f18414SEric Lapuyade memcpy(data, uid, MIFARE_UID_LEN);
63097f18414SEric Lapuyade }
63197f18414SEric Lapuyade
63297f18414SEric Lapuyade return nfc_hci_send_cmd_async(hdev,
63397f18414SEric Lapuyade target->hci_reader_gate,
63497f18414SEric Lapuyade PN544_MIFARE_CMD,
63597f18414SEric Lapuyade skb->data, skb->len,
63697f18414SEric Lapuyade cb, cb_context);
63797f18414SEric Lapuyade } else
63897f18414SEric Lapuyade return 1;
63997f18414SEric Lapuyade case PN544_RF_READER_F_GATE:
640d58ff351SJohannes Berg *(u8 *)skb_push(skb, 1) = 0;
641d58ff351SJohannes Berg *(u8 *)skb_push(skb, 1) = 0;
64297f18414SEric Lapuyade
64397f18414SEric Lapuyade info->async_cb_type = PN544_CB_TYPE_READER_F;
64497f18414SEric Lapuyade info->async_cb = cb;
64597f18414SEric Lapuyade info->async_cb_context = cb_context;
64697f18414SEric Lapuyade
64797f18414SEric Lapuyade return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
64897f18414SEric Lapuyade PN544_FELICA_RAW, skb->data,
64997f18414SEric Lapuyade skb->len,
65097f18414SEric Lapuyade pn544_hci_data_exchange_cb, info);
65197f18414SEric Lapuyade case PN544_RF_READER_JEWEL_GATE:
65297f18414SEric Lapuyade return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
65397f18414SEric Lapuyade PN544_JEWEL_RAW_CMD, skb->data,
65497f18414SEric Lapuyade skb->len, cb, cb_context);
65597f18414SEric Lapuyade case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
656d58ff351SJohannes Berg *(u8 *)skb_push(skb, 1) = 0;
65797f18414SEric Lapuyade
65897f18414SEric Lapuyade return nfc_hci_send_event(hdev, target->hci_reader_gate,
65997f18414SEric Lapuyade PN544_HCI_EVT_SND_DATA, skb->data,
66097f18414SEric Lapuyade skb->len);
66197f18414SEric Lapuyade default:
66297f18414SEric Lapuyade return 1;
66397f18414SEric Lapuyade }
66497f18414SEric Lapuyade }
66597f18414SEric Lapuyade
pn544_hci_tm_send(struct nfc_hci_dev * hdev,struct sk_buff * skb)66697f18414SEric Lapuyade static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
66797f18414SEric Lapuyade {
668924d4a02SEric Lapuyade int r;
669924d4a02SEric Lapuyade
67097f18414SEric Lapuyade /* Set default false for multiple information chaining */
671d58ff351SJohannes Berg *(u8 *)skb_push(skb, 1) = 0;
67297f18414SEric Lapuyade
673924d4a02SEric Lapuyade r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
67497f18414SEric Lapuyade PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
675924d4a02SEric Lapuyade
676924d4a02SEric Lapuyade kfree_skb(skb);
677924d4a02SEric Lapuyade
678924d4a02SEric Lapuyade return r;
67997f18414SEric Lapuyade }
68097f18414SEric Lapuyade
pn544_hci_check_presence(struct nfc_hci_dev * hdev,struct nfc_target * target)68197f18414SEric Lapuyade static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
68297f18414SEric Lapuyade struct nfc_target *target)
68397f18414SEric Lapuyade {
684c4c10784SChristophe JAILLET pr_debug("supported protocol %d\n", target->supported_protocols);
68597f18414SEric Lapuyade if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK |
68697f18414SEric Lapuyade NFC_PROTO_ISO14443_B_MASK)) {
68797f18414SEric Lapuyade return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
68897f18414SEric Lapuyade PN544_RF_READER_CMD_PRESENCE_CHECK,
68997f18414SEric Lapuyade NULL, 0, NULL);
69097f18414SEric Lapuyade } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
69197f18414SEric Lapuyade if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
69297f18414SEric Lapuyade target->nfcid1_len != 10)
69397f18414SEric Lapuyade return -EOPNOTSUPP;
69497f18414SEric Lapuyade
69597f18414SEric Lapuyade return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
69697f18414SEric Lapuyade PN544_RF_READER_CMD_ACTIVATE_NEXT,
69797f18414SEric Lapuyade target->nfcid1, target->nfcid1_len, NULL);
698a69bdc1eSArron Wang } else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK |
699a69bdc1eSArron Wang NFC_PROTO_FELICA_MASK)) {
700a69bdc1eSArron Wang return -EOPNOTSUPP;
70197f18414SEric Lapuyade } else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
70297f18414SEric Lapuyade return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
70397f18414SEric Lapuyade PN544_HCI_CMD_ATTREQUEST,
70497f18414SEric Lapuyade NULL, 0, NULL);
70597f18414SEric Lapuyade }
70697f18414SEric Lapuyade
70797f18414SEric Lapuyade return 0;
70897f18414SEric Lapuyade }
70997f18414SEric Lapuyade
71040d06d36SEric Lapuyade /*
71140d06d36SEric Lapuyade * Returns:
71240d06d36SEric Lapuyade * <= 0: driver handled the event, skb consumed
71340d06d36SEric Lapuyade * 1: driver does not handle the event, please do standard processing
71440d06d36SEric Lapuyade */
pn544_hci_event_received(struct nfc_hci_dev * hdev,u8 pipe,u8 event,struct sk_buff * skb)7158abe3c6aSChristophe Ricard static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
71627c31191SEric Lapuyade struct sk_buff *skb)
71797f18414SEric Lapuyade {
71897f18414SEric Lapuyade struct sk_buff *rgb_skb = NULL;
7198abe3c6aSChristophe Ricard u8 gate = hdev->pipes[pipe].gate;
72040d06d36SEric Lapuyade int r;
72197f18414SEric Lapuyade
72217936b43SJoe Perches pr_debug("hci event %d\n", event);
72397f18414SEric Lapuyade switch (event) {
72497f18414SEric Lapuyade case PN544_HCI_EVT_ACTIVATED:
72540d06d36SEric Lapuyade if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
72627c31191SEric Lapuyade r = nfc_hci_target_discovered(hdev, gate);
72740d06d36SEric Lapuyade } else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
72897f18414SEric Lapuyade r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
72997f18414SEric Lapuyade &rgb_skb);
73097f18414SEric Lapuyade if (r < 0)
73197f18414SEric Lapuyade goto exit;
73297f18414SEric Lapuyade
73327c31191SEric Lapuyade r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
73497f18414SEric Lapuyade NFC_COMM_PASSIVE, rgb_skb->data,
73597f18414SEric Lapuyade rgb_skb->len);
73697f18414SEric Lapuyade
73797f18414SEric Lapuyade kfree_skb(rgb_skb);
73840d06d36SEric Lapuyade } else {
73940d06d36SEric Lapuyade r = -EINVAL;
74097f18414SEric Lapuyade }
74197f18414SEric Lapuyade break;
74297f18414SEric Lapuyade case PN544_HCI_EVT_DEACTIVATED:
74327c31191SEric Lapuyade r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
74427c31191SEric Lapuyade NULL, 0);
74597f18414SEric Lapuyade break;
74697f18414SEric Lapuyade case PN544_HCI_EVT_RCV_DATA:
74797f18414SEric Lapuyade if (skb->len < 2) {
74897f18414SEric Lapuyade r = -EPROTO;
74997f18414SEric Lapuyade goto exit;
75097f18414SEric Lapuyade }
75197f18414SEric Lapuyade
75297f18414SEric Lapuyade if (skb->data[0] != 0) {
75317936b43SJoe Perches pr_debug("data0 %d\n", skb->data[0]);
75497f18414SEric Lapuyade r = -EPROTO;
75597f18414SEric Lapuyade goto exit;
75697f18414SEric Lapuyade }
75797f18414SEric Lapuyade
75897f18414SEric Lapuyade skb_pull(skb, 2);
75927c31191SEric Lapuyade return nfc_tm_data_received(hdev->ndev, skb);
76097f18414SEric Lapuyade default:
76140d06d36SEric Lapuyade return 1;
76297f18414SEric Lapuyade }
76397f18414SEric Lapuyade
76497f18414SEric Lapuyade exit:
76597f18414SEric Lapuyade kfree_skb(skb);
76627c31191SEric Lapuyade
76727c31191SEric Lapuyade return r;
76897f18414SEric Lapuyade }
76997f18414SEric Lapuyade
pn544_hci_fw_download(struct nfc_hci_dev * hdev,const char * firmware_name)7708bd7fc89SEric Lapuyade static int pn544_hci_fw_download(struct nfc_hci_dev *hdev,
7718bd7fc89SEric Lapuyade const char *firmware_name)
7728bd7fc89SEric Lapuyade {
7738bd7fc89SEric Lapuyade struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
7748bd7fc89SEric Lapuyade
7758bd7fc89SEric Lapuyade if (info->fw_download == NULL)
7768bd7fc89SEric Lapuyade return -ENOTSUPP;
7778bd7fc89SEric Lapuyade
778971d63cfSArron Wang return info->fw_download(info->phy_id, firmware_name, hdev->sw_romlib);
7798bd7fc89SEric Lapuyade }
7808bd7fc89SEric Lapuyade
pn544_hci_discover_se(struct nfc_hci_dev * hdev)7815faba2fdSArron Wang static int pn544_hci_discover_se(struct nfc_hci_dev *hdev)
7825faba2fdSArron Wang {
7835faba2fdSArron Wang u32 se_idx = 0;
7845faba2fdSArron Wang u8 ese_mode = 0x01; /* Default mode */
7855faba2fdSArron Wang struct sk_buff *res_skb;
7865faba2fdSArron Wang int r;
7875faba2fdSArron Wang
7885faba2fdSArron Wang r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_TEST_SWP,
7895faba2fdSArron Wang NULL, 0, &res_skb);
7905faba2fdSArron Wang
7915faba2fdSArron Wang if (r == 0) {
7925faba2fdSArron Wang if (res_skb->len == 2 && res_skb->data[0] == 0x00)
7935faba2fdSArron Wang nfc_add_se(hdev->ndev, se_idx++, NFC_SE_UICC);
7945faba2fdSArron Wang
7955faba2fdSArron Wang kfree_skb(res_skb);
7965faba2fdSArron Wang }
7975faba2fdSArron Wang
7985faba2fdSArron Wang r = nfc_hci_send_event(hdev, PN544_NFC_WI_MGMT_GATE,
7995faba2fdSArron Wang PN544_HCI_EVT_SWITCH_MODE,
8005faba2fdSArron Wang &ese_mode, 1);
8015faba2fdSArron Wang if (r == 0)
8025faba2fdSArron Wang nfc_add_se(hdev->ndev, se_idx++, NFC_SE_EMBEDDED);
8035faba2fdSArron Wang
8045faba2fdSArron Wang return !se_idx;
8055faba2fdSArron Wang }
8065faba2fdSArron Wang
80739438261SArron Wang #define PN544_SE_MODE_OFF 0x00
80839438261SArron Wang #define PN544_SE_MODE_ON 0x01
pn544_hci_enable_se(struct nfc_hci_dev * hdev,u32 se_idx)80939438261SArron Wang static int pn544_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
81039438261SArron Wang {
811*f2479c0aSKrzysztof Kozlowski const struct nfc_se *se;
81239438261SArron Wang u8 enable = PN544_SE_MODE_ON;
81339438261SArron Wang static struct uicc_gatelist {
81439438261SArron Wang u8 head;
81539438261SArron Wang u8 adr[2];
81639438261SArron Wang u8 value;
81739438261SArron Wang } uicc_gatelist[] = {
81839438261SArron Wang {0x00, {0x9e, 0xd9}, 0x23},
81939438261SArron Wang {0x00, {0x9e, 0xda}, 0x21},
82039438261SArron Wang {0x00, {0x9e, 0xdb}, 0x22},
82139438261SArron Wang {0x00, {0x9e, 0xdc}, 0x24},
82239438261SArron Wang };
82339438261SArron Wang struct uicc_gatelist *p = uicc_gatelist;
82439438261SArron Wang int count = ARRAY_SIZE(uicc_gatelist);
82539438261SArron Wang struct sk_buff *res_skb;
82639438261SArron Wang int r;
82739438261SArron Wang
82839438261SArron Wang se = nfc_find_se(hdev->ndev, se_idx);
82939438261SArron Wang
83039438261SArron Wang switch (se->type) {
83139438261SArron Wang case NFC_SE_UICC:
83239438261SArron Wang while (count--) {
83339438261SArron Wang r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE,
83439438261SArron Wang PN544_WRITE, (u8 *)p, 4, &res_skb);
83539438261SArron Wang if (r < 0)
83639438261SArron Wang return r;
83739438261SArron Wang
83839438261SArron Wang if (res_skb->len != 1) {
83939438261SArron Wang kfree_skb(res_skb);
84039438261SArron Wang return -EPROTO;
84139438261SArron Wang }
84239438261SArron Wang
84339438261SArron Wang if (res_skb->data[0] != p->value) {
84439438261SArron Wang kfree_skb(res_skb);
84539438261SArron Wang return -EIO;
84639438261SArron Wang }
84739438261SArron Wang
84839438261SArron Wang kfree_skb(res_skb);
84939438261SArron Wang
85039438261SArron Wang p++;
85139438261SArron Wang }
85239438261SArron Wang
85339438261SArron Wang return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
85439438261SArron Wang PN544_SWP_DEFAULT_MODE, &enable, 1);
85539438261SArron Wang case NFC_SE_EMBEDDED:
85639438261SArron Wang return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
85739438261SArron Wang PN544_NFC_ESE_DEFAULT_MODE, &enable, 1);
85839438261SArron Wang
85939438261SArron Wang default:
86039438261SArron Wang return -EINVAL;
86139438261SArron Wang }
86239438261SArron Wang }
86339438261SArron Wang
pn544_hci_disable_se(struct nfc_hci_dev * hdev,u32 se_idx)86439438261SArron Wang static int pn544_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx)
86539438261SArron Wang {
866*f2479c0aSKrzysztof Kozlowski const struct nfc_se *se;
86739438261SArron Wang u8 disable = PN544_SE_MODE_OFF;
86839438261SArron Wang
86939438261SArron Wang se = nfc_find_se(hdev->ndev, se_idx);
87039438261SArron Wang
87139438261SArron Wang switch (se->type) {
87239438261SArron Wang case NFC_SE_UICC:
87339438261SArron Wang return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
87439438261SArron Wang PN544_SWP_DEFAULT_MODE, &disable, 1);
87539438261SArron Wang case NFC_SE_EMBEDDED:
87639438261SArron Wang return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
87739438261SArron Wang PN544_NFC_ESE_DEFAULT_MODE, &disable, 1);
87839438261SArron Wang default:
87939438261SArron Wang return -EINVAL;
88039438261SArron Wang }
88139438261SArron Wang }
88239438261SArron Wang
883094c45c8SKrzysztof Kozlowski static const struct nfc_hci_ops pn544_hci_ops = {
88497f18414SEric Lapuyade .open = pn544_hci_open,
88597f18414SEric Lapuyade .close = pn544_hci_close,
88697f18414SEric Lapuyade .hci_ready = pn544_hci_ready,
88797f18414SEric Lapuyade .xmit = pn544_hci_xmit,
88897f18414SEric Lapuyade .start_poll = pn544_hci_start_poll,
88997f18414SEric Lapuyade .dep_link_up = pn544_hci_dep_link_up,
89097f18414SEric Lapuyade .dep_link_down = pn544_hci_dep_link_down,
89197f18414SEric Lapuyade .target_from_gate = pn544_hci_target_from_gate,
89297f18414SEric Lapuyade .complete_target_discovered = pn544_hci_complete_target_discovered,
89397f18414SEric Lapuyade .im_transceive = pn544_hci_im_transceive,
89497f18414SEric Lapuyade .tm_send = pn544_hci_tm_send,
89597f18414SEric Lapuyade .check_presence = pn544_hci_check_presence,
89697f18414SEric Lapuyade .event_received = pn544_hci_event_received,
8978bd7fc89SEric Lapuyade .fw_download = pn544_hci_fw_download,
8985faba2fdSArron Wang .discover_se = pn544_hci_discover_se,
89939438261SArron Wang .enable_se = pn544_hci_enable_se,
90039438261SArron Wang .disable_se = pn544_hci_disable_se,
90197f18414SEric Lapuyade };
90297f18414SEric Lapuyade
pn544_hci_probe(void * phy_id,const struct nfc_phy_ops * phy_ops,char * llc_name,int phy_headroom,int phy_tailroom,int phy_payload,fw_download_t fw_download,struct nfc_hci_dev ** hdev)9037a5e98daSKrzysztof Kozlowski int pn544_hci_probe(void *phy_id, const struct nfc_phy_ops *phy_ops,
9047a5e98daSKrzysztof Kozlowski char *llc_name, int phy_headroom, int phy_tailroom,
9057a5e98daSKrzysztof Kozlowski int phy_payload, fw_download_t fw_download,
9067a5e98daSKrzysztof Kozlowski struct nfc_hci_dev **hdev)
90797f18414SEric Lapuyade {
90897f18414SEric Lapuyade struct pn544_hci_info *info;
9090b456c41SSamuel Ortiz u32 protocols;
91097f18414SEric Lapuyade struct nfc_hci_init_data init_data;
91197f18414SEric Lapuyade int r;
91297f18414SEric Lapuyade
91397f18414SEric Lapuyade info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);
91497f18414SEric Lapuyade if (!info) {
91597f18414SEric Lapuyade r = -ENOMEM;
91697f18414SEric Lapuyade goto err_info_alloc;
91797f18414SEric Lapuyade }
91897f18414SEric Lapuyade
91997f18414SEric Lapuyade info->phy_ops = phy_ops;
92097f18414SEric Lapuyade info->phy_id = phy_id;
9218bd7fc89SEric Lapuyade info->fw_download = fw_download;
92297f18414SEric Lapuyade info->state = PN544_ST_COLD;
92397f18414SEric Lapuyade mutex_init(&info->info_lock);
92497f18414SEric Lapuyade
92597f18414SEric Lapuyade init_data.gate_count = ARRAY_SIZE(pn544_gates);
92697f18414SEric Lapuyade
92797f18414SEric Lapuyade memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates));
92897f18414SEric Lapuyade
92997f18414SEric Lapuyade /*
93097f18414SEric Lapuyade * TODO: Session id must include the driver name + some bus addr
93197f18414SEric Lapuyade * persistent info to discriminate 2 identical chips
93297f18414SEric Lapuyade */
93397f18414SEric Lapuyade strcpy(init_data.session_id, "ID544HCI");
93497f18414SEric Lapuyade
93597f18414SEric Lapuyade protocols = NFC_PROTO_JEWEL_MASK |
93697f18414SEric Lapuyade NFC_PROTO_MIFARE_MASK |
93797f18414SEric Lapuyade NFC_PROTO_FELICA_MASK |
93897f18414SEric Lapuyade NFC_PROTO_ISO14443_MASK |
93997f18414SEric Lapuyade NFC_PROTO_ISO14443_B_MASK |
94097f18414SEric Lapuyade NFC_PROTO_NFC_DEP_MASK;
94197f18414SEric Lapuyade
942bf71ab8bSEric Lapuyade info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
9430b456c41SSamuel Ortiz protocols, llc_name,
94497f18414SEric Lapuyade phy_headroom + PN544_CMDS_HEADROOM,
94597f18414SEric Lapuyade phy_tailroom, phy_payload);
94697f18414SEric Lapuyade if (!info->hdev) {
94717936b43SJoe Perches pr_err("Cannot allocate nfc hdev\n");
94897f18414SEric Lapuyade r = -ENOMEM;
94997f18414SEric Lapuyade goto err_alloc_hdev;
95097f18414SEric Lapuyade }
95197f18414SEric Lapuyade
95297f18414SEric Lapuyade nfc_hci_set_clientdata(info->hdev, info);
95397f18414SEric Lapuyade
95497f18414SEric Lapuyade r = nfc_hci_register_device(info->hdev);
95597f18414SEric Lapuyade if (r)
95697f18414SEric Lapuyade goto err_regdev;
95797f18414SEric Lapuyade
95897f18414SEric Lapuyade *hdev = info->hdev;
95997f18414SEric Lapuyade
96097f18414SEric Lapuyade return 0;
96197f18414SEric Lapuyade
96297f18414SEric Lapuyade err_regdev:
96397f18414SEric Lapuyade nfc_hci_free_device(info->hdev);
96497f18414SEric Lapuyade
96597f18414SEric Lapuyade err_alloc_hdev:
96697f18414SEric Lapuyade kfree(info);
96797f18414SEric Lapuyade
96897f18414SEric Lapuyade err_info_alloc:
96997f18414SEric Lapuyade return r;
97097f18414SEric Lapuyade }
971aa741030SSamuel Ortiz EXPORT_SYMBOL(pn544_hci_probe);
97297f18414SEric Lapuyade
pn544_hci_remove(struct nfc_hci_dev * hdev)97397f18414SEric Lapuyade void pn544_hci_remove(struct nfc_hci_dev *hdev)
97497f18414SEric Lapuyade {
97597f18414SEric Lapuyade struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
97697f18414SEric Lapuyade
97797f18414SEric Lapuyade nfc_hci_unregister_device(hdev);
97897f18414SEric Lapuyade nfc_hci_free_device(hdev);
97997f18414SEric Lapuyade kfree(info);
98097f18414SEric Lapuyade }
981aa741030SSamuel Ortiz EXPORT_SYMBOL(pn544_hci_remove);
982aa741030SSamuel Ortiz
983aa741030SSamuel Ortiz MODULE_LICENSE("GPL");
984aa741030SSamuel Ortiz MODULE_DESCRIPTION(DRIVER_DESC);
985