diff mbox

[20/30] nfc: st-nci: Add ese-present/uicc-present dts properties

Message ID 1445377701-8353-21-git-send-email-christophe-h.ricard@st.com
State Superseded, archived
Headers show

Commit Message

Christophe Ricard Oct. 20, 2015, 9:48 p.m. UTC
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 pushed us to try to enable 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) if only
one secure element is connected.

Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com>
---
 .../devicetree/bindings/net/nfc/st-nci-i2c.txt     |  7 ++
 .../devicetree/bindings/net/nfc/st-nci-spi.txt     |  9 +-
 drivers/nfc/st-nci/core.c                          |  4 +-
 drivers/nfc/st-nci/i2c.c                           | 12 ++-
 drivers/nfc/st-nci/ndlc.c                          |  7 +-
 drivers/nfc/st-nci/ndlc.h                          |  5 +-
 drivers/nfc/st-nci/spi.c                           | 12 ++-
 drivers/nfc/st-nci/st-nci.h                        |  3 +-
 drivers/nfc/st-nci/st-nci_se.c                     | 98 ++++++++++++++--------
 drivers/nfc/st-nci/st-nci_se.h                     | 10 ++-
 include/linux/platform_data/st-nci.h               |  2 +
 11 files changed, 123 insertions(+), 46 deletions(-)

Comments

Rob Herring Oct. 22, 2015, 6:37 p.m. UTC | #1
On Tue, Oct 20, 2015 at 4:48 PM, Christophe Ricard
<christophe.ricard@gmail.com> wrote:
> 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 pushed us to try to enable 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) if only
> one secure element is connected.
>
> Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com>
> ---
>  .../devicetree/bindings/net/nfc/st-nci-i2c.txt     |  7 ++
>  .../devicetree/bindings/net/nfc/st-nci-spi.txt     |  9 +-

