18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- 38c2ecf20Sopenharmony_ci * Copyright (C) 2014-2016, Intel Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * ------------------------------------------------------------------------- 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/acpi.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/nfc.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 158c2ecf20Sopenharmony_ci#include <net/nfc/nfc.h> 168c2ecf20Sopenharmony_ci#include <net/nfc/nci_core.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "fdp.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define FDP_I2C_DRIVER_NAME "fdp_nci_i2c" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define FDP_DP_CLOCK_TYPE_NAME "clock-type" 238c2ecf20Sopenharmony_ci#define FDP_DP_CLOCK_FREQ_NAME "clock-freq" 248c2ecf20Sopenharmony_ci#define FDP_DP_FW_VSC_CFG_NAME "fw-vsc-cfg" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define FDP_FRAME_HEADROOM 2 278c2ecf20Sopenharmony_ci#define FDP_FRAME_TAILROOM 1 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define FDP_NCI_I2C_MIN_PAYLOAD 5 308c2ecf20Sopenharmony_ci#define FDP_NCI_I2C_MAX_PAYLOAD 261 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define FDP_POWER_OFF 0 338c2ecf20Sopenharmony_ci#define FDP_POWER_ON 1 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define fdp_nci_i2c_dump_skb(dev, prefix, skb) \ 368c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, prefix": ", DUMP_PREFIX_OFFSET, \ 378c2ecf20Sopenharmony_ci 16, 1, (skb)->data, (skb)->len, 0) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void fdp_nci_i2c_reset(struct fdp_i2c_phy *phy) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci /* Reset RST/WakeUP for at least 100 micro-second */ 428c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->power_gpio, FDP_POWER_OFF); 438c2ecf20Sopenharmony_ci usleep_range(1000, 4000); 448c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->power_gpio, FDP_POWER_ON); 458c2ecf20Sopenharmony_ci usleep_range(10000, 14000); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int fdp_nci_i2c_enable(void *phy_id) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct fdp_i2c_phy *phy = phy_id; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci fdp_nci_i2c_reset(phy); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void fdp_nci_i2c_disable(void *phy_id) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct fdp_i2c_phy *phy = phy_id; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci fdp_nci_i2c_reset(phy); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void fdp_nci_i2c_add_len_lrc(struct sk_buff *skb) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci u8 lrc = 0; 678c2ecf20Sopenharmony_ci u16 len, i; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Add length header */ 708c2ecf20Sopenharmony_ci len = skb->len; 718c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = len & 0xff; 728c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = len >> 8; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Compute and add lrc */ 758c2ecf20Sopenharmony_ci for (i = 0; i < len + 2; i++) 768c2ecf20Sopenharmony_ci lrc ^= skb->data[i]; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci skb_put_u8(skb, lrc); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void fdp_nci_i2c_remove_len_lrc(struct sk_buff *skb) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci skb_pull(skb, FDP_FRAME_HEADROOM); 848c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - FDP_FRAME_TAILROOM); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int fdp_nci_i2c_write(void *phy_id, struct sk_buff *skb) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct fdp_i2c_phy *phy = phy_id; 908c2ecf20Sopenharmony_ci struct i2c_client *client = phy->i2c_dev; 918c2ecf20Sopenharmony_ci int r; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (phy->hard_fault != 0) 948c2ecf20Sopenharmony_ci return phy->hard_fault; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci fdp_nci_i2c_add_len_lrc(skb); 978c2ecf20Sopenharmony_ci fdp_nci_i2c_dump_skb(&client->dev, "fdp_wr", skb); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci r = i2c_master_send(client, skb->data, skb->len); 1008c2ecf20Sopenharmony_ci if (r == -EREMOTEIO) { /* Retry, chip was in standby */ 1018c2ecf20Sopenharmony_ci usleep_range(1000, 4000); 1028c2ecf20Sopenharmony_ci r = i2c_master_send(client, skb->data, skb->len); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (r < 0 || r != skb->len) 1068c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s: error err=%d len=%d\n", 1078c2ecf20Sopenharmony_ci __func__, r, skb->len); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (r >= 0) { 1108c2ecf20Sopenharmony_ci if (r != skb->len) { 1118c2ecf20Sopenharmony_ci phy->hard_fault = r; 1128c2ecf20Sopenharmony_ci r = -EREMOTEIO; 1138c2ecf20Sopenharmony_ci } else { 1148c2ecf20Sopenharmony_ci r = 0; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci fdp_nci_i2c_remove_len_lrc(skb); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return r; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct nfc_phy_ops i2c_phy_ops = { 1248c2ecf20Sopenharmony_ci .write = fdp_nci_i2c_write, 1258c2ecf20Sopenharmony_ci .enable = fdp_nci_i2c_enable, 1268c2ecf20Sopenharmony_ci .disable = fdp_nci_i2c_disable, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int fdp_nci_i2c_read(struct fdp_i2c_phy *phy, struct sk_buff **skb) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci int r, len; 1328c2ecf20Sopenharmony_ci u8 tmp[FDP_NCI_I2C_MAX_PAYLOAD], lrc, k; 1338c2ecf20Sopenharmony_ci u16 i; 1348c2ecf20Sopenharmony_ci struct i2c_client *client = phy->i2c_dev; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci *skb = NULL; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Read the length packet and the data packet */ 1398c2ecf20Sopenharmony_ci for (k = 0; k < 2; k++) { 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci len = phy->next_read_size; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci r = i2c_master_recv(client, tmp, len); 1448c2ecf20Sopenharmony_ci if (r != len) { 1458c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s: i2c recv err: %d\n", 1468c2ecf20Sopenharmony_ci __func__, r); 1478c2ecf20Sopenharmony_ci goto flush; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Check packet integruty */ 1518c2ecf20Sopenharmony_ci for (lrc = i = 0; i < r; i++) 1528c2ecf20Sopenharmony_ci lrc ^= tmp[i]; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * LRC check failed. This may due to transmission error or 1568c2ecf20Sopenharmony_ci * desynchronization between driver and FDP. Drop the paquet 1578c2ecf20Sopenharmony_ci * and force resynchronization 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci if (lrc) { 1608c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s: corrupted packet\n", 1618c2ecf20Sopenharmony_ci __func__); 1628c2ecf20Sopenharmony_ci phy->next_read_size = 5; 1638c2ecf20Sopenharmony_ci goto flush; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Packet that contains a length */ 1678c2ecf20Sopenharmony_ci if (tmp[0] == 0 && tmp[1] == 0) { 1688c2ecf20Sopenharmony_ci phy->next_read_size = (tmp[2] << 8) + tmp[3] + 3; 1698c2ecf20Sopenharmony_ci } else { 1708c2ecf20Sopenharmony_ci phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci *skb = alloc_skb(len, GFP_KERNEL); 1738c2ecf20Sopenharmony_ci if (*skb == NULL) { 1748c2ecf20Sopenharmony_ci r = -ENOMEM; 1758c2ecf20Sopenharmony_ci goto flush; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci skb_put_data(*skb, tmp, len); 1798c2ecf20Sopenharmony_ci fdp_nci_i2c_dump_skb(&client->dev, "fdp_rd", *skb); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci fdp_nci_i2c_remove_len_lrc(*skb); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ciflush: 1888c2ecf20Sopenharmony_ci /* Flush the remaining data */ 1898c2ecf20Sopenharmony_ci if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) 1908c2ecf20Sopenharmony_ci r = -EREMOTEIO; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return r; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic irqreturn_t fdp_nci_i2c_irq_thread_fn(int irq, void *phy_id) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct fdp_i2c_phy *phy = phy_id; 1988c2ecf20Sopenharmony_ci struct sk_buff *skb; 1998c2ecf20Sopenharmony_ci int r; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!phy || irq != phy->i2c_dev->irq) { 2028c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 2038c2ecf20Sopenharmony_ci return IRQ_NONE; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci r = fdp_nci_i2c_read(phy, &skb); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (r == -EREMOTEIO) 2098c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2108c2ecf20Sopenharmony_ci else if (r == -ENOMEM || r == -EBADMSG) 2118c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (skb != NULL) 2148c2ecf20Sopenharmony_ci nci_recv_frame(phy->ndev, skb); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void fdp_nci_i2c_read_device_properties(struct device *dev, 2208c2ecf20Sopenharmony_ci u8 *clock_type, u32 *clock_freq, 2218c2ecf20Sopenharmony_ci u8 **fw_vsc_cfg) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci int r; 2248c2ecf20Sopenharmony_ci u8 len; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci r = device_property_read_u8(dev, FDP_DP_CLOCK_TYPE_NAME, clock_type); 2278c2ecf20Sopenharmony_ci if (r) { 2288c2ecf20Sopenharmony_ci dev_dbg(dev, "Using default clock type"); 2298c2ecf20Sopenharmony_ci *clock_type = 0; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci r = device_property_read_u32(dev, FDP_DP_CLOCK_FREQ_NAME, clock_freq); 2338c2ecf20Sopenharmony_ci if (r) { 2348c2ecf20Sopenharmony_ci dev_dbg(dev, "Using default clock frequency\n"); 2358c2ecf20Sopenharmony_ci *clock_freq = 26000; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (device_property_present(dev, FDP_DP_FW_VSC_CFG_NAME)) { 2398c2ecf20Sopenharmony_ci r = device_property_read_u8(dev, FDP_DP_FW_VSC_CFG_NAME, 2408c2ecf20Sopenharmony_ci &len); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (r || len <= 0) 2438c2ecf20Sopenharmony_ci goto vsc_read_err; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Add 1 to the length to inclue the length byte itself */ 2468c2ecf20Sopenharmony_ci len++; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci *fw_vsc_cfg = devm_kmalloc_array(dev, 2498c2ecf20Sopenharmony_ci len, sizeof(**fw_vsc_cfg), 2508c2ecf20Sopenharmony_ci GFP_KERNEL); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (!*fw_vsc_cfg) 2538c2ecf20Sopenharmony_ci goto alloc_err; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci r = device_property_read_u8_array(dev, FDP_DP_FW_VSC_CFG_NAME, 2568c2ecf20Sopenharmony_ci *fw_vsc_cfg, len); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (r) { 2598c2ecf20Sopenharmony_ci devm_kfree(dev, *fw_vsc_cfg); 2608c2ecf20Sopenharmony_ci goto vsc_read_err; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_civsc_read_err: 2648c2ecf20Sopenharmony_ci dev_dbg(dev, "FW vendor specific commands not present\n"); 2658c2ecf20Sopenharmony_ci *fw_vsc_cfg = NULL; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cialloc_err: 2698c2ecf20Sopenharmony_ci dev_dbg(dev, "Clock type: %d, clock frequency: %d, VSC: %s", 2708c2ecf20Sopenharmony_ci *clock_type, *clock_freq, *fw_vsc_cfg != NULL ? "yes" : "no"); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params power_gpios = { 0, 0, false }; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_fdp_gpios[] = { 2768c2ecf20Sopenharmony_ci { "power-gpios", &power_gpios, 1 }, 2778c2ecf20Sopenharmony_ci {}, 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int fdp_nci_i2c_probe(struct i2c_client *client) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct fdp_i2c_phy *phy; 2838c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 2848c2ecf20Sopenharmony_ci u8 *fw_vsc_cfg; 2858c2ecf20Sopenharmony_ci u8 clock_type; 2868c2ecf20Sopenharmony_ci u32 clock_freq; 2878c2ecf20Sopenharmony_ci int r = 0; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 2908c2ecf20Sopenharmony_ci nfc_err(dev, "No I2C_FUNC_I2C support\n"); 2918c2ecf20Sopenharmony_ci return -ENODEV; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Checking if we have an irq */ 2958c2ecf20Sopenharmony_ci if (client->irq <= 0) { 2968c2ecf20Sopenharmony_ci nfc_err(dev, "IRQ not present\n"); 2978c2ecf20Sopenharmony_ci return -ENODEV; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci phy = devm_kzalloc(dev, sizeof(struct fdp_i2c_phy), GFP_KERNEL); 3018c2ecf20Sopenharmony_ci if (!phy) 3028c2ecf20Sopenharmony_ci return -ENOMEM; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci phy->i2c_dev = client; 3058c2ecf20Sopenharmony_ci phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD; 3068c2ecf20Sopenharmony_ci i2c_set_clientdata(client, phy); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci r = devm_request_threaded_irq(dev, client->irq, 3098c2ecf20Sopenharmony_ci NULL, fdp_nci_i2c_irq_thread_fn, 3108c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 3118c2ecf20Sopenharmony_ci FDP_I2C_DRIVER_NAME, phy); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (r < 0) { 3148c2ecf20Sopenharmony_ci nfc_err(&client->dev, "Unable to register IRQ handler\n"); 3158c2ecf20Sopenharmony_ci return r; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci r = devm_acpi_dev_add_driver_gpios(dev, acpi_fdp_gpios); 3198c2ecf20Sopenharmony_ci if (r) 3208c2ecf20Sopenharmony_ci dev_dbg(dev, "Unable to add GPIO mapping table\n"); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Requesting the power gpio */ 3238c2ecf20Sopenharmony_ci phy->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW); 3248c2ecf20Sopenharmony_ci if (IS_ERR(phy->power_gpio)) { 3258c2ecf20Sopenharmony_ci nfc_err(dev, "Power GPIO request failed\n"); 3268c2ecf20Sopenharmony_ci return PTR_ERR(phy->power_gpio); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* read device properties to get the clock and production settings */ 3308c2ecf20Sopenharmony_ci fdp_nci_i2c_read_device_properties(dev, &clock_type, &clock_freq, 3318c2ecf20Sopenharmony_ci &fw_vsc_cfg); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Call the NFC specific probe function */ 3348c2ecf20Sopenharmony_ci r = fdp_nci_probe(phy, &i2c_phy_ops, &phy->ndev, 3358c2ecf20Sopenharmony_ci FDP_FRAME_HEADROOM, FDP_FRAME_TAILROOM, 3368c2ecf20Sopenharmony_ci clock_type, clock_freq, fw_vsc_cfg); 3378c2ecf20Sopenharmony_ci if (r < 0) { 3388c2ecf20Sopenharmony_ci nfc_err(dev, "NCI probing error\n"); 3398c2ecf20Sopenharmony_ci return r; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci dev_dbg(dev, "I2C driver loaded\n"); 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int fdp_nci_i2c_remove(struct i2c_client *client) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct fdp_i2c_phy *phy = i2c_get_clientdata(client); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci fdp_nci_remove(phy->ndev); 3518c2ecf20Sopenharmony_ci fdp_nci_i2c_disable(phy); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic const struct acpi_device_id fdp_nci_i2c_acpi_match[] = { 3578c2ecf20Sopenharmony_ci {"INT339A", 0}, 3588c2ecf20Sopenharmony_ci {} 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, fdp_nci_i2c_acpi_match); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic struct i2c_driver fdp_nci_i2c_driver = { 3638c2ecf20Sopenharmony_ci .driver = { 3648c2ecf20Sopenharmony_ci .name = FDP_I2C_DRIVER_NAME, 3658c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(fdp_nci_i2c_acpi_match), 3668c2ecf20Sopenharmony_ci }, 3678c2ecf20Sopenharmony_ci .probe_new = fdp_nci_i2c_probe, 3688c2ecf20Sopenharmony_ci .remove = fdp_nci_i2c_remove, 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_cimodule_i2c_driver(fdp_nci_i2c_driver); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("I2C driver for Intel Fields Peak NFC controller"); 3748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>"); 375