linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
@ 2012-11-14 14:31 Mathias Leblanc
  2012-11-14 14:31 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C CHROMIUM Mathias Leblanc
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Mathias Leblanc @ 2012-11-14 14:31 UTC (permalink / raw)
  To: Kent Yoder, Rajiv Andrade, Marcel Selhorst, Sirrix AG,
	tpmdd-devel, Debora Velarde
  Cc: linux-kernel, Jean-Luc Blanc, Mathias Leblanc

 * 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.

This is the driver for TPM chip from ST Microelectronics.

If you have a TPM security chip from STMicroelectronics working with
an I2C, in menuconfig or .config choose the tpm driver on
device --> tpm and activate the protocol of your choice before compiling
the kernel.
The driver will be accessible from within Linux.

Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM OS

Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com>
---
 drivers/char/tpm/tpm_stm_st33_i2c.c  |  903 ++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm_stm_st33_i2c.h  |   81 +++
 include/linux/i2c/tpm_stm_st33_i2c.h |   47 ++
 3 files changed, 1031 insertions(+)
 create mode 100644 drivers/char/tpm/tpm_stm_st33_i2c.c
 create mode 100644 drivers/char/tpm/tpm_stm_st33_i2c.h
 create mode 100644 include/linux/i2c/tpm_stm_st33_i2c.h

