* [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
[parent not found: <1422395850-21644-1-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>]
* [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
[parent not found: <1422395850-21644-3-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>]
* 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
* [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
[parent not found: <1422395850-21644-4-git-send-email-christophe-h.ricard-qxv4g6HH51o@public.gmane.org>]
* 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
[parent not found: <54C934DD.2040109-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* 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
[parent not found: <20150128203625.GB10610-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>]
* 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
[parent not found: <78f08c37-9a15-4007-88f6-2c79ba113e6f-2ueSQiBKiTY7tOexoI0I+QC/G2K4zDHf@public.gmane.org>]
* 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
* [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
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 a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).