162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NCI based Driver for STMicroelectronics NFC Chip 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/nfc.h> 1062306a36Sopenharmony_ci#include <net/nfc/nci.h> 1162306a36Sopenharmony_ci#include <net/nfc/nci_core.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "st-nci.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define DRIVER_DESC "NCI NFC driver for ST_NCI" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define ST_NCI1_X_PROPRIETARY_ISO15693 0x83 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int st_nci_init(struct nci_dev *ndev) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct nci_mode_set_cmd cmd; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci cmd.cmd_type = ST_NCI_SET_NFC_MODE; 2462306a36Sopenharmony_ci cmd.mode = 1; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci return nci_prop_cmd(ndev, ST_NCI_CORE_PROP, 2762306a36Sopenharmony_ci sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int st_nci_open(struct nci_dev *ndev) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct st_nci_info *info = nci_get_drvdata(ndev); 3362306a36Sopenharmony_ci int r; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (test_and_set_bit(ST_NCI_RUNNING, &info->flags)) 3662306a36Sopenharmony_ci return 0; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci r = ndlc_open(info->ndlc); 3962306a36Sopenharmony_ci if (r) 4062306a36Sopenharmony_ci clear_bit(ST_NCI_RUNNING, &info->flags); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci return r; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int st_nci_close(struct nci_dev *ndev) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci struct st_nci_info *info = nci_get_drvdata(ndev); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (!test_bit(ST_NCI_RUNNING, &info->flags)) 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ndlc_close(info->ndlc); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci clear_bit(ST_NCI_RUNNING, &info->flags); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int st_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct st_nci_info *info = nci_get_drvdata(ndev); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci skb->dev = (void *)ndev; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (!test_bit(ST_NCI_RUNNING, &info->flags)) 6662306a36Sopenharmony_ci return -EBUSY; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return ndlc_send(info->ndlc, skb); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic __u32 st_nci_get_rfprotocol(struct nci_dev *ndev, 7262306a36Sopenharmony_ci __u8 rf_protocol) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci return rf_protocol == ST_NCI1_X_PROPRIETARY_ISO15693 ? 7562306a36Sopenharmony_ci NFC_PROTO_ISO15693_MASK : 0; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int st_nci_prop_rsp_packet(struct nci_dev *ndev, 7962306a36Sopenharmony_ci struct sk_buff *skb) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci __u8 status = skb->data[0]; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci nci_req_complete(ndev, status); 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic const struct nci_driver_ops st_nci_prop_ops[] = { 8862306a36Sopenharmony_ci { 8962306a36Sopenharmony_ci .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 9062306a36Sopenharmony_ci ST_NCI_CORE_PROP), 9162306a36Sopenharmony_ci .rsp = st_nci_prop_rsp_packet, 9262306a36Sopenharmony_ci }, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic const struct nci_ops st_nci_ops = { 9662306a36Sopenharmony_ci .init = st_nci_init, 9762306a36Sopenharmony_ci .open = st_nci_open, 9862306a36Sopenharmony_ci .close = st_nci_close, 9962306a36Sopenharmony_ci .send = st_nci_send, 10062306a36Sopenharmony_ci .get_rfprotocol = st_nci_get_rfprotocol, 10162306a36Sopenharmony_ci .discover_se = st_nci_discover_se, 10262306a36Sopenharmony_ci .enable_se = st_nci_enable_se, 10362306a36Sopenharmony_ci .disable_se = st_nci_disable_se, 10462306a36Sopenharmony_ci .se_io = st_nci_se_io, 10562306a36Sopenharmony_ci .hci_load_session = st_nci_hci_load_session, 10662306a36Sopenharmony_ci .hci_event_received = st_nci_hci_event_received, 10762306a36Sopenharmony_ci .hci_cmd_received = st_nci_hci_cmd_received, 10862306a36Sopenharmony_ci .prop_ops = st_nci_prop_ops, 10962306a36Sopenharmony_ci .n_prop_ops = ARRAY_SIZE(st_nci_prop_ops), 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciint st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, 11362306a36Sopenharmony_ci int phy_tailroom, struct st_nci_se_status *se_status) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct st_nci_info *info; 11662306a36Sopenharmony_ci int r; 11762306a36Sopenharmony_ci u32 protocols; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci info = devm_kzalloc(ndlc->dev, 12062306a36Sopenharmony_ci sizeof(struct st_nci_info), GFP_KERNEL); 12162306a36Sopenharmony_ci if (!info) 12262306a36Sopenharmony_ci return -ENOMEM; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci protocols = NFC_PROTO_JEWEL_MASK 12562306a36Sopenharmony_ci | NFC_PROTO_MIFARE_MASK 12662306a36Sopenharmony_ci | NFC_PROTO_FELICA_MASK 12762306a36Sopenharmony_ci | NFC_PROTO_ISO14443_MASK 12862306a36Sopenharmony_ci | NFC_PROTO_ISO14443_B_MASK 12962306a36Sopenharmony_ci | NFC_PROTO_ISO15693_MASK 13062306a36Sopenharmony_ci | NFC_PROTO_NFC_DEP_MASK; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(st_nci_prop_ops) > NCI_MAX_PROPRIETARY_CMD); 13362306a36Sopenharmony_ci ndlc->ndev = nci_allocate_device(&st_nci_ops, protocols, 13462306a36Sopenharmony_ci phy_headroom, phy_tailroom); 13562306a36Sopenharmony_ci if (!ndlc->ndev) { 13662306a36Sopenharmony_ci pr_err("Cannot allocate nfc ndev\n"); 13762306a36Sopenharmony_ci return -ENOMEM; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci info->ndlc = ndlc; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci nci_set_drvdata(ndlc->ndev, info); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci r = st_nci_vendor_cmds_init(ndlc->ndev); 14462306a36Sopenharmony_ci if (r) { 14562306a36Sopenharmony_ci pr_err("Cannot register proprietary vendor cmds\n"); 14662306a36Sopenharmony_ci goto err_reg_dev; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci r = nci_register_device(ndlc->ndev); 15062306a36Sopenharmony_ci if (r) { 15162306a36Sopenharmony_ci pr_err("Cannot register nfc device to nci core\n"); 15262306a36Sopenharmony_ci goto err_reg_dev; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return st_nci_se_init(ndlc->ndev, se_status); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cierr_reg_dev: 15862306a36Sopenharmony_ci nci_free_device(ndlc->ndev); 15962306a36Sopenharmony_ci return r; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(st_nci_probe); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_civoid st_nci_remove(struct nci_dev *ndev) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct st_nci_info *info = nci_get_drvdata(ndev); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ndlc_close(info->ndlc); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci nci_unregister_device(ndev); 17062306a36Sopenharmony_ci nci_free_device(ndev); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(st_nci_remove); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 17562306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 176