diff --git a/drivers/char/tpm/tpm_stm_st33_i2c.c b/drivers/char/tpm/tpm_stm_st33_i2c.c
new file mode 100644
index 0000000..b96bb8c
--- /dev/null
+++ b/drivers/char/tpm/tpm_stm_st33_i2c.c
@@ -0,0 +1,903 @@
+/*
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 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@st.com
+ *
+ * @File: tpm_stm_st33_i2c.c
+ *
+ * @Synopsis:
+ *	09/15/2010:	First shot driver tpm_tis driver for 
+			lpc is used as model.
+ */
+
+#include <linux/i2c/tpm_stm_st33_i2c.h>
+
+#include "tpm_stm_st33_i2c.h"
+
+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,
+};
+
+/*
+ * 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 i2c_client *client, u8 tpm_register,
+		      u8 *tpm_data, u16 tpm_size)
+{
+	u8 data;
+	int value = 0;
+	struct st33zp24_platform_data *pin_infos;
+
+	pin_infos = client->dev.platform_data;
+
+	data = tpm_register;
+	memcpy(pin_infos->tpm_i2c_buffer[0], &data, sizeof(data));
+	memcpy(pin_infos->tpm_i2c_buffer[0] + 1, tpm_data, tpm_size);
+	value = i2c_master_send(client, pin_infos->tpm_i2c_buffer[0],
+				tpm_size + 1);
+	return value;
+} /* 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 i2c_client *client, u8 tpm_register,
+		    u8 *tpm_data, int tpm_size)
+{
+	u8 status = 0;
+	u8 data;
+	struct st33zp24_platform_data *pin_infos;
+
+	pin_infos = client->dev.platform_data;
+
+	data = TPM_DUMMY_BYTE;
+	status = write8_reg(client, tpm_register, &data, 1);
+	if (status == 2)
+		status = i2c_master_recv(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: client, 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(client, tpm_register, tpm_data, tpm_size) \
+	(write8_reg(client, 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, 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(client, tpm_register, tpm_data, tpm_size) \
+	(read8_reg(client, tpm_register, tpm_data, tpm_size))
+
+/*
+ * clear_interruption
+ * clear the TPM interrupt register.
+ * @param: tpm, the chip description
+ */
+static void clear_interruption(struct i2c_client *client)
+{
+	u8 interrupt;
+	I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+	I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+	I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+} /* clear_interruption() */
+
+/*
+ * _wait_for_interrupt_serirq_timeout
+ * @param: tpm, the chip description
+ * @param: timeout, the timeout of the interrupt
+ * @return: the status of the interruption.
+ */
+static int _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
+						unsigned long timeout)
+{
+	int status;
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	status = wait_for_completion_interruptible_timeout(
+					&pin_infos->irq_detection,
+						timeout);
+	if (status > 0)
+		enable_irq(gpio_to_irq(pin_infos->io_serirq));
+	gpio_direction_input(pin_infos->io_serirq);
+
+	return status;
+} /* wait_for_interrupt_serirq_timeout() */
+
+int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
+				 unsigned long timeout)
+{
+	int status = 2;
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	status = _wait_for_interrupt_serirq_timeout(chip, timeout);
+	if (!status) {
+		status = -EBUSY;
+	} else{
+		clear_interruption(client);
+		if (condition)
+			status = 1;
+	}
+	return status;
+}
+
+/*
+ * 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 i2c_client *client;
+	u8 data;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	data = TPM_STS_COMMAND_READY;
+	I2C_WRITE_DATA(client, TPM_STS, &data, 1);
+	if (chip->vendor.irq)
+		wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a);
+}	/* 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 i2c_client *client;
+	u8 data;
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	I2C_READ_DATA(client, 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 i2c_client *client;
+	u8 data;
+	u8 status;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	status = I2C_READ_DATA(client, 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 rc;
+	struct i2c_client *client;
+	u8 data;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	if (check_locality(chip) == chip->vendor.locality)
+		return chip->vendor.locality;
+
+	data = TPM_ACCESS_REQUEST_USE;
+	rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
+	if (rc < 0)
+		goto end;
+
+	if (chip->vendor.irq) {
+		rc = wait_for_serirq_timeout(chip, (check_locality
+						       (chip) >= 0),
+						      chip->vendor.timeout_a);
+		if (rc > 0)
+			return chip->vendor.locality;
+	} else{
+		stop = jiffies + chip->vendor.timeout_a;
+		do {
+			if (check_locality(chip) >= 0)
+				return chip->vendor.locality;
+			msleep(TPM_TIMEOUT);
+		} while (time_before(jiffies, stop));
+	}
+	rc = -EACCES;
+end:
+	return rc;
+} /* request_locality() */
+
+/*
+ * release_locality release the active locality
+ * @param: chip, the tpm chip description.
+ */
+static void release_locality(struct tpm_chip *chip)
+{
+	struct i2c_client *client;
+	u8 data;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	data = TPM_ACCESS_ACTIVE_LOCALITY;
+
+	I2C_WRITE_DATA(client, 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 i2c_client *client = (struct i2c_client *) chip->vendor.iobase;
+
+	stop = jiffies + chip->vendor.timeout_d;
+	do {
+		tpm_reg = TPM_STS + 1;
+		status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+		if (status < 0)
+			goto end;
+
+		tpm_reg = tpm_reg + 1;
+		burstcnt = temp;
+		status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+		if (status < 0)
+			goto end;
+
+		burstcnt |= temp << 8;
+		if (burstcnt)
+			return burstcnt;
+		msleep(TPM_TIMEOUT);
+	} while (time_before(jiffies, stop));
+
+end:
+	return -EBUSY;
+} /* get_burstcount() */
+
+/*
+ * wait_for_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.
+ * @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)
+{
+	unsigned long stop;
+	long rc;
+	u8 status;
+
+	 if (chip->vendor.irq) {
+		rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status
+							(chip) & mask) ==
+						       mask), timeout);
+		if (rc > 0)
+			return 0;
+	} else{
+		stop = jiffies + timeout;
+		do {
+			msleep(TPM_TIMEOUT);
+			status = tpm_stm_i2c_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;
+	struct i2c_client *client;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	while (size < count &&
+	       wait_for_stat(chip,
+			     TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+			     chip->vendor.timeout_c,
+			     &chip->vendor.read_queue)
+	       == 0) {
+		burstcnt = get_burstcount(chip);
+		len = min_t(int, burstcnt, count - size);
+		I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len);
+		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 i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	disable_irq_nosync(irq);
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	complete(&pin_infos->irq_detection);
+	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 ret = 0, ordinal,
+	    status,
+	    burstcnt = 0, i, size;
+	u8 data;
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	if (chip == NULL)
+		return -EBUSY;
+	if (len < TPM_HEADER_SIZE)
+		return -EBUSY;
+
+	client = (struct i2c_client *)chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+
+	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.int_queue) < 0) {
+			ret = -ETIME;
+			goto out_err;
+		}
+	}
+
+	for (i = 0 ; i < len - 1 ;) {
+		burstcnt = get_burstcount(chip);
+		size = min_t(int, len - i - 1, burstcnt);
+		ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, 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(client, 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(client, 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;
+
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	client = (struct i2c_client *)chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+
+	if (chip == NULL)
+		return -EBUSY;
+
+	if (count < TPM_HEADER_SIZE) {
+		size = -EIO;
+		goto out;
+	}
+
+	size = recv_data(chip, buf, TPM_HEADER_SIZE);
+	if (size < TPM_HEADER_SIZE) {
+		dev_err(chip->dev, "Unable to read header\n");
+		goto out;
+	}
+
+	expected = be32_to_cpu(*(__be32 *) (buf + 2));
+	if (expected > count) {
+		size = -EIO;
+		goto out;
+	}
+
+	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+					expected - TPM_HEADER_SIZE);
+	if (size < expected) {
+		dev_err(chip->dev, "Unable to read remainder of result\n");
+		size = -ETIME;
+		goto out;
+	}
+
+out:
+	chip->vendor.cancel(chip);
+	release_locality(chip);
+	return size;
+}
+
+static const struct file_operations tpm_st33_i2c_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = tpm_read,
+	.write = tpm_write,
+	.open = tpm_open,
+	.release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
+static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
+static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
+static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute *stm_tpm_attrs[] = {
+	&dev_attr_pubek.attr,
+	&dev_attr_pcrs.attr,
+	&dev_attr_enabled.attr,
+	&dev_attr_active.attr,
+	&dev_attr_owned.attr,
+	&dev_attr_temp_deactivated.attr,
+	&dev_attr_caps.attr,
+	&dev_attr_cancel.attr, NULL,
+};
+
+static struct attribute_group stm_tpm_attr_grp = {
+	.attrs = stm_tpm_attrs
+};
+
+static struct tpm_vendor_specific 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_STS_COMMAND_READY,
+	.attr_group = &stm_tpm_attr_grp,
+	.miscdev = {.fops = &tpm_st33_i2c_fops,},
+};
+
+static int interrupts ;
+module_param(interrupts, bool, 0444);
+MODULE_PARM_DESC(interrupts, "Enable interrupts");
+
+static int power_mgt = 1;
+module_param(power_mgt, bool, 0444);
+MODULE_PARM_DESC(power_mgt, "Power Management");
+
+/*
+ * tpm_st33_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_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	u32 err;
+	u8 intmask;
+	struct tpm_chip *chip;
+	struct st33zp24_platform_data *platform_data;
+
+	err = 0;
+
+	if (client == NULL) {
+		pr_info("client is NULL. exiting.\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_info("client not i2c capable\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
+	if (!chip) {
+		pr_info("fail chip\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	platform_data = client->dev.platform_data;
+	platform_data->tpm_i2c_buffer[0] =
+	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+	if (platform_data->tpm_i2c_buffer[0] == NULL) {
+		err = -ENOMEM;
+		goto _tpm_clean_answer;
+	}
+	platform_data->tpm_i2c_buffer[1] =
+	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+	if (platform_data->tpm_i2c_buffer[1] == NULL) {
+		err = -ENOMEM;
+		goto _tpm_clean_response;
+	}
+
+	chip->vendor.iobase = client;
+
+	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 (power_mgt) {
+		err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD");
+		if (err)
+			goto _gpio_init1;
+		gpio_set_value(platform_data->io_lpcpd, 1);
+	}
+
+	if (interrupts) {
+		init_completion(&platform_data->irq_detection);
+		if (request_locality(chip) != LOCALITY0) {
+			err = -ENODEV;
+			goto _tpm_clean_response;
+		}
+		err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ");
+		if (err)
+			goto _gpio_init2;
+
+		clear_interruption(client);
+		err = request_irq(gpio_to_irq(platform_data->io_serirq),
+				&tpm_ioserirq_handler,
+				IRQF_TRIGGER_HIGH,
+				"TPM SERIRQ management", chip);
+		if (err < 0) {
+			dev_err( chip->dev , "TPM SERIRQ signals %d not available\n",
+			gpio_to_irq(platform_data->io_serirq));
+			goto _irq_set;
+		}
+
+		err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		intmask |= TPM_INTF_CMD_READY_INT
+			|  TPM_INTF_FIFO_AVALAIBLE_INT
+			|  TPM_INTF_WAKE_UP_READY_INT
+			|  TPM_INTF_LOCALITY_CHANGE_INT
+			|  TPM_INTF_STS_VALID_INT
+			|  TPM_INTF_DATA_AVAIL_INT;
+
+		err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		intmask = TPM_GLOBAL_INT_ENABLE;
+		err = I2C_WRITE_DATA(client, TPM_INT_ENABLE + 3, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		chip->vendor.irq = interrupts;
+
+		tpm_gen_interrupt(chip);
+	}
+
+	tpm_get_timeouts(chip);
+
+	i2c_set_clientdata(client, chip);
+	platform_data->bChipF = false;
+
+	dev_info(chip->dev, "TPM I2C Initialized\n");
+	return 0;
+_irq_set:
+	free_irq(gpio_to_irq(platform_data->io_serirq), (void *) chip);
+_gpio_init2:
+	if (platform_data && interrupts)
+		gpio_free(platform_data->io_serirq);
+_gpio_init1:
+	if (platform_data && power_mgt)
+		gpio_free(platform_data->io_lpcpd);
+_tpm_clean_response:
+	tpm_remove_hardware(chip->dev);
+	if (platform_data->tpm_i2c_buffer[1] != NULL) {
+		kzfree(platform_data->tpm_i2c_buffer[1]);
+		platform_data->tpm_i2c_buffer[1] = NULL;
+	}
+_tpm_clean_answer:
+	if (platform_data->tpm_i2c_buffer[0] != NULL) {
+		kzfree(platform_data->tpm_i2c_buffer[0]);
+		platform_data->tpm_i2c_buffer[0] = NULL;
+	}
+
+	platform_data->bChipF = true;
+end:
+	pr_info("TPM I2C initialisation fail\n");
+	return err;
+}
+
+/*
+ * tpm_st33_i2c_remove remove the TPM device
+ * @param: client, the i2c_client drescription (TPM I2C description).
+		clear_bit(0, &chip->is_open);
+ * @return: 0 in case of success.
+ */
+static __devexit int tpm_st33_i2c_remove(struct i2c_client *client)
+{
+	struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
+	struct st33zp24_platform_data *pin_infos =
+		((struct i2c_client *) chip->vendor.iobase)->dev.platform_data;
+
+	if (pin_infos != NULL) {
+		free_irq(pin_infos->io_serirq, chip);
+
+		gpio_free(pin_infos->io_serirq);
+		gpio_free(pin_infos->io_lpcpd);
+
+		if (pin_infos->bChipF != true)
+			tpm_remove_hardware(chip->dev);
+		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
+			kzfree(pin_infos->tpm_i2c_buffer[1]);
+			pin_infos->tpm_i2c_buffer[1] = NULL;
+		}
+		if (pin_infos->tpm_i2c_buffer[0] != NULL) {
+			kzfree(pin_infos->tpm_i2c_buffer[0]);
+			pin_infos->tpm_i2c_buffer[0] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * tpm_st33_i2c_pm_suspend suspend the TPM device
+ * Added: Work around when suspend and no tpm application is running, suspend
+ * may fail because chip->data_buffer is not set (only set in tpm_open in Linux
+ * TPM core)
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @param: mesg, the power management message.
+ * @return: 0 in case of success.
+ */
+static int tpm_st33_i2c_pm_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct tpm_chip *chip =
+	    (struct tpm_chip *)i2c_get_clientdata(client);
+	struct st33zp24_platform_data *pin_infos =
+		((struct i2c_client *)chip->vendor.iobase)->dev.platform_data;
+	int ret = 0;
+
+	if (power_mgt)
+		gpio_set_value(pin_infos->io_lpcpd, 0);
+	else{
+		if (chip->data_buffer == NULL)
+			chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+		ret = tpm_pm_suspend(&client->dev, mesg);
+	}
+	return ret;
+}				/* tpm_st33_i2c_suspend() */
+
+/*
+ * tpm_st33_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_st33_i2c_pm_resume(struct i2c_client *client)
+{
+	struct tpm_chip *chip =
+	    (struct tpm_chip *)i2c_get_clientdata(client);
+	struct st33zp24_platform_data *pin_infos =
+		((struct i2c_client *)chip->vendor.iobase)->dev.platform_data;
+
+	int ret = 0;
+
+	if (power_mgt) {
+	gpio_set_value(pin_infos->io_lpcpd, 1);
+	ret = wait_for_serirq_timeout(chip, (chip->vendor.status(chip) &&
+					  TPM_STS_VALID) == TPM_STS_VALID,
+					  chip->vendor.timeout_b);
+	} else{
+	if (chip->data_buffer == NULL)
+		chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+	ret = tpm_pm_resume(&client->dev);
+	if (!ret)
+		tpm_continue_selftest(chip);
+	}
+	return ret;
+}				/* tpm_st33_i2c_pm_resume() */
+
+static const struct i2c_device_id tpm_st33_i2c_id[] = {
+	{TPM_ST33_I2C, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id);
+
+static struct i2c_driver tpm_st33_i2c_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = TPM_ST33_I2C,
+		   },
+	.probe = tpm_st33_i2c_probe,
+	.remove = tpm_st33_i2c_remove,
+	.resume = tpm_st33_i2c_pm_resume,
+	.suspend = tpm_st33_i2c_pm_suspend,
+	.id_table = tpm_st33_i2c_id
+};
+
+/*
+ * tpm_st33_i2c_init initialize driver
+ * @return: 0 if successful, else non zero value.
+ */
+static int __init tpm_st33_i2c_init(void)
+{
+	return i2c_add_driver(&tpm_st33_i2c_driver);
+}
+
+/*
+ * tpm_st33_i2c_exit The kernel calls this function during unloading the
+ * module or during shut down process
+ */
+static void __exit tpm_st33_i2c_exit(void)
+{
+	i2c_del_driver(&tpm_st33_i2c_driver);
+}
+
+module_init(tpm_st33_i2c_init);
+module_exit(tpm_st33_i2c_exit);
+
+MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
+MODULE_DESCRIPTION("STM TPM I2C ST33 Driver");
+MODULE_VERSION("1.2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_stm_st33_i2c.h b/drivers/char/tpm/tpm_stm_st33_i2c.h
new file mode 100644
index 0000000..d390542
--- /dev/null
+++ b/drivers/char/tpm/tpm_stm_st33_i2c.h
@@ -0,0 +1,81 @@
+/*
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 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@st.com
+ *
+ * @File: stm_st33_tpm_i2c.h
+ *
+ * @Date: 09/15/2010
+ */
+#ifndef __STM_ST33_TPM_I2C_MAIN_H__
+#define __STM_ST33_TPM_I2C_MAIN_H__
+
+#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/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.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/sched.h>
+
+#include "tpm.h"
+
+#define MINOR_NUM_I2C		224
+
+#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
+
+struct st_tpm_hash {
+	int size;
+	u8 *data;
+};
+
+#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
diff --git a/include/linux/i2c/tpm_stm_st33_i2c.h b/include/linux/i2c/tpm_stm_st33_i2c.h
new file mode 100644
index 0000000..e3ce42d
--- /dev/null
+++ b/include/linux/i2c/tpm_stm_st33_i2c.h
@@ -0,0 +1,47 @@
+/*
+* STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
+* Copyright (C) 2009, 2010 STMicroelectronics
+* Christophe RICARD tpmsupport@st.com
+* 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, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* 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.
+*
+* @File: stm_st33_tpm_i2c.h
+*
+* @Date: 06/15/2008
+*/
+#ifndef __STM_ST33_TPM_I2C_H__
+#define __STM_ST33_TPM_I2C_H__
+
+#include <linux/i2c.h>
+
+#define TPM_ST33_I2C			"st33zp24_i2c"
+#define TPM_I2C_ST33_ADDR_WR_LOC0	(0x26 >> 1)
+
+
+struct st33zp24_platform_data {
+	int io_serirq;
+	int io_lpcpd;
+	struct i2c_client *client;
+	bool bChipF;
+	u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
+	struct completion irq_detection;
+	struct mutex lock;
+};
+
+#endif /* __STM_ST33_TPM_I2C_H__ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 1/1] TPM: STMicroelectronics ST33 I2C CHROMIUM
  2012-11-14 14:31 [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Mathias Leblanc
@ 2012-11-14 14:31 ` Mathias Leblanc
  2012-11-14 14:31 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C BUILD STUFF Mathias Leblanc
  2012-11-14 22:06 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Kent Yoder
  2 siblings, 0 replies; 8+ messages in thread
From: Mathias Leblanc @ 2012-11-14 14:31 UTC (permalink / raw)
  To: Kent Yoder, Rajiv Andrade, Marcel Selhorst, Sirrix AG,
	tpmdd-devel, Debora Velarde
  Cc: linux-kernel, Jean-Luc Blanc, Mathias Leblanc

 * 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.

This is the driver for TPM chip from ST Microelectronics.

If you have a TPM security chip from STMicroelectronics working with
an I2C, in menuconfig or .config choose the tpm driver on
device --> tpm and activate the protocol of your choice before compiling
the kernel.
The driver will be accessible from within Linux.

Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM OS

Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com>
---
 drivers/char/tpm/tpm_stm_st33_i2c.c  |  903 ++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm_stm_st33_i2c.h  |   81 +++
 include/linux/i2c/tpm_stm_st33_i2c.h |   47 ++
 3 files changed, 1031 insertions(+)
 create mode 100644 drivers/char/tpm/tpm_stm_st33_i2c.c
 create mode 100644 drivers/char/tpm/tpm_stm_st33_i2c.h
 create mode 100644 include/linux/i2c/tpm_stm_st33_i2c.h

diff --git a/drivers/char/tpm/tpm_stm_st33_i2c.c b/drivers/char/tpm/tpm_stm_st33_i2c.c
new file mode 100644
index 0000000..3ec6ae9
--- /dev/null
+++ b/drivers/char/tpm/tpm_stm_st33_i2c.c
@@ -0,0 +1,903 @@
+/*
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 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@st.com
+ *
+ * @File: tpm_stm_st33_i2c.c
+ *
+ * @Synopsis:
+ *	09/15/2010:	First shot driver tpm_tis driver for 
+			lpc is used as model.
+ */
+
+#include <linux/i2c/tpm_stm_st33_i2c.h>
+
+#include "tpm_stm_st33_i2c.h"
+
+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,
+};
+
+/*
+ * 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 i2c_client *client, u8 tpm_register,
+		      u8 *tpm_data, u16 tpm_size)
+{
+	u8 data;
+	int value = 0;
+	struct st33zp24_platform_data *pin_infos;
+
+	pin_infos = client->dev.platform_data;
+
+	data = tpm_register;
+	memcpy(pin_infos->tpm_i2c_buffer[0], &data, sizeof(data));
+	memcpy(pin_infos->tpm_i2c_buffer[0] + 1, tpm_data, tpm_size);
+	value = i2c_master_send(client, pin_infos->tpm_i2c_buffer[0],
+				tpm_size + 1);
+	return value;
+} /* 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 i2c_client *client, u8 tpm_register,
+		    u8 *tpm_data, int tpm_size)
+{
+	u8 status = 0;
+	u8 data;
+	struct st33zp24_platform_data *pin_infos;
+
+	pin_infos = client->dev.platform_data;
+
+	data = TPM_DUMMY_BYTE;
+	status = write8_reg(client, tpm_register, &data, 1);
+	if (status == 2)
+		status = i2c_master_recv(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: client, 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(client, tpm_register, tpm_data, tpm_size) \
+	(write8_reg(client, 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, 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(client, tpm_register, tpm_data, tpm_size) \
+	(read8_reg(client, tpm_register, tpm_data, tpm_size))
+
+/*
+ * clear_interruption
+ * clear the TPM interrupt register.
+ * @param: tpm, the chip description
+ */
+static void clear_interruption(struct i2c_client *client)
+{
+	u8 interrupt;
+	I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+	I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+	I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+} /* clear_interruption() */
+
+/*
+ * _wait_for_interrupt_serirq_timeout
+ * @param: tpm, the chip description
+ * @param: timeout, the timeout of the interrupt
+ * @return: the status of the interruption.
+ */
+static int _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
+						unsigned long timeout)
+{
+	int status;
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	status = wait_for_completion_interruptible_timeout(
+					&pin_infos->irq_detection,
+						timeout);
+	if (status > 0)
+		enable_irq(gpio_to_irq(pin_infos->io_serirq));
+	gpio_direction_input(pin_infos->io_serirq);
+
+	return status;
+} /* wait_for_interrupt_serirq_timeout() */
+
+int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
+				 unsigned long timeout)
+{
+	int status = 2;
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	status = _wait_for_interrupt_serirq_timeout(chip, timeout);
+	if (!status) {
+		status = -EBUSY;
+	} else{
+		clear_interruption(client);
+		if (condition)
+			status = 1;
+	}
+	return status;
+}
+
+/*
+ * 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 i2c_client *client;
+	u8 data;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	data = TPM_STS_COMMAND_READY;
+	I2C_WRITE_DATA(client, TPM_STS, &data, 1);
+	if (chip->vendor.irq)
+		wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a);
+}	/* 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 i2c_client *client;
+	u8 data;
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	I2C_READ_DATA(client, 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 i2c_client *client;
+	u8 data;
+	u8 status;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	status = I2C_READ_DATA(client, 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 rc;
+	struct i2c_client *client;
+	u8 data;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	if (check_locality(chip) == chip->vendor.locality)
+		return chip->vendor.locality;
+
+	data = TPM_ACCESS_REQUEST_USE;
+	rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
+	if (rc < 0)
+		goto end;
+
+	if (chip->vendor.irq) {
+		rc = wait_for_serirq_timeout(chip, (check_locality
+						       (chip) >= 0),
+						      chip->vendor.timeout_a);
+		if (rc > 0)
+			return chip->vendor.locality;
+	} else{
+		stop = jiffies + chip->vendor.timeout_a;
+		do {
+			if (check_locality(chip) >= 0)
+				return chip->vendor.locality;
+			msleep(TPM_TIMEOUT);
+		} while (time_before(jiffies, stop));
+	}
+	rc = -EACCES;
+end:
+	return rc;
+} /* request_locality() */
+
+/*
+ * release_locality release the active locality
+ * @param: chip, the tpm chip description.
+ */
+static void release_locality(struct tpm_chip *chip)
+{
+	struct i2c_client *client;
+	u8 data;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	data = TPM_ACCESS_ACTIVE_LOCALITY;
+
+	I2C_WRITE_DATA(client, 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 i2c_client *client = (struct i2c_client *) chip->vendor.iobase;
+
+	stop = jiffies + chip->vendor.timeout_d;
+	do {
+		tpm_reg = TPM_STS + 1;
+		status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+		if (status < 0)
+			goto end;
+
+		tpm_reg = tpm_reg + 1;
+		burstcnt = temp;
+		status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+		if (status < 0)
+			goto end;
+
+		burstcnt |= temp << 8;
+		if (burstcnt)
+			return burstcnt;
+		msleep(TPM_TIMEOUT);
+	} while (time_before(jiffies, stop));
+
+end:
+	return -EBUSY;
+} /* get_burstcount() */
+
+/*
+ * wait_for_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.
+ * @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)
+{
+	unsigned long stop;
+	long rc;
+	u8 status;
+
+	 if (chip->vendor.irq) {
+		rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status
+							(chip) & mask) ==
+						       mask), timeout);
+		if (rc > 0)
+			return 0;
+	} else{
+		stop = jiffies + timeout;
+		do {
+			msleep(TPM_TIMEOUT);
+			status = tpm_stm_i2c_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;
+	struct i2c_client *client;
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+
+	while (size < count &&
+	       wait_for_stat(chip,
+			     TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+			     chip->vendor.timeout_c,
+			     &chip->vendor.read_queue)
+	       == 0) {
+		burstcnt = get_burstcount(chip);
+		len = min_t(int, burstcnt, count - size);
+		I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len);
+		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 i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	disable_irq_nosync(irq);
+
+	client = (struct i2c_client *) chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	complete(&pin_infos->irq_detection);
+	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 ret = 0, ordinal,
+	    status,
+	    burstcnt = 0, i, size;
+	u8 data;
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	if (chip == NULL)
+		return -EBUSY;
+	if (len < TPM_HEADER_SIZE)
+		return -EBUSY;
+
+	client = (struct i2c_client *)chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+	ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+
+	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.int_queue) < 0) {
+			ret = -ETIME;
+			goto out_err;
+		}
+	}
+
+	for (i = 0 ; i < len - 1 ;) {
+		burstcnt = get_burstcount(chip);
+		size = min_t(int, len - i - 1, burstcnt);
+		ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, 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(client, 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(client, 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;
+
+	struct i2c_client *client;
+	struct st33zp24_platform_data *pin_infos;
+
+	client = (struct i2c_client *)chip->vendor.iobase;
+	pin_infos = client->dev.platform_data;
+
+
+	if (chip == NULL)
+		return -EBUSY;
+
+	if (count < TPM_HEADER_SIZE) {
+		size = -EIO;
+		goto out;
+	}
+
+	size = recv_data(chip, buf, TPM_HEADER_SIZE);
+	if (size < TPM_HEADER_SIZE) {
+		dev_err(chip->dev, "Unable to read header\n");
+		goto out;
+	}
+
+	expected = be32_to_cpu(*(__be32 *) (buf + 2));
+	if (expected > count) {
+		size = -EIO;
+		goto out;
+	}
+
+	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+					expected - TPM_HEADER_SIZE);
+	if (size < expected) {
+		dev_err(chip->dev, "Unable to read remainder of result\n");
+		size = -ETIME;
+		goto out;
+	}
+
+out:
+	chip->vendor.cancel(chip);
+	release_locality(chip);
+	return size;
+}
+
+static const struct file_operations tpm_st33_i2c_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = tpm_read,
+	.write = tpm_write,
+	.open = tpm_open,
+	.release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
+static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
+static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
+static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute *stm_tpm_attrs[] = {
+	&dev_attr_pubek.attr,
+	&dev_attr_pcrs.attr,
+	&dev_attr_enabled.attr,
+	&dev_attr_active.attr,
+	&dev_attr_owned.attr,
+	&dev_attr_temp_deactivated.attr,
+	&dev_attr_caps.attr,
+	&dev_attr_cancel.attr, NULL,
+};
+
+static struct attribute_group stm_tpm_attr_grp = {
+	.attrs = stm_tpm_attrs
+};
+
+static struct tpm_vendor_specific 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_STS_COMMAND_READY,
+	.attr_group = &stm_tpm_attr_grp,
+	.miscdev = {.fops = &tpm_st33_i2c_fops,},
+};
+
+static int interrupts ;
+module_param(interrupts, bool, 0444);
+MODULE_PARM_DESC(interrupts, "Enable interrupts");
+
+static int power_mgt = 1;
+module_param(power_mgt, bool, 0444);
+MODULE_PARM_DESC(power_mgt, "Power Management");
+
+/*
+ * tpm_st33_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_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	u32 err;
+	u8 intmask;
+	struct tpm_chip *chip;
+	struct st33zp24_platform_data *platform_data;
+
+	err = 0;
+
+	if (client == NULL) {
+		pr_info("client is NULL. exiting.\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_info("client not i2c capable\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
+	if (!chip) {
+		pr_info("fail chip\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	platform_data = client->dev.platform_data;
+	platform_data->tpm_i2c_buffer[0] =
+	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+	if (platform_data->tpm_i2c_buffer[0] == NULL) {
+		err = -ENOMEM;
+		goto _tpm_clean_answer;
+	}
+	platform_data->tpm_i2c_buffer[1] =
+	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+	if (platform_data->tpm_i2c_buffer[1] == NULL) {
+		err = -ENOMEM;
+		goto _tpm_clean_response;
+	}
+
+	chip->vendor.iobase = client;
+
+	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 (power_mgt) {
+		err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD");
+		if (err)
+			goto _gpio_init1;
+		gpio_set_value(platform_data->io_lpcpd, 1);
+	}
+
+	if (interrupts) {
+		init_completion(&platform_data->irq_detection);
+		if (request_locality(chip) != LOCALITY0) {
+			err = -ENODEV;
+			goto _tpm_clean_response;
+		}
+		err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ");
+		if (err)
+			goto _gpio_init2;
+
+		clear_interruption(client);
+		err = request_irq(gpio_to_irq(platform_data->io_serirq),
+				&tpm_ioserirq_handler,
+				IRQF_TRIGGER_HIGH,
+				"TPM SERIRQ management", chip);
+		if (err < 0) {
+			dev_err( chip->dev , "TPM SERIRQ signals %d not available\n",
+			gpio_to_irq(platform_data->io_serirq));
+			goto _irq_set;
+		}
+
+		err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		intmask |= TPM_INTF_CMD_READY_INT
+			|  TPM_INTF_FIFO_AVALAIBLE_INT
+			|  TPM_INTF_WAKE_UP_READY_INT
+			|  TPM_INTF_LOCALITY_CHANGE_INT
+			|  TPM_INTF_STS_VALID_INT
+			|  TPM_INTF_DATA_AVAIL_INT;
+
+		err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		intmask = TPM_GLOBAL_INT_ENABLE;
+		err = I2C_WRITE_DATA(client, TPM_INT_ENABLE + 3, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1);
+		if (err < 0)
+			goto _irq_set;
+
+		chip->vendor.irq = interrupts;
+
+		tpm_gen_interrupt(chip);
+	}
+
+	tpm_get_timeouts(chip);
+
+	i2c_set_clientdata(client, chip);
+	platform_data->bChipF = false;
+
+	dev_info(chip->dev, "TPM I2C Initialized\n");
+	return 0;
+_irq_set:
+	free_irq(gpio_to_irq(platform_data->io_serirq), (void *) chip);
+_gpio_init2:
+	if (platform_data && interrupts)
+		gpio_free(platform_data->io_serirq);
+_gpio_init1:
+	if (platform_data && power_mgt)
+		gpio_free(platform_data->io_lpcpd);
+_tpm_clean_response:
+	tpm_remove_hardware(chip->dev);
+	if (platform_data->tpm_i2c_buffer[1] != NULL) {
+		kzfree(platform_data->tpm_i2c_buffer[1]);
+		platform_data->tpm_i2c_buffer[1] = NULL;
+	}
+_tpm_clean_answer:
+	if (platform_data->tpm_i2c_buffer[0] != NULL) {
+		kzfree(platform_data->tpm_i2c_buffer[0]);
+		platform_data->tpm_i2c_buffer[0] = NULL;
+	}
+
+	platform_data->bChipF = true;
+end:
+	pr_info("TPM I2C initialisation fail\n");
+	return err;
+}
+
+/*
+ * tpm_st33_i2c_remove remove the TPM device
+ * @param: client, the i2c_client drescription (TPM I2C description).
+		clear_bit(0, &chip->is_open);
+ * @return: 0 in case of success.
+ */
+static __devexit int tpm_st33_i2c_remove(struct i2c_client *client)
+{
+	struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
+	struct st33zp24_platform_data *pin_infos =
+		((struct i2c_client *) chip->vendor.iobase)->dev.platform_data;
+
+	if (pin_infos != NULL) {
+		free_irq(pin_infos->io_serirq, chip);
+
+		gpio_free(pin_infos->io_serirq);
+		gpio_free(pin_infos->io_lpcpd);
+
+		if (pin_infos->bChipF != true)
+			tpm_remove_hardware(chip->dev);
+		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
+			kzfree(pin_infos->tpm_i2c_buffer[1]);
+			pin_infos->tpm_i2c_buffer[1] = NULL;
+		}
+		if (pin_infos->tpm_i2c_buffer[0] != NULL) {
+			kzfree(pin_infos->tpm_i2c_buffer[0]);
+			pin_infos->tpm_i2c_buffer[0] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * tpm_st33_i2c_pm_suspend suspend the TPM device
+ * Added: Work around when suspend and no tpm application is running, suspend
+ * may fail because chip->data_buffer is not set (only set in tpm_open in Linux
+ * TPM core)
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @param: mesg, the power management message.
+ * @return: 0 in case of success.
+ */
+static int tpm_st33_i2c_pm_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct tpm_chip *chip =
+	    (struct tpm_chip *)i2c_get_clientdata(client);
+	struct st33zp24_platform_data *pin_infos =
+		((struct i2c_client *)chip->vendor.iobase)->dev.platform_data;
+	int ret = 0;
+
+	if (power_mgt)
+		gpio_set_value(pin_infos->io_lpcpd, 0);
+	else{
+		if (chip->data_buffer == NULL)
+			chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+		ret = tpm_pm_suspend(&client->dev, mesg);
+	}
+	return ret;
+}				/* tpm_st33_i2c_suspend() */
+
+/*
+ * tpm_st33_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_st33_i2c_pm_resume(struct i2c_client *client)
+{
+	struct tpm_chip *chip =
+	    (struct tpm_chip *)i2c_get_clientdata(client);
+	struct st33zp24_platform_data *pin_infos =
+		((struct i2c_client *)chip->vendor.iobase)->dev.platform_data;
+
+	int ret = 0;
+
+	if (power_mgt) {
+	gpio_set_value(pin_infos->io_lpcpd, 1);
+	ret = wait_for_serirq_timeout(chip, (chip->vendor.status(chip) &&
+					  TPM_STS_VALID) == TPM_STS_VALID,
+					  chip->vendor.timeout_b);
+	} else{
+	if (chip->data_buffer == NULL)
+		chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+	ret = tpm_pm_resume(&client->dev);
+	if (!ret)
+		tpm_continue_selftest_nocheck(chip);
+	}
+	return ret;
+}				/* tpm_st33_i2c_pm_resume() */
+
+static const struct i2c_device_id tpm_st33_i2c_id[] = {
+	{TPM_ST33_I2C, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id);
+
+static struct i2c_driver tpm_st33_i2c_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = TPM_ST33_I2C,
+		   },
+	.probe = tpm_st33_i2c_probe,
+	.remove = tpm_st33_i2c_remove,
+	.resume = tpm_st33_i2c_pm_resume,
+	.suspend = tpm_st33_i2c_pm_suspend,
+	.id_table = tpm_st33_i2c_id
+};
+
+/*
+ * tpm_st33_i2c_init initialize driver
+ * @return: 0 if successful, else non zero value.
+ */
+static int __init tpm_st33_i2c_init(void)
+{
+	return i2c_add_driver(&tpm_st33_i2c_driver);
+}
+
+/*
+ * tpm_st33_i2c_exit The kernel calls this function during unloading the
+ * module or during shut down process
+ */
+static void __exit tpm_st33_i2c_exit(void)
+{
+	i2c_del_driver(&tpm_st33_i2c_driver);
+}
+
+module_init(tpm_st33_i2c_init);
+module_exit(tpm_st33_i2c_exit);
+
+MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
+MODULE_DESCRIPTION("STM TPM I2C ST33 Driver");
+MODULE_VERSION("1.2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_stm_st33_i2c.h b/drivers/char/tpm/tpm_stm_st33_i2c.h
new file mode 100644
index 0000000..d390542
--- /dev/null
+++ b/drivers/char/tpm/tpm_stm_st33_i2c.h
@@ -0,0 +1,81 @@
+/*
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 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@st.com
+ *
+ * @File: stm_st33_tpm_i2c.h
+ *
+ * @Date: 09/15/2010
+ */
+#ifndef __STM_ST33_TPM_I2C_MAIN_H__
+#define __STM_ST33_TPM_I2C_MAIN_H__
+
+#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/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.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/sched.h>
+
+#include "tpm.h"
+
+#define MINOR_NUM_I2C		224
+
+#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
+
+struct st_tpm_hash {
+	int size;
+	u8 *data;
+};
+
+#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
diff --git a/include/linux/i2c/tpm_stm_st33_i2c.h b/include/linux/i2c/tpm_stm_st33_i2c.h
new file mode 100644
index 0000000..e3ce42d
--- /dev/null
+++ b/include/linux/i2c/tpm_stm_st33_i2c.h
@@ -0,0 +1,47 @@
+/*
+* STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
+* Copyright (C) 2009, 2010 STMicroelectronics
+* Christophe RICARD tpmsupport@st.com
+* 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, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* 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.
+*
+* @File: stm_st33_tpm_i2c.h
+*
+* @Date: 06/15/2008
+*/
+#ifndef __STM_ST33_TPM_I2C_H__
+#define __STM_ST33_TPM_I2C_H__
+
+#include <linux/i2c.h>
+
+#define TPM_ST33_I2C			"st33zp24_i2c"
+#define TPM_I2C_ST33_ADDR_WR_LOC0	(0x26 >> 1)
+
+
+struct st33zp24_platform_data {
+	int io_serirq;
+	int io_lpcpd;
+	struct i2c_client *client;
+	bool bChipF;
+	u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
+	struct completion irq_detection;
+	struct mutex lock;
+};
+
+#endif /* __STM_ST33_TPM_I2C_H__ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 1/1] TPM: STMicroelectronics ST33 I2C BUILD STUFF
  2012-11-14 14:31 [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Mathias Leblanc
  2012-11-14 14:31 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C CHROMIUM Mathias Leblanc
@ 2012-11-14 14:31 ` Mathias Leblanc
  2012-11-14 22:06 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Kent Yoder
  2 siblings, 0 replies; 8+ messages in thread
From: Mathias Leblanc @ 2012-11-14 14:31 UTC (permalink / raw)
  To: Kent Yoder, Rajiv Andrade, Marcel Selhorst, Sirrix AG,
	tpmdd-devel, Debora Velarde
  Cc: linux-kernel, Jean-Luc Blanc, Mathias Leblanc

 * 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.

This is the driver for TPM chip from ST Microelectronics.

If you have a TPM security chip from STMicroelectronics working with
an I2C, in menuconfig or .config choose the tpm driver on
device --> tpm and activate the protocol of your choice before compiling
the kernel.
The driver will be accessible from within Linux.

Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM OS

Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com>
---
 drivers/char/tpm/Kconfig  |   10 ++++++++++
 drivers/char/tpm/Makefile |    1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 915875e..765d1c7 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -81,4 +81,14 @@ 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_ST33_I2C
+        tristate "STMicroelectronics ST33 I2C TPM"
+        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_stm_st33_i2c.
+
 endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 5b3fc8b..4b04262 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -17,3 +17,4 @@ 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_ST33_I2C) += tpm_stm_st33_i2c.o
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
  2012-11-14 14:31 [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Mathias Leblanc
  2012-11-14 14:31 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C CHROMIUM Mathias Leblanc
  2012-11-14 14:31 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C BUILD STUFF Mathias Leblanc
@ 2012-11-14 22:06 ` Kent Yoder
  2012-11-19 13:48   ` Mathias LEBLANC
  2012-11-20  8:26   ` Mathias LEBLANC
  2 siblings, 2 replies; 8+ messages in thread
From: Kent Yoder @ 2012-11-14 22:06 UTC (permalink / raw)
  To: Mathias Leblanc
  Cc: Rajiv Andrade, Marcel Selhorst, Sirrix AG, tpmdd-devel,
	Debora Velarde, linux-kernel, Jean-Luc Blanc

Hi Mathias,

On Wed, Nov 14, 2012 at 03:31:42PM +0100, Mathias Leblanc wrote:
>  * 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.
> 
> This is the driver for TPM chip from ST Microelectronics.
> 
> If you have a TPM security chip from STMicroelectronics working with
> an I2C, in menuconfig or .config choose the tpm driver on
> device --> tpm and activate the protocol of your choice before compiling
> the kernel.
> The driver will be accessible from within Linux.
> 
> Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM OS

  Getting some build errors here:

drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_interrupts’:
drivers/char/tpm/tpm_stm_st33_i2c.c:615:1: warning: return from
incompatible pointer type [enabled by default]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_power_mgt’:
drivers/char/tpm/tpm_stm_st33_i2c.c:619:1: warning: return from
incompatible pointer type [enabled by default]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘tpm_st33_i2c_probe’:
drivers/char/tpm/tpm_stm_st33_i2c.c:725:3: warning: suggest parentheses
around arithmetic in operand of ‘|’ [-Wparentheses]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function
‘tpm_st33_i2c_pm_suspend’:
drivers/char/tpm/tpm_stm_st33_i2c.c:826:3: error: too many arguments to
function ‘tpm_pm_suspend’
In file included from drivers/char/tpm/tpm_stm_st33_i2c.h:55:0,
                 from drivers/char/tpm/tpm_stm_st33_i2c.c:35:
		 drivers/char/tpm/tpm.h:326:12: note: declared here
		 drivers/char/tpm/tpm_stm_st33_i2c.c: In function
		 ‘tpm_st33_i2c_pm_resume’:
		 drivers/char/tpm/tpm_stm_st33_i2c.c:855:3: error:
		 implicit declaration of function
		 ‘tpm_continue_selftest’
		 [-Werror=implicit-function-declaration]

[cut]
> +/*
> + * _wait_for_interrupt_serirq_timeout
> + * @param: tpm, the chip description
> + * @param: timeout, the timeout of the interrupt
> + * @return: the status of the interruption.
> + */
> +static int _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
> +						unsigned long timeout)
> +{
> +	int status;
> +	struct i2c_client *client;
> +	struct st33zp24_platform_data *pin_infos;
> +
> +	client = (struct i2c_client *) chip->vendor.iobase;
> +	pin_infos = client->dev.platform_data;
> +
> +	status = wait_for_completion_interruptible_timeout(
> +					&pin_infos->irq_detection,
> +						timeout);

  status should be a long here.

[cut]
> +
> +	if (client == NULL) {
> +		pr_info("client is NULL. exiting.\n");
> +		err = -ENODEV;
> +		goto end;
> +	}
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +		pr_info("client not i2c capable\n");
> +		err = -ENODEV;
> +		goto end;
> +	}
> +
> +	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
> +	if (!chip) {
> +		pr_info("fail chip\n");

  Please use dev_info() in place of pr_info().

Thanks,
Kent


^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
  2012-11-14 22:06 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Kent Yoder
@ 2012-11-19 13:48   ` Mathias LEBLANC
  2012-11-20  8:26   ` Mathias LEBLANC
  1 sibling, 0 replies; 8+ messages in thread
From: Mathias LEBLANC @ 2012-11-19 13:48 UTC (permalink / raw)
  To: Kent Yoder
  Cc: Rajiv Andrade, Marcel Selhorst, Sirrix AG, tpmdd-devel,
	Debora Velarde, linux-kernel, Jean-Luc BLANC

Hi Kent,

Which is the version of your kernel?
The tpm_continue_selftest function (declare in tpm.c) seems to be different in the kernel 3.x.x .
I will send a patch for the  2.6.x and 3.x.x

regards,

Mathias Leblanc
________________________________________
From: Kent Yoder [key@linux.vnet.ibm.com]
Sent: 14 November 2012 23:06
To: Mathias LEBLANC
Cc: Rajiv Andrade; Marcel Selhorst; Sirrix AG; tpmdd-devel@lists.sourceforge.net; Debora Velarde; linux-kernel@vger.kernel.org; Jean-Luc BLANC
Subject: Re: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C

Hi Mathias,

On Wed, Nov 14, 2012 at 03:31:42PM +0100, Mathias Leblanc wrote:
>  * 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.
>
> This is the driver for TPM chip from ST Microelectronics.
>
> If you have a TPM security chip from STMicroelectronics working with
> an I2C, in menuconfig or .config choose the tpm driver on
> device --> tpm and activate the protocol of your choice before compiling
> the kernel.
> The driver will be accessible from within Linux.
>
> Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM OS

  Getting some build errors here:

drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_interrupts’:
drivers/char/tpm/tpm_stm_st33_i2c.c:615:1: warning: return from
incompatible pointer type [enabled by default]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_power_mgt’:
drivers/char/tpm/tpm_stm_st33_i2c.c:619:1: warning: return from
incompatible pointer type [enabled by default]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘tpm_st33_i2c_probe’:
drivers/char/tpm/tpm_stm_st33_i2c.c:725:3: warning: suggest parentheses
around arithmetic in operand of ‘|’ [-Wparentheses]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function
‘tpm_st33_i2c_pm_suspend’:
drivers/char/tpm/tpm_stm_st33_i2c.c:826:3: error: too many arguments to
function ‘tpm_pm_suspend’
In file included from drivers/char/tpm/tpm_stm_st33_i2c.h:55:0,
                 from drivers/char/tpm/tpm_stm_st33_i2c.c:35:
                 drivers/char/tpm/tpm.h:326:12: note: declared here
                 drivers/char/tpm/tpm_stm_st33_i2c.c: In function
                 ‘tpm_st33_i2c_pm_resume’:
                 drivers/char/tpm/tpm_stm_st33_i2c.c:855:3: error:
                 implicit declaration of function
                 ‘tpm_continue_selftest’
                 [-Werror=implicit-function-declaration]

[cut]
> +/*
> + * _wait_for_interrupt_serirq_timeout
> + * @param: tpm, the chip description
> + * @param: timeout, the timeout of the interrupt
> + * @return: the status of the interruption.
> + */
> +static int _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
> +                                             unsigned long timeout)
> +{
> +     int status;
> +     struct i2c_client *client;
> +     struct st33zp24_platform_data *pin_infos;
> +
> +     client = (struct i2c_client *) chip->vendor.iobase;
> +     pin_infos = client->dev.platform_data;
> +
> +     status = wait_for_completion_interruptible_timeout(
> +                                     &pin_infos->irq_detection,
> +                                             timeout);

  status should be a long here.

[cut]
> +
> +     if (client == NULL) {
> +             pr_info("client is NULL. exiting.\n");
> +             err = -ENODEV;
> +             goto end;
> +     }
> +
> +     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +             pr_info("client not i2c capable\n");
> +             err = -ENODEV;
> +             goto end;
> +     }
> +
> +     chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
> +     if (!chip) {
> +             pr_info("fail chip\n");

  Please use dev_info() in place of pr_info().

Thanks,
Kent

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
  2012-11-14 22:06 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Kent Yoder
  2012-11-19 13:48   ` Mathias LEBLANC
@ 2012-11-20  8:26   ` Mathias LEBLANC
  2012-11-26 15:51     ` Kent Yoder
  1 sibling, 1 reply; 8+ messages in thread
From: Mathias LEBLANC @ 2012-11-20  8:26 UTC (permalink / raw)
  To: Kent Yoder
  Cc: Rajiv Andrade, Marcel Selhorst, Sirrix AG, tpmdd-devel,
	Debora Velarde, linux-kernel, Jean-Luc BLANC

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3681 bytes --]

Hello,

Does anyone can say me when the driver will be integrated on linux kernel and where can we get it  from the linux source code?

Thanks,

Mathias Leblanc

-----Original Message-----
From: Kent Yoder [mailto:key@linux.vnet.ibm.com] 
Sent: 14 November, 2012 23:07
To: Mathias LEBLANC
Cc: Rajiv Andrade; Marcel Selhorst; Sirrix AG; tpmdd-devel@lists.sourceforge.net; Debora Velarde; linux-kernel@vger.kernel.org; Jean-Luc BLANC
Subject: Re: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C

Hi Mathias,

On Wed, Nov 14, 2012 at 03:31:42PM +0100, Mathias Leblanc wrote:
>  * 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.
> 
> This is the driver for TPM chip from ST Microelectronics.
> 
> If you have a TPM security chip from STMicroelectronics working with 
> an I2C, in menuconfig or .config choose the tpm driver on device --> 
> tpm and activate the protocol of your choice before compiling the 
> kernel.
> The driver will be accessible from within Linux.
> 
> Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM OS

  Getting some build errors here:

drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_interrupts’:
drivers/char/tpm/tpm_stm_st33_i2c.c:615:1: warning: return from incompatible pointer type [enabled by default]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_power_mgt’:
drivers/char/tpm/tpm_stm_st33_i2c.c:619:1: warning: return from incompatible pointer type [enabled by default]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘tpm_st33_i2c_probe’:
drivers/char/tpm/tpm_stm_st33_i2c.c:725:3: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
drivers/char/tpm/tpm_stm_st33_i2c.c: In function
‘tpm_st33_i2c_pm_suspend’:
drivers/char/tpm/tpm_stm_st33_i2c.c:826:3: error: too many arguments to function ‘tpm_pm_suspend’
In file included from drivers/char/tpm/tpm_stm_st33_i2c.h:55:0,
                 from drivers/char/tpm/tpm_stm_st33_i2c.c:35:
		 drivers/char/tpm/tpm.h:326:12: note: declared here
		 drivers/char/tpm/tpm_stm_st33_i2c.c: In function
		 ‘tpm_st33_i2c_pm_resume’:
		 drivers/char/tpm/tpm_stm_st33_i2c.c:855:3: error:
		 implicit declaration of function
		 ‘tpm_continue_selftest’
		 [-Werror=implicit-function-declaration]

[cut]
> +/*
> + * _wait_for_interrupt_serirq_timeout
> + * @param: tpm, the chip description
> + * @param: timeout, the timeout of the interrupt
> + * @return: the status of the interruption.
> + */
> +static int _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
> +						unsigned long timeout)
> +{
> +	int status;
> +	struct i2c_client *client;
> +	struct st33zp24_platform_data *pin_infos;
> +
> +	client = (struct i2c_client *) chip->vendor.iobase;
> +	pin_infos = client->dev.platform_data;
> +
> +	status = wait_for_completion_interruptible_timeout(
> +					&pin_infos->irq_detection,
> +						timeout);

  status should be a long here.

[cut]
> +
> +	if (client == NULL) {
> +		pr_info("client is NULL. exiting.\n");
> +		err = -ENODEV;
> +		goto end;
> +	}
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +		pr_info("client not i2c capable\n");
> +		err = -ENODEV;
> +		goto end;
> +	}
> +
> +	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
> +	if (!chip) {
> +		pr_info("fail chip\n");

  Please use dev_info() in place of pr_info().

Thanks,
Kent

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
  2012-11-20  8:26   ` Mathias LEBLANC
@ 2012-11-26 15:51     ` Kent Yoder
  2012-11-26 16:03       ` Mathias LEBLANC
  0 siblings, 1 reply; 8+ messages in thread
From: Kent Yoder @ 2012-11-26 15:51 UTC (permalink / raw)
  To: Mathias LEBLANC
  Cc: Rajiv Andrade, Marcel Selhorst, Sirrix AG, tpmdd-devel,
	Debora Velarde, linux-kernel, Jean-Luc BLANC

On Tue, Nov 20, 2012 at 09:26:40AM +0100, Mathias LEBLANC wrote:
> Hello,
> 
> Does anyone can say me when the driver will be integrated on linux kernel and where can we get it  from the linux source code?

 Hi Mathias, I'll work with you this week to get this pushed to the
security-next tree.  From there the code is pushed to Linus' tree.

Kent

> Thanks,
> 
> Mathias Leblanc
> 
> -----Original Message-----
> From: Kent Yoder [mailto:key@linux.vnet.ibm.com] 
> Sent: 14 November, 2012 23:07
> To: Mathias LEBLANC
> Cc: Rajiv Andrade; Marcel Selhorst; Sirrix AG; tpmdd-devel@lists.sourceforge.net; Debora Velarde; linux-kernel@vger.kernel.org; Jean-Luc BLANC
> Subject: Re: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
> 
> Hi Mathias,
> 
> On Wed, Nov 14, 2012 at 03:31:42PM +0100, Mathias Leblanc wrote:
> >  * 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.
> > 
> > This is the driver for TPM chip from ST Microelectronics.
> > 
> > If you have a TPM security chip from STMicroelectronics working with 
> > an I2C, in menuconfig or .config choose the tpm driver on device --> 
> > tpm and activate the protocol of your choice before compiling the 
> > kernel.
> > The driver will be accessible from within Linux.
> > 
> > Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM OS
> 
>   Getting some build errors here:
> 
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_interrupts’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:615:1: warning: return from incompatible pointer type [enabled by default]
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_power_mgt’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:619:1: warning: return from incompatible pointer type [enabled by default]
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘tpm_st33_i2c_probe’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:725:3: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function
> ‘tpm_st33_i2c_pm_suspend’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:826:3: error: too many arguments to function ‘tpm_pm_suspend’
> In file included from drivers/char/tpm/tpm_stm_st33_i2c.h:55:0,
>                  from drivers/char/tpm/tpm_stm_st33_i2c.c:35:
> 		 drivers/char/tpm/tpm.h:326:12: note: declared here
> 		 drivers/char/tpm/tpm_stm_st33_i2c.c: In function
> 		 ‘tpm_st33_i2c_pm_resume’:
> 		 drivers/char/tpm/tpm_stm_st33_i2c.c:855:3: error:
> 		 implicit declaration of function
> 		 ‘tpm_continue_selftest’
> 		 [-Werror=implicit-function-declaration]
> 
> [cut]
> > +/*
> > + * _wait_for_interrupt_serirq_timeout
> > + * @param: tpm, the chip description
> > + * @param: timeout, the timeout of the interrupt
> > + * @return: the status of the interruption.
> > + */
> > +static int _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
> > +						unsigned long timeout)
> > +{
> > +	int status;
> > +	struct i2c_client *client;
> > +	struct st33zp24_platform_data *pin_infos;
> > +
> > +	client = (struct i2c_client *) chip->vendor.iobase;
> > +	pin_infos = client->dev.platform_data;
> > +
> > +	status = wait_for_completion_interruptible_timeout(
> > +					&pin_infos->irq_detection,
> > +						timeout);
> 
>   status should be a long here.
> 
> [cut]
> > +
> > +	if (client == NULL) {
> > +		pr_info("client is NULL. exiting.\n");
> > +		err = -ENODEV;
> > +		goto end;
> > +	}
> > +
> > +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> > +		pr_info("client not i2c capable\n");
> > +		err = -ENODEV;
> > +		goto end;
> > +	}
> > +
> > +	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
> > +	if (!chip) {
> > +		pr_info("fail chip\n");
> 
>   Please use dev_info() in place of pr_info().
> 
> Thanks,
> Kent
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
  2012-11-26 15:51     ` Kent Yoder
@ 2012-11-26 16:03       ` Mathias LEBLANC
  0 siblings, 0 replies; 8+ messages in thread
From: Mathias LEBLANC @ 2012-11-26 16:03 UTC (permalink / raw)
  To: Kent Yoder
  Cc: Rajiv Andrade, Marcel Selhorst, Sirrix AG, tpmdd-devel,
	Debora Velarde, linux-kernel, Jean-Luc BLANC

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4596 bytes --]

Hi Kent,
Thanks a lot, if you see other changes to make in  the driver, do not hesitate.
NB: I will not be available on Thursday and Friday in the coming weeks

-----Original Message-----
From: Kent Yoder [mailto:key@linux.vnet.ibm.com] 
Sent: 26 November, 2012 16:52
To: Mathias LEBLANC
Cc: Rajiv Andrade; Marcel Selhorst; Sirrix AG; tpmdd-devel@lists.sourceforge.net; Debora Velarde; linux-kernel@vger.kernel.org; Jean-Luc BLANC
Subject: Re: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C

On Tue, Nov 20, 2012 at 09:26:40AM +0100, Mathias LEBLANC wrote:
> Hello,
> 
> Does anyone can say me when the driver will be integrated on linux kernel and where can we get it  from the linux source code?

 Hi Mathias, I'll work with you this week to get this pushed to the security-next tree.  From there the code is pushed to Linus' tree.

Kent

> Thanks,
> 
> Mathias Leblanc
> 
> -----Original Message-----
> From: Kent Yoder [mailto:key@linux.vnet.ibm.com]
> Sent: 14 November, 2012 23:07
> To: Mathias LEBLANC
> Cc: Rajiv Andrade; Marcel Selhorst; Sirrix AG; 
> tpmdd-devel@lists.sourceforge.net; Debora Velarde; 
> linux-kernel@vger.kernel.org; Jean-Luc BLANC
> Subject: Re: [PATCH 1/1] TPM: STMicroelectronics ST33 I2C
> 
> Hi Mathias,
> 
> On Wed, Nov 14, 2012 at 03:31:42PM +0100, Mathias Leblanc wrote:
> >  * 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.
> > 
> > This is the driver for TPM chip from ST Microelectronics.
> > 
> > If you have a TPM security chip from STMicroelectronics working with 
> > an I2C, in menuconfig or .config choose the tpm driver on device --> 
> > tpm and activate the protocol of your choice before compiling the 
> > kernel.
> > The driver will be accessible from within Linux.
> > 
> > Tested on linux x86/x64, beagleboard REV B & XM REV C and CHROMIUM 
> > OS
> 
>   Getting some build errors here:
> 
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_interrupts’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:615:1: warning: return from 
> incompatible pointer type [enabled by default]
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘__check_power_mgt’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:619:1: warning: return from 
> incompatible pointer type [enabled by default]
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function ‘tpm_st33_i2c_probe’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:725:3: warning: suggest 
> parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
> drivers/char/tpm/tpm_stm_st33_i2c.c: In function
> ‘tpm_st33_i2c_pm_suspend’:
> drivers/char/tpm/tpm_stm_st33_i2c.c:826:3: error: too many arguments to function ‘tpm_pm_suspend’
> In file included from drivers/char/tpm/tpm_stm_st33_i2c.h:55:0,
>                  from drivers/char/tpm/tpm_stm_st33_i2c.c:35:
> 		 drivers/char/tpm/tpm.h:326:12: note: declared here
> 		 drivers/char/tpm/tpm_stm_st33_i2c.c: In function
> 		 ‘tpm_st33_i2c_pm_resume’:
> 		 drivers/char/tpm/tpm_stm_st33_i2c.c:855:3: error:
> 		 implicit declaration of function
> 		 ‘tpm_continue_selftest’
> 		 [-Werror=implicit-function-declaration]
> 
> [cut]
> > +/*
> > + * _wait_for_interrupt_serirq_timeout
> > + * @param: tpm, the chip description
> > + * @param: timeout, the timeout of the interrupt
> > + * @return: the status of the interruption.
> > + */
> > +static int _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
> > +						unsigned long timeout)
> > +{
> > +	int status;
> > +	struct i2c_client *client;
> > +	struct st33zp24_platform_data *pin_infos;
> > +
> > +	client = (struct i2c_client *) chip->vendor.iobase;
> > +	pin_infos = client->dev.platform_data;
> > +
> > +	status = wait_for_completion_interruptible_timeout(
> > +					&pin_infos->irq_detection,
> > +						timeout);
> 
>   status should be a long here.
> 
> [cut]
> > +
> > +	if (client == NULL) {
> > +		pr_info("client is NULL. exiting.\n");
> > +		err = -ENODEV;
> > +		goto end;
> > +	}
> > +
> > +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> > +		pr_info("client not i2c capable\n");
> > +		err = -ENODEV;
> > +		goto end;
> > +	}
> > +
> > +	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
> > +	if (!chip) {
> > +		pr_info("fail chip\n");
> 
>   Please use dev_info() in place of pr_info().
> 
> Thanks,
> Kent
> 

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-11-26 16:04 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-14 14:31 [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Mathias Leblanc
2012-11-14 14:31 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C CHROMIUM Mathias Leblanc
2012-11-14 14:31 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C BUILD STUFF Mathias Leblanc
2012-11-14 22:06 ` [PATCH 1/1] TPM: STMicroelectronics ST33 I2C Kent Yoder
2012-11-19 13:48   ` Mathias LEBLANC
2012-11-20  8:26   ` Mathias LEBLANC
2012-11-26 15:51     ` Kent Yoder
2012-11-26 16:03       ` Mathias LEBLANC

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).