For the binding:

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/nfc/st-nci/core.c                          |  4 +-
>  drivers/nfc/st-nci/i2c.c                           | 12 ++-
>  drivers/nfc/st-nci/ndlc.c                          |  7 +-
>  drivers/nfc/st-nci/ndlc.h                          |  5 +-
>  drivers/nfc/st-nci/spi.c                           | 12 ++-
>  drivers/nfc/st-nci/st-nci.h                        |  3 +-
>  drivers/nfc/st-nci/st-nci_se.c                     | 98 ++++++++++++++--------
>  drivers/nfc/st-nci/st-nci_se.h                     | 10 ++-
>  include/linux/platform_data/st-nci.h               |  2 +
>  11 files changed, 123 insertions(+), 46 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt b/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt
> index d707588..263732e 100644
> --- a/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt
> +++ b/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt
> @@ -11,6 +11,10 @@ Required properties:
>  Optional SoC Specific Properties:
>  - pinctrl-names: Contains only one value - "default".
>  - pintctrl-0: Specifies the pin control groups used for this controller.
> +- ese-present: Specifies that an ese is physically connected to the nfc
> +controller.
> +- uicc-present: Specifies that the uicc swp signal can be physically
> +connected to the nfc controller.
>
>  Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
>
> @@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
>                 interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
>
>                 reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
> +
> +               ese-present;
> +               uicc-present;
>         };
>  };
> diff --git a/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt b/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt
> index 525681b..711ca85 100644
> --- a/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt
> +++ b/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt
> @@ -2,7 +2,7 @@
>
>  Required properties:
>  - compatible: Should be "st,st21nfcb-spi"
> -- spi-max-frequency: Maximum SPI frequency (<= 10000000).
> +- spi-max-frequency: Maximum SPI frequency (<= 4000000).
>  - interrupt-parent: phandle for the interrupt gpio controller
>  - interrupts: GPIO interrupt to which the chip is connected
>  - reset-gpios: Output GPIO pin used to reset the ST21NFCB
> @@ -10,6 +10,10 @@ Required properties:
>  Optional SoC Specific Properties:
>  - pinctrl-names: Contains only one value - "default".
>  - pintctrl-0: Specifies the pin control groups used for this controller.
> +- ese-present: Specifies that an ese is physically connected to the nfc
> +controller.
> +- uicc-present: Specifies that the uicc swp signal can be physically
> +connected to the nfc controller.
>
>  Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
>
> @@ -27,5 +31,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
>                 interrupts = <2 IRQ_TYPE_EDGE_RISING>;
>
>                 reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
> +
> +               ese-present;
> +               uicc-present;
>         };
>  };
> diff --git a/drivers/nfc/st-nci/core.c b/drivers/nfc/st-nci/core.c
> index fd2a5ca..e88c882 100644
> --- a/drivers/nfc/st-nci/core.c
> +++ b/drivers/nfc/st-nci/core.c
> @@ -125,7 +125,7 @@ static struct nci_ops st_nci_ops = {
>  };
>
>  int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
> -                      int phy_tailroom)
> +                int phy_tailroom, struct st_nci_se_status *se_status)
>  {
>         struct st_nci_info *info;
>         int r;
> @@ -166,7 +166,7 @@ int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
>                 goto err_reg_dev;
>         }
>
> -       return st_nci_se_init(ndlc->ndev);
> +       return st_nci_se_init(ndlc->ndev, se_status);
>
>  err_reg_dev:
>         nci_free_device(ndlc->ndev);
> diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c
> index 707ed2e..a2700a6 100644
> --- a/drivers/nfc/st-nci/i2c.c
> +++ b/drivers/nfc/st-nci/i2c.c
> @@ -52,6 +52,8 @@ struct st_nci_i2c_phy {
>
>         unsigned int gpio_reset;
>         unsigned int irq_polarity;
> +
> +       struct st_nci_se_status se_status;
>  };
>
>  #define I2C_DUMP_SKB(info, skb)                                        \
> @@ -245,6 +247,11 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client)
>
>         phy->irq_polarity = irq_get_trigger_type(client->irq);
>
> +       phy->se_status.is_ese_present =
> +                               of_property_read_bool(pp, "ese-present");
> +       phy->se_status.is_uicc_present =
> +                               of_property_read_bool(pp, "uicc-present");
> +
>         return 0;
>  }
>  #else
> @@ -277,6 +284,9 @@ static int st_nci_i2c_request_resources(struct i2c_client *client)
>                 return r;
>         }
>
> +       phy->se_status.is_ese_present = pdata->is_ese_present;
> +       phy->se_status.is_uicc_present = pdata->is_uicc_present;
> +
>         return 0;
>  }
>
> @@ -326,7 +336,7 @@ static int st_nci_i2c_probe(struct i2c_client *client,
>
>         r = ndlc_probe(phy, &i2c_phy_ops, &client->dev,
>                         ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
> -                       &phy->ndlc);
> +                       &phy->ndlc, &phy->se_status);
>         if (r < 0) {
>                 nfc_err(&client->dev, "Unable to register ndlc layer\n");
>                 return r;
> diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c
> index d2cf84e..0884b11 100644
> --- a/drivers/nfc/st-nci/ndlc.c
> +++ b/drivers/nfc/st-nci/ndlc.c
> @@ -19,8 +19,8 @@
>  #include <linux/sched.h>
>  #include <net/nfc/nci_core.h>
>
> -#include "ndlc.h"
>  #include "st-nci.h"
> +#include "ndlc.h"
>
>  #define NDLC_TIMER_T1          100
>  #define NDLC_TIMER_T1_WAIT     400
> @@ -266,7 +266,8 @@ static void ndlc_t2_timeout(unsigned long data)
>  }
>
>  int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
> -              int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id)
> +              int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
> +              struct st_nci_se_status *se_status)
>  {
>         struct llt_ndlc *ndlc;
>
> @@ -296,7 +297,7 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
>
>         INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
>
> -       return st_nci_probe(ndlc, phy_headroom, phy_tailroom);
> +       return st_nci_probe(ndlc, phy_headroom, phy_tailroom, se_status);
>  }
>  EXPORT_SYMBOL(ndlc_probe);
>
> diff --git a/drivers/nfc/st-nci/ndlc.h b/drivers/nfc/st-nci/ndlc.h
> index 6361005..d3b6db7 100644
> --- a/drivers/nfc/st-nci/ndlc.h
> +++ b/drivers/nfc/st-nci/ndlc.h
> @@ -22,6 +22,8 @@
>  #include <linux/skbuff.h>
>  #include <net/nfc/nfc.h>
>
> +#include "st-nci_se.h"
> +
>  /* Low Level Transport description */
>  struct llt_ndlc {
>         struct nci_dev *ndev;
> @@ -55,6 +57,7 @@ void ndlc_close(struct llt_ndlc *ndlc);
>  int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb);
>  void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb);
>  int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
> -       int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id);
> +              int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
> +              struct st_nci_se_status *se_status);
>  void ndlc_remove(struct llt_ndlc *ndlc);
>  #endif /* __LOCAL_NDLC_H__ */
> diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c
> index 887d308..c37ecd4 100644
> --- a/drivers/nfc/st-nci/spi.c
> +++ b/drivers/nfc/st-nci/spi.c
> @@ -53,6 +53,8 @@ struct st_nci_spi_phy {
>
>         unsigned int gpio_reset;
>         unsigned int irq_polarity;
> +
> +       struct st_nci_se_status se_status;
>  };
>
>  #define SPI_DUMP_SKB(info, skb)                                        \
> @@ -260,6 +262,11 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev)
>
>         phy->irq_polarity = irq_get_trigger_type(dev->irq);
>
> +       phy->se_status.is_ese_present =
> +                               of_property_read_bool(pp, "ese-present");
> +       phy->se_status.is_uicc_present =
> +                               of_property_read_bool(pp, "uicc-present");
> +
>         return 0;
>  }
>  #else
> @@ -292,6 +299,9 @@ static int st_nci_spi_request_resources(struct spi_device *dev)
>                 return r;
>         }
>
> +       phy->se_status.is_ese_present = pdata->is_ese_present;
> +       phy->se_status.is_uicc_present = pdata->is_uicc_present;
> +
>         return 0;
>  }
>
> @@ -342,7 +352,7 @@ static int st_nci_spi_probe(struct spi_device *dev)
>
>         r = ndlc_probe(phy, &spi_phy_ops, &dev->dev,
>                         ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
> -                       &phy->ndlc);
> +                       &phy->ndlc, &phy->se_status);
>         if (r < 0) {
>                 nfc_err(&dev->dev, "Unable to register ndlc layer\n");
>                 return r;
> diff --git a/drivers/nfc/st-nci/st-nci.h b/drivers/nfc/st-nci/st-nci.h
> index 858e8e6..b0174a9 100644
> --- a/drivers/nfc/st-nci/st-nci.h
> +++ b/drivers/nfc/st-nci/st-nci.h
> @@ -43,12 +43,13 @@ struct nci_mode_set_rsp {
>  struct st_nci_info {
>         struct llt_ndlc *ndlc;
>         unsigned long flags;
> +
>         struct st_nci_se_info se_info;
>         struct st_nci_vendor_info vendor_info;
>  };
>
>  void st_nci_remove(struct nci_dev *ndev);
>  int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
> -               int phy_tailroom);
> +                int phy_tailroom, struct st_nci_se_status *se_status);
>
>  #endif /* __LOCAL_ST_NCI_H_ */
> diff --git a/drivers/nfc/st-nci/st-nci_se.c b/drivers/nfc/st-nci/st-nci_se.c
> index 45eda3e..28f3c41 100644
> --- a/drivers/nfc/st-nci/st-nci_se.c
> +++ b/drivers/nfc/st-nci/st-nci_se.c
> @@ -415,12 +415,8 @@ void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
>  }
>  EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
>
> -/*
> - * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0)
> - * is rejected
> - */
>  static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
> -                                  u8 state)
> +                            u8 state)
>  {
>         struct st_nci_info *info = nci_get_drvdata(ndev);
>         int r;
> @@ -445,7 +441,7 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
>          * retrieve a relevant host list.
>          */
>         reinit_completion(&info->se_info.req_completion);
> -       r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE);
> +       r = nci_nfcee_mode_set(ndev, se_idx, state);
>         if (r != NCI_STATUS_OK)
>                 return r;
>
> @@ -461,7 +457,9 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
>          * There is no possible synchronization to prevent this.
>          * Adding a small delay is the only way to solve the issue.
>          */
> -       usleep_range(3000, 5000);
> +       if (info->se_info.se_status->is_ese_present &&
> +           info->se_info.se_status->is_uicc_present)
> +               usleep_range(3000, 5000);
>
>         r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
>                         NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list);
> @@ -484,11 +482,20 @@ int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
>
>         pr_debug("st_nci_disable_se\n");
>
> -       if (se_idx == NFC_SE_EMBEDDED) {
> -               r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
> -                               ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
> -               if (r < 0)
> -                       return r;
> +       /*
> +        * According to upper layer, se_idx == NFC_SE_UICC when
> +        * info->se_info.se_status->is_uicc_enable is true should never happen
> +        * Same for eSE.
> +        */
> +       r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_OFF);
> +       if (r < 0) {
> +               /* Do best effort to release SWP */
> +               if (se_idx == NFC_SE_EMBEDDED) {
> +                       r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
> +                                       ST_NCI_EVT_SE_END_OF_APDU_TRANSFER,
> +                                       NULL, 0);
> +               }
> +               return r;
>         }
>
>         return 0;
> @@ -501,11 +508,25 @@ int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
>
>         pr_debug("st_nci_enable_se\n");
>
> -       if (se_idx == ST_NCI_HCI_HOST_ID_ESE) {
> +       /*
> +        * According to upper layer, se_idx == NFC_SE_UICC when
> +        * info->se_info.se_status->is_uicc_enable is true should never happen.
> +        * Same for eSE.
> +        */
> +       r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON);
> +       if (r == ST_NCI_HCI_HOST_ID_ESE) {
> +               st_nci_se_get_atr(ndev);
>                 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
>                                 ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
> -               if (r < 0)
> -                       return r;
> +       }
> +
> +       if (r < 0) {
> +               /*
> +                * The activation procedure failed, the secure element
> +                * is not connected. Remove from the list.
> +                */
> +               nfc_remove_se(ndev->nfc_dev, se_idx);
> +               return r;
>         }
>
>         return 0;
> @@ -588,8 +609,8 @@ exit:
>
>  int st_nci_discover_se(struct nci_dev *ndev)
>  {
> -       u8 param[2];
> -       int r;
> +       u8 white_list[2];
> +       int r, wl_size = 0;
>         int se_count = 0;
>         struct st_nci_info *info = nci_get_drvdata(ndev);
>
> @@ -602,29 +623,34 @@ int st_nci_discover_se(struct nci_dev *ndev)
>         if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
>                 return 0;
>
> -       param[0] = ST_NCI_UICC_HOST_ID;
> -       param[1] = ST_NCI_HCI_HOST_ID_ESE;
> -       r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
> -                               NCI_HCI_ADMIN_PARAM_WHITELIST,
> -                               param, sizeof(param));
> -       if (r != NCI_HCI_ANY_OK)
> -               return r;
> +       if (info->se_info.se_status->is_ese_present &&
> +           info->se_info.se_status->is_uicc_present) {
> +               white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
> +               white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
> +       } else if (!info->se_info.se_status->is_ese_present &&
> +                  info->se_info.se_status->is_uicc_present) {
> +               white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
> +       } else if (info->se_info.se_status->is_ese_present &&
> +                  !info->se_info.se_status->is_uicc_present) {
> +               white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
> +       }
> +
> +       if (wl_size) {
> +               r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
> +                                     NCI_HCI_ADMIN_PARAM_WHITELIST,
> +                                     white_list, wl_size);
> +               if (r != NCI_HCI_ANY_OK)
> +                       return r;
> +       }
>
> -       r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID,
> -                               ST_NCI_SE_MODE_ON);
> -       if (r == ST_NCI_UICC_HOST_ID) {
> +       if (info->se_info.se_status->is_uicc_present) {
>                 nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
>                 se_count++;
>         }
>
> -       /* Try to enable eSE in order to check availability */
> -       r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE,
> -                               ST_NCI_SE_MODE_ON);
> -       if (r == ST_NCI_HCI_HOST_ID_ESE) {
> -               nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE,
> -                          NFC_SE_EMBEDDED);
> +       if (info->se_info.se_status->is_ese_present) {
> +               nfc_add_se(ndev->nfc_dev, ST_NCI_ESE_HOST_ID, NFC_SE_EMBEDDED);
>                 se_count++;
> -               st_nci_se_get_atr(ndev);
>         }
>
>         return !se_count;
> @@ -697,7 +723,7 @@ static void st_nci_se_activation_timeout(unsigned long data)
>         complete(&info->se_info.req_completion);
>  }
>
> -int st_nci_se_init(struct nci_dev *ndev)
> +int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status)
>  {
>         struct st_nci_info *info = nci_get_drvdata(ndev);
>
> @@ -719,6 +745,8 @@ int st_nci_se_init(struct nci_dev *ndev)
>         info->se_info.wt_timeout =
>                 ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
>
> +       info->se_info.se_status = se_status;
> +
>         return 0;
>  }
>  EXPORT_SYMBOL(st_nci_se_init);
> diff --git a/drivers/nfc/st-nci/st-nci_se.h b/drivers/nfc/st-nci/st-nci_se.h
> index ea66e87..e3f8e7e 100644
> --- a/drivers/nfc/st-nci/st-nci_se.h
> +++ b/drivers/nfc/st-nci/st-nci_se.h
> @@ -18,6 +18,8 @@
>  #ifndef __LOCAL_ST_NCI_SE_H_
>  #define __LOCAL_ST_NCI_SE_H_
>
> +#include <net/nfc/nci_core.h>
> +
>  /*
>   * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
>   * sequence of at most 32 characters.
> @@ -25,7 +27,13 @@
>  #define ST_NCI_ESE_MAX_LENGTH  33
>  #define ST_NCI_HCI_HOST_ID_ESE 0xc0
>
> +struct st_nci_se_status {
> +       bool is_ese_present;
> +       bool is_uicc_present;
> +};
> +
>  struct st_nci_se_info {
> +       struct st_nci_se_status *se_status;
>         u8 atr[ST_NCI_ESE_MAX_LENGTH];
>         struct completion req_completion;
>
> @@ -42,7 +50,7 @@ struct st_nci_se_info {
>         void *cb_context;
>  };
>
> -int st_nci_se_init(struct nci_dev *ndev);
> +int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status);
>  void st_nci_se_deinit(struct nci_dev *ndev);
>
>  int st_nci_discover_se(struct nci_dev *ndev);
> diff --git a/include/linux/platform_data/st-nci.h b/include/linux/platform_data/st-nci.h
> index d9d400a..f6494b3 100644
> --- a/include/linux/platform_data/st-nci.h
> +++ b/include/linux/platform_data/st-nci.h
> @@ -24,6 +24,8 @@
>  struct st_nci_nfc_platform_data {
>         unsigned int gpio_reset;
>         unsigned int irq_polarity;
> +       bool is_ese_present;
> +       bool is_uicc_present;
>  };
>
>  #endif /* _ST_NCI_H_ */
> --
> 2.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Samuel Ortiz Oct. 24, 2015, 6:48 a.m. UTC | #2
Hi Christophe,

