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 "nfcmrvl.h" 30 31 #define SPI_WAIT_HANDSHAKE 1 32 33 struct nfcmrvl_spi_drv_data { 34 unsigned long flags; 35 struct spi_device *spi; 36 struct nci_spi *nci_spi; 37 struct completion handshake_completion; 38 struct nfcmrvl_private *priv; 39 }; 40 41 static irqreturn_t nfcmrvl_spi_int_irq_thread_fn(int irq, void *drv_data_ptr) 42 { 43 struct nfcmrvl_spi_drv_data *drv_data = drv_data_ptr; 44 struct sk_buff *skb; 45 46 /* 47 * Special case where we are waiting for SPI_INT deassertion to start a 48 * transfer. 49 */ 50 if (test_and_clear_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags)) { 51 complete(&drv_data->handshake_completion); 52 return IRQ_HANDLED; 53 } 54 55 /* Normal case, SPI_INT deasserted by slave to trigger a master read */ 56 57 skb = nci_spi_read(drv_data->nci_spi); 58 if (!skb) { 59 nfc_err(&drv_data->spi->dev, "failed to read spi packet"); 60 return IRQ_HANDLED; 61 } 62 63 if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0) 64 nfc_err(&drv_data->spi->dev, "corrupted RX packet"); 65 66 return IRQ_HANDLED; 67 } 68 69 static int nfcmrvl_spi_nci_open(struct nfcmrvl_private *priv) 70 { 71 return 0; 72 } 73 74 static int nfcmrvl_spi_nci_close(struct nfcmrvl_private *priv) 75 { 76 return 0; 77 } 78 79 static int nfcmrvl_spi_nci_send(struct nfcmrvl_private *priv, 80 struct sk_buff *skb) 81 { 82 struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data; 83 int err; 84 85 /* Reinit completion for slave handshake */ 86 reinit_completion(&drv_data->handshake_completion); 87 set_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags); 88 89 /* 90 * Append a dummy byte at the end of SPI frame. This is due to a 91 * specific DMA implementation in the controller 92 */ 93 skb_put(skb, 1); 94 95 /* Send the SPI packet */ 96 err = nci_spi_send(drv_data->nci_spi, &drv_data->handshake_completion, 97 skb); 98 if (err) 99 nfc_err(priv->dev, "spi_send failed %d", err); 100 101 return err; 102 } 103 104 static void nfcmrvl_spi_nci_update_config(struct nfcmrvl_private *priv, 105 const void *param) 106 { 107 struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data; 108 const struct nfcmrvl_fw_spi_config *config = param; 109 110 drv_data->nci_spi->xfer_speed_hz = config->clk; 111 } 112 113 static struct nfcmrvl_if_ops spi_ops = { 114 .nci_open = nfcmrvl_spi_nci_open, 115 .nci_close = nfcmrvl_spi_nci_close, 116 .nci_send = nfcmrvl_spi_nci_send, 117 .nci_update_config = nfcmrvl_spi_nci_update_config, 118 }; 119 120 static int nfcmrvl_spi_parse_dt(struct device_node *node, 121 struct nfcmrvl_platform_data *pdata) 122 { 123 int ret; 124 125 ret = nfcmrvl_parse_dt(node, pdata); 126 if (ret < 0) { 127 pr_err("Failed to get generic entries\n"); 128 return ret; 129 } 130 131 ret = irq_of_parse_and_map(node, 0); 132 if (ret < 0) { 133 pr_err("Unable to get irq, error: %d\n", ret); 134 return ret; 135 } 136 pdata->irq = ret; 137 138 return 0; 139 } 140 141 static int nfcmrvl_spi_probe(struct spi_device *spi) 142 { 143 struct nfcmrvl_platform_data *pdata; 144 struct nfcmrvl_platform_data config; 145 struct nfcmrvl_spi_drv_data *drv_data; 146 int ret = 0; 147 148 drv_data = devm_kzalloc(&spi->dev, sizeof(*drv_data), GFP_KERNEL); 149 if (!drv_data) 150 return -ENOMEM; 151 152 drv_data->spi = spi; 153 drv_data->priv = NULL; 154 spi_set_drvdata(spi, drv_data); 155 156 pdata = spi->dev.platform_data; 157 158 if (!pdata && spi->dev.of_node) 159 if (nfcmrvl_spi_parse_dt(spi->dev.of_node, &config) == 0) 160 pdata = &config; 161 162 if (!pdata) 163 return -EINVAL; 164 165 ret = devm_request_threaded_irq(&drv_data->spi->dev, pdata->irq, 166 NULL, nfcmrvl_spi_int_irq_thread_fn, 167 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 168 "nfcmrvl_spi_int", drv_data); 169 if (ret < 0) { 170 nfc_err(&drv_data->spi->dev, "Unable to register IRQ handler"); 171 return -ENODEV; 172 } 173 174 drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_SPI, 175 drv_data, &spi_ops, 176 &drv_data->spi->dev, 177 pdata); 178 if (IS_ERR(drv_data->priv)) 179 return PTR_ERR(drv_data->priv); 180 181 drv_data->priv->support_fw_dnld = true; 182 183 drv_data->nci_spi = nci_spi_allocate_spi(drv_data->spi, 0, 10, 184 drv_data->priv->ndev); 185 186 /* Init completion for slave handshake */ 187 init_completion(&drv_data->handshake_completion); 188 return 0; 189 } 190 191 static int nfcmrvl_spi_remove(struct spi_device *spi) 192 { 193 struct nfcmrvl_spi_drv_data *drv_data = spi_get_drvdata(spi); 194 195 nfcmrvl_nci_unregister_dev(drv_data->priv); 196 return 0; 197 } 198 199 static const struct of_device_id of_nfcmrvl_spi_match[] = { 200 { .compatible = "marvell,nfc-spi", }, 201 {}, 202 }; 203 MODULE_DEVICE_TABLE(of, of_nfcmrvl_spi_match); 204 205 static const struct spi_device_id nfcmrvl_spi_id_table[] = { 206 { "nfcmrvl_spi", 0 }, 207 { } 208 }; 209 MODULE_DEVICE_TABLE(spi, nfcmrvl_spi_id_table); 210 211 static struct spi_driver nfcmrvl_spi_driver = { 212 .probe = nfcmrvl_spi_probe, 213 .remove = nfcmrvl_spi_remove, 214 .id_table = nfcmrvl_spi_id_table, 215 .driver = { 216 .name = "nfcmrvl_spi", 217 .owner = THIS_MODULE, 218 .of_match_table = of_match_ptr(of_nfcmrvl_spi_match), 219 }, 220 }; 221 222 module_spi_driver(nfcmrvl_spi_driver); 223 224 MODULE_AUTHOR("Marvell International Ltd."); 225 MODULE_DESCRIPTION("Marvell NFC-over-SPI driver"); 226 MODULE_LICENSE("GPL v2"); 227