14dd649d1SAditya Srivastava /* 2caf6e49bSVincent Cuissard * Marvell NFC-over-SPI driver: SPI interface related functions 3caf6e49bSVincent Cuissard * 4caf6e49bSVincent Cuissard * Copyright (C) 2015, Marvell International Ltd. 5caf6e49bSVincent Cuissard * 6caf6e49bSVincent Cuissard * This software file (the "File") is distributed by Marvell International 7caf6e49bSVincent Cuissard * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8caf6e49bSVincent Cuissard * (the "License"). You may use, redistribute and/or modify this File in 9caf6e49bSVincent Cuissard * accordance with the terms and conditions of the License, a copy of which 10caf6e49bSVincent Cuissard * is available on the worldwide web at 11caf6e49bSVincent Cuissard * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 12caf6e49bSVincent Cuissard * 13caf6e49bSVincent Cuissard * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 14caf6e49bSVincent Cuissard * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 15caf6e49bSVincent Cuissard * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 16caf6e49bSVincent Cuissard * this warranty disclaimer. 17caf6e49bSVincent Cuissard **/ 18caf6e49bSVincent Cuissard 19caf6e49bSVincent Cuissard #include <linux/module.h> 20caf6e49bSVincent Cuissard #include <linux/interrupt.h> 21caf6e49bSVincent Cuissard #include <linux/pm_runtime.h> 22caf6e49bSVincent Cuissard #include <linux/nfc.h> 23caf6e49bSVincent Cuissard #include <linux/gpio.h> 24caf6e49bSVincent Cuissard #include <linux/of_irq.h> 25caf6e49bSVincent Cuissard #include <linux/of_gpio.h> 26caf6e49bSVincent Cuissard #include <net/nfc/nci.h> 27caf6e49bSVincent Cuissard #include <net/nfc/nci_core.h> 28caf6e49bSVincent Cuissard #include <linux/spi/spi.h> 29caf6e49bSVincent Cuissard #include "nfcmrvl.h" 30caf6e49bSVincent Cuissard 31caf6e49bSVincent Cuissard #define SPI_WAIT_HANDSHAKE 1 32caf6e49bSVincent Cuissard 33caf6e49bSVincent Cuissard struct nfcmrvl_spi_drv_data { 34caf6e49bSVincent Cuissard unsigned long flags; 35caf6e49bSVincent Cuissard struct spi_device *spi; 36caf6e49bSVincent Cuissard struct nci_spi *nci_spi; 37caf6e49bSVincent Cuissard struct completion handshake_completion; 38caf6e49bSVincent Cuissard struct nfcmrvl_private *priv; 39caf6e49bSVincent Cuissard }; 40caf6e49bSVincent Cuissard 41caf6e49bSVincent Cuissard static irqreturn_t nfcmrvl_spi_int_irq_thread_fn(int irq, void *drv_data_ptr) 42caf6e49bSVincent Cuissard { 43caf6e49bSVincent Cuissard struct nfcmrvl_spi_drv_data *drv_data = drv_data_ptr; 44caf6e49bSVincent Cuissard struct sk_buff *skb; 45caf6e49bSVincent Cuissard 46caf6e49bSVincent Cuissard /* 47caf6e49bSVincent Cuissard * Special case where we are waiting for SPI_INT deassertion to start a 48caf6e49bSVincent Cuissard * transfer. 49caf6e49bSVincent Cuissard */ 50caf6e49bSVincent Cuissard if (test_and_clear_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags)) { 51caf6e49bSVincent Cuissard complete(&drv_data->handshake_completion); 52caf6e49bSVincent Cuissard return IRQ_HANDLED; 53caf6e49bSVincent Cuissard } 54caf6e49bSVincent Cuissard 55caf6e49bSVincent Cuissard /* Normal case, SPI_INT deasserted by slave to trigger a master read */ 56caf6e49bSVincent Cuissard 57caf6e49bSVincent Cuissard skb = nci_spi_read(drv_data->nci_spi); 58caf6e49bSVincent Cuissard if (!skb) { 59caf6e49bSVincent Cuissard nfc_err(&drv_data->spi->dev, "failed to read spi packet"); 60caf6e49bSVincent Cuissard return IRQ_HANDLED; 61caf6e49bSVincent Cuissard } 62caf6e49bSVincent Cuissard 63caf6e49bSVincent Cuissard if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0) 64caf6e49bSVincent Cuissard nfc_err(&drv_data->spi->dev, "corrupted RX packet"); 65caf6e49bSVincent Cuissard 66caf6e49bSVincent Cuissard return IRQ_HANDLED; 67caf6e49bSVincent Cuissard } 68caf6e49bSVincent Cuissard 69caf6e49bSVincent Cuissard static int nfcmrvl_spi_nci_open(struct nfcmrvl_private *priv) 70caf6e49bSVincent Cuissard { 71caf6e49bSVincent Cuissard return 0; 72caf6e49bSVincent Cuissard } 73caf6e49bSVincent Cuissard 74caf6e49bSVincent Cuissard static int nfcmrvl_spi_nci_close(struct nfcmrvl_private *priv) 75caf6e49bSVincent Cuissard { 76caf6e49bSVincent Cuissard return 0; 77caf6e49bSVincent Cuissard } 78caf6e49bSVincent Cuissard 79caf6e49bSVincent Cuissard static int nfcmrvl_spi_nci_send(struct nfcmrvl_private *priv, 80caf6e49bSVincent Cuissard struct sk_buff *skb) 81caf6e49bSVincent Cuissard { 82caf6e49bSVincent Cuissard struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data; 83caf6e49bSVincent Cuissard int err; 84caf6e49bSVincent Cuissard 85caf6e49bSVincent Cuissard /* Reinit completion for slave handshake */ 86caf6e49bSVincent Cuissard reinit_completion(&drv_data->handshake_completion); 87caf6e49bSVincent Cuissard set_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags); 88caf6e49bSVincent Cuissard 89caf6e49bSVincent Cuissard /* 90caf6e49bSVincent Cuissard * Append a dummy byte at the end of SPI frame. This is due to a 91caf6e49bSVincent Cuissard * specific DMA implementation in the controller 92caf6e49bSVincent Cuissard */ 93caf6e49bSVincent Cuissard skb_put(skb, 1); 94caf6e49bSVincent Cuissard 95caf6e49bSVincent Cuissard /* Send the SPI packet */ 96caf6e49bSVincent Cuissard err = nci_spi_send(drv_data->nci_spi, &drv_data->handshake_completion, 97caf6e49bSVincent Cuissard skb); 98ca42fb9eSDan Carpenter if (err) 99caf6e49bSVincent Cuissard nfc_err(priv->dev, "spi_send failed %d", err); 100ca42fb9eSDan Carpenter 101caf6e49bSVincent Cuissard return err; 102caf6e49bSVincent Cuissard } 103caf6e49bSVincent Cuissard 104caf6e49bSVincent Cuissard static void nfcmrvl_spi_nci_update_config(struct nfcmrvl_private *priv, 105caf6e49bSVincent Cuissard const void *param) 106caf6e49bSVincent Cuissard { 107caf6e49bSVincent Cuissard struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data; 108caf6e49bSVincent Cuissard const struct nfcmrvl_fw_spi_config *config = param; 109caf6e49bSVincent Cuissard 110caf6e49bSVincent Cuissard drv_data->nci_spi->xfer_speed_hz = config->clk; 111caf6e49bSVincent Cuissard } 112caf6e49bSVincent Cuissard 113caf6e49bSVincent Cuissard static struct nfcmrvl_if_ops spi_ops = { 114caf6e49bSVincent Cuissard .nci_open = nfcmrvl_spi_nci_open, 115caf6e49bSVincent Cuissard .nci_close = nfcmrvl_spi_nci_close, 116caf6e49bSVincent Cuissard .nci_send = nfcmrvl_spi_nci_send, 117caf6e49bSVincent Cuissard .nci_update_config = nfcmrvl_spi_nci_update_config, 118caf6e49bSVincent Cuissard }; 119caf6e49bSVincent Cuissard 120caf6e49bSVincent Cuissard static int nfcmrvl_spi_parse_dt(struct device_node *node, 121caf6e49bSVincent Cuissard struct nfcmrvl_platform_data *pdata) 122caf6e49bSVincent Cuissard { 123caf6e49bSVincent Cuissard int ret; 124caf6e49bSVincent Cuissard 125caf6e49bSVincent Cuissard ret = nfcmrvl_parse_dt(node, pdata); 126caf6e49bSVincent Cuissard if (ret < 0) { 127caf6e49bSVincent Cuissard pr_err("Failed to get generic entries\n"); 128caf6e49bSVincent Cuissard return ret; 129caf6e49bSVincent Cuissard } 130caf6e49bSVincent Cuissard 131caf6e49bSVincent Cuissard ret = irq_of_parse_and_map(node, 0); 132caf6e49bSVincent Cuissard if (ret < 0) { 133caf6e49bSVincent Cuissard pr_err("Unable to get irq, error: %d\n", ret); 134caf6e49bSVincent Cuissard return ret; 135caf6e49bSVincent Cuissard } 136caf6e49bSVincent Cuissard pdata->irq = ret; 137caf6e49bSVincent Cuissard 138caf6e49bSVincent Cuissard return 0; 139caf6e49bSVincent Cuissard } 140caf6e49bSVincent Cuissard 141caf6e49bSVincent Cuissard static int nfcmrvl_spi_probe(struct spi_device *spi) 142caf6e49bSVincent Cuissard { 143caf6e49bSVincent Cuissard struct nfcmrvl_platform_data *pdata; 144caf6e49bSVincent Cuissard struct nfcmrvl_platform_data config; 145caf6e49bSVincent Cuissard struct nfcmrvl_spi_drv_data *drv_data; 146caf6e49bSVincent Cuissard int ret = 0; 147caf6e49bSVincent Cuissard 148caf6e49bSVincent Cuissard drv_data = devm_kzalloc(&spi->dev, sizeof(*drv_data), GFP_KERNEL); 149caf6e49bSVincent Cuissard if (!drv_data) 150caf6e49bSVincent Cuissard return -ENOMEM; 151caf6e49bSVincent Cuissard 152caf6e49bSVincent Cuissard drv_data->spi = spi; 153caf6e49bSVincent Cuissard drv_data->priv = NULL; 154caf6e49bSVincent Cuissard spi_set_drvdata(spi, drv_data); 155caf6e49bSVincent Cuissard 156caf6e49bSVincent Cuissard pdata = spi->dev.platform_data; 157caf6e49bSVincent Cuissard 158caf6e49bSVincent Cuissard if (!pdata && spi->dev.of_node) 159caf6e49bSVincent Cuissard if (nfcmrvl_spi_parse_dt(spi->dev.of_node, &config) == 0) 160caf6e49bSVincent Cuissard pdata = &config; 161caf6e49bSVincent Cuissard 162caf6e49bSVincent Cuissard if (!pdata) 163caf6e49bSVincent Cuissard return -EINVAL; 164caf6e49bSVincent Cuissard 165caf6e49bSVincent Cuissard ret = devm_request_threaded_irq(&drv_data->spi->dev, pdata->irq, 166caf6e49bSVincent Cuissard NULL, nfcmrvl_spi_int_irq_thread_fn, 167caf6e49bSVincent Cuissard IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 168caf6e49bSVincent Cuissard "nfcmrvl_spi_int", drv_data); 169caf6e49bSVincent Cuissard if (ret < 0) { 170caf6e49bSVincent Cuissard nfc_err(&drv_data->spi->dev, "Unable to register IRQ handler"); 171caf6e49bSVincent Cuissard return -ENODEV; 172caf6e49bSVincent Cuissard } 173caf6e49bSVincent Cuissard 174caf6e49bSVincent Cuissard drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_SPI, 175caf6e49bSVincent Cuissard drv_data, &spi_ops, 176caf6e49bSVincent Cuissard &drv_data->spi->dev, 177caf6e49bSVincent Cuissard pdata); 178caf6e49bSVincent Cuissard if (IS_ERR(drv_data->priv)) 179caf6e49bSVincent Cuissard return PTR_ERR(drv_data->priv); 180caf6e49bSVincent Cuissard 181caf6e49bSVincent Cuissard drv_data->priv->support_fw_dnld = true; 182caf6e49bSVincent Cuissard 183caf6e49bSVincent Cuissard drv_data->nci_spi = nci_spi_allocate_spi(drv_data->spi, 0, 10, 184caf6e49bSVincent Cuissard drv_data->priv->ndev); 185caf6e49bSVincent Cuissard 186caf6e49bSVincent Cuissard /* Init completion for slave handshake */ 187caf6e49bSVincent Cuissard init_completion(&drv_data->handshake_completion); 188caf6e49bSVincent Cuissard return 0; 189caf6e49bSVincent Cuissard } 190caf6e49bSVincent Cuissard 191caf6e49bSVincent Cuissard static int nfcmrvl_spi_remove(struct spi_device *spi) 192caf6e49bSVincent Cuissard { 193caf6e49bSVincent Cuissard struct nfcmrvl_spi_drv_data *drv_data = spi_get_drvdata(spi); 194caf6e49bSVincent Cuissard 195caf6e49bSVincent Cuissard nfcmrvl_nci_unregister_dev(drv_data->priv); 196caf6e49bSVincent Cuissard return 0; 197caf6e49bSVincent Cuissard } 198caf6e49bSVincent Cuissard 199*26f20ff5SKrzysztof Kozlowski static const struct of_device_id of_nfcmrvl_spi_match[] __maybe_unused = { 200d8e018c0SVincent Cuissard { .compatible = "marvell,nfc-spi", }, 201caf6e49bSVincent Cuissard {}, 202caf6e49bSVincent Cuissard }; 203caf6e49bSVincent Cuissard MODULE_DEVICE_TABLE(of, of_nfcmrvl_spi_match); 204caf6e49bSVincent Cuissard 205caf6e49bSVincent Cuissard static const struct spi_device_id nfcmrvl_spi_id_table[] = { 206caf6e49bSVincent Cuissard { "nfcmrvl_spi", 0 }, 207caf6e49bSVincent Cuissard { } 208caf6e49bSVincent Cuissard }; 209caf6e49bSVincent Cuissard MODULE_DEVICE_TABLE(spi, nfcmrvl_spi_id_table); 210caf6e49bSVincent Cuissard 211caf6e49bSVincent Cuissard static struct spi_driver nfcmrvl_spi_driver = { 212caf6e49bSVincent Cuissard .probe = nfcmrvl_spi_probe, 213caf6e49bSVincent Cuissard .remove = nfcmrvl_spi_remove, 214caf6e49bSVincent Cuissard .id_table = nfcmrvl_spi_id_table, 215caf6e49bSVincent Cuissard .driver = { 216caf6e49bSVincent Cuissard .name = "nfcmrvl_spi", 217caf6e49bSVincent Cuissard .owner = THIS_MODULE, 218caf6e49bSVincent Cuissard .of_match_table = of_match_ptr(of_nfcmrvl_spi_match), 219caf6e49bSVincent Cuissard }, 220caf6e49bSVincent Cuissard }; 221caf6e49bSVincent Cuissard 222caf6e49bSVincent Cuissard module_spi_driver(nfcmrvl_spi_driver); 223caf6e49bSVincent Cuissard 224caf6e49bSVincent Cuissard MODULE_AUTHOR("Marvell International Ltd."); 225caf6e49bSVincent Cuissard MODULE_DESCRIPTION("Marvell NFC-over-SPI driver"); 226caf6e49bSVincent Cuissard MODULE_LICENSE("GPL v2"); 227