On Tue, Oct 20, 2015 at 11:48:11PM +0200, Christophe Ricard wrote:
> diff --git a/drivers/nfc/st-nci/st-nci_se.h b/drivers/nfc/st-nci/st-nci_se.h
> index ea66e87..e3f8e7e 100644
> --- a/drivers/nfc/st-nci/st-nci_se.h
> +++ b/drivers/nfc/st-nci/st-nci_se.h
> @@ -18,6 +18,8 @@
>  #ifndef __LOCAL_ST_NCI_SE_H_
>  #define __LOCAL_ST_NCI_SE_H_
>  
> +#include <net/nfc/nci_core.h>
> +
Why is that needed ?

Cheers,
Samuel.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt b/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt
index d707588..263732e 100644
--- a/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt
+++ b/Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt
@@ -11,6 +11,10 @@  Required properties:
 Optional SoC Specific Properties:
 - pinctrl-names: Contains only one value - "default".
 - pintctrl-0: Specifies the pin control groups used for this controller.
+- ese-present: Specifies that an ese is physically connected to the nfc
+controller.
+- uicc-present: Specifies that the uicc swp signal can be physically
+connected to the nfc controller.
 
 Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
 
@@ -29,5 +33,8 @@  Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
 		interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
 
 		reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
+
+		ese-present;
+		uicc-present;
 	};
 };
