* [PATCH v5 0/4] st33zp24 new architecture proposal and st33zp24 spi driver
@ 2015-01-27 21:57 Christophe Ricard
[not found] ` <1422395850-21644-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: Christophe Ricard @ 2015-01-27 21:57 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:
- 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:
d4989d9f693b9502f9288da5db279c2f8c2e50be tpm/tpm_tis: Add missing ifdef CONFIG_ACPI for pnp_acpi_device
I confirm also Jarkko Sakkinen's changes are working with this product with both phy's.
- v2 takes into account feedbacks from Jason Gunthorpe.
- v3 is reduced to 4 patches as 6 out of 10 got accepted for 3.20. Also compare to v2:
* Fix build issue with patch v2 04/10 "Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev"
* Fix link issue with patch v2 08/10 "Split tpm_i2c_tpm_st33 in 2 layers (core + phy)" when building as a module.
The symbols wasn't exported in st33zp24.c.
* Add missing MODULE_LICENSE in patch v2 09/10 "Add st33zp24 spi phy"
* Fix node example in dts spi documentation in patch v2 10/10 "Add dts documentation for st33zp24 spi phy"
* Fix typo on Jason Gunthorpe first name. Sorry for that :(...
* Change contact email address as tpmsupport-qxv4g6HH51o@public.gmane.org is no more valid
- v4 adds missing module_license in st33zp24
- v5 includes as best as possible PeterHuewe comments.
Best Regards
Christophe
Christophe Ricard (4):
tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct
st33zp24_platform_data to tpm_stm_dev
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-spi.txt | 34 +
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 | 276 +++++++
drivers/char/tpm/st33zp24/spi.c | 386 +++++++++
drivers/char/tpm/st33zp24/st33zp24.c | 688 ++++++++++++++++
drivers/char/tpm/st33zp24/st33zp24.h | 37 +
drivers/char/tpm/tpm_i2c_stm_st33.c | 911 ---------------------
include/linux/platform_data/st33zp24.h | 28 +
include/linux/platform_data/tpm_stm_st33.h | 39 -
12 files changed, 1493 insertions(+), 961 deletions(-)
create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24-spi.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_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] 11+ messages in thread
* [PATCH v5 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev
[not found] ` <1422395850-21644-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
@ 2015-01-27 21:57 ` Christophe Ricard
2015-01-27 21:57 ` [PATCH v5 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard
` (2 subsequent siblings)
3 siblings, 0 replies; 11+ messages in thread
From: Christophe Ricard @ 2015-01-27 21:57 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.
Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
Signed-off-by: Christophe Ricard <christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
---
drivers/char/tpm/tpm_i2c_stm_st33.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 612845b..882c60a 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -837,11 +837,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);
@@ -856,12 +859,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;
- if (gpio_is_valid(pin_infos->io_lpcpd)) {
- gpio_set_value(pin_infos->io_lpcpd, 1);
+ tpm_dev = (struct tpm_stm_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);
--
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] 11+ messages in thread
* [PATCH v5 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)
[not found] ` <1422395850-21644-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-27 21:57 ` [PATCH v5 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard
@ 2015-01-27 21:57 ` Christophe Ricard
[not found] ` <1422395850-21644-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-27 21:57 ` [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard
2015-01-27 21:57 ` [PATCH v5 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard
3 siblings, 1 reply; 11+ messages in thread
From: Christophe Ricard @ 2015-01-27 21:57 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.
Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
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 | 278 +++++++++
drivers/char/tpm/st33zp24/st33zp24.c | 688 ++++++++++++++++++++++
drivers/char/tpm/st33zp24/st33zp24.h | 34 ++
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, 1059 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..95e3091
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/i2c.c
@@ -0,0 +1,278 @@
+/*
+ * 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/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/tpm.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 const 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)
+{
+ struct tpm_chip *chip = i2c_get_clientdata(client);
+
+ return st33zp24_remove(chip);
+}
+
+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("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@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..0aceb0e
--- /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 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;
+ const 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 the current command execution or
+ * set STS to COMMAND READY.
+ * @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)
+ return ret;
+
+ 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));
+
+ /* could not get locality */
+ return -EACCES;
+} /* 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 value
+ * @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)
+ return -EBUSY;
+
+ tpm_reg = TPM_STS + 1;
+ burstcnt = temp;
+ status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1);
+ if (status < 0)
+ return -EBUSY;
+
+ burstcnt |= temp << 8;
+ if (burstcnt)
+ return burstcnt;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+ 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);
+
+ do {
+ if (ret == -ERESTARTSYS && freezing(current))
+ clear_thread_flag(TIF_SIGPENDING);
+
+ 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;
+ }
+ } while (ret == -ERESTARTSYS && freezing(current));
+
+ 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;
+ }
+
+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, const 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;
+
+ chip = tpmm_chip_alloc(dev, &st33zp24_tpm);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ tpm_dev = devm_kzalloc(dev, sizeof(struct st33zp24_dev),
+ GFP_KERNEL);
+ if (!tpm_dev)
+ return -ENOMEM;
+
+ 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;
+}
+EXPORT_SYMBOL(st33zp24_probe);
+
+/*
+ * st33zp24_remove remove the TPM device
+ * @param: tpm_data, the tpm phy.
+ * @return: 0 in case of success.
+ */
+int st33zp24_remove(struct tpm_chip *chip)
+{
+ tpm_chip_unregister(chip);
+ return 0;
+}
+EXPORT_SYMBOL(st33zp24_remove);
+
+#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_pm_suspend() */
+EXPORT_SYMBOL(st33zp24_pm_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() */
+EXPORT_SYMBOL(st33zp24_pm_resume);
+#endif
+
+MODULE_AUTHOR("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@public.gmane.org)");
+MODULE_DESCRIPTION("ST33ZP24 TPM 1.2 driver");
+MODULE_VERSION("1.3.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h
new file mode 100644
index 0000000..43ad39a
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/st33zp24.h
@@ -0,0 +1,34 @@
+/*
+ * 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 __LOCAL_ST33ZP24_H__
+#define __LOCAL_ST33ZP24_H__
+
+struct st33zp24_phy_ops {
+ int (*send)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size);
+ int (*recv)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size);
+};
+
+#ifdef CONFIG_PM_SLEEP
+int st33zp24_pm_suspend(struct device *dev);
+int st33zp24_pm_resume(struct device *dev);
+#endif
+
+int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops,
+ struct device *dev, int irq, int io_lpcpd);
+int st33zp24_remove(struct tpm_chip *chip);
+#endif /* __LOCAL_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 882c60a..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(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;
-} /* 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..817dfdb
--- /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 __ST33ZP24_H__
+#define __ST33ZP24_H__
+
+#define TPM_ST33_I2C "st33zp24-i2c"
+#define TPM_ST33_SPI "st33zp24-spi"
+
+struct st33zp24_platform_data {
+ int io_lpcpd;
+};
+
+#endif /* __ST33ZP24_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] 11+ messages in thread
* [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy
[not found] ` <1422395850-21644-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-27 21:57 ` [PATCH v5 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard
2015-01-27 21:57 ` [PATCH v5 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard
@ 2015-01-27 21:57 ` Christophe Ricard
[not found] ` <1422395850-21644-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-27 21:57 ` [PATCH v5 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard
3 siblings, 1 reply; 11+ messages in thread
From: Christophe Ricard @ 2015-01-27 21:57 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.
Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
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/i2c.c | 2 -
drivers/char/tpm/st33zp24/spi.c | 386 +++++++++++++++++++++++++++++++++++
drivers/char/tpm/st33zp24/st33zp24.h | 3 +
5 files changed, 402 insertions(+), 2 deletions(-)
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/i2c.c b/drivers/char/tpm/st33zp24/i2c.c
index 95e3091..ad1ee18 100644
--- a/drivers/char/tpm/st33zp24/i2c.c
+++ b/drivers/char/tpm/st33zp24/i2c.c
@@ -27,8 +27,6 @@
#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;
diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c
new file mode 100644
index 0000000..b9ef57c
--- /dev/null
+++ b/drivers/char/tpm/st33zp24/spi.c
@@ -0,0 +1,386 @@
+/*
+ * 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/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/tpm.h>
+#include <linux/platform_data/st33zp24.h>
+
+#include "st33zp24.h"
+
+#define TPM_DATA_FIFO 0x24
+#define TPM_INTF_CAPABILITY 0x14
+
+#define TPM_DUMMY_BYTE 0x00
+
+#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: 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: 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: 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: 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: 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_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 const 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: dev, the spi_device drescription (TPM SPI description).
+ * @return: 0 in case of success.
+ * or a negative value describing the error.
+ */
+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;
+ }
+
+ /* max tpm tx buffer(TPM_BUFSIZE) + max tpm rx buffer(TPM_BUFSIZE / 2)
+ * + MAX_SPI_LATENCY.
+ */
+ phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
+ (TPM_BUFSIZE / 2) + MAX_SPI_LATENCY),
+ GFP_KERNEL);
+ if (!phy->spi_xfer.tx_buf)
+ return -ENOMEM;
+
+ phy->spi_xfer.rx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
+ (TPM_BUFSIZE / 2) + MAX_SPI_LATENCY),
+ 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)
+{
+ struct tpm_chip *chip = spi_get_drvdata(dev);
+
+ return st33zp24_remove(chip);
+}
+
+#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("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@public.gmane.org)");
+MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver");
+MODULE_VERSION("1.3.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h
index 43ad39a..c207ceb 100644
--- a/drivers/char/tpm/st33zp24/st33zp24.h
+++ b/drivers/char/tpm/st33zp24/st33zp24.h
@@ -18,6 +18,9 @@
#ifndef __LOCAL_ST33ZP24_H__
#define __LOCAL_ST33ZP24_H__
+#define TPM_WRITE_DIRECTION 0x80
+#define TPM_BUFSIZE 2048
+
struct st33zp24_phy_ops {
int (*send)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size);
int (*recv)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_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] 11+ messages in thread
* [PATCH v5 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for st33zp24 spi phy
[not found] ` <1422395850-21644-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
` (2 preceding siblings ...)
2015-01-27 21:57 ` [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard
@ 2015-01-27 21:57 ` Christophe Ricard
3 siblings, 0 replies; 11+ messages in thread
From: Christophe Ricard @ 2015-01-27 21:57 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
Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
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..158b016
--- /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 SPI4):
+
+&mcspi4 {
+
+ 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] 11+ messages in thread
* Re: [PATCH v5 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy)
[not found] ` <1422395850-21644-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
@ 2015-01-28 6:34 ` Jarkko Sakkinen
0 siblings, 0 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2015-01-28 6:34 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,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/
On Tue, Jan 27, 2015 at 10:57:28PM +0100, Christophe Ricard wrote:
> 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.
>
> Reviewed-by: Jason Gunthorpe <jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
Acked-by: Jarkko Sakkinen<jarkko.sakknen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Just checked that chip_register/unregister are done in correct places,
register after init and unregister before deinit.
> 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 | 278 +++++++++
> drivers/char/tpm/st33zp24/st33zp24.c | 688 ++++++++++++++++++++++
> drivers/char/tpm/st33zp24/st33zp24.h | 34 ++
> 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, 1059 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..95e3091
> --- /dev/null
> +++ b/drivers/char/tpm/st33zp24/i2c.c
> @@ -0,0 +1,278 @@
> +/*
> + * 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/i2c.h>
> +#include <linux/gpio.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_gpio.h>
> +#include <linux/tpm.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 const 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)
> +{
> + struct tpm_chip *chip = i2c_get_clientdata(client);
> +
> + return st33zp24_remove(chip);
> +}
> +
> +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("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@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..0aceb0e
> --- /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 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;
> + const 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 the current command execution or
> + * set STS to COMMAND READY.
> + * @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)
> + return ret;
> +
> + 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));
> +
> + /* could not get locality */
> + return -EACCES;
> +} /* 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 value
> + * @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)
> + return -EBUSY;
> +
> + tpm_reg = TPM_STS + 1;
> + burstcnt = temp;
> + status = tpm_dev->ops->recv(tpm_dev->phy_id, tpm_reg, &temp, 1);
> + if (status < 0)
> + return -EBUSY;
> +
> + burstcnt |= temp << 8;
> + if (burstcnt)
> + return burstcnt;
> + msleep(TPM_TIMEOUT);
> + } while (time_before(jiffies, stop));
> + 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);
> +
> + do {
> + if (ret == -ERESTARTSYS && freezing(current))
> + clear_thread_flag(TIF_SIGPENDING);
> +
> + 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;
> + }
> + } while (ret == -ERESTARTSYS && freezing(current));
> +
> + 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;
> + }
> +
> +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, const 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;
> +
> + chip = tpmm_chip_alloc(dev, &st33zp24_tpm);
> + if (IS_ERR(chip))
> + return PTR_ERR(chip);
> +
> + tpm_dev = devm_kzalloc(dev, sizeof(struct st33zp24_dev),
> + GFP_KERNEL);
> + if (!tpm_dev)
> + return -ENOMEM;
> +
> + 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;
> +}
> +EXPORT_SYMBOL(st33zp24_probe);
> +
> +/*
> + * st33zp24_remove remove the TPM device
> + * @param: tpm_data, the tpm phy.
> + * @return: 0 in case of success.
> + */
> +int st33zp24_remove(struct tpm_chip *chip)
> +{
> + tpm_chip_unregister(chip);
> + return 0;
> +}
> +EXPORT_SYMBOL(st33zp24_remove);
> +
> +#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_pm_suspend() */
> +EXPORT_SYMBOL(st33zp24_pm_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() */
> +EXPORT_SYMBOL(st33zp24_pm_resume);
> +#endif
> +
> +MODULE_AUTHOR("TPM support (TPMsupport-nkJGhpqTU55BDgjK7y7TUQ@public.gmane.org)");
> +MODULE_DESCRIPTION("ST33ZP24 TPM 1.2 driver");
> +MODULE_VERSION("1.3.0");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h
> new file mode 100644
> index 0000000..43ad39a
> --- /dev/null
> +++ b/drivers/char/tpm/st33zp24/st33zp24.h
> @@ -0,0 +1,34 @@
> +/*
> + * 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 __LOCAL_ST33ZP24_H__
> +#define __LOCAL_ST33ZP24_H__
> +
> +struct st33zp24_phy_ops {
> + int (*send)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size);
> + int (*recv)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size);
> +};
> +
> +#ifdef CONFIG_PM_SLEEP
> +int st33zp24_pm_suspend(struct device *dev);
> +int st33zp24_pm_resume(struct device *dev);
> +#endif
> +
> +int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops,
> + struct device *dev, int irq, int io_lpcpd);
> +int st33zp24_remove(struct tpm_chip *chip);
> +#endif /* __LOCAL_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 882c60a..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(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;
> -} /* 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..817dfdb
> --- /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 __ST33ZP24_H__
> +#define __ST33ZP24_H__
> +
> +#define TPM_ST33_I2C "st33zp24-i2c"
> +#define TPM_ST33_SPI "st33zp24-spi"
> +
> +struct st33zp24_platform_data {
> + int io_lpcpd;
> +};
> +
> +#endif /* __ST33ZP24_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
/Jarkko
--
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] 11+ messages in thread
* Aw: [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy
[not found] ` <1422395850-21644-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
@ 2015-01-28 16:48 ` Peter Huewe
2015-01-28 19:13 ` RICARD Christophe
0 siblings, 1 reply; 11+ messages in thread
From: Peter Huewe @ 2015-01-28 16:48 UTC (permalink / raw)
To: Christophe Ricard
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 Christophe,
sorry to be nitty picky but I still don't get this calculation
+ /* max tpm tx buffer(TPM_BUFSIZE) + max tpm rx buffer(TPM_BUFSIZE / 2)
+ * + MAX_SPI_LATENCY.
+ */
+ phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
+ (TPM_BUFSIZE / 2) + MAX_SPI_LATENCY),
+ GFP_KERNEL);
+ if (!phy->spi_xfer.tx_buf)
+ return -ENOMEM;
+
+ phy->spi_xfer.rx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
+ (TPM_BUFSIZE / 2) + MAX_SPI_LATENCY),
+ GFP_KERNEL);
+ if (!phy->spi_xfer.rx_buf)
+ return -ENOMEM;
and the comment
+ /* max tpm tx buffer(TPM_BUFSIZE) + max tpm rx buffer(TPM_BUFSIZE / 2)
+ * + MAX_SPI_LATENCY.
does not help either.
Why do you define TPM_BUFSIZE as 2048, add TPM_BUFSIZE/2 and something called MAX_SPI_LATENCY to it to use it as your buffer size?
Latency is for me something timing related.
Since you use this TPM_BUFSIZE only in these two lines I'd be happy with either
define which has this magical 2048+2014+15
or (maybe better) add a reasonable comment describing the meaning of this strange calculation.
Thanks,
Peter
--
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] 11+ messages in thread
* Re: Aw: [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy
2015-01-28 16:48 ` Aw: " Peter Huewe
@ 2015-01-28 19:13 ` RICARD Christophe
[not found] ` <54C934DD.2040109-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: RICARD Christophe @ 2015-01-28 19:13 UTC (permalink / raw)
To: Peter Huewe
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 Peter,
A TPM command can be up to 2048 byte, A TPM response can be up to 1024 byte.
Between command and response, there are latency byte (up to 15 usually
on st33zp24 2 are enough).
Overall when sending a command and expecting an answer we need in worst
case:
2048 (for the TPM command) + 1024 (for the TPM answer). We need some
latency byte before the answer is available (max 15).
We have 2048 + 1024 + 15.
I will go for a define making the code more readable together with a
comment.
Best Regards
Christophe
Le 28/01/2015 17:48, Peter Huewe a écrit :
> Hi Christophe,
>
> sorry to be nitty picky but I still don't get this calculation
>
>
> + /* max tpm tx buffer(TPM_BUFSIZE) + max tpm rx buffer(TPM_BUFSIZE / 2)
> + * + MAX_SPI_LATENCY.
> + */
> + phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
> + (TPM_BUFSIZE / 2) + MAX_SPI_LATENCY),
> + GFP_KERNEL);
> + if (!phy->spi_xfer.tx_buf)
> + return -ENOMEM;
> +
> + phy->spi_xfer.rx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
> + (TPM_BUFSIZE / 2) + MAX_SPI_LATENCY),
> + GFP_KERNEL);
> + if (!phy->spi_xfer.rx_buf)
> + return -ENOMEM;
>
>
> and the comment
> + /* max tpm tx buffer(TPM_BUFSIZE) + max tpm rx buffer(TPM_BUFSIZE / 2)
> + * + MAX_SPI_LATENCY.
> does not help either.
>
>
>
> Why do you define TPM_BUFSIZE as 2048, add TPM_BUFSIZE/2 and something called MAX_SPI_LATENCY to it to use it as your buffer size?
> Latency is for me something timing related.
>
> Since you use this TPM_BUFSIZE only in these two lines I'd be happy with either
> define which has this magical 2048+2014+15
> or (maybe better) add a reasonable comment describing the meaning of this strange calculation.
>
>
> Thanks,
> Peter
--
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] 11+ messages in thread
* Re: Aw: [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy
[not found] ` <54C934DD.2040109-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2015-01-28 20:36 ` Jason Gunthorpe
[not found] ` <20150128203625.GB10610-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: Jason Gunthorpe @ 2015-01-28 20:36 UTC (permalink / raw)
To: RICARD Christophe
Cc: Peter Huewe, 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 Wed, Jan 28, 2015 at 08:13:33PM +0100, RICARD Christophe wrote:
> Hi Peter,
>
> A TPM command can be up to 2048 byte, A TPM response can be up to 1024 byte.
> Between command and response, there are latency byte (up to 15
> usually on st33zp24 2 are enough).
>
> Overall when sending a command and expecting an answer we need in
> worst case:
> 2048 (for the TPM command) + 1024 (for the TPM answer). We need
> some latency byte before the answer is available (max 15).
> We have 2048 + 1024 + 15.
>
> I will go for a define making the code more readable together with a
> comment.
You can probably just make these static arrays inside your priv
structure and drop these independent allocations:
> >+ phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
> >+ (TPM_BUFSIZE / 2) + MAX_SPI_LATENCY),
> >+ GFP_KERNEL);
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] 11+ messages in thread
* Re: Aw: [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy
[not found] ` <20150128203625.GB10610-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
@ 2015-01-28 21:49 ` peterhuewe-Mmb7MZpHnFY
[not found] ` <78f08c37-9a15-4007-88f6-2c79ba113e6f-2ueSQiBKiTY7tOexoI0I+QC/G2K4zDHf@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: peterhuewe-Mmb7MZpHnFY @ 2015-01-28 21:49 UTC (permalink / raw)
To: Jason Gunthorpe, RICARD Christophe
Cc: 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 28. Januar 2015 21:36:25 MEZ, Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
>On Wed, Jan 28, 2015 at 08:13:33PM +0100, RICARD Christophe wrote:
>> Hi Peter,
>>
>> A TPM command can be up to 2048 byte, A TPM response can be up to
>1024 byte.
>> Between command and response, there are latency byte (up to 15
>> usually on st33zp24 2 are enough).
>>
>> Overall when sending a command and expecting an answer we need in
>> worst case:
>> 2048 (for the TPM command) + 1024 (for the TPM answer). We need
>> some latency byte before the answer is available (max 15).
>> We have 2048 + 1024 + 15.
>>
>> I will go for a define making the code more readable together with a
>> comment.
>
>You can probably just make these static arrays inside your priv
>structure and drop these independent allocations:
Hmm, doesn' t spi stuff need dma'able buffers?
Peter
--
Sent from my mobile.
--
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] 11+ messages in thread
* Re: Aw: [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy
[not found] ` <78f08c37-9a15-4007-88f6-2c79ba113e6f-2ueSQiBKiTY7tOexoI0I+QC/G2K4zDHf@public.gmane.org>
@ 2015-01-28 21:53 ` Jason Gunthorpe
0 siblings, 0 replies; 11+ messages in thread
From: Jason Gunthorpe @ 2015-01-28 21:53 UTC (permalink / raw)
To: peterhuewe-Mmb7MZpHnFY
Cc: RICARD Christophe, 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 Wed, Jan 28, 2015 at 10:49:39PM +0100, peterhuewe-Mmb7MZpHnFY@public.gmane.org wrote:
> >> I will go for a define making the code more readable together with a
> >> comment.
> >
> >You can probably just make these static arrays inside your priv
> >structure and drop these independent allocations:
>
> Hmm, doesn' t spi stuff need dma'able buffers?
Well, the buffer allocation is already devm_kalloc, so it won't change
the properties to combine it with the devm_kalloc that creates the
priv structure.
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] 11+ messages in thread
end of thread, other threads:[~2015-01-28 21:53 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-27 21:57 [PATCH v5 0/4] st33zp24 new architecture proposal and st33zp24 spi driver Christophe Ricard
[not found] ` <1422395850-21644-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-27 21:57 ` [PATCH v5 1/4] tpm/tpm_i2c_stm_st33: Replace access to io_lpcpd from struct st33zp24_platform_data to tpm_stm_dev Christophe Ricard
2015-01-27 21:57 ` [PATCH v5 2/4] tpm/tpm_i2c_stm_st33: Split tpm_i2c_tpm_st33 in 2 layers (core + phy) Christophe Ricard
[not found] ` <1422395850-21644-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-28 6:34 ` Jarkko Sakkinen
2015-01-27 21:57 ` [PATCH v5 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy Christophe Ricard
[not found] ` <1422395850-21644-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>
2015-01-28 16:48 ` Aw: " Peter Huewe
2015-01-28 19:13 ` RICARD Christophe
[not found] ` <54C934DD.2040109-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-28 20:36 ` Jason Gunthorpe
[not found] ` <20150128203625.GB10610-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2015-01-28 21:49 ` peterhuewe-Mmb7MZpHnFY
[not found] ` <78f08c37-9a15-4007-88f6-2c79ba113e6f-2ueSQiBKiTY7tOexoI0I+QC/G2K4zDHf@public.gmane.org>
2015-01-28 21:53 ` Jason Gunthorpe
2015-01-27 21:57 ` [PATCH v5 4/4] tpm/st33zp24/dts/st33zp24-spi: Add dts documentation for " Christophe Ricard
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.