1a06347c0SRobert Dolca /* ------------------------------------------------------------------------- 2a06347c0SRobert Dolca * Copyright (C) 2014-2016, Intel Corporation 3a06347c0SRobert Dolca * 4a06347c0SRobert Dolca * This program is free software; you can redistribute it and/or modify 5a06347c0SRobert Dolca * it under the terms of the GNU General Public License as published by 6a06347c0SRobert Dolca * the Free Software Foundation; either version 2 of the License, or 7a06347c0SRobert Dolca * (at your option) any later version. 8a06347c0SRobert Dolca * 9a06347c0SRobert Dolca * This program is distributed in the hope that it will be useful, 10a06347c0SRobert Dolca * but WITHOUT ANY WARRANTY; without even the implied warranty of 11a06347c0SRobert Dolca * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12a06347c0SRobert Dolca * GNU General Public License for more details. 13a06347c0SRobert Dolca * ------------------------------------------------------------------------- 14a06347c0SRobert Dolca */ 15a06347c0SRobert Dolca 16a06347c0SRobert Dolca #include <linux/module.h> 17a06347c0SRobert Dolca #include <linux/nfc.h> 18a06347c0SRobert Dolca #include <linux/i2c.h> 19a06347c0SRobert Dolca #include <linux/delay.h> 20a06347c0SRobert Dolca #include <linux/firmware.h> 21a06347c0SRobert Dolca #include <net/nfc/nci_core.h> 22a06347c0SRobert Dolca 23a06347c0SRobert Dolca #include "fdp.h" 24a06347c0SRobert Dolca 25a06347c0SRobert Dolca #define FDP_OTP_PATCH_NAME "otp.bin" 26a06347c0SRobert Dolca #define FDP_RAM_PATCH_NAME "ram.bin" 27a06347c0SRobert Dolca #define FDP_FW_HEADER_SIZE 576 28a06347c0SRobert Dolca #define FDP_FW_UPDATE_SLEEP 1000 29a06347c0SRobert Dolca 30a06347c0SRobert Dolca #define NCI_GET_VERSION_TIMEOUT 8000 31a06347c0SRobert Dolca #define NCI_PATCH_REQUEST_TIMEOUT 8000 32a06347c0SRobert Dolca #define FDP_PATCH_CONN_DEST 0xC2 33a06347c0SRobert Dolca #define FDP_PATCH_CONN_PARAM_TYPE 0xA0 34a06347c0SRobert Dolca 35a06347c0SRobert Dolca #define NCI_PATCH_TYPE_RAM 0x00 36a06347c0SRobert Dolca #define NCI_PATCH_TYPE_OTP 0x01 37a06347c0SRobert Dolca #define NCI_PATCH_TYPE_EOT 0xFF 38a06347c0SRobert Dolca 39a06347c0SRobert Dolca #define NCI_PARAM_ID_FW_RAM_VERSION 0xA0 40a06347c0SRobert Dolca #define NCI_PARAM_ID_FW_OTP_VERSION 0xA1 41a06347c0SRobert Dolca #define NCI_PARAM_ID_OTP_LIMITED_VERSION 0xC5 42a06347c0SRobert Dolca #define NCI_PARAM_ID_KEY_INDEX_ID 0xC6 43a06347c0SRobert Dolca 44a06347c0SRobert Dolca #define NCI_GID_PROP 0x0F 45a06347c0SRobert Dolca #define NCI_OP_PROP_PATCH_OID 0x08 46a06347c0SRobert Dolca #define NCI_OP_PROP_SET_PDATA_OID 0x23 47a06347c0SRobert Dolca 48a06347c0SRobert Dolca struct fdp_nci_info { 49a06347c0SRobert Dolca struct nfc_phy_ops *phy_ops; 50a06347c0SRobert Dolca struct fdp_i2c_phy *phy; 51a06347c0SRobert Dolca struct nci_dev *ndev; 52a06347c0SRobert Dolca 53a06347c0SRobert Dolca const struct firmware *otp_patch; 54a06347c0SRobert Dolca const struct firmware *ram_patch; 55a06347c0SRobert Dolca u32 otp_patch_version; 56a06347c0SRobert Dolca u32 ram_patch_version; 57a06347c0SRobert Dolca 58a06347c0SRobert Dolca u32 otp_version; 59a06347c0SRobert Dolca u32 ram_version; 60a06347c0SRobert Dolca u32 limited_otp_version; 61a06347c0SRobert Dolca u8 key_index; 62a06347c0SRobert Dolca 63a06347c0SRobert Dolca u8 *fw_vsc_cfg; 64a06347c0SRobert Dolca u8 clock_type; 65a06347c0SRobert Dolca u32 clock_freq; 66a06347c0SRobert Dolca 67a06347c0SRobert Dolca atomic_t data_pkt_counter; 68a06347c0SRobert Dolca void (*data_pkt_counter_cb)(struct nci_dev *ndev); 69a06347c0SRobert Dolca u8 setup_patch_sent; 70a06347c0SRobert Dolca u8 setup_patch_ntf; 71a06347c0SRobert Dolca u8 setup_patch_status; 72a06347c0SRobert Dolca u8 setup_reset_ntf; 73a06347c0SRobert Dolca wait_queue_head_t setup_wq; 74a06347c0SRobert Dolca }; 75a06347c0SRobert Dolca 76a06347c0SRobert Dolca static u8 nci_core_get_config_otp_ram_version[5] = { 77a06347c0SRobert Dolca 0x04, 78a06347c0SRobert Dolca NCI_PARAM_ID_FW_RAM_VERSION, 79a06347c0SRobert Dolca NCI_PARAM_ID_FW_OTP_VERSION, 80a06347c0SRobert Dolca NCI_PARAM_ID_OTP_LIMITED_VERSION, 81a06347c0SRobert Dolca NCI_PARAM_ID_KEY_INDEX_ID 82a06347c0SRobert Dolca }; 83a06347c0SRobert Dolca 84a06347c0SRobert Dolca struct nci_core_get_config_rsp { 85a06347c0SRobert Dolca u8 status; 86a06347c0SRobert Dolca u8 count; 87a06347c0SRobert Dolca u8 data[0]; 88a06347c0SRobert Dolca }; 89a06347c0SRobert Dolca 90a06347c0SRobert Dolca static int fdp_nci_create_conn(struct nci_dev *ndev) 91a06347c0SRobert Dolca { 92a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 93a06347c0SRobert Dolca struct core_conn_create_dest_spec_params param; 94a06347c0SRobert Dolca int r; 95a06347c0SRobert Dolca 96a06347c0SRobert Dolca /* proprietary destination specific paramerer without value */ 97a06347c0SRobert Dolca param.type = FDP_PATCH_CONN_PARAM_TYPE; 98a06347c0SRobert Dolca param.length = 0x00; 99a06347c0SRobert Dolca 100a06347c0SRobert Dolca r = nci_core_conn_create(info->ndev, FDP_PATCH_CONN_DEST, 1, 101a06347c0SRobert Dolca sizeof(param), ¶m); 102a06347c0SRobert Dolca if (r) 103a06347c0SRobert Dolca return r; 104a06347c0SRobert Dolca 1059b8d1a4cSChristophe Ricard return nci_get_conn_info_by_dest_type_params(ndev, 1069b8d1a4cSChristophe Ricard FDP_PATCH_CONN_DEST, NULL); 107a06347c0SRobert Dolca } 108a06347c0SRobert Dolca 109a06347c0SRobert Dolca static inline int fdp_nci_get_versions(struct nci_dev *ndev) 110a06347c0SRobert Dolca { 111a06347c0SRobert Dolca return nci_core_cmd(ndev, NCI_OP_CORE_GET_CONFIG_CMD, 112a06347c0SRobert Dolca sizeof(nci_core_get_config_otp_ram_version), 113a06347c0SRobert Dolca (__u8 *) &nci_core_get_config_otp_ram_version); 114a06347c0SRobert Dolca } 115a06347c0SRobert Dolca 116a06347c0SRobert Dolca static inline int fdp_nci_patch_cmd(struct nci_dev *ndev, u8 type) 117a06347c0SRobert Dolca { 118a06347c0SRobert Dolca return nci_prop_cmd(ndev, NCI_OP_PROP_PATCH_OID, sizeof(type), &type); 119a06347c0SRobert Dolca } 120a06347c0SRobert Dolca 121a06347c0SRobert Dolca static inline int fdp_nci_set_production_data(struct nci_dev *ndev, u8 len, 122a06347c0SRobert Dolca char *data) 123a06347c0SRobert Dolca { 124a06347c0SRobert Dolca return nci_prop_cmd(ndev, NCI_OP_PROP_SET_PDATA_OID, len, data); 125a06347c0SRobert Dolca } 126a06347c0SRobert Dolca 127a06347c0SRobert Dolca static int fdp_nci_set_clock(struct nci_dev *ndev, u8 clock_type, 128a06347c0SRobert Dolca u32 clock_freq) 129a06347c0SRobert Dolca { 130a06347c0SRobert Dolca u32 fc = 13560; 131a06347c0SRobert Dolca u32 nd, num, delta; 132a06347c0SRobert Dolca char data[9]; 133a06347c0SRobert Dolca 134a06347c0SRobert Dolca nd = (24 * fc) / clock_freq; 135a06347c0SRobert Dolca delta = 24 * fc - nd * clock_freq; 136a06347c0SRobert Dolca num = (32768 * delta) / clock_freq; 137a06347c0SRobert Dolca 138a06347c0SRobert Dolca data[0] = 0x00; 139a06347c0SRobert Dolca data[1] = 0x00; 140a06347c0SRobert Dolca data[2] = 0x00; 141a06347c0SRobert Dolca 142a06347c0SRobert Dolca data[3] = 0x10; 143a06347c0SRobert Dolca data[4] = 0x04; 144a06347c0SRobert Dolca data[5] = num & 0xFF; 145a06347c0SRobert Dolca data[6] = (num >> 8) & 0xff; 146a06347c0SRobert Dolca data[7] = nd; 147a06347c0SRobert Dolca data[8] = clock_type; 148a06347c0SRobert Dolca 149a06347c0SRobert Dolca return fdp_nci_set_production_data(ndev, 9, data); 150a06347c0SRobert Dolca } 151a06347c0SRobert Dolca 152a06347c0SRobert Dolca static void fdp_nci_send_patch_cb(struct nci_dev *ndev) 153a06347c0SRobert Dolca { 154a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 155a06347c0SRobert Dolca 156a06347c0SRobert Dolca info->setup_patch_sent = 1; 157a06347c0SRobert Dolca wake_up(&info->setup_wq); 158a06347c0SRobert Dolca } 159a06347c0SRobert Dolca 160a06347c0SRobert Dolca /** 161a06347c0SRobert Dolca * Register a packet sent counter and a callback 162a06347c0SRobert Dolca * 163a06347c0SRobert Dolca * We have no other way of knowing when all firmware packets were sent out 164a06347c0SRobert Dolca * on the i2c bus. We need to know that in order to close the connection and 165a06347c0SRobert Dolca * send the patch end message. 166a06347c0SRobert Dolca */ 167a06347c0SRobert Dolca static void fdp_nci_set_data_pkt_counter(struct nci_dev *ndev, 168a06347c0SRobert Dolca void (*cb)(struct nci_dev *ndev), int count) 169a06347c0SRobert Dolca { 170a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 171a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 172a06347c0SRobert Dolca 173a06347c0SRobert Dolca dev_dbg(dev, "NCI data pkt counter %d\n", count); 174a06347c0SRobert Dolca atomic_set(&info->data_pkt_counter, count); 175a06347c0SRobert Dolca info->data_pkt_counter_cb = cb; 176a06347c0SRobert Dolca } 177a06347c0SRobert Dolca 178a06347c0SRobert Dolca /** 179a06347c0SRobert Dolca * The device is expecting a stream of packets. All packets need to 180a06347c0SRobert Dolca * have the PBF flag set to 0x0 (last packet) even if the firmware 181a06347c0SRobert Dolca * file is segmented and there are multiple packets. If we give the 182a06347c0SRobert Dolca * whole firmware to nci_send_data it will segment it and it will set 183a06347c0SRobert Dolca * the PBF flag to 0x01 so we need to do the segmentation here. 184a06347c0SRobert Dolca * 185a06347c0SRobert Dolca * The firmware will be analyzed and applied when we send NCI_OP_PROP_PATCH_CMD 186a06347c0SRobert Dolca * command with NCI_PATCH_TYPE_EOT parameter. The device will send a 187a06347c0SRobert Dolca * NFCC_PATCH_NTF packaet and a NCI_OP_CORE_RESET_NTF packet. 188a06347c0SRobert Dolca */ 189a06347c0SRobert Dolca static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type) 190a06347c0SRobert Dolca { 191a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 192a06347c0SRobert Dolca const struct firmware *fw; 193a06347c0SRobert Dolca struct sk_buff *skb; 194a06347c0SRobert Dolca unsigned long len; 195a06347c0SRobert Dolca u8 max_size, payload_size; 196a06347c0SRobert Dolca int rc = 0; 197a06347c0SRobert Dolca 198a06347c0SRobert Dolca if ((type == NCI_PATCH_TYPE_OTP && !info->otp_patch) || 199a06347c0SRobert Dolca (type == NCI_PATCH_TYPE_RAM && !info->ram_patch)) 200a06347c0SRobert Dolca return -EINVAL; 201a06347c0SRobert Dolca 202a06347c0SRobert Dolca if (type == NCI_PATCH_TYPE_OTP) 203a06347c0SRobert Dolca fw = info->otp_patch; 204a06347c0SRobert Dolca else 205a06347c0SRobert Dolca fw = info->ram_patch; 206a06347c0SRobert Dolca 207a06347c0SRobert Dolca max_size = nci_conn_max_data_pkt_payload_size(ndev, conn_id); 208a06347c0SRobert Dolca if (max_size <= 0) 209a06347c0SRobert Dolca return -EINVAL; 210a06347c0SRobert Dolca 211a06347c0SRobert Dolca len = fw->size; 212a06347c0SRobert Dolca 213a06347c0SRobert Dolca fdp_nci_set_data_pkt_counter(ndev, fdp_nci_send_patch_cb, 214a06347c0SRobert Dolca DIV_ROUND_UP(fw->size, max_size)); 215a06347c0SRobert Dolca 216a06347c0SRobert Dolca while (len) { 217a06347c0SRobert Dolca 218a06347c0SRobert Dolca payload_size = min_t(unsigned long, (unsigned long) max_size, 219a06347c0SRobert Dolca len); 220a06347c0SRobert Dolca 221a06347c0SRobert Dolca skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + payload_size), 222a06347c0SRobert Dolca GFP_KERNEL); 223a06347c0SRobert Dolca if (!skb) { 224a06347c0SRobert Dolca fdp_nci_set_data_pkt_counter(ndev, NULL, 0); 225a06347c0SRobert Dolca return -ENOMEM; 226a06347c0SRobert Dolca } 227a06347c0SRobert Dolca 228a06347c0SRobert Dolca 229a06347c0SRobert Dolca skb_reserve(skb, NCI_CTRL_HDR_SIZE); 230a06347c0SRobert Dolca 23159ae1d12SJohannes Berg skb_put_data(skb, fw->data + (fw->size - len), payload_size); 232a06347c0SRobert Dolca 233a06347c0SRobert Dolca rc = nci_send_data(ndev, conn_id, skb); 234a06347c0SRobert Dolca 235a06347c0SRobert Dolca if (rc) { 236a06347c0SRobert Dolca fdp_nci_set_data_pkt_counter(ndev, NULL, 0); 237a06347c0SRobert Dolca return rc; 238a06347c0SRobert Dolca } 239a06347c0SRobert Dolca 240a06347c0SRobert Dolca len -= payload_size; 241a06347c0SRobert Dolca } 242a06347c0SRobert Dolca 243a06347c0SRobert Dolca return rc; 244a06347c0SRobert Dolca } 245a06347c0SRobert Dolca 246a06347c0SRobert Dolca static int fdp_nci_open(struct nci_dev *ndev) 247a06347c0SRobert Dolca { 248a06347c0SRobert Dolca int r; 249a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 250a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 251a06347c0SRobert Dolca 252a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 253a06347c0SRobert Dolca 254a06347c0SRobert Dolca r = info->phy_ops->enable(info->phy); 255a06347c0SRobert Dolca 256a06347c0SRobert Dolca return r; 257a06347c0SRobert Dolca } 258a06347c0SRobert Dolca 259a06347c0SRobert Dolca static int fdp_nci_close(struct nci_dev *ndev) 260a06347c0SRobert Dolca { 261a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 262a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 263a06347c0SRobert Dolca 264a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 265a06347c0SRobert Dolca return 0; 266a06347c0SRobert Dolca } 267a06347c0SRobert Dolca 268a06347c0SRobert Dolca static int fdp_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 269a06347c0SRobert Dolca { 270a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 271a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 272a06347c0SRobert Dolca 273a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 274a06347c0SRobert Dolca 275a06347c0SRobert Dolca if (atomic_dec_and_test(&info->data_pkt_counter)) 276a06347c0SRobert Dolca info->data_pkt_counter_cb(ndev); 277a06347c0SRobert Dolca 278a06347c0SRobert Dolca return info->phy_ops->write(info->phy, skb); 279a06347c0SRobert Dolca } 280a06347c0SRobert Dolca 281a06347c0SRobert Dolca int fdp_nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb) 282a06347c0SRobert Dolca { 283a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 284a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 285a06347c0SRobert Dolca 286a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 287a06347c0SRobert Dolca return nci_recv_frame(ndev, skb); 288a06347c0SRobert Dolca } 289a06347c0SRobert Dolca EXPORT_SYMBOL(fdp_nci_recv_frame); 290a06347c0SRobert Dolca 291a06347c0SRobert Dolca static int fdp_nci_request_firmware(struct nci_dev *ndev) 292a06347c0SRobert Dolca { 293a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 294a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 295a06347c0SRobert Dolca u8 *data; 296a06347c0SRobert Dolca int r; 297a06347c0SRobert Dolca 298a06347c0SRobert Dolca r = request_firmware(&info->ram_patch, FDP_RAM_PATCH_NAME, dev); 299a06347c0SRobert Dolca if (r < 0) { 300a06347c0SRobert Dolca nfc_err(dev, "RAM patch request error\n"); 301a06347c0SRobert Dolca goto error; 302a06347c0SRobert Dolca } 303a06347c0SRobert Dolca 304a06347c0SRobert Dolca data = (u8 *) info->ram_patch->data; 305a06347c0SRobert Dolca info->ram_patch_version = 306a06347c0SRobert Dolca data[FDP_FW_HEADER_SIZE] | 307a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 1] << 8) | 308a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 2] << 16) | 309a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 3] << 24); 310a06347c0SRobert Dolca 311a06347c0SRobert Dolca dev_dbg(dev, "RAM patch version: %d, size: %d\n", 312a06347c0SRobert Dolca info->ram_patch_version, (int) info->ram_patch->size); 313a06347c0SRobert Dolca 314a06347c0SRobert Dolca 315a06347c0SRobert Dolca r = request_firmware(&info->otp_patch, FDP_OTP_PATCH_NAME, dev); 316a06347c0SRobert Dolca if (r < 0) { 317a06347c0SRobert Dolca nfc_err(dev, "OTP patch request error\n"); 318a06347c0SRobert Dolca goto out; 319a06347c0SRobert Dolca } 320a06347c0SRobert Dolca 321a06347c0SRobert Dolca data = (u8 *) info->otp_patch->data; 322a06347c0SRobert Dolca info->otp_patch_version = 323a06347c0SRobert Dolca data[FDP_FW_HEADER_SIZE] | 324a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 1] << 8) | 325a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE+2] << 16) | 326a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE+3] << 24); 327a06347c0SRobert Dolca 328a06347c0SRobert Dolca dev_dbg(dev, "OTP patch version: %d, size: %d\n", 329a06347c0SRobert Dolca info->otp_patch_version, (int) info->otp_patch->size); 330a06347c0SRobert Dolca out: 331a06347c0SRobert Dolca return 0; 332a06347c0SRobert Dolca error: 333a06347c0SRobert Dolca return r; 334a06347c0SRobert Dolca } 335a06347c0SRobert Dolca 336a06347c0SRobert Dolca static void fdp_nci_release_firmware(struct nci_dev *ndev) 337a06347c0SRobert Dolca { 338a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 339a06347c0SRobert Dolca 340a06347c0SRobert Dolca if (info->otp_patch) { 341a06347c0SRobert Dolca release_firmware(info->otp_patch); 342a06347c0SRobert Dolca info->otp_patch = NULL; 343a06347c0SRobert Dolca } 344a06347c0SRobert Dolca 345a06347c0SRobert Dolca if (info->ram_patch) { 346a06347c0SRobert Dolca release_firmware(info->ram_patch); 347f36acc33SColin Ian King info->ram_patch = NULL; 348a06347c0SRobert Dolca } 349a06347c0SRobert Dolca } 350a06347c0SRobert Dolca 351a06347c0SRobert Dolca static int fdp_nci_patch_otp(struct nci_dev *ndev) 352a06347c0SRobert Dolca { 353a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 354a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 355fa1ce54eSGeert Uytterhoeven int conn_id; 356a06347c0SRobert Dolca int r = 0; 357a06347c0SRobert Dolca 358a06347c0SRobert Dolca if (info->otp_version >= info->otp_patch_version) 359a06347c0SRobert Dolca goto out; 360a06347c0SRobert Dolca 361a06347c0SRobert Dolca info->setup_patch_sent = 0; 362a06347c0SRobert Dolca info->setup_reset_ntf = 0; 363a06347c0SRobert Dolca info->setup_patch_ntf = 0; 364a06347c0SRobert Dolca 365a06347c0SRobert Dolca /* Patch init request */ 366a06347c0SRobert Dolca r = fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_OTP); 367a06347c0SRobert Dolca if (r) 368a06347c0SRobert Dolca goto out; 369a06347c0SRobert Dolca 370a06347c0SRobert Dolca /* Patch data connection creation */ 371a06347c0SRobert Dolca conn_id = fdp_nci_create_conn(ndev); 372a06347c0SRobert Dolca if (conn_id < 0) { 373a06347c0SRobert Dolca r = conn_id; 374a06347c0SRobert Dolca goto out; 375a06347c0SRobert Dolca } 376a06347c0SRobert Dolca 377a06347c0SRobert Dolca /* Send the patch over the data connection */ 378a06347c0SRobert Dolca r = fdp_nci_send_patch(ndev, conn_id, NCI_PATCH_TYPE_OTP); 379a06347c0SRobert Dolca if (r) 380a06347c0SRobert Dolca goto out; 381a06347c0SRobert Dolca 382a06347c0SRobert Dolca /* Wait for all the packets to be send over i2c */ 383a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, 384a06347c0SRobert Dolca info->setup_patch_sent == 1); 385a06347c0SRobert Dolca 386a06347c0SRobert Dolca /* make sure that the NFCC processed the last data packet */ 387a06347c0SRobert Dolca msleep(FDP_FW_UPDATE_SLEEP); 388a06347c0SRobert Dolca 389a06347c0SRobert Dolca /* Close the data connection */ 390a06347c0SRobert Dolca r = nci_core_conn_close(info->ndev, conn_id); 391a06347c0SRobert Dolca if (r) 392a06347c0SRobert Dolca goto out; 393a06347c0SRobert Dolca 394a06347c0SRobert Dolca /* Patch finish message */ 395a06347c0SRobert Dolca if (fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_EOT)) { 396a06347c0SRobert Dolca nfc_err(dev, "OTP patch error 0x%x\n", r); 397a06347c0SRobert Dolca r = -EINVAL; 398a06347c0SRobert Dolca goto out; 399a06347c0SRobert Dolca } 400a06347c0SRobert Dolca 401a06347c0SRobert Dolca /* If the patch notification didn't arrive yet, wait for it */ 402a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_patch_ntf); 403a06347c0SRobert Dolca 404a06347c0SRobert Dolca /* Check if the patching was successful */ 405a06347c0SRobert Dolca r = info->setup_patch_status; 406a06347c0SRobert Dolca if (r) { 407a06347c0SRobert Dolca nfc_err(dev, "OTP patch error 0x%x\n", r); 408a06347c0SRobert Dolca r = -EINVAL; 409a06347c0SRobert Dolca goto out; 410a06347c0SRobert Dolca } 411a06347c0SRobert Dolca 412a06347c0SRobert Dolca /* 413a06347c0SRobert Dolca * We need to wait for the reset notification before we 414a06347c0SRobert Dolca * can continue 415a06347c0SRobert Dolca */ 416a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_reset_ntf); 417a06347c0SRobert Dolca 418a06347c0SRobert Dolca out: 419a06347c0SRobert Dolca return r; 420a06347c0SRobert Dolca } 421a06347c0SRobert Dolca 422a06347c0SRobert Dolca static int fdp_nci_patch_ram(struct nci_dev *ndev) 423a06347c0SRobert Dolca { 424a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 425a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 426fa1ce54eSGeert Uytterhoeven int conn_id; 427a06347c0SRobert Dolca int r = 0; 428a06347c0SRobert Dolca 429a06347c0SRobert Dolca if (info->ram_version >= info->ram_patch_version) 430a06347c0SRobert Dolca goto out; 431a06347c0SRobert Dolca 432a06347c0SRobert Dolca info->setup_patch_sent = 0; 433a06347c0SRobert Dolca info->setup_reset_ntf = 0; 434a06347c0SRobert Dolca info->setup_patch_ntf = 0; 435a06347c0SRobert Dolca 436a06347c0SRobert Dolca /* Patch init request */ 437a06347c0SRobert Dolca r = fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_RAM); 438a06347c0SRobert Dolca if (r) 439a06347c0SRobert Dolca goto out; 440a06347c0SRobert Dolca 441a06347c0SRobert Dolca /* Patch data connection creation */ 442a06347c0SRobert Dolca conn_id = fdp_nci_create_conn(ndev); 443a06347c0SRobert Dolca if (conn_id < 0) { 444a06347c0SRobert Dolca r = conn_id; 445a06347c0SRobert Dolca goto out; 446a06347c0SRobert Dolca } 447a06347c0SRobert Dolca 448a06347c0SRobert Dolca /* Send the patch over the data connection */ 449a06347c0SRobert Dolca r = fdp_nci_send_patch(ndev, conn_id, NCI_PATCH_TYPE_RAM); 450a06347c0SRobert Dolca if (r) 451a06347c0SRobert Dolca goto out; 452a06347c0SRobert Dolca 453a06347c0SRobert Dolca /* Wait for all the packets to be send over i2c */ 454a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, 455a06347c0SRobert Dolca info->setup_patch_sent == 1); 456a06347c0SRobert Dolca 457a06347c0SRobert Dolca /* make sure that the NFCC processed the last data packet */ 458a06347c0SRobert Dolca msleep(FDP_FW_UPDATE_SLEEP); 459a06347c0SRobert Dolca 460a06347c0SRobert Dolca /* Close the data connection */ 461a06347c0SRobert Dolca r = nci_core_conn_close(info->ndev, conn_id); 462a06347c0SRobert Dolca if (r) 463a06347c0SRobert Dolca goto out; 464a06347c0SRobert Dolca 465a06347c0SRobert Dolca /* Patch finish message */ 466a06347c0SRobert Dolca if (fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_EOT)) { 467a06347c0SRobert Dolca nfc_err(dev, "RAM patch error 0x%x\n", r); 468a06347c0SRobert Dolca r = -EINVAL; 469a06347c0SRobert Dolca goto out; 470a06347c0SRobert Dolca } 471a06347c0SRobert Dolca 472a06347c0SRobert Dolca /* If the patch notification didn't arrive yet, wait for it */ 473a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_patch_ntf); 474a06347c0SRobert Dolca 475a06347c0SRobert Dolca /* Check if the patching was successful */ 476a06347c0SRobert Dolca r = info->setup_patch_status; 477a06347c0SRobert Dolca if (r) { 478a06347c0SRobert Dolca nfc_err(dev, "RAM patch error 0x%x\n", r); 479a06347c0SRobert Dolca r = -EINVAL; 480a06347c0SRobert Dolca goto out; 481a06347c0SRobert Dolca } 482a06347c0SRobert Dolca 483a06347c0SRobert Dolca /* 484a06347c0SRobert Dolca * We need to wait for the reset notification before we 485a06347c0SRobert Dolca * can continue 486a06347c0SRobert Dolca */ 487a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_reset_ntf); 488a06347c0SRobert Dolca 489a06347c0SRobert Dolca out: 490a06347c0SRobert Dolca return r; 491a06347c0SRobert Dolca } 492a06347c0SRobert Dolca 493a06347c0SRobert Dolca static int fdp_nci_setup(struct nci_dev *ndev) 494a06347c0SRobert Dolca { 495a06347c0SRobert Dolca /* Format: total length followed by an NCI packet */ 496a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 497a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 498a06347c0SRobert Dolca int r; 499a06347c0SRobert Dolca u8 patched = 0; 500a06347c0SRobert Dolca 501a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 502a06347c0SRobert Dolca 503a06347c0SRobert Dolca r = nci_core_init(ndev); 504a06347c0SRobert Dolca if (r) 505a06347c0SRobert Dolca goto error; 506a06347c0SRobert Dolca 507a06347c0SRobert Dolca /* Get RAM and OTP version */ 508a06347c0SRobert Dolca r = fdp_nci_get_versions(ndev); 509a06347c0SRobert Dolca if (r) 510a06347c0SRobert Dolca goto error; 511a06347c0SRobert Dolca 512a06347c0SRobert Dolca /* Load firmware from disk */ 513a06347c0SRobert Dolca r = fdp_nci_request_firmware(ndev); 514a06347c0SRobert Dolca if (r) 515a06347c0SRobert Dolca goto error; 516a06347c0SRobert Dolca 517a06347c0SRobert Dolca /* Update OTP */ 518a06347c0SRobert Dolca if (info->otp_version < info->otp_patch_version) { 519a06347c0SRobert Dolca r = fdp_nci_patch_otp(ndev); 520a06347c0SRobert Dolca if (r) 521a06347c0SRobert Dolca goto error; 522a06347c0SRobert Dolca patched = 1; 523a06347c0SRobert Dolca } 524a06347c0SRobert Dolca 525a06347c0SRobert Dolca /* Update RAM */ 526a06347c0SRobert Dolca if (info->ram_version < info->ram_patch_version) { 527a06347c0SRobert Dolca r = fdp_nci_patch_ram(ndev); 528a06347c0SRobert Dolca if (r) 529a06347c0SRobert Dolca goto error; 530a06347c0SRobert Dolca patched = 1; 531a06347c0SRobert Dolca } 532a06347c0SRobert Dolca 533a06347c0SRobert Dolca /* Release the firmware buffers */ 534a06347c0SRobert Dolca fdp_nci_release_firmware(ndev); 535a06347c0SRobert Dolca 536a06347c0SRobert Dolca /* If a patch was applied the new version is checked */ 537a06347c0SRobert Dolca if (patched) { 538a06347c0SRobert Dolca r = nci_core_init(ndev); 539a06347c0SRobert Dolca if (r) 540a06347c0SRobert Dolca goto error; 541a06347c0SRobert Dolca 542a06347c0SRobert Dolca r = fdp_nci_get_versions(ndev); 543a06347c0SRobert Dolca if (r) 544a06347c0SRobert Dolca goto error; 545a06347c0SRobert Dolca 546a06347c0SRobert Dolca if (info->otp_version != info->otp_patch_version || 547a06347c0SRobert Dolca info->ram_version != info->ram_patch_version) { 548a06347c0SRobert Dolca nfc_err(dev, "Firmware update failed"); 549a06347c0SRobert Dolca r = -EINVAL; 550a06347c0SRobert Dolca goto error; 551a06347c0SRobert Dolca } 552a06347c0SRobert Dolca } 553a06347c0SRobert Dolca 554a06347c0SRobert Dolca /* 555a06347c0SRobert Dolca * We initialized the devices but the NFC subsystem expects 556a06347c0SRobert Dolca * it to not be initialized. 557a06347c0SRobert Dolca */ 558a06347c0SRobert Dolca return nci_core_reset(ndev); 559a06347c0SRobert Dolca 560a06347c0SRobert Dolca error: 561a06347c0SRobert Dolca fdp_nci_release_firmware(ndev); 562a06347c0SRobert Dolca nfc_err(dev, "Setup error %d\n", r); 563a06347c0SRobert Dolca return r; 564a06347c0SRobert Dolca } 565a06347c0SRobert Dolca 566a06347c0SRobert Dolca static int fdp_nci_post_setup(struct nci_dev *ndev) 567a06347c0SRobert Dolca { 568a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 569a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 570a06347c0SRobert Dolca int r; 571a06347c0SRobert Dolca 572a06347c0SRobert Dolca /* Check if the device has VSC */ 573a06347c0SRobert Dolca if (info->fw_vsc_cfg && info->fw_vsc_cfg[0]) { 574a06347c0SRobert Dolca 575a06347c0SRobert Dolca /* Set the vendor specific configuration */ 576a06347c0SRobert Dolca r = fdp_nci_set_production_data(ndev, info->fw_vsc_cfg[3], 577a06347c0SRobert Dolca &info->fw_vsc_cfg[4]); 578a06347c0SRobert Dolca if (r) { 579a06347c0SRobert Dolca nfc_err(dev, "Vendor specific config set error %d\n", 580a06347c0SRobert Dolca r); 581a06347c0SRobert Dolca return r; 582a06347c0SRobert Dolca } 583a06347c0SRobert Dolca } 584a06347c0SRobert Dolca 585a06347c0SRobert Dolca /* Set clock type and frequency */ 586a06347c0SRobert Dolca r = fdp_nci_set_clock(ndev, info->clock_type, info->clock_freq); 587a06347c0SRobert Dolca if (r) { 588a06347c0SRobert Dolca nfc_err(dev, "Clock set error %d\n", r); 589a06347c0SRobert Dolca return r; 590a06347c0SRobert Dolca } 591a06347c0SRobert Dolca 592a06347c0SRobert Dolca /* 593a06347c0SRobert Dolca * In order to apply the VSC FDP needs a reset 594a06347c0SRobert Dolca */ 595a06347c0SRobert Dolca r = nci_core_reset(ndev); 596a06347c0SRobert Dolca if (r) 597a06347c0SRobert Dolca return r; 598a06347c0SRobert Dolca 599a06347c0SRobert Dolca /** 600a06347c0SRobert Dolca * The nci core was initialized when post setup was called 601a06347c0SRobert Dolca * so we leave it like that 602a06347c0SRobert Dolca */ 603a06347c0SRobert Dolca return nci_core_init(ndev); 604a06347c0SRobert Dolca } 605a06347c0SRobert Dolca 606a06347c0SRobert Dolca static int fdp_nci_core_reset_ntf_packet(struct nci_dev *ndev, 607a06347c0SRobert Dolca struct sk_buff *skb) 608a06347c0SRobert Dolca { 609a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 610a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 611a06347c0SRobert Dolca 612a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 613a06347c0SRobert Dolca info->setup_reset_ntf = 1; 614a06347c0SRobert Dolca wake_up(&info->setup_wq); 615a06347c0SRobert Dolca 616a06347c0SRobert Dolca return 0; 617a06347c0SRobert Dolca } 618a06347c0SRobert Dolca 619a06347c0SRobert Dolca static int fdp_nci_prop_patch_ntf_packet(struct nci_dev *ndev, 620a06347c0SRobert Dolca struct sk_buff *skb) 621a06347c0SRobert Dolca { 622a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 623a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 624a06347c0SRobert Dolca 625a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 626a06347c0SRobert Dolca info->setup_patch_ntf = 1; 627a06347c0SRobert Dolca info->setup_patch_status = skb->data[0]; 628a06347c0SRobert Dolca wake_up(&info->setup_wq); 629a06347c0SRobert Dolca 630a06347c0SRobert Dolca return 0; 631a06347c0SRobert Dolca } 632a06347c0SRobert Dolca 633a06347c0SRobert Dolca static int fdp_nci_prop_patch_rsp_packet(struct nci_dev *ndev, 634a06347c0SRobert Dolca struct sk_buff *skb) 635a06347c0SRobert Dolca { 636a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 637a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 638a06347c0SRobert Dolca u8 status = skb->data[0]; 639a06347c0SRobert Dolca 640a06347c0SRobert Dolca dev_dbg(dev, "%s: status 0x%x\n", __func__, status); 641a06347c0SRobert Dolca nci_req_complete(ndev, status); 642a06347c0SRobert Dolca 643a06347c0SRobert Dolca return 0; 644a06347c0SRobert Dolca } 645a06347c0SRobert Dolca 646a06347c0SRobert Dolca static int fdp_nci_prop_set_production_data_rsp_packet(struct nci_dev *ndev, 647a06347c0SRobert Dolca struct sk_buff *skb) 648a06347c0SRobert Dolca { 649a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 650a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 651a06347c0SRobert Dolca u8 status = skb->data[0]; 652a06347c0SRobert Dolca 653a06347c0SRobert Dolca dev_dbg(dev, "%s: status 0x%x\n", __func__, status); 654a06347c0SRobert Dolca nci_req_complete(ndev, status); 655a06347c0SRobert Dolca 656a06347c0SRobert Dolca return 0; 657a06347c0SRobert Dolca } 658a06347c0SRobert Dolca 659a06347c0SRobert Dolca static int fdp_nci_core_get_config_rsp_packet(struct nci_dev *ndev, 660a06347c0SRobert Dolca struct sk_buff *skb) 661a06347c0SRobert Dolca { 662a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 663a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 664a06347c0SRobert Dolca struct nci_core_get_config_rsp *rsp = (void *) skb->data; 665a06347c0SRobert Dolca u8 i, *p; 666a06347c0SRobert Dolca 667a06347c0SRobert Dolca if (rsp->status == NCI_STATUS_OK) { 668a06347c0SRobert Dolca 669a06347c0SRobert Dolca p = rsp->data; 670a06347c0SRobert Dolca for (i = 0; i < 4; i++) { 671a06347c0SRobert Dolca 672a06347c0SRobert Dolca switch (*p++) { 673a06347c0SRobert Dolca case NCI_PARAM_ID_FW_RAM_VERSION: 674a06347c0SRobert Dolca p++; 675a06347c0SRobert Dolca info->ram_version = le32_to_cpup((__le32 *) p); 676a06347c0SRobert Dolca p += 4; 677a06347c0SRobert Dolca break; 678a06347c0SRobert Dolca case NCI_PARAM_ID_FW_OTP_VERSION: 679a06347c0SRobert Dolca p++; 680a06347c0SRobert Dolca info->otp_version = le32_to_cpup((__le32 *) p); 681a06347c0SRobert Dolca p += 4; 682a06347c0SRobert Dolca break; 683a06347c0SRobert Dolca case NCI_PARAM_ID_OTP_LIMITED_VERSION: 684a06347c0SRobert Dolca p++; 685a06347c0SRobert Dolca info->otp_version = le32_to_cpup((__le32 *) p); 686a06347c0SRobert Dolca p += 4; 687a06347c0SRobert Dolca break; 688a06347c0SRobert Dolca case NCI_PARAM_ID_KEY_INDEX_ID: 689a06347c0SRobert Dolca p++; 690a06347c0SRobert Dolca info->key_index = *p++; 691a06347c0SRobert Dolca } 692a06347c0SRobert Dolca } 693a06347c0SRobert Dolca } 694a06347c0SRobert Dolca 695a06347c0SRobert Dolca dev_dbg(dev, "OTP version %d\n", info->otp_version); 696a06347c0SRobert Dolca dev_dbg(dev, "RAM version %d\n", info->ram_version); 697a06347c0SRobert Dolca dev_dbg(dev, "key index %d\n", info->key_index); 698a06347c0SRobert Dolca dev_dbg(dev, "%s: status 0x%x\n", __func__, rsp->status); 699a06347c0SRobert Dolca 700a06347c0SRobert Dolca nci_req_complete(ndev, rsp->status); 701a06347c0SRobert Dolca 702a06347c0SRobert Dolca return 0; 703a06347c0SRobert Dolca } 704a06347c0SRobert Dolca 705a06347c0SRobert Dolca static struct nci_driver_ops fdp_core_ops[] = { 706a06347c0SRobert Dolca { 707a06347c0SRobert Dolca .opcode = NCI_OP_CORE_GET_CONFIG_RSP, 708a06347c0SRobert Dolca .rsp = fdp_nci_core_get_config_rsp_packet, 709a06347c0SRobert Dolca }, 710a06347c0SRobert Dolca { 711a06347c0SRobert Dolca .opcode = NCI_OP_CORE_RESET_NTF, 712a06347c0SRobert Dolca .ntf = fdp_nci_core_reset_ntf_packet, 713a06347c0SRobert Dolca }, 714a06347c0SRobert Dolca }; 715a06347c0SRobert Dolca 716a06347c0SRobert Dolca static struct nci_driver_ops fdp_prop_ops[] = { 717a06347c0SRobert Dolca { 718a06347c0SRobert Dolca .opcode = nci_opcode_pack(NCI_GID_PROP, NCI_OP_PROP_PATCH_OID), 719a06347c0SRobert Dolca .rsp = fdp_nci_prop_patch_rsp_packet, 720a06347c0SRobert Dolca .ntf = fdp_nci_prop_patch_ntf_packet, 721a06347c0SRobert Dolca }, 722a06347c0SRobert Dolca { 723a06347c0SRobert Dolca .opcode = nci_opcode_pack(NCI_GID_PROP, 724a06347c0SRobert Dolca NCI_OP_PROP_SET_PDATA_OID), 725a06347c0SRobert Dolca .rsp = fdp_nci_prop_set_production_data_rsp_packet, 726a06347c0SRobert Dolca }, 727a06347c0SRobert Dolca }; 728a06347c0SRobert Dolca 729a06347c0SRobert Dolca struct nci_ops nci_ops = { 730a06347c0SRobert Dolca .open = fdp_nci_open, 731a06347c0SRobert Dolca .close = fdp_nci_close, 732a06347c0SRobert Dolca .send = fdp_nci_send, 733a06347c0SRobert Dolca .setup = fdp_nci_setup, 734a06347c0SRobert Dolca .post_setup = fdp_nci_post_setup, 735a06347c0SRobert Dolca .prop_ops = fdp_prop_ops, 736a06347c0SRobert Dolca .n_prop_ops = ARRAY_SIZE(fdp_prop_ops), 737a06347c0SRobert Dolca .core_ops = fdp_core_ops, 738a06347c0SRobert Dolca .n_core_ops = ARRAY_SIZE(fdp_core_ops), 739a06347c0SRobert Dolca }; 740a06347c0SRobert Dolca 741a06347c0SRobert Dolca int fdp_nci_probe(struct fdp_i2c_phy *phy, struct nfc_phy_ops *phy_ops, 742a06347c0SRobert Dolca struct nci_dev **ndevp, int tx_headroom, 743a06347c0SRobert Dolca int tx_tailroom, u8 clock_type, u32 clock_freq, 744a06347c0SRobert Dolca u8 *fw_vsc_cfg) 745a06347c0SRobert Dolca { 746a06347c0SRobert Dolca struct device *dev = &phy->i2c_dev->dev; 747a06347c0SRobert Dolca struct fdp_nci_info *info; 748a06347c0SRobert Dolca struct nci_dev *ndev; 749a06347c0SRobert Dolca u32 protocols; 750a06347c0SRobert Dolca int r; 751a06347c0SRobert Dolca 7527b9fcda9SAndy Shevchenko info = devm_kzalloc(dev, sizeof(struct fdp_nci_info), GFP_KERNEL); 7537b9fcda9SAndy Shevchenko if (!info) 7547b9fcda9SAndy Shevchenko return -ENOMEM; 755a06347c0SRobert Dolca 756a06347c0SRobert Dolca info->phy = phy; 757a06347c0SRobert Dolca info->phy_ops = phy_ops; 758a06347c0SRobert Dolca info->clock_type = clock_type; 759a06347c0SRobert Dolca info->clock_freq = clock_freq; 760a06347c0SRobert Dolca info->fw_vsc_cfg = fw_vsc_cfg; 761a06347c0SRobert Dolca 762a06347c0SRobert Dolca init_waitqueue_head(&info->setup_wq); 763a06347c0SRobert Dolca 764a06347c0SRobert Dolca protocols = NFC_PROTO_JEWEL_MASK | 765a06347c0SRobert Dolca NFC_PROTO_MIFARE_MASK | 766a06347c0SRobert Dolca NFC_PROTO_FELICA_MASK | 767a06347c0SRobert Dolca NFC_PROTO_ISO14443_MASK | 768a06347c0SRobert Dolca NFC_PROTO_ISO14443_B_MASK | 769a06347c0SRobert Dolca NFC_PROTO_NFC_DEP_MASK | 770a06347c0SRobert Dolca NFC_PROTO_ISO15693_MASK; 771a06347c0SRobert Dolca 772a06347c0SRobert Dolca ndev = nci_allocate_device(&nci_ops, protocols, tx_headroom, 773a06347c0SRobert Dolca tx_tailroom); 774a06347c0SRobert Dolca if (!ndev) { 775a06347c0SRobert Dolca nfc_err(dev, "Cannot allocate nfc ndev\n"); 7767b9fcda9SAndy Shevchenko return -ENOMEM; 777a06347c0SRobert Dolca } 778a06347c0SRobert Dolca 779a06347c0SRobert Dolca r = nci_register_device(ndev); 780a06347c0SRobert Dolca if (r) 781a06347c0SRobert Dolca goto err_regdev; 782a06347c0SRobert Dolca 783a06347c0SRobert Dolca *ndevp = ndev; 784a06347c0SRobert Dolca info->ndev = ndev; 785a06347c0SRobert Dolca 786a06347c0SRobert Dolca nci_set_drvdata(ndev, info); 787a06347c0SRobert Dolca 788a06347c0SRobert Dolca return 0; 789a06347c0SRobert Dolca 790a06347c0SRobert Dolca err_regdev: 791a06347c0SRobert Dolca nci_free_device(ndev); 792a06347c0SRobert Dolca return r; 793a06347c0SRobert Dolca } 794a06347c0SRobert Dolca EXPORT_SYMBOL(fdp_nci_probe); 795a06347c0SRobert Dolca 796a06347c0SRobert Dolca void fdp_nci_remove(struct nci_dev *ndev) 797a06347c0SRobert Dolca { 798a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 799a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 800a06347c0SRobert Dolca 801a06347c0SRobert Dolca dev_dbg(dev, "%s\n", __func__); 802a06347c0SRobert Dolca 803a06347c0SRobert Dolca nci_unregister_device(ndev); 804a06347c0SRobert Dolca nci_free_device(ndev); 805a06347c0SRobert Dolca } 806a06347c0SRobert Dolca EXPORT_SYMBOL(fdp_nci_remove); 807a06347c0SRobert Dolca 808a06347c0SRobert Dolca MODULE_LICENSE("GPL"); 809a06347c0SRobert Dolca MODULE_DESCRIPTION("NFC NCI driver for Intel Fields Peak NFC controller"); 810a06347c0SRobert Dolca MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>"); 811