diff --git a/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt b/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt
index 525681b..711ca85 100644
--- a/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt
+++ b/Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt
@@ -2,7 +2,7 @@ 
 
 Required properties:
 - compatible: Should be "st,st21nfcb-spi"
-- spi-max-frequency: Maximum SPI frequency (<= 10000000).
+- spi-max-frequency: Maximum SPI frequency (<= 4000000).
 - interrupt-parent: phandle for the interrupt gpio controller
 - interrupts: GPIO interrupt to which the chip is connected
 - reset-gpios: Output GPIO pin used to reset the ST21NFCB
@@ -10,6 +10,10 @@  Required properties:
 Optional SoC Specific Properties:
 - pinctrl-names: Contains only one value - "default".
 - pintctrl-0: Specifies the pin control groups used for this controller.
+- ese-present: Specifies that an ese is physically connected to the nfc
+controller.
+- uicc-present: Specifies that the uicc swp signal can be physically
+connected to the nfc controller.
 
 Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
 
@@ -27,5 +31,8 @@  Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
 		interrupts = <2 IRQ_TYPE_EDGE_RISING>;
 
 		reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
+
+		ese-present;
+		uicc-present;
 	};
 };
diff --git a/drivers/nfc/st-nci/core.c b/drivers/nfc/st-nci/core.c
index fd2a5ca..e88c882 100644
--- a/drivers/nfc/st-nci/core.c
+++ b/drivers/nfc/st-nci/core.c
@@ -125,7 +125,7 @@  static struct nci_ops st_nci_ops = {
 };
 
 int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
