cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spi.c (5157B)


      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		.owner		= THIS_MODULE,
    203		.of_match_table	= of_match_ptr(of_nfcmrvl_spi_match),
    204	},
    205};
    206
    207module_spi_driver(nfcmrvl_spi_driver);
    208
    209MODULE_AUTHOR("Marvell International Ltd.");
    210MODULE_DESCRIPTION("Marvell NFC-over-SPI driver");
    211MODULE_LICENSE("GPL v2");