···11* Marvell International Ltd. NCI NFC Controller2233Required properties:44-- compatible: Should be "mrvl,nfc-uart".44+- compatible: Should be:55+ - "mrvl,nfc-uart" for UART devices66+ - "mrvl,nfc-i2c" for I2C devices5768Optional SoC specific properties:79- pinctrl-names: Contains only one value - "default".···1412Optional UART-based chip specific properties:1513- flow-control: Specifies that the chip is using RTS/CTS.1614- break-control: Specifies that the chip needs specific break management.1515+1616+Optional I2C-based chip specific properties:1717+- i2c-int-falling: Specifies that the chip read event shall be trigged on1818+ falling edge.1919+- i2c-int-rising: Specifies that the chip read event shall be trigged on2020+ rising edge.17211822Example (for ARM-based BeagleBoard Black with 88W8887 on UART5):1923···3426 hci-muxed;3527 flow-control;3628 }2929+};3030+3131+3232+Example (for ARM-based BeagleBoard Black with 88W8887 on I2C1):3333+3434+&i2c1 {3535+ status = "okay";3636+ clock-frequency = <400000>;3737+3838+ nfcmrvli2c0: i2c@1 {3939+ compatible = "mrvl,nfc-i2c";4040+4141+ reg = <0x8>;4242+4343+ /* I2C INT configuration */4444+ interrupt-parent = <&gpio3>;4545+ interrupts = <21 0>;4646+4747+ /* I2C INT trigger configuration */4848+ i2c-int-rising;4949+5050+ /* Reset IO */5151+ reset-n-io = <&gpio3 19 0>;5252+ };3753};
+12
drivers/nfc/nfcmrvl/Kconfig
···30303131 Say Y here to compile support for Marvell NFC-over-UART driver3232 into the kernel or say M to compile it as module.3333+3434+config NFC_MRVL_I2C3535+ tristate "Marvell NFC-over-I2C driver"3636+ depends on NFC_MRVL && I2C3737+ help3838+ Marvell NFC-over-I2C driver.3939+4040+ This driver provides support for Marvell NFC-over-I2C devices.4141+4242+ Say Y here to compile support for Marvell NFC-over-I2C driver4343+ into the kernel or say M to compile it as module.4444+
···11+/**22+ * Marvell NFC-over-I2C driver: I2C interface related functions33+ *44+ * Copyright (C) 2015, Marvell International Ltd.55+ *66+ * This software file (the "File") is distributed by Marvell International77+ * Ltd. under the terms of the GNU General Public License Version 2, June 199188+ * (the "License"). You may use, redistribute and/or modify this File in99+ * accordance with the terms and conditions of the License, a copy of which1010+ * is available on the worldwide web at1111+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.1212+ *1313+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE1414+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE1515+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about1616+ * this warranty disclaimer.1717+ **/1818+1919+#include <linux/module.h>2020+#include <linux/interrupt.h>2121+#include <linux/i2c.h>2222+#include <linux/pm_runtime.h>2323+#include <linux/nfc.h>2424+#include <linux/gpio.h>2525+#include <linux/delay.h>2626+#include <linux/of_irq.h>2727+#include <linux/of_gpio.h>2828+#include <net/nfc/nci.h>2929+#include <net/nfc/nci_core.h>3030+#include "nfcmrvl.h"3131+3232+struct nfcmrvl_i2c_drv_data {3333+ unsigned long flags;3434+ struct device *dev;3535+ struct i2c_client *i2c;3636+ struct nfcmrvl_private *priv;3737+};3838+3939+static int nfcmrvl_i2c_read(struct nfcmrvl_i2c_drv_data *drv_data,4040+ struct sk_buff **skb)4141+{4242+ int ret;4343+ struct nci_ctrl_hdr nci_hdr;4444+4545+ /* Read NCI header to know the payload size */4646+ ret = i2c_master_recv(drv_data->i2c, (u8 *)&nci_hdr, NCI_CTRL_HDR_SIZE);4747+ if (ret != NCI_CTRL_HDR_SIZE) {4848+ nfc_err(&drv_data->i2c->dev, "cannot read NCI header\n");4949+ return -EBADMSG;5050+ }5151+5252+ if (nci_hdr.plen > NCI_MAX_PAYLOAD_SIZE) {5353+ nfc_err(&drv_data->i2c->dev, "invalid packet payload size\n");5454+ return -EBADMSG;5555+ }5656+5757+ *skb = nci_skb_alloc(drv_data->priv->ndev,5858+ nci_hdr.plen + NCI_CTRL_HDR_SIZE, GFP_KERNEL);5959+ if (!*skb)6060+ return -ENOMEM;6161+6262+ /* Copy NCI header into the SKB */6363+ memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), &nci_hdr, NCI_CTRL_HDR_SIZE);6464+6565+ if (nci_hdr.plen) {6666+ /* Read the NCI payload */6767+ ret = i2c_master_recv(drv_data->i2c,6868+ skb_put(*skb, nci_hdr.plen),6969+ nci_hdr.plen);7070+7171+ if (ret != nci_hdr.plen) {7272+ nfc_err(&drv_data->i2c->dev,7373+ "Invalid frame payload length: %u (expected %u)\n",7474+ ret, nci_hdr.plen);7575+ kfree_skb(*skb);7676+ return -EBADMSG;7777+ }7878+ }7979+8080+ return 0;8181+}8282+8383+static irqreturn_t nfcmrvl_i2c_int_irq_thread_fn(int irq, void *drv_data_ptr)8484+{8585+ struct nfcmrvl_i2c_drv_data *drv_data = drv_data_ptr;8686+ struct sk_buff *skb = NULL;8787+ int ret;8888+8989+ if (!drv_data->priv)9090+ return IRQ_HANDLED;9191+9292+ if (test_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags))9393+ return IRQ_HANDLED;9494+9595+ ret = nfcmrvl_i2c_read(drv_data, &skb);9696+9797+ switch (ret) {9898+ case -EREMOTEIO:9999+ set_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags);100100+ break;101101+ case -ENOMEM:102102+ case -EBADMSG:103103+ nfc_err(&drv_data->i2c->dev, "read failed %d\n", ret);104104+ break;105105+ default:106106+ if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)107107+ nfc_err(&drv_data->i2c->dev, "corrupted RX packet\n");108108+ break;109109+ }110110+ return IRQ_HANDLED;111111+}112112+113113+static int nfcmrvl_i2c_nci_open(struct nfcmrvl_private *priv)114114+{115115+ struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data;116116+117117+ if (!drv_data)118118+ return -ENODEV;119119+120120+ return 0;121121+}122122+123123+static int nfcmrvl_i2c_nci_close(struct nfcmrvl_private *priv)124124+{125125+ return 0;126126+}127127+128128+static int nfcmrvl_i2c_nci_send(struct nfcmrvl_private *priv,129129+ struct sk_buff *skb)130130+{131131+ struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data;132132+ int ret;133133+134134+ if (test_bit(NFCMRVL_PHY_ERROR, &priv->flags))135135+ return -EREMOTEIO;136136+137137+ ret = i2c_master_send(drv_data->i2c, skb->data, skb->len);138138+139139+ /* Retry if chip was in standby */140140+ if (ret == -EREMOTEIO) {141141+ nfc_info(drv_data->dev, "chip may sleep, retry\n");142142+ usleep_range(6000, 10000);143143+ ret = i2c_master_send(drv_data->i2c, skb->data, skb->len);144144+ }145145+146146+ if (ret >= 0) {147147+ if (ret != skb->len) {148148+ nfc_err(drv_data->dev,149149+ "Invalid length sent: %u (expected %u)\n",150150+ ret, skb->len);151151+ ret = -EREMOTEIO;152152+ } else153153+ ret = 0;154154+ kfree_skb(skb);155155+ }156156+157157+ return ret;158158+}159159+160160+static void nfcmrvl_i2c_nci_update_config(struct nfcmrvl_private *priv,161161+ const void *param)162162+{163163+}164164+165165+static struct nfcmrvl_if_ops i2c_ops = {166166+ .nci_open = nfcmrvl_i2c_nci_open,167167+ .nci_close = nfcmrvl_i2c_nci_close,168168+ .nci_send = nfcmrvl_i2c_nci_send,169169+ .nci_update_config = nfcmrvl_i2c_nci_update_config,170170+};171171+172172+static int nfcmrvl_i2c_parse_dt(struct device_node *node,173173+ struct nfcmrvl_platform_data *pdata)174174+{175175+ int ret;176176+177177+ ret = nfcmrvl_parse_dt(node, pdata);178178+ if (ret < 0) {179179+ pr_err("Failed to get generic entries\n");180180+ return ret;181181+ }182182+183183+ if (of_find_property(node, "i2c-int-falling", NULL))184184+ pdata->irq_polarity = IRQF_TRIGGER_FALLING;185185+ else186186+ pdata->irq_polarity = IRQF_TRIGGER_RISING;187187+188188+ ret = irq_of_parse_and_map(node, 0);189189+ if (ret < 0) {190190+ pr_err("Unable to get irq, error: %d\n", ret);191191+ return ret;192192+ }193193+ pdata->irq = ret;194194+195195+ return 0;196196+}197197+198198+static int nfcmrvl_i2c_probe(struct i2c_client *client,199199+ const struct i2c_device_id *id)200200+{201201+ struct nfcmrvl_i2c_drv_data *drv_data;202202+ struct nfcmrvl_platform_data *pdata;203203+ struct nfcmrvl_platform_data config;204204+ int ret;205205+206206+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {207207+ nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");208208+ return -ENODEV;209209+ }210210+211211+ drv_data = devm_kzalloc(&client->dev, sizeof(*drv_data), GFP_KERNEL);212212+ if (!drv_data)213213+ return -ENOMEM;214214+215215+ drv_data->i2c = client;216216+ drv_data->dev = &client->dev;217217+ drv_data->priv = NULL;218218+219219+ i2c_set_clientdata(client, drv_data);220220+221221+ pdata = client->dev.platform_data;222222+223223+ if (!pdata && client->dev.of_node)224224+ if (nfcmrvl_i2c_parse_dt(client->dev.of_node, &config) == 0)225225+ pdata = &config;226226+227227+ if (!pdata)228228+ return -EINVAL;229229+230230+ /* Request the read IRQ */231231+ ret = devm_request_threaded_irq(&drv_data->i2c->dev, pdata->irq,232232+ NULL, nfcmrvl_i2c_int_irq_thread_fn,233233+ pdata->irq_polarity | IRQF_ONESHOT,234234+ "nfcmrvl_i2c_int", drv_data);235235+ if (ret < 0) {236236+ nfc_err(&drv_data->i2c->dev,237237+ "Unable to register IRQ handler\n");238238+ return ret;239239+ }240240+241241+ drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_I2C,242242+ drv_data, &i2c_ops,243243+ &drv_data->i2c->dev, pdata);244244+245245+ if (IS_ERR(drv_data->priv))246246+ return PTR_ERR(drv_data->priv);247247+248248+ drv_data->priv->support_fw_dnld = true;249249+250250+ return 0;251251+}252252+253253+static int nfcmrvl_i2c_remove(struct i2c_client *client)254254+{255255+ struct nfcmrvl_i2c_drv_data *drv_data = i2c_get_clientdata(client);256256+257257+ nfcmrvl_nci_unregister_dev(drv_data->priv);258258+259259+ return 0;260260+}261261+262262+263263+static const struct of_device_id of_nfcmrvl_i2c_match[] = {264264+ { .compatible = "mrvl,nfc-i2c", },265265+ {},266266+};267267+MODULE_DEVICE_TABLE(of, of_nfcmrvl_i2c_match);268268+269269+static struct i2c_device_id nfcmrvl_i2c_id_table[] = {270270+ { "nfcmrvl_i2c", 0 },271271+ {}272272+};273273+MODULE_DEVICE_TABLE(i2c, nfcmrvl_i2c_id_table);274274+275275+static struct i2c_driver nfcmrvl_i2c_driver = {276276+ .probe = nfcmrvl_i2c_probe,277277+ .id_table = nfcmrvl_i2c_id_table,278278+ .remove = nfcmrvl_i2c_remove,279279+ .driver = {280280+ .name = "nfcmrvl_i2c",281281+ .owner = THIS_MODULE,282282+ .of_match_table = of_match_ptr(of_nfcmrvl_i2c_match),283283+ },284284+};285285+286286+module_i2c_driver(nfcmrvl_i2c_driver);287287+288288+MODULE_AUTHOR("Marvell International Ltd.");289289+MODULE_DESCRIPTION("Marvell NFC-over-I2C driver");290290+MODULE_LICENSE("GPL v2");
+5-4
drivers/nfc/nfcmrvl/main.c
···3333 if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags))3434 return 0;35353636+ /* Reset possible fault of previous session */3737+ clear_bit(NFCMRVL_PHY_ERROR, &priv->flags);3838+3639 err = priv->if_ops->nci_open(priv);37403841 if (err)···229226230227void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)231228{232232- /*233233- * This function does not take care if someone is using the device.234234- * To be improved.235235- */229229+ /* Reset possible fault of previous session */230230+ clear_bit(NFCMRVL_PHY_ERROR, &priv->flags);236231237232 if (priv->config.reset_n_io) {238233 nfc_info(priv->dev, "reset the chip\n");
···3535 unsigned int flow_control;3636 /* Tell if firmware supports break control for power management */3737 unsigned int break_control;3838+3939+4040+ /*4141+ * I2C specific4242+ */4343+4444+ unsigned int irq;4545+ unsigned int irq_polarity;3846};39474048#endif /* _NFCMRVL_PTF_H_ */