-		       int phy_tailroom)
+		 int phy_tailroom, struct st_nci_se_status *se_status)
 {
 	struct st_nci_info *info;
 	int r;
@@ -166,7 +166,7 @@  int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
 		goto err_reg_dev;
 	}
 
-	return st_nci_se_init(ndlc->ndev);
+	return st_nci_se_init(ndlc->ndev, se_status);
 
 err_reg_dev:
 	nci_free_device(ndlc->ndev);
diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c
index 707ed2e..a2700a6 100644
--- a/drivers/nfc/st-nci/i2c.c
+++ b/drivers/nfc/st-nci/i2c.c
@@ -52,6 +52,8 @@  struct st_nci_i2c_phy {
 
 	unsigned int gpio_reset;
 	unsigned int irq_polarity;
+
+	struct st_nci_se_status se_status;
 };
 
 #define I2C_DUMP_SKB(info, skb)					\
@@ -245,6 +247,11 @@  static int st_nci_i2c_of_request_resources(struct i2c_client *client)
 
 	phy->irq_polarity = irq_get_trigger_type(client->irq);
 
+	phy->se_status.is_ese_present =
+				of_property_read_bool(pp, "ese-present");
+	phy->se_status.is_uicc_present =
+				of_property_read_bool(pp, "uicc-present");
+
 	return 0;
 }
 #else
