* [PATCH v1 00/10] st33zp24 new architecture proposal and st33zp24 spi driver
@ 2015-01-10 11:20 Christophe Ricard
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
0 siblings, 1 reply; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
Hi,
The following patchset:
- clean the current tpm_i2c_stm_st33 driver
- propose a new architecture allowing to share a core st33zp24 data management
layer with different phy (i2c & spi). For st33zp24 both phy have a proprietary transport
protocol. Both are relying on the TCG TIS protocol. At the end, it simplifies the maintenance.
- Add an spi phy allowing to support st33zp24 using with an SPI bus.
The complete solution got tested in polling and interrupt mode successfully with i2c & spi phy.
This patchset applies on top of Peter's tree https://github.com/PeterHuewe/linux-tpmdd.git for-james branch
on top of:
tpm: TPM 2.0 FIFO Interface 2c71d9fb22289a196a4b51d6158cf0d2f9abcfb9
I confirm also Jarkko Sakkinen's changes are working with this product with both phy's.
Best Regards
Christophe
Christophe Ricard (10):
tpm/tpm_i2c_stm_st33: Remove sparse spaces
tpm/tpm_i2c_stm_st33: Sanity cleanup
tpm/tpm_i2c_stm_st33: Replace remaining r by ret
tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct
st33zp24_platform_data to tpm_stm_dev
tpm/tpm_i2c_stm_st33: Change tpm_i2c_stm_st33.h to tpm_stm_st33.h
tpm/tpm_i2c_stm_st33: Add status check when reading data on the FIFO
tpm/tpm_i2c_stm_st33/dts/st33zp24-i2c: Rename st33zp24 dts
documentation
tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)
tpm/st33zp24/spi: Add st33zp24 spi phy
tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for st33zp24 spi
phy
.../bindings/security/tpm/st33zp24-i2c.txt | 36 +
.../bindings/security/tpm/st33zp24-spi.txt | 34 +
.../devicetree/bindings/security/tpm/st33zp24.txt | 36 -
drivers/char/tpm/Kconfig | 11 +-
drivers/char/tpm/Makefile | 2 +-
drivers/char/tpm/st33zp24/Kconfig | 30 +
drivers/char/tpm/st33zp24/Makefile | 12 +
drivers/char/tpm/st33zp24/i2c.c | 283 +++++++
drivers/char/tpm/st33zp24/spi.c | 399 +++++++++
drivers/char/tpm/st33zp24/st33zp24.c | 688 ++++++++++++++++
drivers/char/tpm/st33zp24/st33zp24.h | 32 +
drivers/char/tpm/tpm_i2c_stm_st33.c | 910 ---------------------
include/linux/platform_data/st33zp24.h | 28 +
include/linux/platform_data/tpm_i2c_stm_st33.h | 39 -
14 files changed, 1544 insertions(+), 996 deletions(-)
create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt
create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt
delete mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24.txt
create mode 100644 drivers/char/tpm/st33zp24/Kconfig
create mode 100644 drivers/char/tpm/st33zp24/Makefile
create mode 100644 drivers/char/tpm/st33zp24/i2c.c
create mode 100644 drivers/char/tpm/st33zp24/spi.c
create mode 100644 drivers/char/tpm/st33zp24/st33zp24.c
create mode 100644 drivers/char/tpm/st33zp24/st33zp24.h
delete mode 100644 drivers/char/tpm/tpm_i2c_stm_st33.c
create mode 100644 include/linux/platform_data/st33zp24.h
delete mode 100644 include/linux/platform_data/tpm_i2c_stm_st33.h
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v1 01/10] tpm/tpm_i2c_stm_st33: Remove sparse spaces
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 02/10] tpm/tpm_i2c_stm_st33: Sanity cleanup Christophe Ricard
` (9 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
Remove some useless spaces (new line or space)
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/tpm_i2c_stm_st33.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 48c4808..5deb9cc 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -238,7 +238,6 @@ static int check_locality(struct tpm_chip *chip)
return chip->vendor.locality;
return -EACCES;
-
} /* check_locality() */
/*
@@ -352,7 +351,7 @@ static u8 interrupt_to_status(u8 irq_mask)
{
u8 status = 0;
- if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT)
+ if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT)
status |= TPM_STS_VALID;
if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT)
status |= TPM_STS_DATA_AVAIL;
@@ -570,7 +569,7 @@ out_err:
* @param: buf, the buffer to store datas.
* @param: count, the number of bytes to send.
* @return: In case of success the number of bytes received.
- * In other case, a < 0 value describing the issue.
+ * In other case, a < 0 value describing the issue.
*/
static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
size_t count)
@@ -633,7 +632,6 @@ static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip)
struct device_node *pp;
struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
struct i2c_client *client = tpm_dev->client;
-
int gpio;
int ret;
@@ -846,7 +844,7 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev)
ret = tpm_pm_suspend(dev);
return ret;
-} /* tpm_stm_i2c_suspend() */
+} /* tpm_stm_i2c_suspend() */
/*
* tpm_stm_i2c_pm_resume resume the TPM device
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 02/10] tpm/tpm_i2c_stm_st33: Sanity cleanup
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-10 11:20 ` [PATCH v1 01/10] tpm/tpm_i2c_stm_st33: Remove sparse spaces Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 03/10] tpm/tpm_i2c_stm_st33: Replace remaining r by ret Christophe Ricard
` (8 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
Cleanup header description and correct some indent.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/tpm_i2c_stm_st33.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 5deb9cc..2d6e50e 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -811,8 +811,7 @@ _tpm_clean_answer:
/*
* tpm_stm_i2c_remove remove the TPM device
- * @param: client, the i2c_client drescription (TPM I2C description).
- * clear_bit(0, &chip->is_open);
+ * @param: client, the i2c_client description (TPM I2C description).
* @return: 0 in case of success.
*/
static int tpm_stm_i2c_remove(struct i2c_client *client)
@@ -887,7 +886,8 @@ MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match);
#endif
static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend,
- tpm_stm_i2c_pm_resume);
+ tpm_stm_i2c_pm_resume);
+
static struct i2c_driver tpm_stm_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 03/10] tpm/tpm_i2c_stm_st33: Replace remaining r by ret
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-10 11:20 ` [PATCH v1 01/10] tpm/tpm_i2c_stm_st33: Remove sparse spaces Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 02/10] tpm/tpm_i2c_stm_st33: Sanity cleanup Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 04/10] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard
` (7 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
Some places are still using r instead of ret.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/tpm_i2c_stm_st33.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 2d6e50e..d12d507 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -374,7 +374,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
wait_queue_head_t *queue, bool check_cancel)
{
unsigned long stop;
- int r;
+ int ret;
bool canceled = false;
bool condition;
u32 cur_intrs;
@@ -400,7 +400,7 @@ again:
if ((long) timeout <= 0)
return -1;
- r = wait_event_interruptible_timeout(*queue,
+ ret = wait_event_interruptible_timeout(*queue,
cur_intrs != tpm_dev->intrs, timeout);
interrupt |= clear_interruption(tpm_dev);
@@ -408,12 +408,12 @@ again:
condition = wait_for_tpm_stat_cond(chip, mask,
check_cancel, &canceled);
- if (r >= 0 && condition) {
+ if (ret >= 0 && condition) {
if (canceled)
return -ECANCELED;
return 0;
}
- if (r == -ERESTARTSYS && freezing(current)) {
+ if (ret == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
}
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 04/10] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (2 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 03/10] tpm/tpm_i2c_stm_st33: Replace remaining r by ret Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 05/10] tpm/tpm_i2c_stm_st33: Change tpm_i2c_stm_st33.h to tpm_stm_st33.h Christophe Ricard
` (6 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
io_lpcpd is accessible from struct tpm_stm_dev.
struct st33zp24_platform_data is only valid when using static platform
configuration data, not when using dts.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/tpm_i2c_stm_st33.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index d12d507..9d3c9c8 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -834,11 +834,14 @@ static int tpm_stm_i2c_remove(struct i2c_client *client)
*/
static int tpm_stm_i2c_pm_suspend(struct device *dev)
{
- struct st33zp24_platform_data *pin_infos = dev->platform_data;
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ struct tpm_stm_dev *tpm_dev;
int ret = 0;
- if (gpio_is_valid(pin_infos->io_lpcpd))
- gpio_set_value(pin_infos->io_lpcpd, 0);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+
+ if (gpio_is_valid(tpm_dev->io_lpcpd))
+ gpio_set_value(tpm_dev->io_lpcpd, 0);
else
ret = tpm_pm_suspend(dev);
@@ -853,12 +856,13 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev)
static int tpm_stm_i2c_pm_resume(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
- struct st33zp24_platform_data *pin_infos = dev->platform_data;
-
+ struct tpm_stm_dev *tpm_dev;
int ret = 0;
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+
if (gpio_is_valid(pin_infos->io_lpcpd)) {
- gpio_set_value(pin_infos->io_lpcpd, 1);
+ gpio_set_value(tpm_dev->io_lpcpd, 1);
ret = wait_for_stat(chip,
TPM_STS_VALID, chip->vendor.timeout_b,
&chip->vendor.read_queue, false);
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 05/10] tpm/tpm_i2c_stm_st33: Change tpm_i2c_stm_st33.h to tpm_stm_st33.h
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (3 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 04/10] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 06/10] tpm/tpm_i2c_stm_st33: Add status check when reading data on the FIFO Christophe Ricard
` (5 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
include/linux/platform_data/tpm_i2c_stm_st33.h can be used by other st33
tpm device driver not using i2c protocol.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/tpm_i2c_stm_st33.c | 2 +-
include/linux/platform_data/tpm_i2c_stm_st33.h | 39 --------------------------
include/linux/platform_data/tpm_stm_st33.h | 39 ++++++++++++++++++++++++++
3 files changed, 40 insertions(+), 40 deletions(-)
delete mode 100644 include/linux/platform_data/tpm_i2c_stm_st33.h
create mode 100644 include/linux/platform_data/tpm_stm_st33.h
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 9d3c9c8..3289f9d 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -50,7 +50,7 @@
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
-#include <linux/platform_data/tpm_i2c_stm_st33.h>
+#include <linux/platform_data/tpm_stm_st33.h>
#include "tpm.h"
#define TPM_ACCESS 0x0
diff --git a/include/linux/platform_data/tpm_i2c_stm_st33.h b/include/linux/platform_data/tpm_i2c_stm_st33.h
deleted file mode 100644
index 85775cf..0000000
--- a/include/linux/platform_data/tpm_i2c_stm_st33.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
- * Copyright (C) 2009, 2010 STMicroelectronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * STMicroelectronics version 1.2.0, Copyright (C) 2010
- * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
- * This is free software, and you are welcome to redistribute it
- * under certain conditions.
- *
- * @Author: Christophe RICARD tpmsupport-qxv4g6HH51o@public.gmane.org
- *
- * @File: stm_st33_tpm_i2c.h
- *
- * @Date: 09/15/2010
- */
-#ifndef __STM_ST33_TPM_I2C_MAIN_H__
-#define __STM_ST33_TPM_I2C_MAIN_H__
-
-
-#define TPM_ST33_I2C "st33zp24_i2c"
-
-struct st33zp24_platform_data {
- int io_lpcpd;
-};
-
-#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
diff --git a/include/linux/platform_data/tpm_stm_st33.h b/include/linux/platform_data/tpm_stm_st33.h
new file mode 100644
index 0000000..ff75310
--- /dev/null
+++ b/include/linux/platform_data/tpm_stm_st33.h
@@ -0,0 +1,39 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
+ * Copyright (C) 2009, 2010 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * STMicroelectronics version 1.2.0, Copyright (C) 2010
+ * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
+ * This is free software, and you are welcome to redistribute it
+ * under certain conditions.
+ *
+ * @Author: Christophe RICARD tpmsupport-qxv4g6HH51o@public.gmane.org
+ *
+ * @File: stm_st33_tpm.h
+ *
+ * @Date: 09/15/2010
+ */
+#ifndef __STM_ST33_TPM_H__
+#define __STM_ST33_TPM_H__
+
+#define TPM_ST33_I2C "st33zp24-i2c"
+#define TPM_ST33_SPI "st33zp24-spi"
+
+struct st33zp24_platform_data {
+ int io_lpcpd;
+};
+
+#endif /* __STM_ST33_TPM_H__ */
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 06/10] tpm/tpm_i2c_stm_st33: Add status check when reading data on the FIFO
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (4 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 05/10] tpm/tpm_i2c_stm_st33: Change tpm_i2c_stm_st33.h to tpm_stm_st33.h Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 07/10] tpm/tpm_i2c_stm_st33/dts/st33zp24-i2c: Rename st33zp24 dts documentation Christophe Ricard
` (4 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
Add a return value check when reading data from the FIFO register.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/tpm_i2c_stm_st33.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 3289f9d..eeb4816 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -440,7 +440,7 @@ again:
*/
static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
{
- int size = 0, burstcnt, len;
+ int size = 0, burstcnt, len, ret;
struct tpm_stm_dev *tpm_dev;
tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
@@ -454,7 +454,10 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
if (burstcnt < 0)
return burstcnt;
len = min_t(int, burstcnt, count - size);
- I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len);
+ ret = I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len);
+ if (ret < 0)
+ return ret;
+
size += len;
}
return size;
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 07/10] tpm/tpm_i2c_stm_st33/dts/st33zp24-i2c: Rename st33zp24 dts documentation
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (5 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 06/10] tpm/tpm_i2c_stm_st33: Add status check when reading data on the FIFO Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 08/10] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard
` (3 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
st33zp24 exists in i2c and spi version. Both have different possible
configuration.
st33zp24.txt is renamed st33zp24-i2c.txt.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
.../bindings/security/tpm/st33zp24-i2c.txt | 36 ++++++++++++++++++++++
.../devicetree/bindings/security/tpm/st33zp24.txt | 36 ----------------------
2 files changed, 36 insertions(+), 36 deletions(-)
create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt
delete mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24.txt
diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt
new file mode 100644
index 0000000..3ad115e
--- /dev/null
+++ b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt
@@ -0,0 +1,36 @@
+* STMicroelectronics SAS. ST33ZP24 TPM SoC
+
+Required properties:
+- compatible: Should be "st,st33zp24-i2c".
+- clock-frequency: I²C work frequency.
+- reg: address on the bus
+
+Optional ST33ZP24 Properties:
+- interrupt-parent: phandle for the interrupt gpio controller
+- interrupts: GPIO interrupt to which the chip is connected
+- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state.
+If set, power must be present when the platform is going into sleep/hibernate mode.
+
+Optional SoC Specific Properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+
+Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2):
+
+&i2c2 {
+
+ status = "okay";
+
+ st33zp24: st33zp24@13 {
+
+ compatible = "st,st33zp24-i2c";
+
+ reg = <0x13>;
+ clock-frequency = <400000>;
+
+ interrupt-parent = <&gpio5>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+
+ lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24.txt
deleted file mode 100644
index 0a7361d..0000000
--- a/Documentation/devicetree/bindings/security/tpm/st33zp24.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-* STMicroelectronics SAS. ST33ZP24 TPM SoC
-
-Required properties:
-- compatible: Should be "st,st33zp24-i2c".
-- clock-frequency: I²C work frequency.
-- reg: address on the bus
-
-Optional ST33ZP24 Properties:
-- interrupt-parent: phandle for the interrupt gpio controller
-- interrupts: GPIO interrupt to which the chip is connected
-- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state.
-If set, power must be present when the platform is going into sleep/hibernate mode.
-
-Optional SoC Specific Properties:
-- pinctrl-names: Contains only one value - "default".
-- pintctrl-0: Specifies the pin control groups used for this controller.
-
-Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2):
-
-&i2c2 {
-
- status = "okay";
-
- st33zp24: st33zp24@13 {
-
- compatible = "st,st33zp24-i2c";
-
- reg = <0x013>;
- clock-frequency = <400000>;
-
- interrupt-parent = <&gpio5>;
- interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
-
- lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
- };
-};
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 08/10] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (6 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 07/10] tpm/tpm_i2c_stm_st33/dts/st33zp24-i2c: Rename st33zp24 dts documentation Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
[not found] ` <1420888831-17491-9-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-10 11:20 ` [PATCH v1 09/10] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard
` (2 subsequent siblings)
10 siblings, 1 reply; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
tpm_i2c_stm_st33 is a TIS 1.2 TPM with a core interface which can be used
by different phy such as i2c or spi. The core part is called st33zp24 which
is also the main part reference.
include/linux/platform_data/tpm_stm_st33.h is renamed consequently.
The driver is also split into an i2c phy in charge of sending/receiving
data as well as managing platform data or dts configuration.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/Kconfig | 11 +-
drivers/char/tpm/Makefile | 2 +-
drivers/char/tpm/st33zp24/Kconfig | 20 +
drivers/char/tpm/st33zp24/Makefile | 9 +
drivers/char/tpm/st33zp24/i2c.c | 283 +++++++++
drivers/char/tpm/st33zp24/st33zp24.c | 688 ++++++++++++++++++++++
drivers/char/tpm/st33zp24/st33zp24.h | 32 +
drivers/char/tpm/tpm_i2c_stm_st33.c | 915 -----------------------------
include/linux/platform_data/st33zp24.h | 28 +
include/linux/platform_data/tpm_stm_st33.h | 39 --
10 files changed, 1062 insertions(+), 965 deletions(-)
create mode 100644 drivers/char/tpm/st33zp24/Kconfig
create mode 100644 drivers/char/tpm/st33zp24/Makefile
create mode 100644 drivers/char/tpm/st33zp24/i2c.c
create mode 100644 drivers/char/tpm/st33zp24/st33zp24.c
create mode 100644 drivers/char/tpm/st33zp24/st33zp24.h
delete mode 100644 drivers/char/tpm/tpm_i2c_stm_st33.c
create mode 100644 include/linux/platform_data/st33zp24.h
delete mode 100644 include/linux/platform_data/tpm_stm_st33.h
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 9d4e375..2dc16d3 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -100,16 +100,6 @@ config TCG_IBMVTPM
will be accessible from within Linux. To compile this driver
as a module, choose M here; the module will be called tpm_ibmvtpm.
-config TCG_TIS_I2C_ST33
- tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)"
- depends on I2C
- depends on GPIOLIB
- ---help---
- If you have a TPM security chip from STMicroelectronics working with
- an I2C bus say Yes and it will be accessible from within Linux.
- To compile this driver as a module, choose M here; the module will be
- called tpm_i2c_stm_st33.
-
config TCG_XEN
tristate "XEN TPM Interface"
depends on TCG_TPM && XEN
@@ -131,4 +121,5 @@ config TCG_CRB
from within Linux. To compile this driver as a module, choose
M here; the module will be called tpm_crb.
+source "drivers/char/tpm/st33zp24/Kconfig"
endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 990cf18..56e8f1f 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -20,6 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
-obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o
+obj-$(CONFIG_TCG_TIS_ST33ZP24) += st33zp24/
obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
obj-$(CONFIG_TCG_CRB) += tpm_crb.o
diff --git a/drivers/char/tpm/st33zp24/Kconfig b/drivers/char/tpm/st33zp24/Kconfig
new file mode 100644
index 0000000..51dcef5
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/Kconfig
@@ -0,0 +1,20 @@
+config TCG_TIS_ST33ZP24
+ tristate "STMicroelectronics TPM Interface Specification 1.2 Interface"
+ depends on GPIOLIB
+ ---help---
+ STMicroelectronics ST33ZP24 core driver. It implements the core
+ TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will
+ register against it.
+
+ To compile this driver as a module, choose m here. The module will be called
+ tpm_st33zp24.
+
+config TCG_TIS_ST33ZP24_I2C
+ tristate "TPM 1.2 ST33ZP24 I2C support"
+ depends on TCG_TIS_ST33ZP24
+ depends on I2C
+ ---help---
+ This module adds support for the STMicroelectronics TPM security chip
+ ST33ZP24 with i2c interface.
+ To compile this driver as a module, choose M here; the module will be
+ called tpm_st33zp24_i2c.
diff --git a/drivers/char/tpm/st33zp24/Makefile b/drivers/char/tpm/st33zp24/Makefile
new file mode 100644
index 0000000..414497f
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for ST33ZP24 TPM 1.2 driver
+#
+
+tpm_st33zp24-objs = st33zp24.o
+obj-$(CONFIG_TCG_TIS_ST33ZP24) += tpm_st33zp24.o
+
+tpm_st33zp24_i2c-objs = i2c.o
+obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o
diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c
new file mode 100644
index 0000000..5a7e9b0
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/i2c.c
@@ -0,0 +1,283 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
+ * Copyright (C) 2009 - 2015 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+
+#include <linux/platform_data/st33zp24.h>
+
+#include "st33zp24.h"
+
+#define TPM_DUMMY_BYTE 0xAA
+#define TPM_WRITE_DIRECTION 0x80
+#define TPM_BUFSIZE 2048
+
+struct st33zp24_i2c_phy {
+ struct i2c_client *client;
+ u8 buf[TPM_BUFSIZE + 1];
+ int io_lpcpd;
+};
+
+/*
+ * write8_reg
+ * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: tpm_register, the tpm tis register where the data should be written
+ * @param: tpm_data, the tpm_data to write inside the tpm_register
+ * @param: tpm_size, The length of the data
+ * @return: Returns negative errno, or else the number of bytes written.
+ */
+static int write8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size)
+{
+ struct st33zp24_i2c_phy *phy = phy_id;
+
+ phy->buf[0] = tpm_register;
+ memcpy(phy->buf + 1, tpm_data, tpm_size);
+ return i2c_master_send(phy->client, phy->buf, tpm_size + 1);
+} /* write8_reg() */
+
+/*
+ * read8_reg
+ * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: tpm_register, the tpm tis register where the data should be read
+ * @param: tpm_data, the TPM response
+ * @param: tpm_size, tpm TPM response size to read.
+ * @return: number of byte read successfully: should be one if success.
+ */
+static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size)
+{
+ struct st33zp24_i2c_phy *phy = phy_id;
+ u8 status = 0;
+ u8 data;
+
+ data = TPM_DUMMY_BYTE;
+ status = write8_reg(phy, tpm_register, &data, 1);
+ if (status == 2)
+ status = i2c_master_recv(phy->client, tpm_data, tpm_size);
+ return status;
+} /* read8_reg() */
+
+/*
+ * st33zp24_i2c_send
+ * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: phy_id, the phy description
+ * @param: tpm_register, the tpm tis register where the data should be written
+ * @param: tpm_data, the tpm_data to write inside the tpm_register
+ * @param: tpm_size, the length of the data
+ * @return: number of byte written successfully: should be one if success.
+ */
+static int st33zp24_i2c_send(void *phy_id, u8 tpm_register, u8 *tpm_data,
+ int tpm_size)
+{
+ return write8_reg(phy_id, tpm_register | TPM_WRITE_DIRECTION, tpm_data,
+ tpm_size);
+}
+
+/*
+ * st33zp24_i2c_recv
+ * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: phy_id, the phy description
+ * @param: tpm_register, the tpm tis register where the data should be read
+ * @param: tpm_data, the TPM response
+ * @param: tpm_size, tpm TPM response size to read.
+ * @return: number of byte read successfully: should be one if success.
+ */
+static int st33zp24_i2c_recv(void *phy_id, u8 tpm_register, u8 *tpm_data,
+ int tpm_size)
+{
+ return read8_reg(phy_id, tpm_register, tpm_data, tpm_size);
+}
+
+static struct st33zp24_phy_ops i2c_phy_ops = {
+ .send = st33zp24_i2c_send,
+ .recv = st33zp24_i2c_recv,
+};
+
+#ifdef CONFIG_OF
+static int st33zp24_i2c_of_request_resources(struct st33zp24_i2c_phy *phy)
+{
+ struct device_node *pp;
+ struct i2c_client *client = phy->client;
+ int gpio;
+ int ret;
+
+ pp = client->dev.of_node;
+ if (!pp) {
+ dev_err(&client->dev, "No platform data\n");
+ return -ENODEV;
+ }
+
+ /* Get GPIO from device tree */
+ gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
+ if (gpio < 0) {
+ dev_err(&client->dev,
+ "Failed to retrieve lpcpd-gpios from dts.\n");
+ phy->io_lpcpd = -1;
+ /*
+ * lpcpd pin is not specified. This is not an issue as
+ * power management can be also managed by TPM specific
+ * commands. So leave with a success status code.
+ */
+ return 0;
+ }
+ /* GPIO request and configuration */
+ ret = devm_gpio_request_one(&client->dev, gpio,
+ GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
+ if (ret) {
+ dev_err(&client->dev, "Failed to request lpcpd pin\n");
+ return -ENODEV;
+ }
+ phy->io_lpcpd = gpio;
+
+ return 0;
+}
+#else
+static int st33zp24_i2c_of_request_resources(struct st33zp24_i2c_phy *phy)
+{
+ return -ENODEV;
+}
+#endif
+
+static int st33zp24_i2c_request_resources(struct i2c_client *client,
+ struct st33zp24_i2c_phy *phy)
+{
+ struct st33zp24_platform_data *pdata;
+ int ret;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "No platform data\n");
+ return -ENODEV;
+ }
+
+ /* store for late use */
+ phy->io_lpcpd = pdata->io_lpcpd;
+
+ if (gpio_is_valid(pdata->io_lpcpd)) {
+ ret = devm_gpio_request_one(&client->dev,
+ pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
+ "TPM IO_LPCPD");
+ if (ret) {
+ dev_err(&client->dev, "Failed to request lpcpd pin\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * st33zp24_i2c_probe initialize the TPM device
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @param: id, the i2c_device_id struct.
+ * @return: 0 in case of success.
+ * -1 in other case.
+ */
+static int st33zp24_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct st33zp24_platform_data *pdata;
+ struct st33zp24_i2c_phy *phy;
+
+ if (!client) {
+ pr_info("%s: i2c client is NULL. Device not accessible.\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_info(&client->dev, "client not i2c capable\n");
+ return -ENODEV;
+ }
+
+ phy = devm_kzalloc(&client->dev, sizeof(struct st33zp24_i2c_phy),
+ GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->client = client;
+ pdata = client->dev.platform_data;
+ if (!pdata && client->dev.of_node) {
+ ret = st33zp24_i2c_of_request_resources(phy);
+ if (ret)
+ return ret;
+ } else if (pdata) {
+ ret = st33zp24_i2c_request_resources(client, phy);
+ if (ret)
+ return ret;
+ }
+
+ return st33zp24_probe(phy, &i2c_phy_ops, &client->dev, client->irq,
+ phy->io_lpcpd);
+}
+
+/*
+ * st33zp24_i2c_remove remove the TPM device
+ * @param: client, the i2c_client description (TPM I2C description).
+ * @return: 0 in case of success.
+ */
+static int st33zp24_i2c_remove(struct i2c_client *client)
+{
+ void *tpm_data = i2c_get_clientdata(client);
+
+ if (tpm_data)
+ st33zp24_remove(tpm_data);
+
+ return 0;
+}
+
+static const struct i2c_device_id st33zp24_i2c_id[] = {
+ {TPM_ST33_I2C, 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_st33zp24_i2c_match[] = {
+ { .compatible = "st,st33zp24-i2c", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match);
+#endif
+
+static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend,
+ st33zp24_pm_resume);
+
+static struct i2c_driver st33zp24_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = TPM_ST33_I2C,
+ .pm = &st33zp24_i2c_ops,
+ .of_match_table = of_match_ptr(of_st33zp24_i2c_match),
+ },
+ .probe = st33zp24_i2c_probe,
+ .remove = st33zp24_i2c_remove,
+ .id_table = st33zp24_i2c_id
+};
+
+module_i2c_driver(st33zp24_i2c_driver);
+
+MODULE_AUTHOR("Christophe Ricard (tpmsupport-qxv4g6HH51o@public.gmane.org)");
+MODULE_DESCRIPTION("STM TPM 1.2 I2C ST33 Driver");
+MODULE_VERSION("1.3.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c
new file mode 100644
index 0000000..a425022
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/st33zp24.c
@@ -0,0 +1,688 @@
+/*
+ * STMicroelectronics TPM Linux driver for TPM ST33ZP24
+ * Copyright (C) 2009 - 2015 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/freezer.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "../tpm.h"
+#include "st33zp24.h"
+
+#define TPM_ACCESS 0x0
+#define TPM_STS 0x18
+#define TPM_DATA_FIFO 0x24
+#define TPM_INTF_CAPABILITY 0x14
+#define TPM_INT_STATUS 0x10
+#define TPM_INT_ENABLE 0x08
+
+#define TPM_HEADER_SIZE 10
+#define TPM_BUFSIZE 2048
+
+#define LOCALITY0 0
+
+enum st33zp24_access {
+ TPM_ACCESS_VALID = 0x80,
+ TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
+ TPM_ACCESS_REQUEST_PENDING = 0x04,
+ TPM_ACCESS_REQUEST_USE = 0x02,
+};
+
+enum st33zp24_status {
+ TPM_STS_VALID = 0x80,
+ TPM_STS_COMMAND_READY = 0x40,
+ TPM_STS_GO = 0x20,
+ TPM_STS_DATA_AVAIL = 0x10,
+ TPM_STS_DATA_EXPECT = 0x08,
+};
+
+enum st33zp24_int_flags {
+ TPM_GLOBAL_INT_ENABLE = 0x80,
+ TPM_INTF_CMD_READY_INT = 0x080,
+ TPM_INTF_FIFO_AVALAIBLE_INT = 0x040,
+ TPM_INTF_WAKE_UP_READY_INT = 0x020,
+ TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
+ TPM_INTF_STS_VALID_INT = 0x002,
+ TPM_INTF_DATA_AVAIL_INT = 0x001,
+};
+
+enum tis_defaults {
+ TIS_SHORT_TIMEOUT = 750,
+ TIS_LONG_TIMEOUT = 2000,
+};
+
+struct st33zp24_dev {
+ struct tpm_chip *chip;
+ void *phy_id;
+ struct st33zp24_phy_ops *ops;
+ u32 intrs;
+ int io_lpcpd;
+};
+
+/*
+ * clear_interruption clear the pending interrupt.
+ * @param: tpm_dev, the tpm device device.
+ * @return: the interrupt status value.
+ */
+static u8 clear_interruption(struct st33zp24_dev *tpm_dev)
+{
+ u8 interrupt;
+
+ tpm_dev->ops->recv(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1);
+ tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1);
+ return interrupt;
+} /* clear_interruption() */
+
+/*
+ * st33zp24_cancel, cancel is not implemented.
+ * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
+ */
+static void st33zp24_cancel(struct tpm_chip *chip)
+{
+ struct st33zp24_dev *tpm_dev;
+ u8 data;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ data = TPM_STS_COMMAND_READY;
+ tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1);
+} /* st33zp24_cancel() */
+
+/*
+ * st33zp24_status return the TPM_STS register
+ * @param: chip, the tpm chip description
+ * @return: the TPM_STS register value.
+ */
+static u8 st33zp24_status(struct tpm_chip *chip)
+{
+ struct st33zp24_dev *tpm_dev;
+ u8 data;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ tpm_dev->ops->recv(tpm_dev->phy_id, TPM_STS, &data, 1);
+ return data;
+} /* st33zp24_status() */
+
+/*
+ * check_locality if the locality is active
+ * @param: chip, the tpm chip description
+ * @return: the active locality or -EACCESS.
+ */
+static int check_locality(struct tpm_chip *chip)
+{
+ struct st33zp24_dev *tpm_dev;
+ u8 data;
+ u8 status;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ status = tpm_dev->ops->recv(tpm_dev->phy_id, TPM_ACCESS, &data, 1);
+ if (status && (data &
+ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
+ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
+ return chip->vendor.locality;
+
+ return -EACCES;
+} /* check_locality() */
+
+/*
+ * request_locality request the TPM locality
+ * @param: chip, the chip description
+ * @return: the active locality or negative value.
+ */
+static int request_locality(struct tpm_chip *chip)
+{
+ unsigned long stop;
+ long ret;
+ struct st33zp24_dev *tpm_dev;
+ u8 data;
+
+ if (check_locality(chip) == chip->vendor.locality)
+ return chip->vendor.locality;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ data = TPM_ACCESS_REQUEST_USE;
+ ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_ACCESS, &data, 1);
+ if (ret < 0)
+ goto end;
+
+ stop = jiffies + chip->vendor.timeout_a;
+
+ /* Request locality is usually effective after the request */
+ do {
+ if (check_locality(chip) >= 0)
+ return chip->vendor.locality;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+ ret = -EACCES;
+end:
+ return ret;
+} /* request_locality() */
+
+/*
+ * release_locality release the active locality
+ * @param: chip, the tpm chip description.
+ */
+static void release_locality(struct tpm_chip *chip)
+{
+ struct st33zp24_dev *tpm_dev;
+ u8 data;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+ data = TPM_ACCESS_ACTIVE_LOCALITY;
+
+ tpm_dev->ops->send(tpm_dev->phy_id, TPM_ACCESS, &data, 1);
+}
+
+/*
+ * get_burstcount return the burstcount address 0x19 0x1A
+ * @param: chip, the chip description
+ * return: the burstcount or negative value.
+ */
+static int get_burstcount(struct tpm_chip *chip)
+{
+ unsigned long stop;
+ int burstcnt, status;
+ u8 tpm_reg, temp;
+ struct st33zp24_dev *tpm_dev;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ stop = jiffies + chip->vendor.timeout_d;
+ do {
+ tpm_reg = TPM_STS + 1;
+ status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1);
+ if (status < 0)
+ goto end;
+
+ tpm_reg = tpm_reg + 1;
+ burstcnt = temp;
+ status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1);
+ if (status < 0)
+ goto end;
+
+ burstcnt |= temp << 8;
+ if (burstcnt)
+ return burstcnt;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+
+end:
+ return -EBUSY;
+} /* get_burstcount() */
+
+
+/*
+ * wait_for_tpm_stat_cond
+ * @param: chip, chip description
+ * @param: mask, expected mask value
+ * @param: check_cancel, does the command expected to be canceled ?
+ * @param: canceled, did we received a cancel request ?
+ * @return: true if status == mask or if the command is canceled.
+ * false in other cases.
+ */
+static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
+ bool check_cancel, bool *canceled)
+{
+ u8 status = chip->ops->status(chip);
+
+ *canceled = false;
+ if ((status & mask) == mask)
+ return true;
+ if (check_cancel && chip->ops->req_canceled(chip, status)) {
+ *canceled = true;
+ return true;
+ }
+ return false;
+}
+
+/*
+ * wait_for_stat wait for a TPM_STS value
+ * @param: chip, the tpm chip description
+ * @param: mask, the value mask to wait
+ * @param: timeout, the timeout
+ * @param: queue, the wait queue.
+ * @param: check_cancel, does the command can be cancelled ?
+ * @return: the tpm status, 0 if success, -ETIME if timeout is reached.
+ */
+static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
+ wait_queue_head_t *queue, bool check_cancel)
+{
+ unsigned long stop;
+ int ret;
+ bool canceled = false;
+ bool condition;
+ u32 cur_intrs;
+ u8 status;
+ struct st33zp24_dev *tpm_dev;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ /* check current status */
+ status = st33zp24_status(chip);
+ if ((status & mask) == mask)
+ return 0;
+
+ stop = jiffies + timeout;
+
+ if (chip->vendor.irq) {
+ cur_intrs = tpm_dev->intrs;
+ clear_interruption(tpm_dev);
+ enable_irq(chip->vendor.irq);
+
+again:
+ timeout = stop - jiffies;
+ if ((long) timeout <= 0)
+ return -1;
+
+ ret = wait_event_interruptible_timeout(*queue,
+ cur_intrs != tpm_dev->intrs, timeout);
+ clear_interruption(tpm_dev);
+ condition = wait_for_tpm_stat_cond(chip, mask,
+ check_cancel, &canceled);
+ if (ret >= 0 && condition) {
+ if (canceled)
+ return -ECANCELED;
+ return 0;
+ }
+ if (ret == -ERESTARTSYS && freezing(current)) {
+ clear_thread_flag(TIF_SIGPENDING);
+ goto again;
+ }
+ disable_irq_nosync(chip->vendor.irq);
+
+ } else {
+ do {
+ msleep(TPM_TIMEOUT);
+ status = chip->ops->status(chip);
+ if ((status & mask) == mask)
+ return 0;
+ } while (time_before(jiffies, stop));
+ }
+
+ return -ETIME;
+} /* wait_for_stat() */
+
+/*
+ * recv_data receive data
+ * @param: chip, the tpm chip description
+ * @param: buf, the buffer where the data are received
+ * @param: count, the number of data to receive
+ * @return: the number of bytes read from TPM FIFO.
+ */
+static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ int size = 0, burstcnt, len, ret;
+ struct st33zp24_dev *tpm_dev;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ while (size < count &&
+ wait_for_stat(chip,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ chip->vendor.timeout_c,
+ &chip->vendor.read_queue, true) == 0) {
+ burstcnt = get_burstcount(chip);
+ if (burstcnt < 0)
+ return burstcnt;
+ len = min_t(int, burstcnt, count - size);
+ ret = tpm_dev->ops->recv(tpm_dev->phy_id, TPM_DATA_FIFO,
+ buf + size, len);
+ if (ret < 0)
+ return ret;
+
+ size += len;
+ }
+ return size;
+}
+
+/*
+ * tpm_ioserirq_handler the serirq irq handler
+ * @param: irq, the tpm chip description
+ * @param: dev_id, the description of the chip
+ * @return: the status of the handler.
+ */
+static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
+{
+ struct tpm_chip *chip = dev_id;
+ struct st33zp24_dev *tpm_dev;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ tpm_dev->intrs++;
+ wake_up_interruptible(&chip->vendor.read_queue);
+ disable_irq_nosync(chip->vendor.irq);
+
+ return IRQ_HANDLED;
+} /* tpm_ioserirq_handler() */
+
+/*
+ * st33zp24_send send TPM commands through the I2C bus.
+ *
+ * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
+ * @param: buf, the buffer to send.
+ * @param: count, the number of bytes to send.
+ * @return: In case of success the number of bytes sent.
+ * In other case, a < 0 value describing the issue.
+ */
+static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
+ size_t len)
+{
+ u32 status, i, size;
+ int burstcnt = 0;
+ int ret;
+ u8 data;
+ struct st33zp24_dev *tpm_dev;
+
+ if (!chip)
+ return -EBUSY;
+ if (len < TPM_HEADER_SIZE)
+ return -EBUSY;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ ret = request_locality(chip);
+ if (ret < 0)
+ return ret;
+
+ status = st33zp24_status(chip);
+ if ((status & TPM_STS_COMMAND_READY) == 0) {
+ st33zp24_cancel(chip);
+ if (wait_for_stat
+ (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
+ &chip->vendor.read_queue, false) < 0) {
+ ret = -ETIME;
+ goto out_err;
+ }
+ }
+
+ for (i = 0; i < len - 1;) {
+ burstcnt = get_burstcount(chip);
+ if (burstcnt < 0)
+ return burstcnt;
+ size = min_t(int, len - i - 1, burstcnt);
+ ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO,
+ buf + i, size);
+ if (ret < 0)
+ goto out_err;
+
+ i += size;
+ }
+
+ status = st33zp24_status(chip);
+ if ((status & TPM_STS_DATA_EXPECT) == 0) {
+ ret = -EIO;
+ goto out_err;
+ }
+
+ ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO,
+ buf + len - 1, 1);
+ if (ret < 0)
+ goto out_err;
+
+ status = st33zp24_status(chip);
+ if ((status & TPM_STS_DATA_EXPECT) != 0) {
+ ret = -EIO;
+ goto out_err;
+ }
+
+ data = TPM_STS_GO;
+ ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1);
+ if (ret < 0)
+ goto out_err;
+
+ return len;
+out_err:
+ st33zp24_cancel(chip);
+ release_locality(chip);
+ return ret;
+}
+
+/*
+ * st33zp24_recv received TPM response through TPM phy.
+ * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
+ * @param: buf, the buffer to store datas.
+ * @param: count, the number of bytes to send.
+ * @return: In case of success the number of bytes received.
+ * In other case, a < 0 value describing the issue.
+ */
+static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf,
+ size_t count)
+{
+ int size = 0;
+ int expected;
+
+ if (!chip)
+ return -EBUSY;
+
+ if (count < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
+
+ size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ if (size < TPM_HEADER_SIZE) {
+ dev_err(&chip->dev, "Unable to read header\n");
+ goto out;
+ }
+
+ expected = be32_to_cpu(*(__be32 *)(buf + 2));
+ if (expected > count) {
+ size = -EIO;
+ goto out;
+ }
+
+ size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
+ if (size < expected) {
+ dev_err(&chip->dev, "Unable to read remainder of result\n");
+ size = -ETIME;
+ goto out;
+ }
+
+out:
+ st33zp24_cancel(chip);
+ release_locality(chip);
+ return size;
+}
+
+/*
+ * st33zp24_req_canceled
+ * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
+ * @param: status, the TPM status.
+ * @return: Does TPM ready to compute a new command ? true.
+ */
+static bool st33zp24_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ return (status == TPM_STS_COMMAND_READY);
+}
+
+static const struct tpm_class_ops st33zp24_tpm = {
+ .send = st33zp24_send,
+ .recv = st33zp24_recv,
+ .cancel = st33zp24_cancel,
+ .status = st33zp24_status,
+ .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ .req_canceled = st33zp24_req_canceled,
+};
+
+/*
+ * st33zp24_probe initialize the TPM device
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @param: id, the i2c_device_id struct.
+ * @return: 0 in case of success.
+ * -1 in other case.
+ */
+int st33zp24_probe(void *phy_id, struct st33zp24_phy_ops *ops,
+ struct device *dev, int irq, int io_lpcpd)
+{
+ int ret;
+ u8 intmask = 0;
+ struct tpm_chip *chip;
+ struct st33zp24_dev *tpm_dev;
+
+ tpm_dev = devm_kzalloc(dev, sizeof(struct st33zp24_dev),
+ GFP_KERNEL);
+ if (!tpm_dev)
+ return -ENOMEM;
+
+ chip = tpmm_chip_alloc(dev, &st33zp24_tpm);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ TPM_VPRIV(chip) = tpm_dev;
+ tpm_dev->phy_id = phy_id;
+ tpm_dev->ops = ops;
+
+ chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
+ chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+
+ chip->vendor.locality = LOCALITY0;
+
+ if (irq) {
+ /* INTERRUPT Setup */
+ init_waitqueue_head(&chip->vendor.read_queue);
+ tpm_dev->intrs = 0;
+
+ if (request_locality(chip) != LOCALITY0) {
+ ret = -ENODEV;
+ goto _tpm_clean_answer;
+ }
+
+ clear_interruption(tpm_dev);
+ ret = devm_request_irq(dev, irq, tpm_ioserirq_handler,
+ IRQF_TRIGGER_HIGH, "TPM SERIRQ management",
+ chip);
+ if (ret < 0) {
+ dev_err(&chip->dev , "TPM SERIRQ signals %d not available\n",
+ irq);
+ goto _tpm_clean_answer;
+ }
+
+ intmask |= TPM_INTF_CMD_READY_INT
+ | TPM_INTF_STS_VALID_INT
+ | TPM_INTF_DATA_AVAIL_INT;
+
+ ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_ENABLE,
+ &intmask, 1);
+ if (ret < 0)
+ goto _tpm_clean_answer;
+
+ intmask = TPM_GLOBAL_INT_ENABLE;
+ ret = tpm_dev->ops->send(tpm_dev->phy_id, (TPM_INT_ENABLE + 3),
+ &intmask, 1);
+ if (ret < 0)
+ goto _tpm_clean_answer;
+
+ chip->vendor.irq = irq;
+
+ disable_irq_nosync(chip->vendor.irq);
+
+ tpm_gen_interrupt(chip);
+ }
+
+ tpm_get_timeouts(chip);
+ tpm_do_selftest(chip);
+
+ return tpm_chip_register(chip);
+_tpm_clean_answer:
+ dev_info(&chip->dev, "TPM initialization fail\n");
+ return ret;
+}
+
+/*
+ * st33zp24_remove remove the TPM device
+ * @param: tpm_data, the tpm phy.
+ * @return: 0 in case of success.
+ */
+int st33zp24_remove(void *tpm_data)
+{
+ struct st33zp24_dev *tpm_dev = (struct st33zp24_dev *)tpm_data;
+ struct tpm_chip *chip = tpm_dev->chip;
+
+ if (chip)
+ tpm_chip_unregister(chip);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * st33zp24_pm_suspend suspend the TPM device
+ * @param: tpm_data, the tpm phy.
+ * @param: mesg, the power management message.
+ * @return: 0 in case of success.
+ */
+int st33zp24_pm_suspend(struct device *dev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ struct st33zp24_dev *tpm_dev;
+ int ret = 0;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ if (gpio_is_valid(tpm_dev->io_lpcpd))
+ gpio_set_value(tpm_dev->io_lpcpd, 0);
+ else
+ ret = tpm_pm_suspend(dev);
+
+ return ret;
+} /* st33zp24_suspend() */
+
+/*
+ * st33zp24_pm_resume resume the TPM device
+ * @param: tpm_data, the tpm phy.
+ * @return: 0 in case of success.
+ */
+int st33zp24_pm_resume(struct device *dev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ struct st33zp24_dev *tpm_dev;
+ int ret = 0;
+
+ tpm_dev = (struct st33zp24_dev *)TPM_VPRIV(chip);
+
+ if (gpio_is_valid(tpm_dev->io_lpcpd)) {
+ gpio_set_value(tpm_dev->io_lpcpd, 1);
+ ret = wait_for_stat(chip,
+ TPM_STS_VALID, chip->vendor.timeout_b,
+ &chip->vendor.read_queue, false);
+ } else {
+ ret = tpm_pm_resume(dev);
+ if (!ret)
+ tpm_do_selftest(chip);
+ }
+ return ret;
+} /* st33zp24_pm_resume() */
+#endif
diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h
new file mode 100644
index 0000000..ba1d8c0
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/st33zp24.h
@@ -0,0 +1,32 @@
+/*
+ * STMicroelectronics TPM Linux driver for TPM ST33ZP24
+ * Copyright (C) 2009 - 2015 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ST33ZP24_H__
+#define __ST33ZP24_H__
+
+struct st33zp24_phy_ops {
+ int (*send)(void *dev_id, u8 tpm_register, u8 *tpm_data, int tpm_size);
+ int (*recv)(void *dev_id, u8 tpm_register, u8 *tpm_data, int tpm_size);
+};
+
+int st33zp24_pm_suspend(struct device *dev);
+int st33zp24_pm_resume(struct device *dev);
+
+int st33zp24_probe(void *phy_id, struct st33zp24_phy_ops *ops,
+ struct device *dev, int irq, int io_lpcpd);
+int st33zp24_remove(void *tpm_data);
+#endif /* __ST33ZP24_H__ */
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
deleted file mode 100644
index eeb4816..0000000
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ /dev/null
@@ -1,915 +0,0 @@
-/*
- * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
- * Copyright (C) 2009, 2010, 2014 STMicroelectronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * STMicroelectronics version 1.2.1, Copyright (C) 2014
- * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
- * This is free software, and you are welcome to redistribute it
- * under certain conditions.
- *
- * @Author: Christophe RICARD tpmsupport-qxv4g6HH51o@public.gmane.org
- *
- * @File: tpm_stm_st33_i2c.c
- *
- * @Synopsis:
- * 09/15/2010: First shot driver tpm_tis driver for
- * lpc is used as model.
- */
-
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
-#include <linux/freezer.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/gpio.h>
-#include <linux/sched.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
-
-#include <linux/platform_data/tpm_stm_st33.h>
-#include "tpm.h"
-
-#define TPM_ACCESS 0x0
-#define TPM_STS 0x18
-#define TPM_HASH_END 0x20
-#define TPM_DATA_FIFO 0x24
-#define TPM_HASH_DATA 0x24
-#define TPM_HASH_START 0x28
-#define TPM_INTF_CAPABILITY 0x14
-#define TPM_INT_STATUS 0x10
-#define TPM_INT_ENABLE 0x08
-
-#define TPM_DUMMY_BYTE 0xAA
-#define TPM_WRITE_DIRECTION 0x80
-#define TPM_HEADER_SIZE 10
-#define TPM_BUFSIZE 2048
-
-#define LOCALITY0 0
-
-
-enum stm33zp24_access {
- TPM_ACCESS_VALID = 0x80,
- TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
- TPM_ACCESS_REQUEST_PENDING = 0x04,
- TPM_ACCESS_REQUEST_USE = 0x02,
-};
-
-enum stm33zp24_status {
- TPM_STS_VALID = 0x80,
- TPM_STS_COMMAND_READY = 0x40,
- TPM_STS_GO = 0x20,
- TPM_STS_DATA_AVAIL = 0x10,
- TPM_STS_DATA_EXPECT = 0x08,
-};
-
-enum stm33zp24_int_flags {
- TPM_GLOBAL_INT_ENABLE = 0x80,
- TPM_INTF_CMD_READY_INT = 0x080,
- TPM_INTF_FIFO_AVALAIBLE_INT = 0x040,
- TPM_INTF_WAKE_UP_READY_INT = 0x020,
- TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
- TPM_INTF_STS_VALID_INT = 0x002,
- TPM_INTF_DATA_AVAIL_INT = 0x001,
-};
-
-enum tis_defaults {
- TIS_SHORT_TIMEOUT = 750,
- TIS_LONG_TIMEOUT = 2000,
-};
-
-struct tpm_stm_dev {
- struct i2c_client *client;
- struct tpm_chip *chip;
- u8 buf[TPM_BUFSIZE + 1];
- u32 intrs;
- int io_lpcpd;
-};
-
-/*
- * write8_reg
- * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
- * @param: tpm_register, the tpm tis register where the data should be written
- * @param: tpm_data, the tpm_data to write inside the tpm_register
- * @param: tpm_size, The length of the data
- * @return: Returns negative errno, or else the number of bytes written.
- */
-static int write8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register,
- u8 *tpm_data, u16 tpm_size)
-{
- tpm_dev->buf[0] = tpm_register;
- memcpy(tpm_dev->buf + 1, tpm_data, tpm_size);
- return i2c_master_send(tpm_dev->client, tpm_dev->buf, tpm_size + 1);
-} /* write8_reg() */
-
-/*
- * read8_reg
- * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
- * @param: tpm_register, the tpm tis register where the data should be read
- * @param: tpm_data, the TPM response
- * @param: tpm_size, tpm TPM response size to read.
- * @return: number of byte read successfully: should be one if success.
- */
-static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register,
- u8 *tpm_data, int tpm_size)
-{
- u8 status = 0;
- u8 data;
-
- data = TPM_DUMMY_BYTE;
- status = write8_reg(tpm_dev, tpm_register, &data, 1);
- if (status == 2)
- status = i2c_master_recv(tpm_dev->client, tpm_data, tpm_size);
- return status;
-} /* read8_reg() */
-
-/*
- * I2C_WRITE_DATA
- * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
- * @param: tpm_dev, the chip description
- * @param: tpm_register, the tpm tis register where the data should be written
- * @param: tpm_data, the tpm_data to write inside the tpm_register
- * @param: tpm_size, The length of the data
- * @return: number of byte written successfully: should be one if success.
- */
-#define I2C_WRITE_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \
- (write8_reg(tpm_dev, tpm_register | \
- TPM_WRITE_DIRECTION, tpm_data, tpm_size))
-
-/*
- * I2C_READ_DATA
- * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
- * @param: tpm_dev, the chip description
- * @param: tpm_register, the tpm tis register where the data should be read
- * @param: tpm_data, the TPM response
- * @param: tpm_size, tpm TPM response size to read.
- * @return: number of byte read successfully: should be one if success.
- */
-#define I2C_READ_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \
- (read8_reg(tpm_dev, tpm_register, tpm_data, tpm_size))
-
-/*
- * clear_interruption
- * clear the TPM interrupt register.
- * @param: tpm, the chip description
- * @return: the TPM_INT_STATUS value
- */
-static u8 clear_interruption(struct tpm_stm_dev *tpm_dev)
-{
- u8 interrupt;
-
- I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
- I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
- return interrupt;
-} /* clear_interruption() */
-
-/*
- * tpm_stm_i2c_cancel, cancel is not implemented.
- * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
- */
-static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
-{
- struct tpm_stm_dev *tpm_dev;
- u8 data;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- data = TPM_STS_COMMAND_READY;
- I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1);
-} /* tpm_stm_i2c_cancel() */
-
-/*
- * tpm_stm_spi_status return the TPM_STS register
- * @param: chip, the tpm chip description
- * @return: the TPM_STS register value.
- */
-static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
-{
- struct tpm_stm_dev *tpm_dev;
- u8 data;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1);
- return data;
-} /* tpm_stm_i2c_status() */
-
-
-/*
- * check_locality if the locality is active
- * @param: chip, the tpm chip description
- * @return: the active locality or -EACCESS.
- */
-static int check_locality(struct tpm_chip *chip)
-{
- struct tpm_stm_dev *tpm_dev;
- u8 data;
- u8 status;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1);
- if (status && (data &
- (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
- (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
- return chip->vendor.locality;
-
- return -EACCES;
-} /* check_locality() */
-
-/*
- * request_locality request the TPM locality
- * @param: chip, the chip description
- * @return: the active locality or EACCESS.
- */
-static int request_locality(struct tpm_chip *chip)
-{
- unsigned long stop;
- long ret;
- struct tpm_stm_dev *tpm_dev;
- u8 data;
-
- if (check_locality(chip) == chip->vendor.locality)
- return chip->vendor.locality;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- data = TPM_ACCESS_REQUEST_USE;
- ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
- if (ret < 0)
- goto end;
-
- stop = jiffies + chip->vendor.timeout_a;
-
- /* Request locality is usually effective after the request */
- do {
- if (check_locality(chip) >= 0)
- return chip->vendor.locality;
- msleep(TPM_TIMEOUT);
- } while (time_before(jiffies, stop));
- ret = -EACCES;
-end:
- return ret;
-} /* request_locality() */
-
-/*
- * release_locality release the active locality
- * @param: chip, the tpm chip description.
- */
-static void release_locality(struct tpm_chip *chip)
-{
- struct tpm_stm_dev *tpm_dev;
- u8 data;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
- data = TPM_ACCESS_ACTIVE_LOCALITY;
-
- I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
-}
-
-/*
- * get_burstcount return the burstcount address 0x19 0x1A
- * @param: chip, the chip description
- * return: the burstcount.
- */
-static int get_burstcount(struct tpm_chip *chip)
-{
- unsigned long stop;
- int burstcnt, status;
- u8 tpm_reg, temp;
- struct tpm_stm_dev *tpm_dev;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- stop = jiffies + chip->vendor.timeout_d;
- do {
- tpm_reg = TPM_STS + 1;
- status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1);
- if (status < 0)
- goto end;
-
- tpm_reg = tpm_reg + 1;
- burstcnt = temp;
- status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1);
- if (status < 0)
- goto end;
-
- burstcnt |= temp << 8;
- if (burstcnt)
- return burstcnt;
- msleep(TPM_TIMEOUT);
- } while (time_before(jiffies, stop));
-
-end:
- return -EBUSY;
-} /* get_burstcount() */
-
-static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
- bool check_cancel, bool *canceled)
-{
- u8 status = chip->ops->status(chip);
-
- *canceled = false;
- if ((status & mask) == mask)
- return true;
- if (check_cancel && chip->ops->req_canceled(chip, status)) {
- *canceled = true;
- return true;
- }
- return false;
-}
-
-/*
- * interrupt_to_status
- * @param: irq_mask, the irq mask value to wait
- * @return: the corresponding tpm_sts value
- */
-static u8 interrupt_to_status(u8 irq_mask)
-{
- u8 status = 0;
-
- if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT)
- status |= TPM_STS_VALID;
- if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT)
- status |= TPM_STS_DATA_AVAIL;
- if ((irq_mask & TPM_INTF_CMD_READY_INT) == TPM_INTF_CMD_READY_INT)
- status |= TPM_STS_COMMAND_READY;
-
- return status;
-} /* status_to_interrupt() */
-
-/*
- * wait_for_stat wait for a TPM_STS value
- * @param: chip, the tpm chip description
- * @param: mask, the value mask to wait
- * @param: timeout, the timeout
- * @param: queue, the wait queue.
- * @param: check_cancel, does the command can be cancelled ?
- * @return: the tpm status, 0 if success, -ETIME if timeout is reached.
- */
-static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
- wait_queue_head_t *queue, bool check_cancel)
-{
- unsigned long stop;
- int ret;
- bool canceled = false;
- bool condition;
- u32 cur_intrs;
- u8 interrupt, status;
- struct tpm_stm_dev *tpm_dev;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- /* check current status */
- status = tpm_stm_i2c_status(chip);
- if ((status & mask) == mask)
- return 0;
-
- stop = jiffies + timeout;
-
- if (chip->vendor.irq) {
- cur_intrs = tpm_dev->intrs;
- interrupt = clear_interruption(tpm_dev);
- enable_irq(chip->vendor.irq);
-
-again:
- timeout = stop - jiffies;
- if ((long) timeout <= 0)
- return -1;
-
- ret = wait_event_interruptible_timeout(*queue,
- cur_intrs != tpm_dev->intrs, timeout);
-
- interrupt |= clear_interruption(tpm_dev);
- status = interrupt_to_status(interrupt);
- condition = wait_for_tpm_stat_cond(chip, mask,
- check_cancel, &canceled);
-
- if (ret >= 0 && condition) {
- if (canceled)
- return -ECANCELED;
- return 0;
- }
- if (ret == -ERESTARTSYS && freezing(current)) {
- clear_thread_flag(TIF_SIGPENDING);
- goto again;
- }
- disable_irq_nosync(chip->vendor.irq);
-
- } else {
- do {
- msleep(TPM_TIMEOUT);
- status = chip->ops->status(chip);
- if ((status & mask) == mask)
- return 0;
- } while (time_before(jiffies, stop));
- }
-
- return -ETIME;
-} /* wait_for_stat() */
-
-/*
- * recv_data receive data
- * @param: chip, the tpm chip description
- * @param: buf, the buffer where the data are received
- * @param: count, the number of data to receive
- * @return: the number of bytes read from TPM FIFO.
- */
-static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
-{
- int size = 0, burstcnt, len, ret;
- struct tpm_stm_dev *tpm_dev;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- while (size < count &&
- wait_for_stat(chip,
- TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- chip->vendor.timeout_c,
- &chip->vendor.read_queue, true) == 0) {
- burstcnt = get_burstcount(chip);
- if (burstcnt < 0)
- return burstcnt;
- len = min_t(int, burstcnt, count - size);
- ret = I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len);
- if (ret < 0)
- return ret;
-
- size += len;
- }
- return size;
-}
-
-/*
- * tpm_ioserirq_handler the serirq irq handler
- * @param: irq, the tpm chip description
- * @param: dev_id, the description of the chip
- * @return: the status of the handler.
- */
-static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
-{
- struct tpm_chip *chip = dev_id;
- struct tpm_stm_dev *tpm_dev;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- tpm_dev->intrs++;
- wake_up_interruptible(&chip->vendor.read_queue);
- disable_irq_nosync(chip->vendor.irq);
-
- return IRQ_HANDLED;
-} /* tpm_ioserirq_handler() */
-
-
-/*
- * tpm_stm_i2c_send send TPM commands through the I2C bus.
- *
- * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
- * @param: buf, the buffer to send.
- * @param: count, the number of bytes to send.
- * @return: In case of success the number of bytes sent.
- * In other case, a < 0 value describing the issue.
- */
-static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
- size_t len)
-{
- u32 status, i, size;
- int burstcnt = 0;
- int ret;
- u8 data;
- struct i2c_client *client;
- struct tpm_stm_dev *tpm_dev;
-
- if (!chip)
- return -EBUSY;
- if (len < TPM_HEADER_SIZE)
- return -EBUSY;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
- client = tpm_dev->client;
-
- client->flags = 0;
-
- ret = request_locality(chip);
- if (ret < 0)
- return ret;
-
- status = tpm_stm_i2c_status(chip);
- if ((status & TPM_STS_COMMAND_READY) == 0) {
- tpm_stm_i2c_cancel(chip);
- if (wait_for_stat
- (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
- &chip->vendor.read_queue, false) < 0) {
- ret = -ETIME;
- goto out_err;
- }
- }
-
- for (i = 0; i < len - 1;) {
- burstcnt = get_burstcount(chip);
- if (burstcnt < 0)
- return burstcnt;
- size = min_t(int, len - i - 1, burstcnt);
- ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size);
- if (ret < 0)
- goto out_err;
-
- i += size;
- }
-
- status = tpm_stm_i2c_status(chip);
- if ((status & TPM_STS_DATA_EXPECT) == 0) {
- ret = -EIO;
- goto out_err;
- }
-
- ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + len - 1, 1);
- if (ret < 0)
- goto out_err;
-
- status = tpm_stm_i2c_status(chip);
- if ((status & TPM_STS_DATA_EXPECT) != 0) {
- ret = -EIO;
- goto out_err;
- }
-
- data = TPM_STS_GO;
- I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1);
-
- return len;
-out_err:
- tpm_stm_i2c_cancel(chip);
- release_locality(chip);
- return ret;
-}
-
-/*
- * tpm_stm_i2c_recv received TPM response through the I2C bus.
- * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
- * @param: buf, the buffer to store datas.
- * @param: count, the number of bytes to send.
- * @return: In case of success the number of bytes received.
- * In other case, a < 0 value describing the issue.
- */
-static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
- size_t count)
-{
- int size = 0;
- int expected;
-
- if (!chip)
- return -EBUSY;
-
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
-
- size = recv_data(chip, buf, TPM_HEADER_SIZE);
- if (size < TPM_HEADER_SIZE) {
- dev_err(chip->pdev, "Unable to read header\n");
- goto out;
- }
-
- expected = be32_to_cpu(*(__be32 *)(buf + 2));
- if (expected > count) {
- size = -EIO;
- goto out;
- }
-
- size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
- if (size < expected) {
- dev_err(chip->pdev, "Unable to read remainder of result\n");
- size = -ETIME;
- goto out;
- }
-
-out:
- chip->ops->cancel(chip);
- release_locality(chip);
- return size;
-}
-
-static bool tpm_stm_i2c_req_canceled(struct tpm_chip *chip, u8 status)
-{
- return (status == TPM_STS_COMMAND_READY);
-}
-
-static const struct tpm_class_ops st_i2c_tpm = {
- .send = tpm_stm_i2c_send,
- .recv = tpm_stm_i2c_recv,
- .cancel = tpm_stm_i2c_cancel,
- .status = tpm_stm_i2c_status,
- .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- .req_canceled = tpm_stm_i2c_req_canceled,
-};
-
-#ifdef CONFIG_OF
-static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip)
-{
- struct device_node *pp;
- struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
- struct i2c_client *client = tpm_dev->client;
- int gpio;
- int ret;
-
- pp = client->dev.of_node;
- if (!pp) {
- dev_err(chip->pdev, "No platform data\n");
- return -ENODEV;
- }
-
- /* Get GPIO from device tree */
- gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
- if (gpio < 0) {
- dev_err(chip->pdev, "Failed to retrieve lpcpd-gpios from dts.\n");
- tpm_dev->io_lpcpd = -1;
- /*
- * lpcpd pin is not specified. This is not an issue as
- * power management can be also managed by TPM specific
- * commands. So leave with a success status code.
- */
- return 0;
- }
- /* GPIO request and configuration */
- ret = devm_gpio_request_one(&client->dev, gpio,
- GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
- if (ret) {
- dev_err(chip->pdev, "Failed to request lpcpd pin\n");
- return -ENODEV;
- }
- tpm_dev->io_lpcpd = gpio;
-
- return 0;
-}
-#else
-static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip)
-{
- return -ENODEV;
-}
-#endif
-
-static int tpm_stm_i2c_request_resources(struct i2c_client *client,
- struct tpm_chip *chip)
-{
- struct st33zp24_platform_data *pdata;
- struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
- int ret;
-
- pdata = client->dev.platform_data;
- if (!pdata) {
- dev_err(chip->pdev, "No platform data\n");
- return -ENODEV;
- }
-
- /* store for late use */
- tpm_dev->io_lpcpd = pdata->io_lpcpd;
-
- if (gpio_is_valid(pdata->io_lpcpd)) {
- ret = devm_gpio_request_one(&client->dev,
- pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
- "TPM IO_LPCPD");
- if (ret) {
- dev_err(chip->pdev, "%s : reset gpio_request failed\n",
- __FILE__);
- return ret;
- }
- }
-
- return 0;
-}
-
-/*
- * tpm_stm_i2c_probe initialize the TPM device
- * @param: client, the i2c_client drescription (TPM I2C description).
- * @param: id, the i2c_device_id struct.
- * @return: 0 in case of success.
- * -1 in other case.
- */
-static int
-tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
-{
- int ret;
- u8 intmask = 0;
- struct tpm_chip *chip;
- struct st33zp24_platform_data *platform_data;
- struct tpm_stm_dev *tpm_dev;
-
- if (!client) {
- pr_info("%s: i2c client is NULL. Device not accessible.\n",
- __func__);
- return -ENODEV;
- }
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_info(&client->dev, "client not i2c capable\n");
- return -ENODEV;
- }
-
- tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev),
- GFP_KERNEL);
- if (!tpm_dev)
- return -ENOMEM;
-
- chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm);
- if (IS_ERR(chip))
- return PTR_ERR(chip);
-
- TPM_VPRIV(chip) = tpm_dev;
- tpm_dev->client = client;
-
- platform_data = client->dev.platform_data;
- if (!platform_data && client->dev.of_node) {
- ret = tpm_stm_i2c_of_request_resources(chip);
- if (ret)
- goto _tpm_clean_answer;
- } else if (platform_data) {
- ret = tpm_stm_i2c_request_resources(client, chip);
- if (ret)
- goto _tpm_clean_answer;
- }
-
- chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
- chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
- chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
- chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-
- chip->vendor.locality = LOCALITY0;
-
- if (client->irq) {
- /* INTERRUPT Setup */
- init_waitqueue_head(&chip->vendor.read_queue);
- tpm_dev->intrs = 0;
-
- if (request_locality(chip) != LOCALITY0) {
- ret = -ENODEV;
- goto _tpm_clean_answer;
- }
-
- clear_interruption(tpm_dev);
- ret = devm_request_irq(&client->dev, client->irq,
- tpm_ioserirq_handler,
- IRQF_TRIGGER_HIGH,
- "TPM SERIRQ management", chip);
- if (ret < 0) {
- dev_err(chip->pdev , "TPM SERIRQ signals %d not available\n",
- client->irq);
- goto _tpm_clean_answer;
- }
-
- intmask |= TPM_INTF_CMD_READY_INT
- | TPM_INTF_STS_VALID_INT
- | TPM_INTF_DATA_AVAIL_INT;
-
- ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1);
- if (ret < 0)
- goto _tpm_clean_answer;
-
- intmask = TPM_GLOBAL_INT_ENABLE;
- ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3),
- &intmask, 1);
- if (ret < 0)
- goto _tpm_clean_answer;
-
- chip->vendor.irq = client->irq;
-
- disable_irq_nosync(chip->vendor.irq);
-
- tpm_gen_interrupt(chip);
- }
-
- tpm_get_timeouts(chip);
- tpm_do_selftest(chip);
-
- return tpm_chip_register(chip);
-_tpm_clean_answer:
- dev_info(chip->pdev, "TPM I2C initialisation fail\n");
- return ret;
-}
-
-/*
- * tpm_stm_i2c_remove remove the TPM device
- * @param: client, the i2c_client description (TPM I2C description).
- * @return: 0 in case of success.
- */
-static int tpm_stm_i2c_remove(struct i2c_client *client)
-{
- struct tpm_chip *chip =
- (struct tpm_chip *) i2c_get_clientdata(client);
-
- if (chip)
- tpm_chip_unregister(chip);
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-/*
- * tpm_stm_i2c_pm_suspend suspend the TPM device
- * @param: client, the i2c_client drescription (TPM I2C description).
- * @param: mesg, the power management message.
- * @return: 0 in case of success.
- */
-static int tpm_stm_i2c_pm_suspend(struct device *dev)
-{
- struct tpm_chip *chip = dev_get_drvdata(dev);
- struct tpm_stm_dev *tpm_dev;
- int ret = 0;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- if (gpio_is_valid(tpm_dev->io_lpcpd))
- gpio_set_value(tpm_dev->io_lpcpd, 0);
- else
- ret = tpm_pm_suspend(dev);
-
- return ret;
-} /* tpm_stm_i2c_suspend() */
-
-/*
- * tpm_stm_i2c_pm_resume resume the TPM device
- * @param: client, the i2c_client drescription (TPM I2C description).
- * @return: 0 in case of success.
- */
-static int tpm_stm_i2c_pm_resume(struct device *dev)
-{
- struct tpm_chip *chip = dev_get_drvdata(dev);
- struct tpm_stm_dev *tpm_dev;
- int ret = 0;
-
- tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
-
- if (gpio_is_valid(pin_infos->io_lpcpd)) {
- gpio_set_value(tpm_dev->io_lpcpd, 1);
- ret = wait_for_stat(chip,
- TPM_STS_VALID, chip->vendor.timeout_b,
- &chip->vendor.read_queue, false);
- } else {
- ret = tpm_pm_resume(dev);
- if (!ret)
- tpm_do_selftest(chip);
- }
- return ret;
-} /* tpm_stm_i2c_pm_resume() */
-#endif
-
-static const struct i2c_device_id tpm_stm_i2c_id[] = {
- {TPM_ST33_I2C, 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id);
-
-#ifdef CONFIG_OF
-static const struct of_device_id of_st33zp24_i2c_match[] = {
- { .compatible = "st,st33zp24-i2c", },
- {}
-};
-MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match);
-#endif
-
-static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend,
- tpm_stm_i2c_pm_resume);
-
-static struct i2c_driver tpm_stm_i2c_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = TPM_ST33_I2C,
- .pm = &tpm_stm_i2c_ops,
- .of_match_table = of_match_ptr(of_st33zp24_i2c_match),
- },
- .probe = tpm_stm_i2c_probe,
- .remove = tpm_stm_i2c_remove,
- .id_table = tpm_stm_i2c_id
-};
-
-module_i2c_driver(tpm_stm_i2c_driver);
-
-MODULE_AUTHOR("Christophe Ricard (tpmsupport-qxv4g6HH51o@public.gmane.org)");
-MODULE_DESCRIPTION("STM TPM I2C ST33 Driver");
-MODULE_VERSION("1.2.1");
-MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/st33zp24.h b/include/linux/platform_data/st33zp24.h
new file mode 100644
index 0000000..031aa8b
--- /dev/null
+++ b/include/linux/platform_data/st33zp24.h
@@ -0,0 +1,28 @@
+/*
+ * STMicroelectronics TPM Linux driver for TPM 1.2 ST33ZP24
+ * Copyright (C) 2009 - 2015 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __STM_ST33_TPM_H__
+#define __STM_ST33_TPM_H__
+
+#define TPM_ST33_I2C "st33zp24-i2c"
+#define TPM_ST33_SPI "st33zp24-spi"
+
+struct st33zp24_platform_data {
+ int io_lpcpd;
+};
+
+#endif /* __STM_ST33_TPM_H__ */
diff --git a/include/linux/platform_data/tpm_stm_st33.h b/include/linux/platform_data/tpm_stm_st33.h
deleted file mode 100644
index ff75310..0000000
--- a/include/linux/platform_data/tpm_stm_st33.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
- * Copyright (C) 2009, 2010 STMicroelectronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * STMicroelectronics version 1.2.0, Copyright (C) 2010
- * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
- * This is free software, and you are welcome to redistribute it
- * under certain conditions.
- *
- * @Author: Christophe RICARD tpmsupport-qxv4g6HH51o@public.gmane.org
- *
- * @File: stm_st33_tpm.h
- *
- * @Date: 09/15/2010
- */
-#ifndef __STM_ST33_TPM_H__
-#define __STM_ST33_TPM_H__
-
-#define TPM_ST33_I2C "st33zp24-i2c"
-#define TPM_ST33_SPI "st33zp24-spi"
-
-struct st33zp24_platform_data {
- int io_lpcpd;
-};
-
-#endif /* __STM_ST33_TPM_H__ */
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 09/10] tpm/st33zp24/spi: Add st33zp24 spi phy
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (7 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 08/10] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 10/10] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard
2015-01-12 18:26 ` [PATCH v1 00/10] st33zp24 new architecture proposal and st33zp24 spi driver Jason Gunthorpe
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
st33zp24 TIS 1.2 support also SPI. It is using a proprietary protocol to
transport TIS data.
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/st33zp24/Kconfig | 10 +
drivers/char/tpm/st33zp24/Makefile | 3 +
drivers/char/tpm/st33zp24/spi.c | 399 +++++++++++++++++++++++++++++++++++++
3 files changed, 412 insertions(+)
create mode 100644 drivers/char/tpm/st33zp24/spi.c
diff --git a/drivers/char/tpm/st33zp24/Kconfig b/drivers/char/tpm/st33zp24/Kconfig
index 51dcef5..09cb7278 100644
--- a/drivers/char/tpm/st33zp24/Kconfig
+++ b/drivers/char/tpm/st33zp24/Kconfig
@@ -18,3 +18,13 @@ config TCG_TIS_ST33ZP24_I2C
ST33ZP24 with i2c interface.
To compile this driver as a module, choose M here; the module will be
called tpm_st33zp24_i2c.
+
+config TCG_TIS_ST33ZP24_SPI
+ tristate "TPM 1.2 ST33ZP24 SPI support"
+ depends on TCG_TIS_ST33ZP24
+ depends on SPI
+ ---help---
+ This module adds support for the STMicroelectronics TPM security chip
+ ST33ZP24 with spi interface.
+ To compile this driver as a module, choose M here; the module will be
+ called tpm_st33zp24_spi.
diff --git a/drivers/char/tpm/st33zp24/Makefile b/drivers/char/tpm/st33zp24/Makefile
index 414497f..74a722e 100644
--- a/drivers/char/tpm/st33zp24/Makefile
+++ b/drivers/char/tpm/st33zp24/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_TCG_TIS_ST33ZP24) += tpm_st33zp24.o
tpm_st33zp24_i2c-objs = i2c.o
obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o
+
+tpm_st33zp24_spi-objs = spi.o
+obj-$(CONFIG_TCG_TIS_ST33ZP24_SPI) += tpm_st33zp24_spi.o
diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c
new file mode 100644
index 0000000..b54fff5
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/spi.c
@@ -0,0 +1,399 @@
+/*
+ * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24
+ * Copyright (C) 2009 - 2015 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+
+#include <linux/platform_data/st33zp24.h>
+#include <linux/tpm.h>
+
+#include "st33zp24.h"
+
+#define TPM_DATA_FIFO 0x24
+#define TPM_INTF_CAPABILITY 0x14
+
+#define TPM_DUMMY_BYTE 0x00
+#define TPM_WRITE_DIRECTION 0x80
+#define TPM_BUFSIZE 2048
+
+#define MAX_SPI_LATENCY 15
+#define LOCALITY0 0
+
+#define ST33ZP24_OK 0x5A
+#define ST33ZP24_UNDEFINED_ERR 0x80
+#define ST33ZP24_BADLOCALITY 0x81
+#define ST33ZP24_TISREGISTER_UKNOWN 0x82
+#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83
+#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84
+#define ST33ZP24_BAD_COMMAND_ORDER 0x85
+#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86
+#define ST33ZP24_TPM_FIFO_OVERFLOW 0x89
+#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A
+#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B
+#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90
+#define ST33ZP24_DUMMY_BYTES 0x00
+
+struct st33zp24_spi_phy {
+ struct spi_device *spi_device;
+ struct spi_transfer spi_xfer;
+ int io_lpcpd;
+ int latency;
+};
+
+static int st33zp24_status_to_errno(u8 code)
+{
+ switch (code) {
+ case ST33ZP24_OK:
+ return 0;
+ case ST33ZP24_UNDEFINED_ERR:
+ case ST33ZP24_BADLOCALITY:
+ case ST33ZP24_TISREGISTER_UKNOWN:
+ case ST33ZP24_LOCALITY_NOT_ACTIVATED:
+ case ST33ZP24_HASH_END_BEFORE_HASH_START:
+ case ST33ZP24_BAD_COMMAND_ORDER:
+ case ST33ZP24_UNEXPECTED_READ_FIFO:
+ case ST33ZP24_UNEXPECTED_WRITE_FIFO:
+ case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END:
+ return -EPROTO;
+ case ST33ZP24_INCORECT_RECEIVED_LENGTH:
+ case ST33ZP24_TPM_FIFO_OVERFLOW:
+ return -EMSGSIZE;
+ case ST33ZP24_DUMMY_BYTES:
+ default:
+ return -ENOSYS;
+ }
+}
+
+/*
+ * st33zp24_spi_send
+ * Send byte to the TIS register according to the ST33ZP24 SPI protocol.
+ * @param: tpm, the chip description
+ * @param: tpm_register, the tpm tis register where the data should be written
+ * @param: tpm_data, the tpm_data to write inside the tpm_register
+ * @param: tpm_size, The length of the data
+ * @return: should be zero if success else a negative error code.
+ */
+static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data,
+ int tpm_size)
+{
+ u8 data = 0;
+ int total_length = 0, nbr_dummy_bytes = 0, ret = 0;
+ struct st33zp24_spi_phy *phy = phy_id;
+ struct spi_device *dev = phy->spi_device;
+ u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf;
+ u8 *rx_buf = phy->spi_xfer.rx_buf;
+
+ /* Pre-Header */
+ data = TPM_WRITE_DIRECTION | LOCALITY0;
+ memcpy(tx_buf + total_length, &data, sizeof(data));
+ total_length++;
+ data = tpm_register;
+ memcpy(tx_buf + total_length, &data, sizeof(data));
+ total_length++;
+
+ if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) {
+ tx_buf[total_length++] = tpm_size >> 8;
+ tx_buf[total_length++] = tpm_size;
+ }
+
+ memcpy(&tx_buf[total_length], tpm_data, tpm_size);
+ total_length += tpm_size;
+
+ nbr_dummy_bytes = phy->latency;
+ memset(&tx_buf[total_length], TPM_DUMMY_BYTE, nbr_dummy_bytes);
+
+ phy->spi_xfer.len = total_length + nbr_dummy_bytes;
+
+ ret = spi_sync_transfer(dev, &phy->spi_xfer, 1);
+
+ if (ret == 0)
+ ret = rx_buf[total_length + nbr_dummy_bytes - 1];
+
+ return st33zp24_status_to_errno(ret);
+} /* st33zp24_spi_send() */
+
+/*
+ * read8_recv
+ * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
+ * @param: tpm, the chip description
+ * @param: tpm_register, the tpm tis register where the data should be read
+ * @param: tpm_data, the TPM response
+ * @param: tpm_size, tpm TPM response size to read.
+ * @return: should be zero if success else a negative error code.
+ */
+static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size)
+{
+ u8 data = 0;
+ int total_length = 0, nbr_dummy_bytes, ret;
+ struct st33zp24_spi_phy *phy = phy_id;
+ struct spi_device *dev = phy->spi_device;
+ u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf;
+ u8 *rx_buf = phy->spi_xfer.rx_buf;
+
+ /* Pre-Header */
+ data = LOCALITY0;
+ memcpy(tx_buf + total_length, &data, sizeof(data));
+ total_length++;
+ data = tpm_register;
+ memcpy(tx_buf + total_length, &data, sizeof(data));
+ total_length++;
+
+ nbr_dummy_bytes = phy->latency;
+ memset(&tx_buf[total_length], TPM_DUMMY_BYTE,
+ nbr_dummy_bytes + tpm_size);
+
+ phy->spi_xfer.len = total_length + nbr_dummy_bytes + tpm_size;
+
+ /* header + status byte + size of the data + status byte */
+ ret = spi_sync_transfer(dev, &phy->spi_xfer, 1);
+ if (tpm_size > 0 && ret == 0) {
+ ret = rx_buf[total_length + nbr_dummy_bytes - 1];
+
+ memcpy(tpm_data, rx_buf + total_length + nbr_dummy_bytes,
+ tpm_size);
+ }
+
+ return ret;
+} /* read8_reg() */
+
+/*
+ * st33zp24_spi_recv
+ * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
+ * @param: tpm, the chip description
+ * @param: tpm_register, the tpm tis register where the data should be read
+ * @param: tpm_data, the TPM response
+ * @param: tpm_size, tpm TPM response size to read.
+ * @return: number of byte written successfully: should be one if success.
+ */
+static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data,
+ int tpm_size)
+{
+ int ret;
+
+ ret = read8_reg(phy_id, tpm_register, tpm_data, tpm_size);
+ if (!ret)
+ return tpm_size;
+ return ret;
+} /* st33zp24_spi_recv() */
+
+static int evaluate_latency(void *phy_id)
+{
+ struct st33zp24_spi_phy *phy = phy_id;
+ int latency = 1, status = 0;
+ u8 data = 0;
+
+ while (!status && latency < MAX_SPI_LATENCY) {
+ phy->latency = latency;
+ status = read8_reg(phy_id, TPM_INTF_CAPABILITY, &data, 1);
+ latency++;
+ }
+ return latency - 1;
+} /* evaluate_latency() */
+
+static struct st33zp24_phy_ops spi_phy_ops = {
+ .send = st33zp24_spi_send,
+ .recv = st33zp24_spi_recv,
+};
+
+#ifdef CONFIG_OF
+static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy)
+{
+ struct device_node *pp;
+ struct spi_device *dev = phy->spi_device;
+ int gpio;
+ int ret;
+
+ pp = dev->dev.of_node;
+ if (!pp) {
+ dev_err(&dev->dev, "No platform data\n");
+ return -ENODEV;
+ }
+
+ /* Get GPIO from device tree */
+ gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
+ if (gpio < 0) {
+ dev_err(&dev->dev,
+ "Failed to retrieve lpcpd-gpios from dts.\n");
+ phy->io_lpcpd = -1;
+ /*
+ * lpcpd pin is not specified. This is not an issue as
+ * power management can be also managed by TPM specific
+ * commands. So leave with a success status code.
+ */
+ return 0;
+ }
+ /* GPIO request and configuration */
+ ret = devm_gpio_request_one(&dev->dev, gpio,
+ GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
+ if (ret) {
+ dev_err(&dev->dev, "Failed to request lpcpd pin\n");
+ return -ENODEV;
+ }
+ phy->io_lpcpd = gpio;
+
+ return 0;
+}
+#else
+static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy)
+{
+ return -ENODEV;
+}
+#endif
+
+static int tpm_stm_spi_request_resources(struct spi_device *dev,
+ struct st33zp24_spi_phy *phy)
+{
+ struct st33zp24_platform_data *pdata;
+ int ret;
+
+ pdata = dev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&dev->dev, "No platform data\n");
+ return -ENODEV;
+ }
+
+ /* store for late use */
+ phy->io_lpcpd = pdata->io_lpcpd;
+
+ if (gpio_is_valid(pdata->io_lpcpd)) {
+ ret = devm_gpio_request_one(&dev->dev,
+ pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
+ "TPM IO_LPCPD");
+ if (ret) {
+ dev_err(&dev->dev, "%s : reset gpio_request failed\n",
+ __FILE__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * tpm_st33_spi_probe initialize the TPM device
+ * @param: client, the spi_device drescription (TPM SPI description).
+ * @param: id, the spi_device_id struct.
+ * @return: 0 in case of success.
+ * -1 in other case.
+ */
+static int
+tpm_st33_spi_probe(struct spi_device *dev)
+{
+ int ret;
+ struct st33zp24_platform_data *pdata;
+ struct st33zp24_spi_phy *phy;
+
+ /* Check SPI platform functionnalities */
+ if (!dev) {
+ pr_info("%s: dev is NULL. Device is not accessible.\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy),
+ GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->spi_device = dev;
+ pdata = dev->dev.platform_data;
+ if (!pdata && dev->dev.of_node) {
+ ret = tpm_stm_spi_of_request_resources(phy);
+ if (ret)
+ return ret;
+ } else if (pdata) {
+ ret = tpm_stm_spi_request_resources(dev, phy);
+ if (ret)
+ return ret;
+ }
+
+ phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
+ (TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) *
+ sizeof(u8), GFP_KERNEL);
+ if (!phy->spi_xfer.tx_buf)
+ return -ENOMEM;
+
+ phy->spi_xfer.rx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
+ (TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) *
+ sizeof(u8), GFP_KERNEL);
+ if (!phy->spi_xfer.rx_buf)
+ return -ENOMEM;
+
+ phy->latency = evaluate_latency(phy);
+ if (phy->latency <= 0)
+ return -ENODEV;
+
+ return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq,
+ phy->io_lpcpd);
+}
+
+/*
+ * tpm_st33_spi_remove remove the TPM device
+ * @param: client, the spi_device drescription (TPM SPI description).
+ * @return: 0 in case of success.
+ */
+static int tpm_st33_spi_remove(struct spi_device *dev)
+{
+ void *tpm_data = spi_get_drvdata(dev);
+
+ if (tpm_data)
+ st33zp24_remove(tpm_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_st33zp24_spi_match[] = {
+ { .compatible = "st,st33zp24-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match);
+#endif
+
+static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend,
+ st33zp24_pm_resume);
+
+static struct spi_driver tpm_st33_spi_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = TPM_ST33_SPI,
+ .pm = &st33zp24_spi_ops,
+ .of_match_table = of_match_ptr(of_st33zp24_spi_match),
+ },
+ .probe = tpm_st33_spi_probe,
+ .remove = tpm_st33_spi_remove,
+};
+
+module_spi_driver(tpm_st33_spi_driver);
+
+MODULE_AUTHOR("Christophe Ricard (tpmsupport-qxv4g6HH51o@public.gmane.org)");
+MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver");
+MODULE_VERSION("1.3.0");
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v1 10/10] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for st33zp24 spi phy
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (8 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 09/10] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard
@ 2015-01-10 11:20 ` Christophe Ricard
2015-01-12 18:26 ` [PATCH v1 00/10] st33zp24 new architecture proposal and st33zp24 spi driver Jason Gunthorpe
10 siblings, 0 replies; 13+ messages in thread
From: Christophe Ricard @ 2015-01-10 11:20 UTC (permalink / raw)
To: PeterHuewe-Mmb7MZpHnFY
Cc: ashley-fm2HMyfA2y6tG0bUXCXiUA, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
.../bindings/security/tpm/st33zp24-spi.txt | 34 ++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt
diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt
new file mode 100644
index 0000000..923c55d
--- /dev/null
+++ b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt
@@ -0,0 +1,34 @@
+* STMicroelectronics SAS. ST33ZP24 TPM SoC
+
+Required properties:
+- compatible: Should be "st,st33zp24-spi".
+- spi-max-frequency: Maximum SPI frequency (<= 10000000).
+
+Optional ST33ZP24 Properties:
+- interrupt-parent: phandle for the interrupt gpio controller
+- interrupts: GPIO interrupt to which the chip is connected
+- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state.
+If set, power must be present when the platform is going into sleep/hibernate mode.
+
+Optional SoC Specific Properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+
+Example (for ARM-based BeagleBoard xM with ST33ZP24 on SPI2):
+
+&i2c2 {
+
+ status = "okay";
+
+ st33zp24@0 {
+
+ compatible = "st,st33zp24-spi";
+
+ spi-max-frequency = <10000000>;
+
+ interrupt-parent = <&gpio5>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+
+ lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+ };
+};
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v1 00/10] st33zp24 new architecture proposal and st33zp24 spi driver
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (9 preceding siblings ...)
2015-01-10 11:20 ` [PATCH v1 10/10] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard
@ 2015-01-12 18:26 ` Jason Gunthorpe
10 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe @ 2015-01-12 18:26 UTC (permalink / raw)
To: Christophe Ricard
Cc: PeterHuewe-Mmb7MZpHnFY, ashley-fm2HMyfA2y6tG0bUXCXiUA,
tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
On Sat, Jan 10, 2015 at 12:20:21PM +0100, Christophe Ricard wrote:
> Hi,
>
> The following patchset:
> - clean the current tpm_i2c_stm_st33 driver
> - propose a new architecture allowing to share a core st33zp24 data management
> layer with different phy (i2c & spi). For st33zp24 both phy have a proprietary transport
> protocol. Both are relying on the TCG TIS protocol. At the end, it simplifies the maintenance.
> - Add an spi phy allowing to support st33zp24 using with an SPI bus.
I read through this and not much stood out, just one comment on patch 8
Patch 4 and 6 do not seem to be part of this series and seem to be
bug fixes, the should be seperated so Peter can fast track them
into the kernel.
So excluding patch 8:
Reviewed-By: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
Jason
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 08/10] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)
[not found] ` <1420888831-17491-9-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
@ 2015-01-12 20:26 ` Jason Gunthorpe
0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe @ 2015-01-12 20:26 UTC (permalink / raw)
To: Christophe Ricard
Cc: PeterHuewe-Mmb7MZpHnFY, ashley-fm2HMyfA2y6tG0bUXCXiUA,
tpmdd-yWjUBOtONefk1uMJSBkQmQ,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
christophe-h.ricard-qxv4g6HH51o, jean-luc.blanc-qxv4g6HH51o,
benoit.houyere-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA
On Sat, Jan 10, 2015 at 12:20:29PM +0100, Christophe Ricard wrote:
For reference:
> -static int tpm_stm_i2c_remove(struct i2c_client *client)
> -{
> - struct tpm_chip *chip =
> - (struct tpm_chip *) i2c_get_clientdata(client);
> -
> - if (chip)
> - tpm_chip_unregister(chip);
> -
> - return 0;
> -}
Became:
> +static int st33zp24_i2c_remove(struct i2c_client *client)
> +{
> + void *tpm_data = i2c_get_clientdata(client);
> +
> + if (tpm_data)
> + st33zp24_remove(tpm_data);
> +
> + return 0;
> +}
The value of i2c_get_clientdata hasn't/can't be changed, it must be
the tpm_chip, so tpm_data should be tpm_chip *, not void *.
The 'if (tpm_data)' is an anti-pattern, please remove it
Same comment applies to patch 9
> +int st33zp24_remove(void *tpm_data)
> +{
> + struct st33zp24_dev *tpm_dev = (struct st33zp24_dev *)tpm_data;
> + struct tpm_chip *chip = tpm_dev->chip;
> +
> + if (chip)
> + tpm_chip_unregister(chip);
> +
> + return 0;
> +}
Now this looks wrong. st33zp24_dev is the TPM_VPRIV of the chip, but
tpm_data is the tpm_chip already, so that cast is surely wrong.
Again, remove the 'if (chip)' anti-pattern.
> +static struct st33zp24_phy_ops i2c_phy_ops = {
> + .send = st33zp24_i2c_send,
> + .recv = st33zp24_i2c_recv,
> +};
Should be 'static const struct', same comment for patch 9
> + tpm_dev = devm_kzalloc(dev, sizeof(struct st33zp24_dev),
> + GFP_KERNEL);
> + if (!tpm_dev)
> + return -ENOMEM;
> +
> + chip = tpmm_chip_alloc(dev, &st33zp24_tpm);
> + if (IS_ERR(chip))
> + return PTR_ERR(chip);
It is idomatic in the TPM drivers for the tpmm_chip_alloc to be first,
then the priv allocation to be second. Someday we might merge the two
calls.
Jason
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2015-01-12 20:26 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-10 11:20 [PATCH v1 00/10] st33zp24 new architecture proposal and st33zp24 spi driver Christophe Ricard
[not found] ` <1420888831-17491-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-10 11:20 ` [PATCH v1 01/10] tpm/tpm_i2c_stm_st33: Remove sparse spaces Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 02/10] tpm/tpm_i2c_stm_st33: Sanity cleanup Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 03/10] tpm/tpm_i2c_stm_st33: Replace remaining r by ret Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 04/10] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 05/10] tpm/tpm_i2c_stm_st33: Change tpm_i2c_stm_st33.h to tpm_stm_st33.h Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 06/10] tpm/tpm_i2c_stm_st33: Add status check when reading data on the FIFO Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 07/10] tpm/tpm_i2c_stm_st33/dts/st33zp24-i2c: Rename st33zp24 dts documentation Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 08/10] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard
[not found] ` <1420888831-17491-9-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-12 20:26 ` Jason Gunthorpe
2015-01-10 11:20 ` [PATCH v1 09/10] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard
2015-01-10 11:20 ` [PATCH v1 10/10] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard
2015-01-12 18:26 ` [PATCH v1 00/10] st33zp24 new architecture proposal and st33zp24 spi driver Jason Gunthorpe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).