File Index
Files and directories
Sign in
FILE

spi.c

File preview with syntax highlighting.

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