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