@@ -277,6 +284,9 @@  static int st_nci_i2c_request_resources(struct i2c_client *client)
 		return r;
 	}
 
+	phy->se_status.is_ese_present = pdata->is_ese_present;
+	phy->se_status.is_uicc_present = pdata->is_uicc_present;
+
 	return 0;
 }
 
@@ -326,7 +336,7 @@  static int st_nci_i2c_probe(struct i2c_client *client,
 
 	r = ndlc_probe(phy, &i2c_phy_ops, &client->dev,
 			ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
-			&phy->ndlc);
+			&phy->ndlc, &phy->se_status);
 	if (r < 0) {
 		nfc_err(&client->dev, "Unable to register ndlc layer\n");
 		return r;
diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c
index d2cf84e..0884b11 100644
--- a/drivers/nfc/st-nci/ndlc.c
+++ b/drivers/nfc/st-nci/ndlc.c
@@ -19,8 +19,8 @@ 
 #include <linux/sched.h>
 #include <net/nfc/nci_core.h>
 
-#include "ndlc.h"
 #include "st-nci.h"
+#include "ndlc.h"
 
 #define NDLC_TIMER_T1		100
 #define NDLC_TIMER_T1_WAIT	400
@@ -266,7 +266,8 @@  static void ndlc_t2_timeout(unsigned long data)
 }
 
 int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
-	       int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id)
+	       int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
+	       struct st_nci_se_status *se_status)
 {
 	struct llt_ndlc *ndlc;
 
@@ -296,7 +297,7 @@  int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
 
 	INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
 
-	return st_nci_probe(ndlc, phy_headroom, phy_tailroom);
+	return st_nci_probe(ndlc, phy_headroom, phy_tailroom, se_status);
 }
 EXPORT_SYMBOL(ndlc_probe);
 
diff --git a/drivers/nfc/st-nci/ndlc.h b/drivers/nfc/st-nci/ndlc.h
index 6361005..d3b6db7 100644
--- a/drivers/nfc/st-nci/ndlc.h
+++ b/drivers/nfc/st-nci/ndlc.h
@@ -22,6 +22,8 @@ 
 #include <linux/skbuff.h>
 #include <net/nfc/nfc.h>
 
+#include "st-nci_se.h"
+
 /* Low Level Transport description */
 struct llt_ndlc {
 	struct nci_dev *ndev;
@@ -55,6 +57,7 @@  void ndlc_close(struct llt_ndlc *ndlc);
 int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb);
 void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb);
 int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
-	int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id);
+	       int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
+	       struct st_nci_se_status *se_status);
 void ndlc_remove(struct llt_ndlc *ndlc);
 #endif /* __LOCAL_NDLC_H__ */
diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c
index 887d308..c37ecd4 100644
--- a/drivers/nfc/st-nci/spi.c
+++ b/drivers/nfc/st-nci/spi.c
@@ -53,6 +53,8 @@  struct st_nci_spi_phy {
 
 	unsigned int gpio_reset;
 	unsigned int irq_polarity;
+
+	struct st_nci_se_status se_status;
 };
 
 #define SPI_DUMP_SKB(info, skb)					\
@@ -260,6 +262,11 @@  static int st_nci_spi_of_request_resources(struct spi_device *dev)
 
 	phy->irq_polarity = irq_get_trigger_type(dev->irq);
 
+	phy->se_status.is_ese_present =
+				of_property_read_bool(pp, "ese-present");
+	phy->se_status.is_uicc_present =
+				of_property_read_bool(pp, "uicc-present");
+
 	return 0;
 }
 #else
@@ -292,6 +299,9 @@  static int st_nci_spi_request_resources(struct spi_device *dev)
 		return r;
 	}
 
