Commit | Line | Data |
---|---|---|
6be88670 CP |
1 | /* |
2 | * I2C link layer for the NXP NCI driver | |
3 | * | |
4 | * Copyright (C) 2014 NXP Semiconductors All rights reserved. | |
551e3069 | 5 | * Copyright (C) 2012-2015 Intel Corporation. All rights reserved. |
6be88670 CP |
6 | * |
7 | * Authors: Clément Perrochaud <clement.perrochaud@nxp.com> | |
551e3069 | 8 | * Authors: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com> |
6be88670 CP |
9 | * |
10 | * Derived from PN544 device driver: | |
11 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or modify it | |
14 | * under the terms and conditions of the GNU General Public License, | |
15 | * version 2, as published by the Free Software Foundation. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License | |
23 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
24 | */ | |
25 | ||
26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
27 | ||
551e3069 | 28 | #include <linux/acpi.h> |
6be88670 CP |
29 | #include <linux/delay.h> |
30 | #include <linux/i2c.h> | |
31 | #include <linux/interrupt.h> | |
32 | #include <linux/miscdevice.h> | |
33 | #include <linux/module.h> | |
34 | #include <linux/nfc.h> | |
262e7198 | 35 | #include <linux/gpio/consumer.h> |
6be88670 CP |
36 | #include <linux/of_gpio.h> |
37 | #include <linux/of_irq.h> | |
38 | #include <linux/platform_data/nxp-nci.h> | |
39 | #include <linux/unaligned/access_ok.h> | |
40 | ||
41 | #include <net/nfc/nfc.h> | |
42 | ||
43 | #include "nxp-nci.h" | |
44 | ||
45 | #define NXP_NCI_I2C_DRIVER_NAME "nxp-nci_i2c" | |
46 | ||
47 | #define NXP_NCI_I2C_MAX_PAYLOAD 32 | |
48 | ||
49 | struct nxp_nci_i2c_phy { | |
50 | struct i2c_client *i2c_dev; | |
51 | struct nci_dev *ndev; | |
52 | ||
53 | unsigned int gpio_en; | |
54 | unsigned int gpio_fw; | |
55 | ||
56 | int hard_fault; /* | |
57 | * < 0 if hardware error occurred (e.g. i2c err) | |
58 | * and prevents normal operation. | |
59 | */ | |
60 | }; | |
61 | ||
62 | static int nxp_nci_i2c_set_mode(void *phy_id, | |
63 | enum nxp_nci_mode mode) | |
64 | { | |
65 | struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id; | |
66 | ||
67 | gpio_set_value(phy->gpio_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0); | |
68 | gpio_set_value(phy->gpio_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0); | |
69 | usleep_range(10000, 15000); | |
70 | ||
71 | if (mode == NXP_NCI_MODE_COLD) | |
72 | phy->hard_fault = 0; | |
73 | ||
74 | return 0; | |
75 | } | |
76 | ||
77 | static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb) | |
78 | { | |
79 | int r; | |
80 | struct nxp_nci_i2c_phy *phy = phy_id; | |
81 | struct i2c_client *client = phy->i2c_dev; | |
82 | ||
83 | if (phy->hard_fault != 0) | |
84 | return phy->hard_fault; | |
85 | ||
86 | r = i2c_master_send(client, skb->data, skb->len); | |
59df9bb2 | 87 | if (r < 0) { |
6be88670 CP |
88 | /* Retry, chip was in standby */ |
89 | usleep_range(110000, 120000); | |
90 | r = i2c_master_send(client, skb->data, skb->len); | |
91 | } | |
92 | ||
93 | if (r < 0) { | |
94 | nfc_err(&client->dev, "Error %d on I2C send\n", r); | |
95 | } else if (r != skb->len) { | |
96 | nfc_err(&client->dev, | |
97 | "Invalid length sent: %u (expected %u)\n", | |
98 | r, skb->len); | |
99 | r = -EREMOTEIO; | |
100 | } else { | |
101 | /* Success but return 0 and not number of bytes */ | |
102 | r = 0; | |
103 | } | |
104 | ||
105 | return r; | |
106 | } | |
107 | ||
7cf6d08c | 108 | static const struct nxp_nci_phy_ops i2c_phy_ops = { |
6be88670 CP |
109 | .set_mode = nxp_nci_i2c_set_mode, |
110 | .write = nxp_nci_i2c_write, | |
111 | }; | |
112 | ||
113 | static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy, | |
114 | struct sk_buff **skb) | |
115 | { | |
116 | struct i2c_client *client = phy->i2c_dev; | |
117 | u16 header; | |
118 | size_t frame_len; | |
119 | int r; | |
120 | ||
121 | r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN); | |
122 | if (r < 0) { | |
123 | goto fw_read_exit; | |
124 | } else if (r != NXP_NCI_FW_HDR_LEN) { | |
125 | nfc_err(&client->dev, "Incorrect header length: %u\n", r); | |
126 | r = -EBADMSG; | |
127 | goto fw_read_exit; | |
128 | } | |
129 | ||
130 | frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) + | |
131 | NXP_NCI_FW_CRC_LEN; | |
132 | ||
133 | *skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL); | |
134 | if (*skb == NULL) { | |
135 | r = -ENOMEM; | |
136 | goto fw_read_exit; | |
137 | } | |
138 | ||
139 | memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN); | |
140 | ||
141 | r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len); | |
142 | if (r != frame_len) { | |
143 | nfc_err(&client->dev, | |
144 | "Invalid frame length: %u (expected %zu)\n", | |
145 | r, frame_len); | |
146 | r = -EBADMSG; | |
147 | goto fw_read_exit_free_skb; | |
148 | } | |
149 | ||
150 | return 0; | |
151 | ||
152 | fw_read_exit_free_skb: | |
153 | kfree_skb(*skb); | |
154 | fw_read_exit: | |
155 | return r; | |
156 | } | |
157 | ||
158 | static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy, | |
159 | struct sk_buff **skb) | |
160 | { | |
161 | struct nci_ctrl_hdr header; /* May actually be a data header */ | |
162 | struct i2c_client *client = phy->i2c_dev; | |
163 | int r; | |
164 | ||
165 | r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE); | |
166 | if (r < 0) { | |
167 | goto nci_read_exit; | |
168 | } else if (r != NCI_CTRL_HDR_SIZE) { | |
169 | nfc_err(&client->dev, "Incorrect header length: %u\n", r); | |
170 | r = -EBADMSG; | |
171 | goto nci_read_exit; | |
172 | } | |
173 | ||
174 | *skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL); | |
175 | if (*skb == NULL) { | |
176 | r = -ENOMEM; | |
177 | goto nci_read_exit; | |
178 | } | |
179 | ||
180 | memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header, | |
181 | NCI_CTRL_HDR_SIZE); | |
182 | ||
183 | r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen); | |
184 | if (r != header.plen) { | |
185 | nfc_err(&client->dev, | |
186 | "Invalid frame payload length: %u (expected %u)\n", | |
187 | r, header.plen); | |
188 | r = -EBADMSG; | |
189 | goto nci_read_exit_free_skb; | |
190 | } | |
191 | ||
192 | return 0; | |
193 | ||
194 | nci_read_exit_free_skb: | |
195 | kfree_skb(*skb); | |
196 | nci_read_exit: | |
197 | return r; | |
198 | } | |
199 | ||
200 | static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id) | |
201 | { | |
202 | struct nxp_nci_i2c_phy *phy = phy_id; | |
203 | struct i2c_client *client; | |
204 | struct nxp_nci_info *info; | |
205 | ||
206 | struct sk_buff *skb = NULL; | |
207 | int r = 0; | |
208 | ||
209 | if (!phy || !phy->ndev) | |
210 | goto exit_irq_none; | |
211 | ||
212 | client = phy->i2c_dev; | |
213 | ||
214 | if (!client || irq != client->irq) | |
215 | goto exit_irq_none; | |
216 | ||
217 | info = nci_get_drvdata(phy->ndev); | |
218 | ||
219 | if (!info) | |
220 | goto exit_irq_none; | |
221 | ||
222 | mutex_lock(&info->info_lock); | |
223 | ||
224 | if (phy->hard_fault != 0) | |
225 | goto exit_irq_handled; | |
226 | ||
227 | switch (info->mode) { | |
228 | case NXP_NCI_MODE_NCI: | |
229 | r = nxp_nci_i2c_nci_read(phy, &skb); | |
230 | break; | |
231 | case NXP_NCI_MODE_FW: | |
232 | r = nxp_nci_i2c_fw_read(phy, &skb); | |
233 | break; | |
234 | case NXP_NCI_MODE_COLD: | |
235 | r = -EREMOTEIO; | |
236 | break; | |
237 | } | |
238 | ||
239 | if (r == -EREMOTEIO) { | |
240 | phy->hard_fault = r; | |
241 | skb = NULL; | |
242 | } else if (r < 0) { | |
243 | nfc_err(&client->dev, "Read failed with error %d\n", r); | |
244 | goto exit_irq_handled; | |
245 | } | |
246 | ||
247 | switch (info->mode) { | |
248 | case NXP_NCI_MODE_NCI: | |
249 | nci_recv_frame(phy->ndev, skb); | |
250 | break; | |
251 | case NXP_NCI_MODE_FW: | |
252 | nxp_nci_fw_recv_frame(phy->ndev, skb); | |
253 | break; | |
254 | case NXP_NCI_MODE_COLD: | |
255 | break; | |
256 | } | |
257 | ||
258 | exit_irq_handled: | |
259 | mutex_unlock(&info->info_lock); | |
260 | return IRQ_HANDLED; | |
261 | exit_irq_none: | |
262 | WARN_ON_ONCE(1); | |
263 | return IRQ_NONE; | |
264 | } | |
265 | ||
6be88670 CP |
266 | static int nxp_nci_i2c_parse_devtree(struct i2c_client *client) |
267 | { | |
268 | struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); | |
269 | struct device_node *pp; | |
270 | int r; | |
271 | ||
272 | pp = client->dev.of_node; | |
273 | if (!pp) | |
274 | return -ENODEV; | |
275 | ||
276 | r = of_get_named_gpio(pp, "enable-gpios", 0); | |
277 | if (r == -EPROBE_DEFER) | |
278 | r = of_get_named_gpio(pp, "enable-gpios", 0); | |
279 | if (r < 0) { | |
280 | nfc_err(&client->dev, "Failed to get EN gpio, error: %d\n", r); | |
281 | return r; | |
282 | } | |
283 | phy->gpio_en = r; | |
284 | ||
285 | r = of_get_named_gpio(pp, "firmware-gpios", 0); | |
286 | if (r == -EPROBE_DEFER) | |
287 | r = of_get_named_gpio(pp, "firmware-gpios", 0); | |
288 | if (r < 0) { | |
289 | nfc_err(&client->dev, "Failed to get FW gpio, error: %d\n", r); | |
290 | return r; | |
291 | } | |
292 | phy->gpio_fw = r; | |
293 | ||
6be88670 CP |
294 | return 0; |
295 | } | |
296 | ||
551e3069 OZ |
297 | static int nxp_nci_i2c_acpi_config(struct nxp_nci_i2c_phy *phy) |
298 | { | |
299 | struct i2c_client *client = phy->i2c_dev; | |
be103b71 | 300 | struct gpio_desc *gpiod_en, *gpiod_fw; |
551e3069 | 301 | |
3bfe7680 UKK |
302 | gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2, GPIOD_OUT_LOW); |
303 | gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1, GPIOD_OUT_LOW); | |
551e3069 | 304 | |
be103b71 | 305 | if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw)) { |
551e3069 OZ |
306 | nfc_err(&client->dev, "No GPIOs\n"); |
307 | return -EINVAL; | |
308 | } | |
309 | ||
551e3069 OZ |
310 | phy->gpio_en = desc_to_gpio(gpiod_en); |
311 | phy->gpio_fw = desc_to_gpio(gpiod_fw); | |
551e3069 OZ |
312 | |
313 | return 0; | |
314 | } | |
315 | ||
6be88670 CP |
316 | static int nxp_nci_i2c_probe(struct i2c_client *client, |
317 | const struct i2c_device_id *id) | |
318 | { | |
319 | struct nxp_nci_i2c_phy *phy; | |
320 | struct nxp_nci_nfc_platform_data *pdata; | |
321 | int r; | |
322 | ||
323 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | |
324 | nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); | |
325 | r = -ENODEV; | |
326 | goto probe_exit; | |
327 | } | |
328 | ||
329 | phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy), | |
330 | GFP_KERNEL); | |
331 | if (!phy) { | |
332 | r = -ENOMEM; | |
333 | goto probe_exit; | |
334 | } | |
335 | ||
336 | phy->i2c_dev = client; | |
337 | i2c_set_clientdata(client, phy); | |
338 | ||
339 | pdata = client->dev.platform_data; | |
340 | ||
341 | if (!pdata && client->dev.of_node) { | |
342 | r = nxp_nci_i2c_parse_devtree(client); | |
343 | if (r < 0) { | |
344 | nfc_err(&client->dev, "Failed to get DT data\n"); | |
345 | goto probe_exit; | |
346 | } | |
347 | } else if (pdata) { | |
348 | phy->gpio_en = pdata->gpio_en; | |
349 | phy->gpio_fw = pdata->gpio_fw; | |
551e3069 OZ |
350 | } else if (ACPI_HANDLE(&client->dev)) { |
351 | r = nxp_nci_i2c_acpi_config(phy); | |
352 | if (r < 0) | |
353 | goto probe_exit; | |
354 | goto nci_probe; | |
6be88670 CP |
355 | } else { |
356 | nfc_err(&client->dev, "No platform data\n"); | |
357 | r = -EINVAL; | |
358 | goto probe_exit; | |
359 | } | |
360 | ||
361 | r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en, | |
362 | GPIOF_OUT_INIT_LOW, "nxp_nci_en"); | |
363 | if (r < 0) | |
364 | goto probe_exit; | |
365 | ||
366 | r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw, | |
367 | GPIOF_OUT_INIT_LOW, "nxp_nci_fw"); | |
368 | if (r < 0) | |
369 | goto probe_exit; | |
370 | ||
551e3069 | 371 | nci_probe: |
6be88670 CP |
372 | r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops, |
373 | NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev); | |
374 | if (r < 0) | |
375 | goto probe_exit; | |
376 | ||
377 | r = request_threaded_irq(client->irq, NULL, | |
378 | nxp_nci_i2c_irq_thread_fn, | |
379 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | |
380 | NXP_NCI_I2C_DRIVER_NAME, phy); | |
381 | if (r < 0) | |
382 | nfc_err(&client->dev, "Unable to register IRQ handler\n"); | |
383 | ||
384 | probe_exit: | |
385 | return r; | |
386 | } | |
387 | ||
388 | static int nxp_nci_i2c_remove(struct i2c_client *client) | |
389 | { | |
390 | struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); | |
391 | ||
392 | nxp_nci_remove(phy->ndev); | |
393 | free_irq(client->irq, phy); | |
394 | ||
395 | return 0; | |
396 | } | |
397 | ||
398 | static struct i2c_device_id nxp_nci_i2c_id_table[] = { | |
399 | {"nxp-nci_i2c", 0}, | |
400 | {} | |
401 | }; | |
402 | MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table); | |
403 | ||
404 | static const struct of_device_id of_nxp_nci_i2c_match[] = { | |
405 | { .compatible = "nxp,nxp-nci-i2c", }, | |
406 | {}, | |
407 | }; | |
408 | MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match); | |
409 | ||
551e3069 OZ |
410 | #ifdef CONFIG_ACPI |
411 | static struct acpi_device_id acpi_id[] = { | |
412 | { "NXP7471" }, | |
413 | { }, | |
414 | }; | |
415 | MODULE_DEVICE_TABLE(acpi, acpi_id); | |
416 | #endif | |
417 | ||
6be88670 CP |
418 | static struct i2c_driver nxp_nci_i2c_driver = { |
419 | .driver = { | |
420 | .name = NXP_NCI_I2C_DRIVER_NAME, | |
551e3069 | 421 | .acpi_match_table = ACPI_PTR(acpi_id), |
6be88670 CP |
422 | .of_match_table = of_match_ptr(of_nxp_nci_i2c_match), |
423 | }, | |
424 | .probe = nxp_nci_i2c_probe, | |
425 | .id_table = nxp_nci_i2c_id_table, | |
426 | .remove = nxp_nci_i2c_remove, | |
427 | }; | |
428 | ||
429 | module_i2c_driver(nxp_nci_i2c_driver); | |
430 | ||
431 | MODULE_LICENSE("GPL"); | |
432 | MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers"); | |
433 | MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>"); | |
551e3069 | 434 | MODULE_AUTHOR("Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>"); |