aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2015-10-25 17:54:39 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2015-10-26 22:55:10 -0400
commit3648dc6d27f648b8e3ce9b48874627a833d53c3a (patch)
tree196aee67d701a3856d0ca3bfed0d43f1de20d0c6 /drivers/nfc
parentbe73c2cbc857a4a3424c0e3cdd70002d5a27a756 (diff)
NFC: st-nci: Add ese-present/uicc-present dts properties
In order to align with st21nfca, dts configuration properties ese_present and uicc_present are made available in st-nci driver. So far, in early development firmware, because nci_nfcee_mode_set(DISABLE) was not supported we had to try to enable it during the secure element discovery phase. After several trials on commercial and qualified firmware it appears that nci_nfcee_mode_set(ENABLE) and nci_nfcee_mode_set(DISABLE) are properly supported. Such feature also help us to eventually save some time (~5ms) when only one secure element is connected. Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/nfc')
-rw-r--r--drivers/nfc/st-nci/core.c4
-rw-r--r--drivers/nfc/st-nci/i2c.c12
-rw-r--r--drivers/nfc/st-nci/ndlc.c6
-rw-r--r--drivers/nfc/st-nci/ndlc.h5
-rw-r--r--drivers/nfc/st-nci/se.c98
-rw-r--r--drivers/nfc/st-nci/spi.c12
-rw-r--r--drivers/nfc/st-nci/st-nci.h13
7 files changed, 105 insertions, 45 deletions
diff --git a/drivers/nfc/st-nci/core.c b/drivers/nfc/st-nci/core.c
index 73d36dd8345c..c693128ee6fb 100644
--- a/drivers/nfc/st-nci/core.c
+++ b/drivers/nfc/st-nci/core.c
@@ -123,7 +123,7 @@ static struct nci_ops st_nci_ops = {
123}; 123};
124 124
125int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, 125int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
126 int phy_tailroom) 126 int phy_tailroom, struct st_nci_se_status *se_status)
127{ 127{
128 struct st_nci_info *info; 128 struct st_nci_info *info;
129 int r; 129 int r;
@@ -164,7 +164,7 @@ int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
164 goto err_reg_dev; 164 goto err_reg_dev;
165 } 165 }
166 166
167 return st_nci_se_init(ndlc->ndev); 167 return st_nci_se_init(ndlc->ndev, se_status);
168 168
169err_reg_dev: 169err_reg_dev:
170 nci_free_device(ndlc->ndev); 170 nci_free_device(ndlc->ndev);
diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c
index 02e585f2be74..172cbc34cc9f 100644
--- a/drivers/nfc/st-nci/i2c.c
+++ b/drivers/nfc/st-nci/i2c.c
@@ -52,6 +52,8 @@ struct st_nci_i2c_phy {
52 52
53 unsigned int gpio_reset; 53 unsigned int gpio_reset;
54 unsigned int irq_polarity; 54 unsigned int irq_polarity;
55
56 struct st_nci_se_status se_status;
55}; 57};
56 58
57#define I2C_DUMP_SKB(info, skb) \ 59#define I2C_DUMP_SKB(info, skb) \
@@ -245,6 +247,11 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client)
245 247
246 phy->irq_polarity = irq_get_trigger_type(client->irq); 248 phy->irq_polarity = irq_get_trigger_type(client->irq);
247 249
250 phy->se_status.is_ese_present =
251 of_property_read_bool(pp, "ese-present");
252 phy->se_status.is_uicc_present =
253 of_property_read_bool(pp, "uicc-present");
254
248 return 0; 255 return 0;
249} 256}
250#else 257#else
@@ -277,6 +284,9 @@ static int st_nci_i2c_request_resources(struct i2c_client *client)
277 return r; 284 return r;
278 } 285 }
279 286
287 phy->se_status.is_ese_present = pdata->is_ese_present;
288 phy->se_status.is_uicc_present = pdata->is_uicc_present;
289
280 return 0; 290 return 0;
281} 291}
282 292
@@ -326,7 +336,7 @@ static int st_nci_i2c_probe(struct i2c_client *client,
326 336
327 r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, 337 r = ndlc_probe(phy, &i2c_phy_ops, &client->dev,
328 ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, 338 ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
329 &phy->ndlc); 339 &phy->ndlc, &phy->se_status);
330 if (r < 0) { 340 if (r < 0) {
331 nfc_err(&client->dev, "Unable to register ndlc layer\n"); 341 nfc_err(&client->dev, "Unable to register ndlc layer\n");
332 return r; 342 return r;
diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c
index fb50007ac32a..0884b11001ef 100644
--- a/drivers/nfc/st-nci/ndlc.c
+++ b/drivers/nfc/st-nci/ndlc.c
@@ -20,6 +20,7 @@
20#include <net/nfc/nci_core.h> 20#include <net/nfc/nci_core.h>
21 21
22#include "st-nci.h" 22#include "st-nci.h"
23#include "ndlc.h"
23 24
24#define NDLC_TIMER_T1 100 25#define NDLC_TIMER_T1 100
25#define NDLC_TIMER_T1_WAIT 400 26#define NDLC_TIMER_T1_WAIT 400
@@ -265,7 +266,8 @@ static void ndlc_t2_timeout(unsigned long data)
265} 266}
266 267
267int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, 268int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
268 int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id) 269 int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
270 struct st_nci_se_status *se_status)
269{ 271{
270 struct llt_ndlc *ndlc; 272 struct llt_ndlc *ndlc;
271 273
@@ -295,7 +297,7 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
295 297
296 INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work); 298 INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
297 299
298 return st_nci_probe(ndlc, phy_headroom, phy_tailroom); 300 return st_nci_probe(ndlc, phy_headroom, phy_tailroom, se_status);
299} 301}
300EXPORT_SYMBOL(ndlc_probe); 302EXPORT_SYMBOL(ndlc_probe);
301 303
diff --git a/drivers/nfc/st-nci/ndlc.h b/drivers/nfc/st-nci/ndlc.h
index 6361005ef003..bdf78ffd5bb7 100644
--- a/drivers/nfc/st-nci/ndlc.h
+++ b/drivers/nfc/st-nci/ndlc.h
@@ -22,6 +22,8 @@
22#include <linux/skbuff.h> 22#include <linux/skbuff.h>
23#include <net/nfc/nfc.h> 23#include <net/nfc/nfc.h>
24 24
25struct st_nci_se_status;
26
25/* Low Level Transport description */ 27/* Low Level Transport description */
26struct llt_ndlc { 28struct llt_ndlc {
27 struct nci_dev *ndev; 29 struct nci_dev *ndev;
@@ -55,6 +57,7 @@ void ndlc_close(struct llt_ndlc *ndlc);
55int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb); 57int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb);
56void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb); 58void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb);
57int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, 59int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
58 int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id); 60 int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
61 struct st_nci_se_status *se_status);
59void ndlc_remove(struct llt_ndlc *ndlc); 62void ndlc_remove(struct llt_ndlc *ndlc);
60#endif /* __LOCAL_NDLC_H__ */ 63#endif /* __LOCAL_NDLC_H__ */
diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c
index 281288484794..147e2d904c63 100644
--- a/drivers/nfc/st-nci/se.c
+++ b/drivers/nfc/st-nci/se.c
@@ -419,12 +419,8 @@ void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
419} 419}
420EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received); 420EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
421 421
422/*
423 * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0)
424 * is rejected
425 */
426static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx, 422static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
427 u8 state) 423 u8 state)
428{ 424{
429 struct st_nci_info *info = nci_get_drvdata(ndev); 425 struct st_nci_info *info = nci_get_drvdata(ndev);
430 int r; 426 int r;
@@ -449,7 +445,7 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
449 * retrieve a relevant host list. 445 * retrieve a relevant host list.
450 */ 446 */
451 reinit_completion(&info->se_info.req_completion); 447 reinit_completion(&info->se_info.req_completion);
452 r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE); 448 r = nci_nfcee_mode_set(ndev, se_idx, state);
453 if (r != NCI_STATUS_OK) 449 if (r != NCI_STATUS_OK)
454 return r; 450 return r;
455 451
@@ -465,7 +461,9 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
465 * There is no possible synchronization to prevent this. 461 * There is no possible synchronization to prevent this.
466 * Adding a small delay is the only way to solve the issue. 462 * Adding a small delay is the only way to solve the issue.
467 */ 463 */
468 usleep_range(3000, 5000); 464 if (info->se_info.se_status->is_ese_present &&
465 info->se_info.se_status->is_uicc_present)
466 usleep_range(3000, 5000);
469 467
470 r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE, 468 r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
471 NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list); 469 NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list);
@@ -488,11 +486,20 @@ int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
488 486
489 pr_debug("st_nci_disable_se\n"); 487 pr_debug("st_nci_disable_se\n");
490 488
491 if (se_idx == NFC_SE_EMBEDDED) { 489 /*
492 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, 490 * According to upper layer, se_idx == NFC_SE_UICC when
493 ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); 491 * info->se_info.se_status->is_uicc_enable is true should never happen
494 if (r < 0) 492 * Same for eSE.
495 return r; 493 */
494 r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_OFF);
495 if (r < 0) {
496 /* Do best effort to release SWP */
497 if (se_idx == NFC_SE_EMBEDDED) {
498 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
499 ST_NCI_EVT_SE_END_OF_APDU_TRANSFER,
500 NULL, 0);
501 }
502 return r;
496 } 503 }
497 504
498 return 0; 505 return 0;
@@ -505,11 +512,25 @@ int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
505 512
506 pr_debug("st_nci_enable_se\n"); 513 pr_debug("st_nci_enable_se\n");
507 514
508 if (se_idx == ST_NCI_HCI_HOST_ID_ESE) { 515 /*
516 * According to upper layer, se_idx == NFC_SE_UICC when
517 * info->se_info.se_status->is_uicc_enable is true should never happen.
518 * Same for eSE.
519 */
520 r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON);
521 if (r == ST_NCI_HCI_HOST_ID_ESE) {
522 st_nci_se_get_atr(ndev);
509 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, 523 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
510 ST_NCI_EVT_SE_SOFT_RESET, NULL, 0); 524 ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
511 if (r < 0) 525 }
512 return r; 526
527 if (r < 0) {
528 /*
529 * The activation procedure failed, the secure element
530 * is not connected. Remove from the list.
531 */
532 nfc_remove_se(ndev->nfc_dev, se_idx);
533 return r;
513 } 534 }
514 535
515 return 0; 536 return 0;
@@ -592,8 +613,8 @@ exit:
592 613
593int st_nci_discover_se(struct nci_dev *ndev) 614int st_nci_discover_se(struct nci_dev *ndev)
594{ 615{
595 u8 param[2]; 616 u8 white_list[2];
596 int r; 617 int r, wl_size = 0;
597 int se_count = 0; 618 int se_count = 0;
598 struct st_nci_info *info = nci_get_drvdata(ndev); 619 struct st_nci_info *info = nci_get_drvdata(ndev);
599 620
@@ -606,29 +627,34 @@ int st_nci_discover_se(struct nci_dev *ndev)
606 if (test_bit(ST_NCI_FACTORY_MODE, &info->flags)) 627 if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
607 return 0; 628 return 0;
608 629
609 param[0] = ST_NCI_UICC_HOST_ID; 630 if (info->se_info.se_status->is_ese_present &&
610 param[1] = ST_NCI_HCI_HOST_ID_ESE; 631 info->se_info.se_status->is_uicc_present) {
611 r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, 632 white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
612 NCI_HCI_ADMIN_PARAM_WHITELIST, 633 white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
613 param, sizeof(param)); 634 } else if (!info->se_info.se_status->is_ese_present &&
614 if (r != NCI_HCI_ANY_OK) 635 info->se_info.se_status->is_uicc_present) {
615 return r; 636 white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
637 } else if (info->se_info.se_status->is_ese_present &&
638 !info->se_info.se_status->is_uicc_present) {
639 white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
640 }
641
642 if (wl_size) {
643 r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
644 NCI_HCI_ADMIN_PARAM_WHITELIST,
645 white_list, wl_size);
646 if (r != NCI_HCI_ANY_OK)
647 return r;
648 }
616 649
617 r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID, 650 if (info->se_info.se_status->is_uicc_present) {
618 ST_NCI_SE_MODE_ON);
619 if (r == ST_NCI_UICC_HOST_ID) {
620 nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC); 651 nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
621 se_count++; 652 se_count++;
622 } 653 }
623 654
624 /* Try to enable eSE in order to check availability */ 655 if (info->se_info.se_status->is_ese_present) {
625 r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE, 656 nfc_add_se(ndev->nfc_dev, ST_NCI_ESE_HOST_ID, NFC_SE_EMBEDDED);
626 ST_NCI_SE_MODE_ON);
627 if (r == ST_NCI_HCI_HOST_ID_ESE) {
628 nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE,
629 NFC_SE_EMBEDDED);
630 se_count++; 657 se_count++;
631 st_nci_se_get_atr(ndev);
632 } 658 }
633 659
634 return !se_count; 660 return !se_count;
@@ -701,7 +727,7 @@ static void st_nci_se_activation_timeout(unsigned long data)
701 complete(&info->se_info.req_completion); 727 complete(&info->se_info.req_completion);
702} 728}
703 729
704int st_nci_se_init(struct nci_dev *ndev) 730int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status)
705{ 731{
706 struct st_nci_info *info = nci_get_drvdata(ndev); 732 struct st_nci_info *info = nci_get_drvdata(ndev);
707 733
@@ -723,6 +749,8 @@ int st_nci_se_init(struct nci_dev *ndev)
723 info->se_info.wt_timeout = 749 info->se_info.wt_timeout =
724 ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI); 750 ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
725 751
752 info->se_info.se_status = se_status;
753
726 return 0; 754 return 0;
727} 755}
728EXPORT_SYMBOL(st_nci_se_init); 756EXPORT_SYMBOL(st_nci_se_init);
diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c
index b43f448b8d78..889720336474 100644
--- a/drivers/nfc/st-nci/spi.c
+++ b/drivers/nfc/st-nci/spi.c
@@ -53,6 +53,8 @@ struct st_nci_spi_phy {
53 53
54 unsigned int gpio_reset; 54 unsigned int gpio_reset;
55 unsigned int irq_polarity; 55 unsigned int irq_polarity;
56
57 struct st_nci_se_status se_status;
56}; 58};
57 59
58#define SPI_DUMP_SKB(info, skb) \ 60#define SPI_DUMP_SKB(info, skb) \
@@ -260,6 +262,11 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev)
260 262
261 phy->irq_polarity = irq_get_trigger_type(dev->irq); 263 phy->irq_polarity = irq_get_trigger_type(dev->irq);
262 264
265 phy->se_status.is_ese_present =
266 of_property_read_bool(pp, "ese-present");
267 phy->se_status.is_uicc_present =
268 of_property_read_bool(pp, "uicc-present");
269
263 return 0; 270 return 0;
264} 271}
265#else 272#else
@@ -292,6 +299,9 @@ static int st_nci_spi_request_resources(struct spi_device *dev)
292 return r; 299 return r;
293 } 300 }
294 301
302 phy->se_status.is_ese_present = pdata->is_ese_present;
303 phy->se_status.is_uicc_present = pdata->is_uicc_present;
304
295 return 0; 305 return 0;
296} 306}
297 307
@@ -342,7 +352,7 @@ static int st_nci_spi_probe(struct spi_device *dev)
342 352
343 r = ndlc_probe(phy, &spi_phy_ops, &dev->dev, 353 r = ndlc_probe(phy, &spi_phy_ops, &dev->dev,
344 ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, 354 ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
345 &phy->ndlc); 355 &phy->ndlc, &phy->se_status);
346 if (r < 0) { 356 if (r < 0) {
347 nfc_err(&dev->dev, "Unable to register ndlc layer\n"); 357 nfc_err(&dev->dev, "Unable to register ndlc layer\n");
348 return r; 358 return r;
diff --git a/drivers/nfc/st-nci/st-nci.h b/drivers/nfc/st-nci/st-nci.h
index 9c9bb19cc9ff..8b9f77b0249c 100644
--- a/drivers/nfc/st-nci/st-nci.h
+++ b/drivers/nfc/st-nci/st-nci.h
@@ -48,7 +48,13 @@ struct nci_mode_set_rsp {
48 u8 status; 48 u8 status;
49} __packed; 49} __packed;
50 50
51struct st_nci_se_status {
52 bool is_ese_present;
53 bool is_uicc_present;
54};
55
51struct st_nci_se_info { 56struct st_nci_se_info {
57 struct st_nci_se_status *se_status;
52 u8 atr[ST_NCI_ESE_MAX_LENGTH]; 58 u8 atr[ST_NCI_ESE_MAX_LENGTH];
53 struct completion req_completion; 59 struct completion req_completion;
54 60
@@ -126,15 +132,16 @@ struct st_nci_vendor_info {
126struct st_nci_info { 132struct st_nci_info {
127 struct llt_ndlc *ndlc; 133 struct llt_ndlc *ndlc;
128 unsigned long flags; 134 unsigned long flags;
135
129 struct st_nci_se_info se_info; 136 struct st_nci_se_info se_info;
130 struct st_nci_vendor_info vendor_info; 137 struct st_nci_vendor_info vendor_info;
131}; 138};
132 139
133void st_nci_remove(struct nci_dev *ndev); 140void st_nci_remove(struct nci_dev *ndev);
134int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, 141int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
135 int phy_tailroom); 142 int phy_tailroom, struct st_nci_se_status *se_status);
136 143
137int st_nci_se_init(struct nci_dev *ndev); 144int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status);
138void st_nci_se_deinit(struct nci_dev *ndev); 145void st_nci_se_deinit(struct nci_dev *ndev);
139 146
140int st_nci_discover_se(struct nci_dev *ndev); 147int st_nci_discover_se(struct nci_dev *ndev);
@@ -150,7 +157,7 @@ void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
150 struct sk_buff *skb); 157 struct sk_buff *skb);
151 158
152void st_nci_hci_loopback_event_received(struct nci_dev *ndev, u8 event, 159void st_nci_hci_loopback_event_received(struct nci_dev *ndev, u8 event,
153 struct sk_buff *skb); 160 struct sk_buff *skb);
154int st_nci_vendor_cmds_init(struct nci_dev *ndev); 161int st_nci_vendor_cmds_init(struct nci_dev *ndev);
155 162
156#endif /* __LOCAL_ST_NCI_H_ */ 163#endif /* __LOCAL_ST_NCI_H_ */