+	phy->se_status.is_ese_present = pdata->is_ese_present;
+	phy->se_status.is_uicc_present = pdata->is_uicc_present;
+
 	return 0;
 }
 
@@ -342,7 +352,7 @@  static int st_nci_spi_probe(struct spi_device *dev)
 
 	r = ndlc_probe(phy, &spi_phy_ops, &dev->dev,
 			ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
-			&phy->ndlc);
+			&phy->ndlc, &phy->se_status);
 	if (r < 0) {
 		nfc_err(&dev->dev, "Unable to register ndlc layer\n");
 		return r;
diff --git a/drivers/nfc/st-nci/st-nci.h b/drivers/nfc/st-nci/st-nci.h
index 858e8e6..b0174a9 100644
--- a/drivers/nfc/st-nci/st-nci.h
+++ b/drivers/nfc/st-nci/st-nci.h
@@ -43,12 +43,13 @@  struct nci_mode_set_rsp {
 struct st_nci_info {
 	struct llt_ndlc *ndlc;
 	unsigned long flags;
+
 	struct st_nci_se_info se_info;
 	struct st_nci_vendor_info vendor_info;
 };
 
 void st_nci_remove(struct nci_dev *ndev);
 int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
-		int phy_tailroom);
+		 int phy_tailroom, struct st_nci_se_status *se_status);
 
 #endif /* __LOCAL_ST_NCI_H_ */
diff --git a/drivers/nfc/st-nci/st-nci_se.c b/drivers/nfc/st-nci/st-nci_se.c
index 45eda3e..28f3c41 100644
--- a/drivers/nfc/st-nci/st-nci_se.c
+++ b/drivers/nfc/st-nci/st-nci_se.c
@@ -415,12 +415,8 @@  void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
 }
 EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
 
-/*
- * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0)
- * is rejected
- */
 static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
-				   u8 state)
+			     u8 state)
 {
 	struct st_nci_info *info = nci_get_drvdata(ndev);
 	int r;
@@ -445,7 +441,7 @@  static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
 	 * retrieve a relevant host list.
 	 */
 	reinit_completion(&info->se_info.req_completion);
-	r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE);
+	r = nci_nfcee_mode_set(ndev, se_idx, state);
 	if (r != NCI_STATUS_OK)
 		return r;
 
@@ -461,7 +457,9 @@  static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
 	 * There is no possible synchronization to prevent this.
 	 * Adding a small delay is the only way to solve the issue.
 	 */
-	usleep_range(3000, 5000);
+	if (info->se_info.se_status->is_ese_present &&
+	    info->se_info.se_status->is_uicc_present)
+		usleep_range(3000, 5000);
 
 	r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
 			NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list);
@@ -484,11 +482,20 @@  int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
 
 	pr_debug("st_nci_disable_se\n");
 
-	if (se_idx == NFC_SE_EMBEDDED) {
-		r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
-				ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
-		if (r < 0)
-			return r;
+	/*
+	 * According to upper layer, se_idx == NFC_SE_UICC when
+	 * info->se_info.se_status->is_uicc_enable is true should never happen
+	 * Same for eSE.
+	 */
+	r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_OFF);
+	if (r < 0) {
+		/* Do best effort to release SWP */
+		if (se_idx == NFC_SE_EMBEDDED) {
+			r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
+					ST_NCI_EVT_SE_END_OF_APDU_TRANSFER,
+					NULL, 0);
+		}
+		return r;
 	}
 
 	return 0;
@@ -501,11 +508,25 @@  int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
 
 	pr_debug("st_nci_enable_se\n");
 
-	if (se_idx == ST_NCI_HCI_HOST_ID_ESE) {
+	/*
+	 * According to upper layer, se_idx == NFC_SE_UICC when
+	 * info->se_info.se_status->is_uicc_enable is true should never happen.
+	 * Same for eSE.
+	 */
+	r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON);
+	if (r == ST_NCI_HCI_HOST_ID_ESE) {
+		st_nci_se_get_atr(ndev);
 		r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
 				ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
-		if (r < 0)
-			return r;
+	}
+
+	if (r < 0) {
+		/*
+		 * The activation procedure failed, the secure element
+		 * is not connected. Remove from the list.
+		 */
+		nfc_remove_se(ndev->nfc_dev, se_idx);
+		return r;
 	}
 
 	return 0;
