Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFC: nfcmrvl: add i2c driver

This driver adds the support of I2C-based Marvell NFC controller.

Signed-off-by: Vincent Cuissard <cuissard@marvell.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Vincent Cuissard and committed by
Samuel Ortiz
b5b3e23e 58d34aa6

+353 -5
+33 -1
Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt
··· 1 1 * Marvell International Ltd. NCI NFC Controller 2 2 3 3 Required properties: 4 - - compatible: Should be "mrvl,nfc-uart". 4 + - compatible: Should be: 5 + - "mrvl,nfc-uart" for UART devices 6 + - "mrvl,nfc-i2c" for I2C devices 5 7 6 8 Optional SoC specific properties: 7 9 - pinctrl-names: Contains only one value - "default". ··· 14 12 Optional UART-based chip specific properties: 15 13 - flow-control: Specifies that the chip is using RTS/CTS. 16 14 - break-control: Specifies that the chip needs specific break management. 15 + 16 + Optional I2C-based chip specific properties: 17 + - i2c-int-falling: Specifies that the chip read event shall be trigged on 18 + falling edge. 19 + - i2c-int-rising: Specifies that the chip read event shall be trigged on 20 + rising edge. 17 21 18 22 Example (for ARM-based BeagleBoard Black with 88W8887 on UART5): 19 23 ··· 34 26 hci-muxed; 35 27 flow-control; 36 28 } 29 + }; 30 + 31 + 32 + Example (for ARM-based BeagleBoard Black with 88W8887 on I2C1): 33 + 34 + &i2c1 { 35 + status = "okay"; 36 + clock-frequency = <400000>; 37 + 38 + nfcmrvli2c0: i2c@1 { 39 + compatible = "mrvl,nfc-i2c"; 40 + 41 + reg = <0x8>; 42 + 43 + /* I2C INT configuration */ 44 + interrupt-parent = <&gpio3>; 45 + interrupts = <21 0>; 46 + 47 + /* I2C INT trigger configuration */ 48 + i2c-int-rising; 49 + 50 + /* Reset IO */ 51 + reset-n-io = <&gpio3 19 0>; 52 + }; 37 53 };
+12
drivers/nfc/nfcmrvl/Kconfig
··· 30 30 31 31 Say Y here to compile support for Marvell NFC-over-UART driver 32 32 into the kernel or say M to compile it as module. 33 + 34 + config NFC_MRVL_I2C 35 + tristate "Marvell NFC-over-I2C driver" 36 + depends on NFC_MRVL && I2C 37 + help 38 + Marvell NFC-over-I2C driver. 39 + 40 + This driver provides support for Marvell NFC-over-I2C devices. 41 + 42 + Say Y here to compile support for Marvell NFC-over-I2C driver 43 + into the kernel or say M to compile it as module. 44 +
+3
drivers/nfc/nfcmrvl/Makefile
··· 10 10 11 11 nfcmrvl_uart-y += uart.o 12 12 obj-$(CONFIG_NFC_MRVL_UART) += nfcmrvl_uart.o 13 + 14 + nfcmrvl_i2c-y += i2c.o 15 + obj-$(CONFIG_NFC_MRVL_I2C) += nfcmrvl_i2c.o
+290
drivers/nfc/nfcmrvl/i2c.c
··· 1 + /** 2 + * Marvell NFC-over-I2C driver: I2C 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/i2c.h> 22 + #include <linux/pm_runtime.h> 23 + #include <linux/nfc.h> 24 + #include <linux/gpio.h> 25 + #include <linux/delay.h> 26 + #include <linux/of_irq.h> 27 + #include <linux/of_gpio.h> 28 + #include <net/nfc/nci.h> 29 + #include <net/nfc/nci_core.h> 30 + #include "nfcmrvl.h" 31 + 32 + struct nfcmrvl_i2c_drv_data { 33 + unsigned long flags; 34 + struct device *dev; 35 + struct i2c_client *i2c; 36 + struct nfcmrvl_private *priv; 37 + }; 38 + 39 + static int nfcmrvl_i2c_read(struct nfcmrvl_i2c_drv_data *drv_data, 40 + struct sk_buff **skb) 41 + { 42 + int ret; 43 + struct nci_ctrl_hdr nci_hdr; 44 + 45 + /* Read NCI header to know the payload size */ 46 + ret = i2c_master_recv(drv_data->i2c, (u8 *)&nci_hdr, NCI_CTRL_HDR_SIZE); 47 + if (ret != NCI_CTRL_HDR_SIZE) { 48 + nfc_err(&drv_data->i2c->dev, "cannot read NCI header\n"); 49 + return -EBADMSG; 50 + } 51 + 52 + if (nci_hdr.plen > NCI_MAX_PAYLOAD_SIZE) { 53 + nfc_err(&drv_data->i2c->dev, "invalid packet payload size\n"); 54 + return -EBADMSG; 55 + } 56 + 57 + *skb = nci_skb_alloc(drv_data->priv->ndev, 58 + nci_hdr.plen + NCI_CTRL_HDR_SIZE, GFP_KERNEL); 59 + if (!*skb) 60 + return -ENOMEM; 61 + 62 + /* Copy NCI header into the SKB */ 63 + memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), &nci_hdr, NCI_CTRL_HDR_SIZE); 64 + 65 + if (nci_hdr.plen) { 66 + /* Read the NCI payload */ 67 + ret = i2c_master_recv(drv_data->i2c, 68 + skb_put(*skb, nci_hdr.plen), 69 + nci_hdr.plen); 70 + 71 + if (ret != nci_hdr.plen) { 72 + nfc_err(&drv_data->i2c->dev, 73 + "Invalid frame payload length: %u (expected %u)\n", 74 + ret, nci_hdr.plen); 75 + kfree_skb(*skb); 76 + return -EBADMSG; 77 + } 78 + } 79 + 80 + return 0; 81 + } 82 + 83 + static irqreturn_t nfcmrvl_i2c_int_irq_thread_fn(int irq, void *drv_data_ptr) 84 + { 85 + struct nfcmrvl_i2c_drv_data *drv_data = drv_data_ptr; 86 + struct sk_buff *skb = NULL; 87 + int ret; 88 + 89 + if (!drv_data->priv) 90 + return IRQ_HANDLED; 91 + 92 + if (test_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags)) 93 + return IRQ_HANDLED; 94 + 95 + ret = nfcmrvl_i2c_read(drv_data, &skb); 96 + 97 + switch (ret) { 98 + case -EREMOTEIO: 99 + set_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags); 100 + break; 101 + case -ENOMEM: 102 + case -EBADMSG: 103 + nfc_err(&drv_data->i2c->dev, "read failed %d\n", ret); 104 + break; 105 + default: 106 + if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0) 107 + nfc_err(&drv_data->i2c->dev, "corrupted RX packet\n"); 108 + break; 109 + } 110 + return IRQ_HANDLED; 111 + } 112 + 113 + static int nfcmrvl_i2c_nci_open(struct nfcmrvl_private *priv) 114 + { 115 + struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data; 116 + 117 + if (!drv_data) 118 + return -ENODEV; 119 + 120 + return 0; 121 + } 122 + 123 + static int nfcmrvl_i2c_nci_close(struct nfcmrvl_private *priv) 124 + { 125 + return 0; 126 + } 127 + 128 + static int nfcmrvl_i2c_nci_send(struct nfcmrvl_private *priv, 129 + struct sk_buff *skb) 130 + { 131 + struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data; 132 + int ret; 133 + 134 + if (test_bit(NFCMRVL_PHY_ERROR, &priv->flags)) 135 + return -EREMOTEIO; 136 + 137 + ret = i2c_master_send(drv_data->i2c, skb->data, skb->len); 138 + 139 + /* Retry if chip was in standby */ 140 + if (ret == -EREMOTEIO) { 141 + nfc_info(drv_data->dev, "chip may sleep, retry\n"); 142 + usleep_range(6000, 10000); 143 + ret = i2c_master_send(drv_data->i2c, skb->data, skb->len); 144 + } 145 + 146 + if (ret >= 0) { 147 + if (ret != skb->len) { 148 + nfc_err(drv_data->dev, 149 + "Invalid length sent: %u (expected %u)\n", 150 + ret, skb->len); 151 + ret = -EREMOTEIO; 152 + } else 153 + ret = 0; 154 + kfree_skb(skb); 155 + } 156 + 157 + return ret; 158 + } 159 + 160 + static void nfcmrvl_i2c_nci_update_config(struct nfcmrvl_private *priv, 161 + const void *param) 162 + { 163 + } 164 + 165 + static struct nfcmrvl_if_ops i2c_ops = { 166 + .nci_open = nfcmrvl_i2c_nci_open, 167 + .nci_close = nfcmrvl_i2c_nci_close, 168 + .nci_send = nfcmrvl_i2c_nci_send, 169 + .nci_update_config = nfcmrvl_i2c_nci_update_config, 170 + }; 171 + 172 + static int nfcmrvl_i2c_parse_dt(struct device_node *node, 173 + struct nfcmrvl_platform_data *pdata) 174 + { 175 + int ret; 176 + 177 + ret = nfcmrvl_parse_dt(node, pdata); 178 + if (ret < 0) { 179 + pr_err("Failed to get generic entries\n"); 180 + return ret; 181 + } 182 + 183 + if (of_find_property(node, "i2c-int-falling", NULL)) 184 + pdata->irq_polarity = IRQF_TRIGGER_FALLING; 185 + else 186 + pdata->irq_polarity = IRQF_TRIGGER_RISING; 187 + 188 + ret = irq_of_parse_and_map(node, 0); 189 + if (ret < 0) { 190 + pr_err("Unable to get irq, error: %d\n", ret); 191 + return ret; 192 + } 193 + pdata->irq = ret; 194 + 195 + return 0; 196 + } 197 + 198 + static int nfcmrvl_i2c_probe(struct i2c_client *client, 199 + const struct i2c_device_id *id) 200 + { 201 + struct nfcmrvl_i2c_drv_data *drv_data; 202 + struct nfcmrvl_platform_data *pdata; 203 + struct nfcmrvl_platform_data config; 204 + int ret; 205 + 206 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 207 + nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); 208 + return -ENODEV; 209 + } 210 + 211 + drv_data = devm_kzalloc(&client->dev, sizeof(*drv_data), GFP_KERNEL); 212 + if (!drv_data) 213 + return -ENOMEM; 214 + 215 + drv_data->i2c = client; 216 + drv_data->dev = &client->dev; 217 + drv_data->priv = NULL; 218 + 219 + i2c_set_clientdata(client, drv_data); 220 + 221 + pdata = client->dev.platform_data; 222 + 223 + if (!pdata && client->dev.of_node) 224 + if (nfcmrvl_i2c_parse_dt(client->dev.of_node, &config) == 0) 225 + pdata = &config; 226 + 227 + if (!pdata) 228 + return -EINVAL; 229 + 230 + /* Request the read IRQ */ 231 + ret = devm_request_threaded_irq(&drv_data->i2c->dev, pdata->irq, 232 + NULL, nfcmrvl_i2c_int_irq_thread_fn, 233 + pdata->irq_polarity | IRQF_ONESHOT, 234 + "nfcmrvl_i2c_int", drv_data); 235 + if (ret < 0) { 236 + nfc_err(&drv_data->i2c->dev, 237 + "Unable to register IRQ handler\n"); 238 + return ret; 239 + } 240 + 241 + drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_I2C, 242 + drv_data, &i2c_ops, 243 + &drv_data->i2c->dev, pdata); 244 + 245 + if (IS_ERR(drv_data->priv)) 246 + return PTR_ERR(drv_data->priv); 247 + 248 + drv_data->priv->support_fw_dnld = true; 249 + 250 + return 0; 251 + } 252 + 253 + static int nfcmrvl_i2c_remove(struct i2c_client *client) 254 + { 255 + struct nfcmrvl_i2c_drv_data *drv_data = i2c_get_clientdata(client); 256 + 257 + nfcmrvl_nci_unregister_dev(drv_data->priv); 258 + 259 + return 0; 260 + } 261 + 262 + 263 + static const struct of_device_id of_nfcmrvl_i2c_match[] = { 264 + { .compatible = "mrvl,nfc-i2c", }, 265 + {}, 266 + }; 267 + MODULE_DEVICE_TABLE(of, of_nfcmrvl_i2c_match); 268 + 269 + static struct i2c_device_id nfcmrvl_i2c_id_table[] = { 270 + { "nfcmrvl_i2c", 0 }, 271 + {} 272 + }; 273 + MODULE_DEVICE_TABLE(i2c, nfcmrvl_i2c_id_table); 274 + 275 + static struct i2c_driver nfcmrvl_i2c_driver = { 276 + .probe = nfcmrvl_i2c_probe, 277 + .id_table = nfcmrvl_i2c_id_table, 278 + .remove = nfcmrvl_i2c_remove, 279 + .driver = { 280 + .name = "nfcmrvl_i2c", 281 + .owner = THIS_MODULE, 282 + .of_match_table = of_match_ptr(of_nfcmrvl_i2c_match), 283 + }, 284 + }; 285 + 286 + module_i2c_driver(nfcmrvl_i2c_driver); 287 + 288 + MODULE_AUTHOR("Marvell International Ltd."); 289 + MODULE_DESCRIPTION("Marvell NFC-over-I2C driver"); 290 + MODULE_LICENSE("GPL v2");
+5 -4
drivers/nfc/nfcmrvl/main.c
··· 33 33 if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags)) 34 34 return 0; 35 35 36 + /* Reset possible fault of previous session */ 37 + clear_bit(NFCMRVL_PHY_ERROR, &priv->flags); 38 + 36 39 err = priv->if_ops->nci_open(priv); 37 40 38 41 if (err) ··· 229 226 230 227 void nfcmrvl_chip_reset(struct nfcmrvl_private *priv) 231 228 { 232 - /* 233 - * This function does not take care if someone is using the device. 234 - * To be improved. 235 - */ 229 + /* Reset possible fault of previous session */ 230 + clear_bit(NFCMRVL_PHY_ERROR, &priv->flags); 236 231 237 232 if (priv->config.reset_n_io) { 238 233 nfc_info(priv->dev, "reset the chip\n");
+1
drivers/nfc/nfcmrvl/nfcmrvl.h
··· 25 25 26 26 /* Define private flags: */ 27 27 #define NFCMRVL_NCI_RUNNING 1 28 + #define NFCMRVL_PHY_ERROR 2 28 29 29 30 #define NFCMRVL_EXT_COEX_ID 0xE0 30 31 #define NFCMRVL_NOT_ALLOWED_ID 0xE1
+8
include/linux/platform_data/nfcmrvl.h
··· 35 35 unsigned int flow_control; 36 36 /* Tell if firmware supports break control for power management */ 37 37 unsigned int break_control; 38 + 39 + 40 + /* 41 + * I2C specific 42 + */ 43 + 44 + unsigned int irq; 45 + unsigned int irq_polarity; 38 46 }; 39 47 40 48 #endif /* _NFCMRVL_PTF_H_ */
+1
include/net/nfc/nci.h
··· 35 35 #define NCI_MAX_NUM_RF_CONFIGS 10 36 36 #define NCI_MAX_NUM_CONN 10 37 37 #define NCI_MAX_PARAM_LEN 251 38 + #define NCI_MAX_PAYLOAD_SIZE 255 38 39 #define NCI_MAX_PACKET_SIZE 258 39 40 40 41 /* NCI Status Codes */