18c2ecf20Sopenharmony_ci/** 28c2ecf20Sopenharmony_ci * Marvell NFC-over-SPI driver: SPI interface related functions 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2015, Marvell International Ltd. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by Marvell International 78c2ecf20Sopenharmony_ci * Ltd. under the terms of the GNU General Public License Version 2, June 1991 88c2ecf20Sopenharmony_ci * (the "License"). You may use, redistribute and/or modify this File in 98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which 108c2ecf20Sopenharmony_ci * is available on the worldwide web at 118c2ecf20Sopenharmony_ci * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 148c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 158c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 168c2ecf20Sopenharmony_ci * this warranty disclaimer. 178c2ecf20Sopenharmony_ci **/ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 218c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 228c2ecf20Sopenharmony_ci#include <linux/nfc.h> 238c2ecf20Sopenharmony_ci#include <linux/gpio.h> 248c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 258c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 268c2ecf20Sopenharmony_ci#include <net/nfc/nci.h> 278c2ecf20Sopenharmony_ci#include <net/nfc/nci_core.h> 288c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 298c2ecf20Sopenharmony_ci#include "nfcmrvl.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SPI_WAIT_HANDSHAKE 1 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct nfcmrvl_spi_drv_data { 348c2ecf20Sopenharmony_ci unsigned long flags; 358c2ecf20Sopenharmony_ci struct spi_device *spi; 368c2ecf20Sopenharmony_ci struct nci_spi *nci_spi; 378c2ecf20Sopenharmony_ci struct completion handshake_completion; 388c2ecf20Sopenharmony_ci struct nfcmrvl_private *priv; 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic irqreturn_t nfcmrvl_spi_int_irq_thread_fn(int irq, void *drv_data_ptr) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct nfcmrvl_spi_drv_data *drv_data = drv_data_ptr; 448c2ecf20Sopenharmony_ci struct sk_buff *skb; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* 478c2ecf20Sopenharmony_ci * Special case where we are waiting for SPI_INT deassertion to start a 488c2ecf20Sopenharmony_ci * transfer. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci if (test_and_clear_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags)) { 518c2ecf20Sopenharmony_ci complete(&drv_data->handshake_completion); 528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Normal case, SPI_INT deasserted by slave to trigger a master read */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci skb = nci_spi_read(drv_data->nci_spi); 588c2ecf20Sopenharmony_ci if (!skb) { 598c2ecf20Sopenharmony_ci nfc_err(&drv_data->spi->dev, "failed to read spi packet"); 608c2ecf20Sopenharmony_ci return IRQ_HANDLED; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0) 648c2ecf20Sopenharmony_ci nfc_err(&drv_data->spi->dev, "corrupted RX packet"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return IRQ_HANDLED; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int nfcmrvl_spi_nci_open(struct nfcmrvl_private *priv) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int nfcmrvl_spi_nci_close(struct nfcmrvl_private *priv) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int nfcmrvl_spi_nci_send(struct nfcmrvl_private *priv, 808c2ecf20Sopenharmony_ci struct sk_buff *skb) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data; 838c2ecf20Sopenharmony_ci int err; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Reinit completion for slave handshake */ 868c2ecf20Sopenharmony_ci reinit_completion(&drv_data->handshake_completion); 878c2ecf20Sopenharmony_ci set_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* 908c2ecf20Sopenharmony_ci * Append a dummy byte at the end of SPI frame. This is due to a 918c2ecf20Sopenharmony_ci * specific DMA implementation in the controller 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci skb_put(skb, 1); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Send the SPI packet */ 968c2ecf20Sopenharmony_ci err = nci_spi_send(drv_data->nci_spi, &drv_data->handshake_completion, 978c2ecf20Sopenharmony_ci skb); 988c2ecf20Sopenharmony_ci if (err) 998c2ecf20Sopenharmony_ci nfc_err(priv->dev, "spi_send failed %d", err); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return err; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void nfcmrvl_spi_nci_update_config(struct nfcmrvl_private *priv, 1058c2ecf20Sopenharmony_ci const void *param) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data; 1088c2ecf20Sopenharmony_ci const struct nfcmrvl_fw_spi_config *config = param; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci drv_data->nci_spi->xfer_speed_hz = config->clk; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic struct nfcmrvl_if_ops spi_ops = { 1148c2ecf20Sopenharmony_ci .nci_open = nfcmrvl_spi_nci_open, 1158c2ecf20Sopenharmony_ci .nci_close = nfcmrvl_spi_nci_close, 1168c2ecf20Sopenharmony_ci .nci_send = nfcmrvl_spi_nci_send, 1178c2ecf20Sopenharmony_ci .nci_update_config = nfcmrvl_spi_nci_update_config, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int nfcmrvl_spi_parse_dt(struct device_node *node, 1218c2ecf20Sopenharmony_ci struct nfcmrvl_platform_data *pdata) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int ret; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ret = nfcmrvl_parse_dt(node, pdata); 1268c2ecf20Sopenharmony_ci if (ret < 0) { 1278c2ecf20Sopenharmony_ci pr_err("Failed to get generic entries\n"); 1288c2ecf20Sopenharmony_ci return ret; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ret = irq_of_parse_and_map(node, 0); 1328c2ecf20Sopenharmony_ci if (!ret) { 1338c2ecf20Sopenharmony_ci pr_err("Unable to get irq\n"); 1348c2ecf20Sopenharmony_ci return -EINVAL; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci pdata->irq = ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int nfcmrvl_spi_probe(struct spi_device *spi) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct nfcmrvl_platform_data *pdata; 1448c2ecf20Sopenharmony_ci struct nfcmrvl_platform_data config; 1458c2ecf20Sopenharmony_ci struct nfcmrvl_spi_drv_data *drv_data; 1468c2ecf20Sopenharmony_ci int ret = 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci drv_data = devm_kzalloc(&spi->dev, sizeof(*drv_data), GFP_KERNEL); 1498c2ecf20Sopenharmony_ci if (!drv_data) 1508c2ecf20Sopenharmony_ci return -ENOMEM; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci drv_data->spi = spi; 1538c2ecf20Sopenharmony_ci drv_data->priv = NULL; 1548c2ecf20Sopenharmony_ci spi_set_drvdata(spi, drv_data); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci pdata = spi->dev.platform_data; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!pdata && spi->dev.of_node) 1598c2ecf20Sopenharmony_ci if (nfcmrvl_spi_parse_dt(spi->dev.of_node, &config) == 0) 1608c2ecf20Sopenharmony_ci pdata = &config; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!pdata) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&drv_data->spi->dev, pdata->irq, 1668c2ecf20Sopenharmony_ci NULL, nfcmrvl_spi_int_irq_thread_fn, 1678c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 1688c2ecf20Sopenharmony_ci "nfcmrvl_spi_int", drv_data); 1698c2ecf20Sopenharmony_ci if (ret < 0) { 1708c2ecf20Sopenharmony_ci nfc_err(&drv_data->spi->dev, "Unable to register IRQ handler"); 1718c2ecf20Sopenharmony_ci return -ENODEV; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_SPI, 1758c2ecf20Sopenharmony_ci drv_data, &spi_ops, 1768c2ecf20Sopenharmony_ci &drv_data->spi->dev, 1778c2ecf20Sopenharmony_ci pdata); 1788c2ecf20Sopenharmony_ci if (IS_ERR(drv_data->priv)) 1798c2ecf20Sopenharmony_ci return PTR_ERR(drv_data->priv); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci drv_data->priv->support_fw_dnld = true; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci drv_data->nci_spi = nci_spi_allocate_spi(drv_data->spi, 0, 10, 1848c2ecf20Sopenharmony_ci drv_data->priv->ndev); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Init completion for slave handshake */ 1878c2ecf20Sopenharmony_ci init_completion(&drv_data->handshake_completion); 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int nfcmrvl_spi_remove(struct spi_device *spi) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct nfcmrvl_spi_drv_data *drv_data = spi_get_drvdata(spi); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci nfcmrvl_nci_unregister_dev(drv_data->priv); 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic const struct of_device_id of_nfcmrvl_spi_match[] = { 2008c2ecf20Sopenharmony_ci { .compatible = "marvell,nfc-spi", }, 2018c2ecf20Sopenharmony_ci {}, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_nfcmrvl_spi_match); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic const struct spi_device_id nfcmrvl_spi_id_table[] = { 2068c2ecf20Sopenharmony_ci { "nfcmrvl_spi", 0 }, 2078c2ecf20Sopenharmony_ci { } 2088c2ecf20Sopenharmony_ci}; 2098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, nfcmrvl_spi_id_table); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic struct spi_driver nfcmrvl_spi_driver = { 2128c2ecf20Sopenharmony_ci .probe = nfcmrvl_spi_probe, 2138c2ecf20Sopenharmony_ci .remove = nfcmrvl_spi_remove, 2148c2ecf20Sopenharmony_ci .id_table = nfcmrvl_spi_id_table, 2158c2ecf20Sopenharmony_ci .driver = { 2168c2ecf20Sopenharmony_ci .name = "nfcmrvl_spi", 2178c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2188c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(of_nfcmrvl_spi_match), 2198c2ecf20Sopenharmony_ci }, 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cimodule_spi_driver(nfcmrvl_spi_driver); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marvell International Ltd."); 2258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Marvell NFC-over-SPI driver"); 2268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 227