@@ -588,8 +609,8 @@  exit:
 
 int st_nci_discover_se(struct nci_dev *ndev)
 {
-	u8 param[2];
-	int r;
+	u8 white_list[2];
+	int r, wl_size = 0;
 	int se_count = 0;
 	struct st_nci_info *info = nci_get_drvdata(ndev);
 
@@ -602,29 +623,34 @@  int st_nci_discover_se(struct nci_dev *ndev)
 	if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
 		return 0;
 
-	param[0] = ST_NCI_UICC_HOST_ID;
-	param[1] = ST_NCI_HCI_HOST_ID_ESE;
-	r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
-				NCI_HCI_ADMIN_PARAM_WHITELIST,
-				param, sizeof(param));
-	if (r != NCI_HCI_ANY_OK)
-		return r;
+	if (info->se_info.se_status->is_ese_present &&
+	    info->se_info.se_status->is_uicc_present) {
+		white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
+		white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
+	} else if (!info->se_info.se_status->is_ese_present &&
+		   info->se_info.se_status->is_uicc_present) {
+		white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
+	} else if (info->se_info.se_status->is_ese_present &&
+		   !info->se_info.se_status->is_uicc_present) {
+		white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
+	}
+
+	if (wl_size) {
+		r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
+				      NCI_HCI_ADMIN_PARAM_WHITELIST,
+				      white_list, wl_size);
+		if (r != NCI_HCI_ANY_OK)
+			return r;
+	}
 
-	r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID,
-				ST_NCI_SE_MODE_ON);
-	if (r == ST_NCI_UICC_HOST_ID) {
+	if (info->se_info.se_status->is_uicc_present) {
 		nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
 		se_count++;
 	}
 
-	/* Try to enable eSE in order to check availability */
-	r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE,
-				ST_NCI_SE_MODE_ON);
-	if (r == ST_NCI_HCI_HOST_ID_ESE) {
-		nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE,
-			   NFC_SE_EMBEDDED);
+	if (info->se_info.se_status->is_ese_present) {
+		nfc_add_se(ndev->nfc_dev, ST_NCI_ESE_HOST_ID, NFC_SE_EMBEDDED);
 		se_count++;
-		st_nci_se_get_atr(ndev);
 	}
 
 	return !se_count;
@@ -697,7 +723,7 @@  static void st_nci_se_activation_timeout(unsigned long data)
 	complete(&info->se_info.req_completion);
 }
 
-int st_nci_se_init(struct nci_dev *ndev)
+int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status)
 {
 	struct st_nci_info *info = nci_get_drvdata(ndev);
 
@@ -719,6 +745,8 @@  int st_nci_se_init(struct nci_dev *ndev)
 	info->se_info.wt_timeout =
 		ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
 
+	info->se_info.se_status = se_status;
+
 	return 0;
 }
 EXPORT_SYMBOL(st_nci_se_init);
diff --git a/drivers/nfc/st-nci/st-nci_se.h b/drivers/nfc/st-nci/st-nci_se.h
index ea66e87..e3f8e7e 100644
--- a/drivers/nfc/st-nci/st-nci_se.h
+++ b/drivers/nfc/st-nci/st-nci_se.h
@@ -18,6 +18,8 @@ 
 #ifndef __LOCAL_ST_NCI_SE_H_
 #define __LOCAL_ST_NCI_SE_H_
 
+#include <net/nfc/nci_core.h>
+
 /*
  * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
  * sequence of at most 32 characters.
@@ -25,7 +27,13 @@ 
 #define ST_NCI_ESE_MAX_LENGTH	33
 #define ST_NCI_HCI_HOST_ID_ESE	0xc0
 
+struct st_nci_se_status {
+	bool is_ese_present;
+	bool is_uicc_present;
+};
+
 struct st_nci_se_info {
+	struct st_nci_se_status *se_status;
 	u8 atr[ST_NCI_ESE_MAX_LENGTH];
 	struct completion req_completion;
 
@@ -42,7 +50,7 @@  struct st_nci_se_info {
 	void *cb_context;
 };
 
-int st_nci_se_init(struct nci_dev *ndev);
+int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status);
 void st_nci_se_deinit(struct nci_dev *ndev);
 
 int st_nci_discover_se(struct nci_dev *ndev);
diff --git a/include/linux/platform_data/st-nci.h b/include/linux/platform_data/st-nci.h
index d9d400a..f6494b3 100644
--- a/include/linux/platform_data/st-nci.h
+++ b/include/linux/platform_data/st-nci.h
@@ -24,6 +24,8 @@ 
 struct st_nci_nfc_platform_data {
 	unsigned int gpio_reset;
 	unsigned int irq_polarity;
+	bool is_ese_present;
+	bool is_uicc_present;
 };
 
 #endif /* _ST_NCI_H_ */