xref: /linux/drivers/nfc/st-nci/spi.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
146fe7771SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22bc4d4f8SChristophe Ricard /*
32bc4d4f8SChristophe Ricard  * SPI Link Layer for ST NCI based Driver
42bc4d4f8SChristophe Ricard  * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
52bc4d4f8SChristophe Ricard  */
62bc4d4f8SChristophe Ricard 
72bc4d4f8SChristophe Ricard #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
82bc4d4f8SChristophe Ricard 
92bc4d4f8SChristophe Ricard #include <linux/module.h>
102bc4d4f8SChristophe Ricard #include <linux/spi/spi.h>
1160cd6d89SChristophe Ricard #include <linux/gpio/consumer.h>
1260cd6d89SChristophe Ricard #include <linux/acpi.h>
132bc4d4f8SChristophe Ricard #include <linux/interrupt.h>
142bc4d4f8SChristophe Ricard #include <linux/delay.h>
152bc4d4f8SChristophe Ricard #include <linux/nfc.h>
16a89e68f1SAndy Shevchenko #include <linux/of.h>
17a1269dd1SChristophe Ricard #include <net/nfc/nci.h>
182bc4d4f8SChristophe Ricard 
19e67e7e59SChristophe Ricard #include "st-nci.h"
202bc4d4f8SChristophe Ricard 
212bc4d4f8SChristophe Ricard #define DRIVER_DESC "NCI NFC driver for ST_NCI"
222bc4d4f8SChristophe Ricard 
232bc4d4f8SChristophe Ricard /* ndlc header */
242bc4d4f8SChristophe Ricard #define ST_NCI_FRAME_HEADROOM	1
252bc4d4f8SChristophe Ricard #define ST_NCI_FRAME_TAILROOM	0
262bc4d4f8SChristophe Ricard 
272bc4d4f8SChristophe Ricard #define ST_NCI_SPI_MIN_SIZE 4   /* PCB(1) + NCI Packet header(3) */
282bc4d4f8SChristophe Ricard #define ST_NCI_SPI_MAX_SIZE 250 /* req 4.2.1 */
292bc4d4f8SChristophe Ricard 
3061a04101SAndy Shevchenko #define ST_NCI_DRIVER_NAME "st_nci"
312bc4d4f8SChristophe Ricard #define ST_NCI_SPI_DRIVER_NAME "st_nci_spi"
322bc4d4f8SChristophe Ricard 
332bc4d4f8SChristophe Ricard struct st_nci_spi_phy {
342bc4d4f8SChristophe Ricard 	struct spi_device *spi_dev;
352bc4d4f8SChristophe Ricard 	struct llt_ndlc *ndlc;
362bc4d4f8SChristophe Ricard 
37bb2496c3SChristophe Ricard 	bool irq_active;
38bb2496c3SChristophe Ricard 
39a89e68f1SAndy Shevchenko 	struct gpio_desc *gpiod_reset;
403648dc6dSChristophe Ricard 
413648dc6dSChristophe Ricard 	struct st_nci_se_status se_status;
422bc4d4f8SChristophe Ricard };
432bc4d4f8SChristophe Ricard 
st_nci_spi_enable(void * phy_id)442bc4d4f8SChristophe Ricard static int st_nci_spi_enable(void *phy_id)
452bc4d4f8SChristophe Ricard {
462bc4d4f8SChristophe Ricard 	struct st_nci_spi_phy *phy = phy_id;
472bc4d4f8SChristophe Ricard 
48a89e68f1SAndy Shevchenko 	gpiod_set_value(phy->gpiod_reset, 0);
492bc4d4f8SChristophe Ricard 	usleep_range(10000, 15000);
50a89e68f1SAndy Shevchenko 	gpiod_set_value(phy->gpiod_reset, 1);
512bc4d4f8SChristophe Ricard 	usleep_range(80000, 85000);
522bc4d4f8SChristophe Ricard 
53bb2496c3SChristophe Ricard 	if (phy->ndlc->powered == 0 && phy->irq_active == 0) {
542bc4d4f8SChristophe Ricard 		enable_irq(phy->spi_dev->irq);
55bb2496c3SChristophe Ricard 		phy->irq_active = true;
56bb2496c3SChristophe Ricard 	}
572bc4d4f8SChristophe Ricard 
582bc4d4f8SChristophe Ricard 	return 0;
592bc4d4f8SChristophe Ricard }
602bc4d4f8SChristophe Ricard 
st_nci_spi_disable(void * phy_id)612bc4d4f8SChristophe Ricard static void st_nci_spi_disable(void *phy_id)
622bc4d4f8SChristophe Ricard {
632bc4d4f8SChristophe Ricard 	struct st_nci_spi_phy *phy = phy_id;
642bc4d4f8SChristophe Ricard 
652bc4d4f8SChristophe Ricard 	disable_irq_nosync(phy->spi_dev->irq);
66bb2496c3SChristophe Ricard 	phy->irq_active = false;
672bc4d4f8SChristophe Ricard }
682bc4d4f8SChristophe Ricard 
692bc4d4f8SChristophe Ricard /*
702bc4d4f8SChristophe Ricard  * Writing a frame must not return the number of written bytes.
712bc4d4f8SChristophe Ricard  * It must return either zero for success, or <0 for error.
722bc4d4f8SChristophe Ricard  * In addition, it must not alter the skb
732bc4d4f8SChristophe Ricard  */
st_nci_spi_write(void * phy_id,struct sk_buff * skb)742bc4d4f8SChristophe Ricard static int st_nci_spi_write(void *phy_id, struct sk_buff *skb)
752bc4d4f8SChristophe Ricard {
762bc4d4f8SChristophe Ricard 	int r;
772bc4d4f8SChristophe Ricard 	struct st_nci_spi_phy *phy = phy_id;
782bc4d4f8SChristophe Ricard 	struct spi_device *dev = phy->spi_dev;
792bc4d4f8SChristophe Ricard 	struct sk_buff *skb_rx;
80a1269dd1SChristophe Ricard 	u8 buf[ST_NCI_SPI_MAX_SIZE + NCI_DATA_HDR_SIZE +
81a1269dd1SChristophe Ricard 	       ST_NCI_FRAME_HEADROOM + ST_NCI_FRAME_TAILROOM];
822bc4d4f8SChristophe Ricard 	struct spi_transfer spi_xfer = {
832bc4d4f8SChristophe Ricard 		.tx_buf = skb->data,
842bc4d4f8SChristophe Ricard 		.rx_buf = buf,
852bc4d4f8SChristophe Ricard 		.len = skb->len,
862bc4d4f8SChristophe Ricard 	};
872bc4d4f8SChristophe Ricard 
882bc4d4f8SChristophe Ricard 	if (phy->ndlc->hard_fault != 0)
892bc4d4f8SChristophe Ricard 		return phy->ndlc->hard_fault;
902bc4d4f8SChristophe Ricard 
912bc4d4f8SChristophe Ricard 	r = spi_sync_transfer(dev, &spi_xfer, 1);
922bc4d4f8SChristophe Ricard 	/*
932bc4d4f8SChristophe Ricard 	 * We may have received some valuable data on miso line.
942bc4d4f8SChristophe Ricard 	 * Send them back in the ndlc state machine.
952bc4d4f8SChristophe Ricard 	 */
962bc4d4f8SChristophe Ricard 	if (!r) {
972bc4d4f8SChristophe Ricard 		skb_rx = alloc_skb(skb->len, GFP_KERNEL);
98eba43facSwengjianfeng 		if (!skb_rx)
99eba43facSwengjianfeng 			return -ENOMEM;
1002bc4d4f8SChristophe Ricard 
1012bc4d4f8SChristophe Ricard 		skb_put(skb_rx, skb->len);
1022bc4d4f8SChristophe Ricard 		memcpy(skb_rx->data, buf, skb->len);
1032bc4d4f8SChristophe Ricard 		ndlc_recv(phy->ndlc, skb_rx);
1042bc4d4f8SChristophe Ricard 	}
1052bc4d4f8SChristophe Ricard 
1062bc4d4f8SChristophe Ricard 	return r;
1072bc4d4f8SChristophe Ricard }
1082bc4d4f8SChristophe Ricard 
1092bc4d4f8SChristophe Ricard /*
1102bc4d4f8SChristophe Ricard  * Reads an ndlc frame and returns it in a newly allocated sk_buff.
1112bc4d4f8SChristophe Ricard  * returns:
1122bc4d4f8SChristophe Ricard  * 0 : if received frame is complete
1132bc4d4f8SChristophe Ricard  * -EREMOTEIO : i2c read error (fatal)
1142bc4d4f8SChristophe Ricard  * -EBADMSG : frame was incorrect and discarded
1152bc4d4f8SChristophe Ricard  * -ENOMEM : cannot allocate skb, frame dropped
1162bc4d4f8SChristophe Ricard  */
st_nci_spi_read(struct st_nci_spi_phy * phy,struct sk_buff ** skb)1172bc4d4f8SChristophe Ricard static int st_nci_spi_read(struct st_nci_spi_phy *phy,
1182bc4d4f8SChristophe Ricard 			struct sk_buff **skb)
1192bc4d4f8SChristophe Ricard {
1202bc4d4f8SChristophe Ricard 	int r;
1212bc4d4f8SChristophe Ricard 	u8 len;
1222bc4d4f8SChristophe Ricard 	u8 buf[ST_NCI_SPI_MAX_SIZE];
1232bc4d4f8SChristophe Ricard 	struct spi_device *dev = phy->spi_dev;
1242bc4d4f8SChristophe Ricard 	struct spi_transfer spi_xfer = {
1252bc4d4f8SChristophe Ricard 		.rx_buf = buf,
1262bc4d4f8SChristophe Ricard 		.len = ST_NCI_SPI_MIN_SIZE,
1272bc4d4f8SChristophe Ricard 	};
1282bc4d4f8SChristophe Ricard 
1292bc4d4f8SChristophe Ricard 	r = spi_sync_transfer(dev, &spi_xfer, 1);
1302bc4d4f8SChristophe Ricard 	if (r < 0)
1312bc4d4f8SChristophe Ricard 		return -EREMOTEIO;
1322bc4d4f8SChristophe Ricard 
1332bc4d4f8SChristophe Ricard 	len = be16_to_cpu(*(__be16 *) (buf + 2));
1342bc4d4f8SChristophe Ricard 	if (len > ST_NCI_SPI_MAX_SIZE) {
1352bc4d4f8SChristophe Ricard 		nfc_err(&dev->dev, "invalid frame len\n");
1362bc4d4f8SChristophe Ricard 		phy->ndlc->hard_fault = 1;
1372bc4d4f8SChristophe Ricard 		return -EBADMSG;
1382bc4d4f8SChristophe Ricard 	}
1392bc4d4f8SChristophe Ricard 
1402bc4d4f8SChristophe Ricard 	*skb = alloc_skb(ST_NCI_SPI_MIN_SIZE + len, GFP_KERNEL);
1412bc4d4f8SChristophe Ricard 	if (*skb == NULL)
1422bc4d4f8SChristophe Ricard 		return -ENOMEM;
1432bc4d4f8SChristophe Ricard 
1442bc4d4f8SChristophe Ricard 	skb_reserve(*skb, ST_NCI_SPI_MIN_SIZE);
1452bc4d4f8SChristophe Ricard 	skb_put(*skb, ST_NCI_SPI_MIN_SIZE);
1462bc4d4f8SChristophe Ricard 	memcpy((*skb)->data, buf, ST_NCI_SPI_MIN_SIZE);
1472bc4d4f8SChristophe Ricard 
1482bc4d4f8SChristophe Ricard 	if (!len)
1492bc4d4f8SChristophe Ricard 		return 0;
1502bc4d4f8SChristophe Ricard 
1512bc4d4f8SChristophe Ricard 	spi_xfer.len = len;
1522bc4d4f8SChristophe Ricard 	r = spi_sync_transfer(dev, &spi_xfer, 1);
1532bc4d4f8SChristophe Ricard 	if (r < 0) {
1542bc4d4f8SChristophe Ricard 		kfree_skb(*skb);
1552bc4d4f8SChristophe Ricard 		return -EREMOTEIO;
1562bc4d4f8SChristophe Ricard 	}
1572bc4d4f8SChristophe Ricard 
1582bc4d4f8SChristophe Ricard 	skb_put(*skb, len);
1592bc4d4f8SChristophe Ricard 	memcpy((*skb)->data + ST_NCI_SPI_MIN_SIZE, buf, len);
1602bc4d4f8SChristophe Ricard 
1612bc4d4f8SChristophe Ricard 	return 0;
1622bc4d4f8SChristophe Ricard }
1632bc4d4f8SChristophe Ricard 
1642bc4d4f8SChristophe Ricard /*
1652bc4d4f8SChristophe Ricard  * Reads an ndlc frame from the chip.
1662bc4d4f8SChristophe Ricard  *
1672bc4d4f8SChristophe Ricard  * On ST21NFCB, IRQ goes in idle state when read starts.
1682bc4d4f8SChristophe Ricard  */
st_nci_irq_thread_fn(int irq,void * phy_id)1692bc4d4f8SChristophe Ricard static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id)
1702bc4d4f8SChristophe Ricard {
1712bc4d4f8SChristophe Ricard 	struct st_nci_spi_phy *phy = phy_id;
1722bc4d4f8SChristophe Ricard 	struct sk_buff *skb = NULL;
1732bc4d4f8SChristophe Ricard 	int r;
1742bc4d4f8SChristophe Ricard 
1752bc4d4f8SChristophe Ricard 	if (!phy || !phy->ndlc || irq != phy->spi_dev->irq) {
1762bc4d4f8SChristophe Ricard 		WARN_ON_ONCE(1);
1772bc4d4f8SChristophe Ricard 		return IRQ_NONE;
1782bc4d4f8SChristophe Ricard 	}
1792bc4d4f8SChristophe Ricard 
1802bc4d4f8SChristophe Ricard 	if (phy->ndlc->hard_fault)
1812bc4d4f8SChristophe Ricard 		return IRQ_HANDLED;
1822bc4d4f8SChristophe Ricard 
1832bc4d4f8SChristophe Ricard 	if (!phy->ndlc->powered) {
1842bc4d4f8SChristophe Ricard 		st_nci_spi_disable(phy);
1852bc4d4f8SChristophe Ricard 		return IRQ_HANDLED;
1862bc4d4f8SChristophe Ricard 	}
1872bc4d4f8SChristophe Ricard 
1882bc4d4f8SChristophe Ricard 	r = st_nci_spi_read(phy, &skb);
1892bc4d4f8SChristophe Ricard 	if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG)
1902bc4d4f8SChristophe Ricard 		return IRQ_HANDLED;
1912bc4d4f8SChristophe Ricard 
1922bc4d4f8SChristophe Ricard 	ndlc_recv(phy->ndlc, skb);
1932bc4d4f8SChristophe Ricard 
1942bc4d4f8SChristophe Ricard 	return IRQ_HANDLED;
1952bc4d4f8SChristophe Ricard }
1962bc4d4f8SChristophe Ricard 
1977a5e98daSKrzysztof Kozlowski static const struct nfc_phy_ops spi_phy_ops = {
1982bc4d4f8SChristophe Ricard 	.write = st_nci_spi_write,
1992bc4d4f8SChristophe Ricard 	.enable = st_nci_spi_enable,
2002bc4d4f8SChristophe Ricard 	.disable = st_nci_spi_disable,
2012bc4d4f8SChristophe Ricard };
2022bc4d4f8SChristophe Ricard 
20385d23e77SAndy Shevchenko static const struct acpi_gpio_params reset_gpios = { 1, 0, false };
20485d23e77SAndy Shevchenko 
20585d23e77SAndy Shevchenko static const struct acpi_gpio_mapping acpi_st_nci_gpios[] = {
20685d23e77SAndy Shevchenko 	{ "reset-gpios", &reset_gpios, 1 },
20785d23e77SAndy Shevchenko 	{},
20885d23e77SAndy Shevchenko };
20985d23e77SAndy Shevchenko 
st_nci_spi_probe(struct spi_device * dev)2102bc4d4f8SChristophe Ricard static int st_nci_spi_probe(struct spi_device *dev)
2112bc4d4f8SChristophe Ricard {
2122bc4d4f8SChristophe Ricard 	struct st_nci_spi_phy *phy;
2132bc4d4f8SChristophe Ricard 	int r;
2142bc4d4f8SChristophe Ricard 
2152bc4d4f8SChristophe Ricard 	/* Check SPI platform functionnalities */
2162bc4d4f8SChristophe Ricard 	if (!dev) {
2172bc4d4f8SChristophe Ricard 		pr_debug("%s: dev is NULL. Device is not accessible.\n",
2182bc4d4f8SChristophe Ricard 			__func__);
2192bc4d4f8SChristophe Ricard 		return -ENODEV;
2202bc4d4f8SChristophe Ricard 	}
2212bc4d4f8SChristophe Ricard 
2222bc4d4f8SChristophe Ricard 	phy = devm_kzalloc(&dev->dev, sizeof(struct st_nci_spi_phy),
2232bc4d4f8SChristophe Ricard 			   GFP_KERNEL);
2242bc4d4f8SChristophe Ricard 	if (!phy)
2252bc4d4f8SChristophe Ricard 		return -ENOMEM;
2262bc4d4f8SChristophe Ricard 
2272bc4d4f8SChristophe Ricard 	phy->spi_dev = dev;
2282bc4d4f8SChristophe Ricard 
2292bc4d4f8SChristophe Ricard 	spi_set_drvdata(dev, phy);
2302bc4d4f8SChristophe Ricard 
231c745120eSAndy Shevchenko 	r = devm_acpi_dev_add_driver_gpios(&dev->dev, acpi_st_nci_gpios);
232c745120eSAndy Shevchenko 	if (r)
233c745120eSAndy Shevchenko 		dev_dbg(&dev->dev, "Unable to add GPIO mapping table\n");
234c745120eSAndy Shevchenko 
235c745120eSAndy Shevchenko 	/* Get RESET GPIO */
236c745120eSAndy Shevchenko 	phy->gpiod_reset = devm_gpiod_get(&dev->dev, "reset", GPIOD_OUT_HIGH);
237c745120eSAndy Shevchenko 	if (IS_ERR(phy->gpiod_reset)) {
238c745120eSAndy Shevchenko 		nfc_err(&dev->dev, "Unable to get RESET GPIO\n");
239c745120eSAndy Shevchenko 		return PTR_ERR(phy->gpiod_reset);
2402bc4d4f8SChristophe Ricard 	}
2412bc4d4f8SChristophe Ricard 
24275719b2bSAndy Shevchenko 	phy->se_status.is_ese_present =
24375719b2bSAndy Shevchenko 			device_property_read_bool(&dev->dev, "ese-present");
24475719b2bSAndy Shevchenko 	phy->se_status.is_uicc_present =
24575719b2bSAndy Shevchenko 			device_property_read_bool(&dev->dev, "uicc-present");
24675719b2bSAndy Shevchenko 
2472bc4d4f8SChristophe Ricard 	r = ndlc_probe(phy, &spi_phy_ops, &dev->dev,
2482bc4d4f8SChristophe Ricard 			ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
2493648dc6dSChristophe Ricard 			&phy->ndlc, &phy->se_status);
2502bc4d4f8SChristophe Ricard 	if (r < 0) {
2512bc4d4f8SChristophe Ricard 		nfc_err(&dev->dev, "Unable to register ndlc layer\n");
2522bc4d4f8SChristophe Ricard 		return r;
2532bc4d4f8SChristophe Ricard 	}
2542bc4d4f8SChristophe Ricard 
255bb2496c3SChristophe Ricard 	phy->irq_active = true;
2562bc4d4f8SChristophe Ricard 	r = devm_request_threaded_irq(&dev->dev, dev->irq, NULL,
2572bc4d4f8SChristophe Ricard 				st_nci_irq_thread_fn,
2581af9fea6SAndy Shevchenko 				IRQF_ONESHOT,
2592bc4d4f8SChristophe Ricard 				ST_NCI_SPI_DRIVER_NAME, phy);
2602bc4d4f8SChristophe Ricard 	if (r < 0)
2612bc4d4f8SChristophe Ricard 		nfc_err(&dev->dev, "Unable to register IRQ handler\n");
2622bc4d4f8SChristophe Ricard 
2632bc4d4f8SChristophe Ricard 	return r;
2642bc4d4f8SChristophe Ricard }
2652bc4d4f8SChristophe Ricard 
st_nci_spi_remove(struct spi_device * dev)266*a0386bbaSUwe Kleine-König static void st_nci_spi_remove(struct spi_device *dev)
2672bc4d4f8SChristophe Ricard {
2682bc4d4f8SChristophe Ricard 	struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
2692bc4d4f8SChristophe Ricard 
2702bc4d4f8SChristophe Ricard 	ndlc_remove(phy->ndlc);
2712bc4d4f8SChristophe Ricard }
2722bc4d4f8SChristophe Ricard 
2733252897fSChristophe Ricard static struct spi_device_id st_nci_spi_id_table[] = {
2743252897fSChristophe Ricard 	{ST_NCI_SPI_DRIVER_NAME, 0},
27531339440SMark Brown 	{"st21nfcb-spi", 0},
2763252897fSChristophe Ricard 	{}
2773252897fSChristophe Ricard };
2783252897fSChristophe Ricard MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
2793252897fSChristophe Ricard 
280255fcc7bSKrzysztof Kozlowski static const struct acpi_device_id st_nci_spi_acpi_match[] __maybe_unused = {
28160cd6d89SChristophe Ricard 	{"SMO2101", 0},
28260cd6d89SChristophe Ricard 	{}
28360cd6d89SChristophe Ricard };
28460cd6d89SChristophe Ricard MODULE_DEVICE_TABLE(acpi, st_nci_spi_acpi_match);
28560cd6d89SChristophe Ricard 
286255fcc7bSKrzysztof Kozlowski static const struct of_device_id of_st_nci_spi_match[] __maybe_unused = {
2872bc4d4f8SChristophe Ricard 	{ .compatible = "st,st21nfcb-spi", },
2882bc4d4f8SChristophe Ricard 	{}
2892bc4d4f8SChristophe Ricard };
2902bc4d4f8SChristophe Ricard MODULE_DEVICE_TABLE(of, of_st_nci_spi_match);
2912bc4d4f8SChristophe Ricard 
2922bc4d4f8SChristophe Ricard static struct spi_driver st_nci_spi_driver = {
2932bc4d4f8SChristophe Ricard 	.driver = {
2942bc4d4f8SChristophe Ricard 		.name = ST_NCI_SPI_DRIVER_NAME,
2952bc4d4f8SChristophe Ricard 		.of_match_table = of_match_ptr(of_st_nci_spi_match),
29660cd6d89SChristophe Ricard 		.acpi_match_table = ACPI_PTR(st_nci_spi_acpi_match),
2972bc4d4f8SChristophe Ricard 	},
2982bc4d4f8SChristophe Ricard 	.probe = st_nci_spi_probe,
2992bc4d4f8SChristophe Ricard 	.id_table = st_nci_spi_id_table,
3002bc4d4f8SChristophe Ricard 	.remove = st_nci_spi_remove,
3012bc4d4f8SChristophe Ricard };
3022bc4d4f8SChristophe Ricard module_spi_driver(st_nci_spi_driver);
3032bc4d4f8SChristophe Ricard 
3042bc4d4f8SChristophe Ricard MODULE_LICENSE("GPL");
3052bc4d4f8SChristophe Ricard MODULE_DESCRIPTION(DRIVER_DESC);
306