public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] New stm i2c tpm device driver
@ 2010-09-30 19:09 Rajiv Andrade
  2010-09-30 19:09 ` [PATCH 1/3] TPM: new stm i2c " Rajiv Andrade
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Rajiv Andrade @ 2010-09-30 19:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: jmorris, joe, christophe-h.ricard

The following patches include a new STMicroelectronics i2c tpm device 
driver together with a document describing the platform on which the 
code was tested, and subsequent improvements submitted by Joe Perches.

Christophe Henri RICARD (1):
  TPM: New I2C TPM device driver

Joe Perches (2):
  drivers/char/tpm/tpm_stm_st19_i2c.c: Use pr_fmt, pr_<level> and
    FUNC_ENTER
  drivers/char/tpm/tpm_stm_st19_i2c.c: Add missing break and neatening

 Documentation/tpm/tpm_stm_st19_i2c.txt |  168 +++++++
 drivers/char/tpm/Kconfig               |    9 +
 drivers/char/tpm/Makefile              |    1 +
 drivers/char/tpm/tpm_stm_st19_i2c.c    |  835 ++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm_stm_st19_i2c.h    |   63 +++
 include/linux/i2c/tpm_stm_st19_i2c.h   |   45 ++
 6 files changed, 1121 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/tpm/tpm_stm_st19_i2c.txt
 create mode 100644 drivers/char/tpm/tpm_stm_st19_i2c.c
 create mode 100644 drivers/char/tpm/tpm_stm_st19_i2c.h
 create mode 100644 include/linux/i2c/tpm_stm_st19_i2c.h

-- 
1.7.2.2


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

* [PATCH 1/3] TPM: new stm i2c device driver
  2010-09-30 19:09 [PATCH 0/3] New stm i2c tpm device driver Rajiv Andrade
@ 2010-09-30 19:09 ` Rajiv Andrade
  2010-09-30 21:20   ` matt mooney
  2010-10-01  0:51   ` James Morris
  2010-09-30 19:09 ` [PATCH 2/3] TPM: Use pr_fmt, pr_<level> and FUNC_ENTER Rajiv Andrade
  2010-09-30 19:09 ` [PATCH 3/3] TPM: Add missing break and neatening Rajiv Andrade
  2 siblings, 2 replies; 14+ messages in thread
From: Rajiv Andrade @ 2010-09-30 19:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: jmorris, joe, christophe-h.ricard

From: Christophe Henri RICARD <christophe-h.ricard@st.com>

This driver uses the Linux I2C, TPM and generic gpio interfaces.

Signed-off-by: Christophe Henri RICARD <christophe-h.ricard@st.com>
Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
---
 Documentation/tpm/tpm_stm_st19_i2c.txt |  168 +++++++
 drivers/char/tpm/Kconfig               |    9 +
 drivers/char/tpm/Makefile              |    1 +
 drivers/char/tpm/tpm_stm_st19_i2c.c    |  822 ++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm_stm_st19_i2c.h    |   63 +++
 include/linux/i2c/tpm_stm_st19_i2c.h   |   45 ++
 6 files changed, 1108 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/tpm/tpm_stm_st19_i2c.txt
 create mode 100644 drivers/char/tpm/tpm_stm_st19_i2c.c
 create mode 100644 drivers/char/tpm/tpm_stm_st19_i2c.h
 create mode 100644 include/linux/i2c/tpm_stm_st19_i2c.h

diff --git a/Documentation/tpm/tpm_stm_st19_i2c.txt b/Documentation/tpm/tpm_stm_st19_i2c.txt
new file mode 100644
index 0000000..39e3ed8
--- /dev/null
+++ b/Documentation/tpm/tpm_stm_st19_i2c.txt
@@ -0,0 +1,168 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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
+ */
+
+PURPOSE OF THE DOCUMENT
+------------------------
+This document is intend to describe how to install the TPM driver for
+TPM ST19NP18 using I2C protocols.
+
+
+PLATFORM USED FOR TESTING
+--------------------------
+During the development, several embedded platforms running ARM CPU have been
+used.
+Validated platforms listing:
+- TI Beagleboard
+- STMicroelectronics Spear 300
+- STMicroelectronics Spear 600
+
+REQUIREMENTS
+-------------
+Software
+=========
+This TPM driver could be install under a kernel which implement at least the
+following features:
+- Linux GENERIC_GPIO programming interfaces.
+- I2C new style programming interface base (with probe & remove functions)
+- 1 I2C adapter (I2C Linux controller driver) or use of I2C_GPIO driver for I2C
+bitbanging.
+
+
+Hardware
+=========
+To run a TPM the platform needs  at least:
+- 2 Power supply (3.3V).
+- 1 I2C controller or 2 GPIOs used for SDA & SCL (I2C bit bang method).
+- 2 GPIOs for signals accept_command & data_available.
+
+TPM I2C speed is 100Khz (Maximum)
+
+All TPM signals work at 3.3V
+
+HOW TO INSTALL
+---------------
+Platform installation file
+===========================
+(N.B: platform file in arch/<processor_type>/mach-<platform-name>/
+
+
+1 - Software integration
+=========================
+<processor_type> could be: alpha, arm, avr32, blackfin, cris, frv, h8300, ia64,
+m32r, m68k, m68knommu, parisc, powerpc, s390, sh, sparc, sparc64, um, x86,
+xtensa...
+<platform-name> corresponds to your platform
+
+In the file where the machine_init() function exists, the developer must
+declare:
+- 1 struct st19np18_platform_data to provide which gpio the driver will use.
+	* The accept_pin and data_avail_pin gpio are configured as input only.
+	* This gpio management is under the platform developer responsability.
+
+Finally in the machine_init() function provided in the same file, the developer
+should use the well known function i2c_register_board_info() from the I2C Linux
+API Core.
+
+2- Hardware integration
+========================
+- ST recommends connecting VPS1 and VPS2 to board power supply and at least two
+GNDs (on each side of TSSOP28 package). (See datasheet for further informations)
+
+- As the ST19NP18 has no internal pull up, ST recommands to had:
+  * 2 external pull up on SDA & SCL signals (RpSDA/RpSCL) with value according
+to the abacus on page 40 or the "I2C Bus specification", version 2.1 January
+2000.
+
+
+Platform integration advises
+=============================
+
+For power management purposes, the kernel will send a TPM_SaveState command in the
+suspend tpm driver function.
+If the platform generate a TPM Init event on wakeup, the first TPM command that should
+be executed before the Linux kernel is back (resume function execution) is
+TPM_Startup(ST_STATE).
+
+Here is an example with beagleboard:
+====================================
+Depending on the platform, the developper should specify in
+the platform init file the following informations:
+- The platform gpio's used to managed the tpm's accept_pin/data_avail_pin
+(in a struct st19np18_platform_data declaration).
+- The TPM I2C 7 bits address (TPM_I2C_ST19_ADDR_WR) (in a struct i2c_board_info).
+
+Then the developper should add  the TPM slave device to the good i2c adapter with the
+i2c_register_board_info function (Assuming that the gpio and the i2c bus are well configured).
+
+file arch\arm\mach-omap2\board-omap3beagle.c
+add the following:
+-----------------------------------------------------------------------
+
+static struct st19np18_platform_data tpm_data = {
+        .accept_pin = 135,
+        .data_avail_pin = 143,
+};
+
+static struct i2c_board_info __initdata tpm_st19_i2c_board_info[] = {
+        {
+         I2C_BOARD_INFO(TPM_DRIVER_NAME, TPM_I2C_ST19_ADDR_WR),
+         .platform_data = &tpm_data,
+         },
+};
+
+------------------------------------------------------------------------
+Then complete the beagleboard init to be like that:
+------------------------------------------------------------------------
+static void __init omap3_beagle_init(void)
+{
+        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+        omap3_beagle_i2c_init();
+        platform_add_devices(omap3_beagle_devices,
+                        ARRAY_SIZE(omap3_beagle_devices));
+        omap_serial_init();
+
+        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
+        gpio_request(170, "DVI_nPD");
+        /* REVISIT leave DVI powered down until it's needed ... */
+        gpio_direction_output(170, true);
+
+        usb_musb_init(&musb_board_data);
+        usb_ehci_init(&ehci_pdata);
+        omap3beagle_flash_init();
+
+        beagle_display_init();
+
+        /* Ensure SDRC pins are mux'd for self-refresh */
+        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+        omap_mux_init_gpio(((struct st19np18_platform_data *)
+                           tpm_st19_i2c_board_info[0].platform_data)->data_avail_pin,
+                           OMAP_PIN_INPUT);
+	omap_mux_init_gpio(((struct st19np18_platform_data *)
+                           tpm_st19_i2c_board_info[0].platform_data)->accept_pin,
+                           OMAP_PIN_INPUT);
+
+	i2c_register_board_info(3, tpm_st19_i2c_board_info, ARRAY_SIZE(tpm_st19_i2c_board_info));
+}
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 4dc338f..2e99033 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -60,4 +60,13 @@ config TCG_INFINEON
 	  Further information on this driver and the supported hardware
 	  can be found at http://www.prosec.rub.de/tpm
 
+config TCG_ST19_I2C
+        tristate "STMicroelectronics ST19 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_st19_i2c.
 endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index ea3a1e0..f2f9526 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_TCG_TIS) += tpm_tis.o
 obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
+obj-$(CONFIG_TCG_ST19_I2C) += tpm_stm_st19_i2c.o
diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c b/drivers/char/tpm/tpm_stm_st19_i2c.c
new file mode 100644
index 0000000..35307d2
--- /dev/null
+++ b/drivers/char/tpm/tpm_stm_st19_i2c.c
@@ -0,0 +1,822 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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_st19_i2c.c
+ *
+ * @Synopsis:
+ * ----------------------------------------------------------------------
+ *	02/12/2008
+ *	- Stand alone implementation (without any TPM api)
+ * ----------------------------------------------------------------------
+ *	03/02/2010
+ *	- Power management (suspend and resume functions)
+ *	implementation
+ * ----------------------------------------------------------------------
+ *	03/19/2010
+ *	- Use of the linux kernel TPM api --> driver/char/tpm
+ * ----------------------------------------------------------------------
+ *	05/26/2010
+ *	- Update code for code submission and bug fixes:
+ *	- Comments spelling fixes
+ *	- Lindent script execution
+ *	- checkpatch.pl script execution
+ *	- fix syslog error when loaded as a module:
+ *	 "release() function missing and must be fixed"
+ *	- name files change from
+ *	  stm_st19_tpm_i2c to tpm_stm_st19_i2c
+ * ----------------------------------------------------------------------
+ *	06/15/2010
+ *	- Update for new tpm core device.
+ *	num_opens --> is_open
+ * ----------------------------------------------------------------------
+ *	07/08/2010
+ *	- Update probe, resume suspend functions
+ *	- Fix issue suspend buffer and work around related to the
+ *	chip->data_buffer not allocated.
+ * ----------------------------------------------------------------------
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.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/i2c/tpm_stm_st19_i2c.h>
+
+#include "tpm.h"
+
+#include "tpm_stm_st19_i2c.h"
+
+/*
+ * @Comments: tpm_stm_st19_platform_specific.h deliver shows a platform specific
+ * file example.
+ * It has been created to split TPM datas and platform.
+ * This example could be used when the driver is built as a module.
+ * In case of other platform, please add a struct i2c_board_info in your arch/
+ * platform file.
+ */
+static struct st19np18_platform_data *pin_infos;
+
+/*
+ * gpio_readpin is a wrapper to read a gpio value.
+ * Use generic gpio APIs
+ * @param: pin_id, the pin identifier where the value will be read.
+ * @return: the gpio value (should be 0 or 1) or negative errno
+ */
+static int gpio_readpin(int pin_id)
+{
+	int ret;
+	ret = gpio_direction_input(pin_id);
+	if (ret == 0)
+		return gpio_get_value(pin_id);
+	return ret;
+}
+
+/*
+ * gpio_writepin is a wrapper to write a gpio value.
+ * Use generic gpio APIs.
+ * @param: pin_id, the pin identifier where the value will be wrote.
+ * @param: value, the value that will be written.
+ * @return: 0 in case of success
+ */
+#ifdef DEBUG
+static int gpio_writepin(int pin_id, int value)
+{
+	int ret;
+	ret = gpio_direction_output(pin_id, value);
+
+	if (ret == 0)
+		gpio_set_value(pin_id, value);
+	return ret;
+}
+#endif
+
+static int wait_until_good_shape(void)
+{
+	int state_data = 0;
+	int state_command = 0;
+	int timeout = msecs_to_jiffies(STARTUP_WAIT_INTERVAL);
+	int time = msecs_to_jiffies(TICK_GPIO_SPOOLING);
+	int ret = 0;
+	wait_queue_head_t queue;
+
+	int wait_time = 0;
+	DEFINE_WAIT(__wait);
+	init_waitqueue_head(&queue);
+
+	do {
+		prepare_to_wait(&queue, &__wait, TASK_INTERRUPTIBLE);
+		state_data = gpio_readpin(pin_infos->data_avail_pin);
+		state_command = gpio_readpin(pin_infos->accept_pin);
+
+		if (state_data == 0 && state_command > 0)
+			return 0;
+		else if (wait_time >= timeout)
+			return -EIO;
+		else if (!signal_pending(current)) {
+			ret = schedule_timeout(time);
+			wait_time += time;
+		} else
+			ret = -ERESTARTSYS;
+	} while (1);
+	finish_wait(&queue, &__wait);
+
+	return ret;
+}
+
+/*
+ * wait_event_interruptible_on_gpio is a function that poll on
+ * GPIO dataavailable and GPIO acceptcommand
+ * @param: queue, the queue where the work will be stored
+ * @param: timeout, maximal pooling time.
+ * @return: DATA_ON in case of data_available pin goes high (logical value 1).
+ * COMMAND_ON in case of accept_command pin goes high (logical value 1).
+ * -EIO in case of data_available & accept_command pin goes high
+ *		(logical value 1).
+ * -EPERM in case of data_available & accept_command pin still low
+ *		(logical value 0).
+ */
+static int wait_event_interruptible_on_gpio(wait_queue_head_t queue,
+					    int timeout)
+{
+	int state_data = 0;
+	int state_command = 0;
+	int ret = msecs_to_jiffies(TICK_GPIO_SPOOLING);
+	struct tpm_chip *chip =
+	    (struct tpm_chip *)i2c_get_clientdata(pin_infos->client);
+	int long_timeout =
+	    tpm_calc_ordinal_duration(chip, TPM_I2C_ORDINAL_LONG);
+	int wait_time = 0;
+	DEFINE_WAIT(__wait);
+
+	if (timeout > long_timeout)
+		timeout = long_timeout;
+
+	do {
+		prepare_to_wait(&queue, &__wait, TASK_INTERRUPTIBLE);
+		state_data = gpio_readpin(pin_infos->data_avail_pin);
+		state_command = gpio_readpin(pin_infos->accept_pin);
+
+		if (state_data > 0 || state_command > 0)
+			break;
+		else if (wait_time >= timeout)
+			break;
+		else if (!signal_pending(current)) {
+			ret =
+			    schedule_timeout(msecs_to_jiffies
+					     (TICK_GPIO_SPOOLING));
+			wait_time += msecs_to_jiffies(TICK_GPIO_SPOOLING);
+		} else {
+			ret = -ERESTARTSYS;
+			break;
+		}
+	} while (1);
+	finish_wait(&queue, &__wait);
+
+	return (state_data && state_command) ? -EIO : state_data ? DATA_ON :
+	    state_command ? COMMAND_ON : -EPERM;
+}
+
+/*
+ * responseSize return the command size
+ * @param: buffer, command buffer.
+ * @param: size, the buffer size.
+ * @return: the command size.
+ */
+static int responseSize(const char *buffer, size_t size)
+{
+	size_t val = 0;
+	if (size >= TPM_HEADER_SIZE) {
+		val = (size_t) (((unsigned)buffer[2]) << 24
+				| ((unsigned)buffer[3]) << 16
+				| ((unsigned)buffer[4]) << 8 | (unsigned)
+				buffer[5]);
+	}
+
+	if (val < TPM_BUFSIZE)
+		return val;
+	else
+		return TPM_BUFSIZE;
+}
+
+/*
+ * tpm_stm_i2c_send send TPM commands through the I2C bus.
+ * Before sending any TPM commands, tpm_stm_i2c_send poll data_available and
+ * accept_command TPM GPIOs.
+ *
+ * In case the data_available is high (logical value 1), tpm_stm_i2c_send will
+ * empty the TPM FIFO by reading all the datas stored inside the TPM.
+ *
+ * Then, if the accept_command TPM GPIO is high(logical value 1)
+ * tpm_stm_i2c_send will first send the 10 bytes header of the TCG commands and
+ * then send the others bytes by 40 bytes blocks.
+ *
+ * data_available and accept_command TPM GPIOs will goes low when the TPM
+ * compute the command.
+ *
+ * @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 count)
+{
+	u32 ret = 0, i, size, ordinal, pin = 0;
+	struct i2c_client *client;
+
+#ifdef DEBUG
+	printk(KERN_INFO "tpm_st19_i2c: tpm_stm_i2c_send\n");
+#endif
+
+	if (chip == NULL)
+		return -EBUSY;
+	if (count < TPM_HEADER_SIZE)
+		return -EBUSY;
+	client = (struct i2c_client *)pin_infos->client;
+
+	ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+
+	/* i2c_client initialization */
+	client->flags = 0;
+
+	/* Wait for AcceptCmd signal high */
+	/* Check if data are available before */
+	/* sending data (data_avail_pin hight) */
+	/* If data are available, we read the data */
+	init_waitqueue_head(&pin_infos->write_queue);
+	pin = wait_event_interruptible_on_gpio(pin_infos->write_queue,
+					       tpm_calc_ordinal_duration
+					       (chip, ordinal));
+	if (pin < 0) {
+		ret = pin;
+		goto end;
+	}
+
+	client->flags = I2C_M_RD;
+
+	size = TPM_HEADER_SIZE;
+	for (i = 0; pin == DATA_ON && i < size;) {
+		ret = i2c_master_recv(client,
+				      pin_infos->tpm_i2c_buffer[1],
+				      (i == 0) ? TPM_HEADER_SIZE :
+				      count - i > TPM_I2C_BLOCK_SIZE ?
+				      TPM_I2C_BLOCK_SIZE : count - i);
+		if (ret < 0)
+			goto end;
+		if (i == 0)
+			size =
+			    responseSize(pin_infos->tpm_i2c_buffer[1], count);
+		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
+
+		if (i < size)
+			pin =
+			    wait_event_interruptible_on_gpio(pin_infos->
+							     write_queue,
+							     msecs_to_jiffies
+							     (TPM_I2C_SHORT));
+	}
+
+	pin = wait_event_interruptible_on_gpio(pin_infos->write_queue,
+					       msecs_to_jiffies(TPM_I2C_SHORT));
+
+	/* i2c_client initialization */
+	client->flags = 0;
+
+	size = TPM_HEADER_SIZE;
+	for (i = 0; i < size && pin == COMMAND_ON;) {
+		memcpy(pin_infos->tpm_i2c_buffer[0], buf + i,
+		       (i == 0) ? TPM_HEADER_SIZE : count - i >
+		       TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE : count - i);
+
+		if (i == 0) {
+			size = responseSize(buf, count);
+			size = (size < count ? size : count);
+		}
+		ret =
+		    i2c_master_send(client,
+				    pin_infos->tpm_i2c_buffer[0],
+				    count >= TPM_HEADER_SIZE ? (i ==
+								0) ?
+				    TPM_HEADER_SIZE : count - i >
+				    TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
+				    count - i : count);
+		if (ret < 0) {
+			printk(KERN_INFO "tpm_st19_i2c: Failed to send data\n");
+			goto end;
+		}
+
+		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
+		/* Wait for AcceptCmd signal hight */
+		if (i < size)
+			pin =
+			    wait_event_interruptible_on_gpio(pin_infos->
+							     write_queue,
+							     msecs_to_jiffies
+							     (TPM_I2C_SHORT));
+
+		if (pin != COMMAND_ON) {
+			printk(KERN_INFO
+			       "tpm_st19_i2c:"
+			       " Failed to read gpio pin (AcceptCmd)\n");
+			ret = -EIO;
+			goto end;
+		}
+	}
+	if (i == 0) {
+		printk(KERN_INFO
+		       "tpm_st19_i2c: Failed to read gpio pin (AcceptCmd)\n");
+		ret = -EIO;
+	}
+end:
+	return ret ? ret : count;
+}
+
+/*
+ * tpm_stm_i2c_recv received TPM response through the I2C bus.
+ * Before receiving any TPM response, tpm_stm_i2c_recv poll data_available and
+ * accept_command TPM GPIOs.
+ *
+ * In case the accept_command is high (logical value 1), tpm_stm_i2c_recv will
+ * do nothing.
+ *
+ * Then, if the data_available TPM GPIO is high(logical value 1)
+ * tpm_stm_i2c_recv will first receive the 10 bytes header of the TCG TPM
+ * response and then receive the others bytes by 40 bytes blocks.
+ *
+ * accept_command TPM GPIOs will goes high when the TPM Fofo is empty.
+ *
+ * @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 ret = 0;
+	int i, size;
+	int pin = 0;
+	struct i2c_client *client;
+
+#ifdef DEBUG
+	printk(KERN_INFO "tpm_st19_i2c: tpm_stm_i2c_recv\n");
+#endif
+
+	if (chip == NULL)
+		return -EBUSY;
+	if (count < TPM_HEADER_SIZE)
+		return -EBUSY;
+
+	client = (struct i2c_client *)pin_infos->client;
+
+	/* Configure TPM I2C */
+	client->flags = I2C_M_RD;
+
+	/* Spool on the good gpio as long as pin GPIO 3 not HIGHT */
+	init_waitqueue_head(&chip->vendor.read_queue);
+	pin = wait_event_interruptible_on_gpio(chip->vendor.read_queue,
+					       tpm_calc_ordinal_duration
+					       (chip, TPM_I2C_ORDINAL_LONG));
+
+	size = TPM_HEADER_SIZE;
+	for (i = 0; i < size && pin == DATA_ON;) {
+		ret =
+		    i2c_master_recv(client,
+				    pin_infos->tpm_i2c_buffer[1],
+				    (count >= TPM_HEADER_SIZE ? i ==
+				     0 ? TPM_HEADER_SIZE : (size - i) >
+				     TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
+				     size - i : count));
+		if (ret < 0) {
+			printk(KERN_INFO
+			       "tpm_st19_i2c:"
+			       " Failed to read gpio pin (DataAvalaible)\n");
+			goto end;
+		}
+
+		if (buf != NULL) {
+			memcpy(buf + i, pin_infos->tpm_i2c_buffer[1],
+			       (count >= TPM_HEADER_SIZE ? i == 0 ?
+				TPM_HEADER_SIZE : (size - i) >
+				TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE : size -
+				i : count));
+
+			if (i == 0) {
+				size = responseSize(buf, size);
+				if (size > count)
+					size = count;
+			}
+		} else {
+			printk(KERN_INFO "tpm_st19_i2c: read buffer is NULL\n");
+			goto end;
+		}
+
+		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
+
+		if (i < size)
+			pin =
+			    wait_event_interruptible_on_gpio(chip->vendor.
+							     read_queue,
+							     msecs_to_jiffies
+							     (TPM_I2C_SHORT));
+	}
+
+	if (i == 0) {
+		printk(KERN_INFO
+		       "tpm_st19_i2c: "
+		       "Failed to read gpio pin (DataAvalaible)\n");
+		ret = -EIO;
+		goto end;
+	}
+	return size;
+end:
+	return ret;
+}
+
+/*
+ * 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)
+{
+}				/* tpm_stm_i2c_cancel() */
+
+/*
+ * tpm_stm_i2c_status is not implemented because TIS registers are not
+ * implemented.
+ */
+static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
+{
+	return -ENOSYS;
+}				/* tpm_stm_i2c_status() */
+
+#ifdef _MODULE
+
+static void tpm_st19_i2c_dummy(struct device *dev)
+{
+
+}				/*tpm_st19_i2c_dummy() */
+
+/*
+ * tpm_st19_i2c_release do nothing
+ * @param: kobj, not used
+ */
+static void tpm_st19_i2c_release(struct kobject *kobj)
+{
+	struct tpm_chip *chip;
+	printk(KERN_INFO "tpm_st19_i2c_release\n");
+
+	if (_client != NULL) {
+		chip = (struct tpm_chip *)i2c_get_clientdata(_client);
+
+		if (chip != NULL) {
+			chip->release = tpm_st19_i2c_dummy;
+			chip->dev->release(chip->dev);
+		}
+	}
+}				/* tpm_st19_i2c_release() */
+#endif /*_MODULE */
+/*
+ * tpm_st19_i2c_ioctl provides 2 handles:
+ * - TPMIOC_CANCEL: allow to CANCEL a TPM commands execution.
+ *   See tpm_stm_i2c_cancel description above
+ * - TPMIOC_TRANSMIT: allow to transmit a TPM commands.
+ *
+ * @return: In case of success, return TPM response size.
+ * In other case return < 0 value describing the issue.
+ */
+static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file *file,
+				  unsigned int cmd, unsigned long arg)
+{
+	int in_size = 0, out_size = 0;
+	struct tpm_chip *chip = file->private_data;
+
+	switch (cmd) {
+	case TPMIOC_CANCEL:
+		tpm_stm_i2c_cancel(chip);
+		return -ENOSYS;
+	case TPMIOC_TRANSMIT:
+		if (copy_from_user(pin_infos->tpm_i2c_buffer[0],
+		    (const char *)arg, TPM_HEADER_SIZE))
+			return -EFAULT;
+		in_size = responseSize(pin_infos->tpm_i2c_buffer[0],
+				      TPM_HEADER_SIZE);
+		if (in_size > sizeof(pin_infos->tpm_i2c_buffer[0]))
+			in_size = sizeof(pin_infos->tpm_i2c_buffer[0]);
+		if (copy_from_user(pin_infos->tpm_i2c_buffer[0],
+				   (const char *)arg, in_size))
+			return -EFAULT;
+		tpm_stm_i2c_send(chip, pin_infos->tpm_i2c_buffer[0], in_size);
+
+		out_size = tpm_stm_i2c_recv(chip, pin_infos->tpm_i2c_buffer[1],
+					    TPM_BUFSIZE);
+		if (copy_to_user((char *)arg, pin_infos->tpm_i2c_buffer[1],
+				 out_size))
+			return -EFAULT;
+		return out_size;
+	default:
+		return -ENOTTY;
+	}
+	return -ENOTTY;
+}
+
+static const struct file_operations tpm_st19_i2c_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = tpm_read,
+	.ioctl = tpm_st19_i2c_ioctl,
+	.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,
+	.attr_group = &stm_tpm_attr_grp,
+	.miscdev = {.fops = &tpm_st19_i2c_fops,},
+};
+
+/*
+ * tpm_st19_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_st19_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int err;
+	struct tpm_chip *chip;
+	struct st19np18_platform_data *platform_data;
+
+	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_probe\n");
+
+	err = 0;
+
+	/* Check I2C platform functionnalities */
+	if (client == NULL) {
+		printk(KERN_INFO "client is NULL. exiting.\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		printk(KERN_INFO "tpm_st19_i2c: client not i2c capable\n");
+		err = -ENODEV;
+		goto end;
+	}
+
+	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
+	if (!chip) {
+		err = -ENODEV;
+		goto end;
+	}
+
+	/*
+	 * ST19 TPM does not support interrupt. chip->vendor.irq is only
+	 * set to a value greater that 0 because status function have no
+	 * sense with this device (TIS register not available)
+	 */
+	chip->vendor.irq = 1;
+
+	platform_data = client->dev.platform_data;
+	pin_infos = 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;
+	}
+
+	platform_data->client = client;
+
+	/* Register GPIO pin through generic Linux GPIO API */
+	err = gpio_request(platform_data->accept_pin, "accept command");
+	if (err)
+		goto _gpio_init;
+
+	err = gpio_request(platform_data->data_avail_pin, "data available");
+	if (err)
+		goto _gpio_init;
+
+	err = wait_until_good_shape();
+	if (err)
+		goto _gpio_set;
+
+	tpm_get_timeouts(chip);
+
+	/* attach chip datas to client */
+	i2c_set_clientdata(client, chip);
+	pin_infos->bChipF = false;
+
+	printk(KERN_INFO "tpm_st19_i2c: TPM I2C Initialized\n");
+	return 0;
+_gpio_set:
+_gpio_init:
+	if (platform_data) {
+		gpio_free(platform_data->accept_pin);
+		gpio_free(platform_data->data_avail_pin);
+	}
+_tpm_clean_response:
+	tpm_remove_hardware(chip->dev);
+	if (platform_data->tpm_i2c_buffer[1] != NULL) {
+		kfree(platform_data->tpm_i2c_buffer[1]);
+		platform_data->tpm_i2c_buffer[1] = NULL;
+	}
+_tpm_clean_answer:
+	if (platform_data->tpm_i2c_buffer[0] != NULL) {
+		kfree(platform_data->tpm_i2c_buffer[0]);
+		platform_data->tpm_i2c_buffer[0] = NULL;
+	}
+	pin_infos->bChipF = true;
+end:
+	printk(KERN_INFO "tpm_st19_i2c: TPM I2C initialisation fail\n");
+	return err;
+}
+
+/*
+ * tpm_st19_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_st19_i2c_remove(struct i2c_client *client)
+{
+	struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
+	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_remove\n");
+
+	if (pin_infos != NULL) {
+		gpio_free(pin_infos->accept_pin);
+		gpio_free(pin_infos->data_avail_pin);
+
+		/* Check if chip has been previously clean */
+		if (pin_infos->bChipF != true)
+			tpm_remove_hardware(chip->dev);
+		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
+			kfree(pin_infos->tpm_i2c_buffer[1]);
+			pin_infos->tpm_i2c_buffer[1] = NULL;
+		}
+		if (pin_infos->tpm_i2c_buffer[0] != NULL) {
+			kfree(pin_infos->tpm_i2c_buffer[0]);
+			pin_infos->tpm_i2c_buffer[0] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * tpm_st19_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_st19_i2c_pm_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct tpm_chip *chip =
+	    (struct tpm_chip *)i2c_get_clientdata(pin_infos->client);
+	int ret = 0;
+	if (chip->data_buffer == NULL)
+		chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+	ret = tpm_pm_suspend(&client->dev, mesg);
+	return ret;
+}				/* tpm_st19_i2c_suspend() */
+
+/*
+ * tpm_st19_i2c_pm_resume resume the TPM device
+ * This part of the Linux driver should be move in an other part or
+ * environment (bootloader ?)
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @return: 0 in case of success.
+ */
+static int tpm_st19_i2c_pm_resume(struct i2c_client *client)
+{
+	struct tpm_chip *chip =
+	    (struct tpm_chip *)i2c_get_clientdata(pin_infos->client);
+	int ret = 0;
+	if (chip->data_buffer == NULL)
+		chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+	ret = tpm_pm_resume(&client->dev);
+	return ret;
+}				/* tpm_st19_i2c_pm_resume() */
+
+static const struct i2c_device_id tpm_st19_i2c_id[] = {
+	{TPM_DRIVER_NAME, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tpm_st19_i2c_id);
+
+static struct i2c_driver tpm_st19_i2c_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = TPM_DRIVER_NAME,
+		   },
+	.probe = tpm_st19_i2c_probe,
+	.remove = tpm_st19_i2c_remove,
+	.resume = tpm_st19_i2c_pm_resume,
+	.suspend = tpm_st19_i2c_pm_suspend,
+	.id_table = tpm_st19_i2c_id
+};
+
+/*
+ * tpm_st19_i2c_init initialize driver
+ * @return: 0 if successful, else non zero value.
+ */
+static int __init tpm_st19_i2c_init(void)
+{
+	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_init\n");
+	return i2c_add_driver(&tpm_st19_i2c_driver);
+}
+
+/*
+ * tpm_st19_i2c_exit The kernel calls this function during unloading the
+ * module or during shut down process
+ */
+static void __exit tpm_st19_i2c_exit(void)
+{
+	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_exit\n");
+	i2c_del_driver(&tpm_st19_i2c_driver);
+}
+
+module_init(tpm_st19_i2c_init);
+module_exit(tpm_st19_i2c_exit);
+
+MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
+MODULE_DESCRIPTION("STM TPM I2C ST19 Driver");
+MODULE_VERSION("1.2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.h b/drivers/char/tpm/tpm_stm_st19_i2c.h
new file mode 100644
index 0000000..db3a059
--- /dev/null
+++ b/drivers/char/tpm/tpm_stm_st19_i2c.h
@@ -0,0 +1,63 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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_st19_tpm_i2c.h
+ *
+ * @Date: 02/12/2008
+ */
+#ifndef __STM_ST19_TPM_I2C_MAIN_H__
+#define __STM_ST19_TPM_I2C_MAIN_H__
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+
+#define MINOR_NUM_I2C		224
+
+#define TPM_DRIVER_NAME		"st19np18"
+
+#define	TPM_BUFSIZE		2048
+
+#define TPM_HEADER_SIZE		10
+#define TPM_I2C_BLOCK_SIZE	0x28
+
+#define TPM_I2C_ORDINAL_LONG	0x0D	/* TPM_ORD_TakeOwnership */
+
+#define TPM_I2C_SHORT	2000	/* 2s */
+#define TICK_GPIO_SPOOLING	2
+#define STARTUP_WAIT_INTERVAL	8 /* 8ms */
+
+/* ioctl commands */
+#define TPMIOC_CANCEL		_IO('T', 0x00)	/* Not supported */
+#define TPMIOC_TRANSMIT		_IO('T', 0x01)
+
+#define DATA_ON			  1	/* data available */
+#define COMMAND_ON		  2	/* accept command */
+
+#endif /* __STM_ST19_TPM_I2C_MAIN_H__ */
diff --git a/include/linux/i2c/tpm_stm_st19_i2c.h b/include/linux/i2c/tpm_stm_st19_i2c.h
new file mode 100644
index 0000000..cdac5f4
--- /dev/null
+++ b/include/linux/i2c/tpm_stm_st19_i2c.h
@@ -0,0 +1,45 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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_st19_tpm_i2c.h
+ *
+ * @Date: 06/15/2008
+ */
+#ifndef __STM_ST19_TPM_I2C_H__
+#define __STM_ST19_TPM_I2C_H__
+
+#include <linux/i2c.h>
+
+#define TPM_DRIVER_NAME         "st19np18"
+#define TPM_I2C_ST19_ADDR_WR	(0x26 >> 1)
+
+struct st19np18_platform_data {
+	int accept_pin;	/* accept command pin */
+	int data_avail_pin;/* data available pin */
+	struct i2c_client *client;
+	bool bChipF;
+	u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
+	wait_queue_head_t write_queue;
+};
+
+#endif /* __STM_ST19_TPM_I2C_H__ */
-- 
1.7.2.2


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

* [PATCH 2/3] TPM: Use pr_fmt, pr_<level> and FUNC_ENTER
  2010-09-30 19:09 [PATCH 0/3] New stm i2c tpm device driver Rajiv Andrade
  2010-09-30 19:09 ` [PATCH 1/3] TPM: new stm i2c " Rajiv Andrade
@ 2010-09-30 19:09 ` Rajiv Andrade
  2010-09-30 19:09 ` [PATCH 3/3] TPM: Add missing break and neatening Rajiv Andrade
  2 siblings, 0 replies; 14+ messages in thread
From: Rajiv Andrade @ 2010-09-30 19:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: jmorris, joe, christophe-h.ricard

From: Joe Perches <joe@perches.com>

Add FUNC_ENTER to emit pr_info("%s\n", __func_) with #DEBUG

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
---
 drivers/char/tpm/tpm_stm_st19_i2c.c |   57 ++++++++++++++++++-----------------
 1 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c b/drivers/char/tpm/tpm_stm_st19_i2c.c
index 35307d2..cdf2eb3 100644
--- a/drivers/char/tpm/tpm_stm_st19_i2c.c
+++ b/drivers/char/tpm/tpm_stm_st19_i2c.c
@@ -58,6 +58,8 @@
  * ----------------------------------------------------------------------
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -81,6 +83,12 @@
 
 #include "tpm_stm_st19_i2c.h"
 
+#ifdef DEBUG
+#define FUNC_ENTER()	pr_info("%s\n", __func__)
+#else
+#define FUNC_ENTER()	do {} while (0)
+#endif
+
 /*
  * @Comments: tpm_stm_st19_platform_specific.h deliver shows a platform specific
  * file example.
@@ -260,9 +268,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 	u32 ret = 0, i, size, ordinal, pin = 0;
 	struct i2c_client *client;
 
-#ifdef DEBUG
-	printk(KERN_INFO "tpm_st19_i2c: tpm_stm_i2c_send\n");
-#endif
+	FUNC_ENTER();
 
 	if (chip == NULL)
 		return -EBUSY;
@@ -337,7 +343,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 				    TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
 				    count - i : count);
 		if (ret < 0) {
-			printk(KERN_INFO "tpm_st19_i2c: Failed to send data\n");
+			pr_info("Failed to send data\n");
 			goto end;
 		}
 
@@ -351,16 +357,13 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 							     (TPM_I2C_SHORT));
 
 		if (pin != COMMAND_ON) {
-			printk(KERN_INFO
-			       "tpm_st19_i2c:"
-			       " Failed to read gpio pin (AcceptCmd)\n");
+			pr_info("Failed to read gpio pin (AcceptCmd)\n");
 			ret = -EIO;
 			goto end;
 		}
 	}
 	if (i == 0) {
-		printk(KERN_INFO
-		       "tpm_st19_i2c: Failed to read gpio pin (AcceptCmd)\n");
+		pr_info("Failed to read gpio pin (AcceptCmd)\n");
 		ret = -EIO;
 	}
 end:
@@ -395,9 +398,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 	int pin = 0;
 	struct i2c_client *client;
 
-#ifdef DEBUG
-	printk(KERN_INFO "tpm_st19_i2c: tpm_stm_i2c_recv\n");
-#endif
+	FUNC_ENTER();
 
 	if (chip == NULL)
 		return -EBUSY;
@@ -425,9 +426,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 				     TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
 				     size - i : count));
 		if (ret < 0) {
-			printk(KERN_INFO
-			       "tpm_st19_i2c:"
-			       " Failed to read gpio pin (DataAvalaible)\n");
+			pr_info("Failed to read gpio pin (DataAvailable)\n");
 			goto end;
 		}
 
@@ -444,7 +443,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 					size = count;
 			}
 		} else {
-			printk(KERN_INFO "tpm_st19_i2c: read buffer is NULL\n");
+			pr_info("read buffer is NULL\n");
 			goto end;
 		}
 
@@ -459,9 +458,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 	}
 
 	if (i == 0) {
-		printk(KERN_INFO
-		       "tpm_st19_i2c: "
-		       "Failed to read gpio pin (DataAvalaible)\n");
+		pr_info("Failed to read gpio pin (DataAvailable)\n");
 		ret = -EIO;
 		goto end;
 	}
@@ -501,7 +498,8 @@ static void tpm_st19_i2c_dummy(struct device *dev)
 static void tpm_st19_i2c_release(struct kobject *kobj)
 {
 	struct tpm_chip *chip;
-	printk(KERN_INFO "tpm_st19_i2c_release\n");
+
+	FUNC_ENTER();
 
 	if (_client != NULL) {
 		chip = (struct tpm_chip *)i2c_get_clientdata(_client);
@@ -614,19 +612,19 @@ tpm_st19_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	struct tpm_chip *chip;
 	struct st19np18_platform_data *platform_data;
 
-	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_probe\n");
+	FUNC_ENTER();
 
 	err = 0;
 
 	/* Check I2C platform functionnalities */
 	if (client == NULL) {
-		printk(KERN_INFO "client is NULL. exiting.\n");
+		pr_info("client is NULL. exiting.\n");
 		err = -ENODEV;
 		goto end;
 	}
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-		printk(KERN_INFO "tpm_st19_i2c: client not i2c capable\n");
+		pr_info("client not i2c capable\n");
 		err = -ENODEV;
 		goto end;
 	}
@@ -680,7 +678,7 @@ tpm_st19_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	i2c_set_clientdata(client, chip);
 	pin_infos->bChipF = false;
 
-	printk(KERN_INFO "tpm_st19_i2c: TPM I2C Initialized\n");
+	pr_info("TPM I2C Initialized\n");
 	return 0;
 _gpio_set:
 _gpio_init:
@@ -701,7 +699,7 @@ _tpm_clean_answer:
 	}
 	pin_infos->bChipF = true;
 end:
-	printk(KERN_INFO "tpm_st19_i2c: TPM I2C initialisation fail\n");
+	pr_info("TPM I2C initialisation fail\n");
 	return err;
 }
 
@@ -714,7 +712,8 @@ end:
 static __devexit int tpm_st19_i2c_remove(struct i2c_client *client)
 {
 	struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
-	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_remove\n");
+
+	FUNC_ENTER();
 
 	if (pin_infos != NULL) {
 		gpio_free(pin_infos->accept_pin);
@@ -799,7 +798,8 @@ static struct i2c_driver tpm_st19_i2c_driver = {
  */
 static int __init tpm_st19_i2c_init(void)
 {
-	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_init\n");
+	FUNC_ENTER();
+
 	return i2c_add_driver(&tpm_st19_i2c_driver);
 }
 
@@ -809,7 +809,8 @@ static int __init tpm_st19_i2c_init(void)
  */
 static void __exit tpm_st19_i2c_exit(void)
 {
-	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_exit\n");
+	FUNC_ENTER();
+
 	i2c_del_driver(&tpm_st19_i2c_driver);
 }
 
-- 
1.7.2.2


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

* [PATCH 3/3] TPM: Add missing break and neatening
  2010-09-30 19:09 [PATCH 0/3] New stm i2c tpm device driver Rajiv Andrade
  2010-09-30 19:09 ` [PATCH 1/3] TPM: new stm i2c " Rajiv Andrade
  2010-09-30 19:09 ` [PATCH 2/3] TPM: Use pr_fmt, pr_<level> and FUNC_ENTER Rajiv Andrade
@ 2010-09-30 19:09 ` Rajiv Andrade
  2 siblings, 0 replies; 14+ messages in thread
From: Rajiv Andrade @ 2010-09-30 19:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: jmorris, joe, christophe-h.ricard

From: Joe Perches <joe@perches.com>

Add missing break in wait_until_good_shape
Use init; while (test) loops not for(init;test;)
Calculate bytes to transfer using if and min_t not multiple ?:
Miscellaneous function whitespace aliging

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
---
 drivers/char/tpm/tpm_stm_st19_i2c.c |  158 +++++++++++++++++++----------------
 1 files changed, 85 insertions(+), 73 deletions(-)

diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c b/drivers/char/tpm/tpm_stm_st19_i2c.c
index cdf2eb3..4b1ed05 100644
--- a/drivers/char/tpm/tpm_stm_st19_i2c.c
+++ b/drivers/char/tpm/tpm_stm_st19_i2c.c
@@ -158,8 +158,10 @@ static int wait_until_good_shape(void)
 		else if (!signal_pending(current)) {
 			ret = schedule_timeout(time);
 			wait_time += time;
-		} else
+		} else {
 			ret = -ERESTARTSYS;
+			break;
+		}
 	} while (1);
 	finish_wait(&queue, &__wait);
 
@@ -204,10 +206,10 @@ static int wait_event_interruptible_on_gpio(wait_queue_head_t queue,
 		else if (wait_time >= timeout)
 			break;
 		else if (!signal_pending(current)) {
-			ret =
-			    schedule_timeout(msecs_to_jiffies
-					     (TICK_GPIO_SPOOLING));
-			wait_time += msecs_to_jiffies(TICK_GPIO_SPOOLING);
+			int time = msecs_to_jiffies(TICK_GPIO_SPOOLING);
+
+			ret = schedule_timeout(time);
+			wait_time += time;
 		} else {
 			ret = -ERESTARTSYS;
 			break;
@@ -286,9 +288,9 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 	/* sending data (data_avail_pin hight) */
 	/* If data are available, we read the data */
 	init_waitqueue_head(&pin_infos->write_queue);
-	pin = wait_event_interruptible_on_gpio(pin_infos->write_queue,
-					       tpm_calc_ordinal_duration
-					       (chip, ordinal));
+	pin = wait_event_interruptible_on_gpio(
+			pin_infos->write_queue,
+			tpm_calc_ordinal_duration(chip, ordinal));
 	if (pin < 0) {
 		ret = pin;
 		goto end;
@@ -297,25 +299,30 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 	client->flags = I2C_M_RD;
 
 	size = TPM_HEADER_SIZE;
-	for (i = 0; pin == DATA_ON && i < size;) {
-		ret = i2c_master_recv(client,
-				      pin_infos->tpm_i2c_buffer[1],
-				      (i == 0) ? TPM_HEADER_SIZE :
-				      count - i > TPM_I2C_BLOCK_SIZE ?
-				      TPM_I2C_BLOCK_SIZE : count - i);
+	i = 0;
+	while (i < size && pin == DATA_ON) {
+		int bytes;
+
+		if (i == 0)
+			bytes = TPM_HEADER_SIZE;
+		else
+			bytes = min_t(int, count - i, TPM_I2C_BLOCK_SIZE);
+
+		ret = i2c_master_recv(client, pin_infos->tpm_i2c_buffer[1],
+				      bytes);
 		if (ret < 0)
 			goto end;
-		if (i == 0)
-			size =
-			    responseSize(pin_infos->tpm_i2c_buffer[1], count);
-		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
+		if (i == 0) {
+			size = responseSize(pin_infos->tpm_i2c_buffer[1],
+					    count);
+			i += TPM_HEADER_SIZE;
+		} else
+			i += TPM_I2C_BLOCK_SIZE;
 
 		if (i < size)
-			pin =
-			    wait_event_interruptible_on_gpio(pin_infos->
-							     write_queue,
-							     msecs_to_jiffies
-							     (TPM_I2C_SHORT));
+			pin = wait_event_interruptible_on_gpio(
+					pin_infos->write_queue,
+					msecs_to_jiffies(TPM_I2C_SHORT));
 	}
 
 	pin = wait_event_interruptible_on_gpio(pin_infos->write_queue,
@@ -325,36 +332,41 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 	client->flags = 0;
 
 	size = TPM_HEADER_SIZE;
-	for (i = 0; i < size && pin == COMMAND_ON;) {
-		memcpy(pin_infos->tpm_i2c_buffer[0], buf + i,
-		       (i == 0) ? TPM_HEADER_SIZE : count - i >
-		       TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE : count - i);
+	i = 0;
+	while (i < size && pin == COMMAND_ON) {
+		int bytes;
+
+		if (i == 0)
+			bytes = TPM_HEADER_SIZE;
+		else
+			bytes = min_t(int, count - i, TPM_I2C_BLOCK_SIZE);
+
+		memcpy(pin_infos->tpm_i2c_buffer[0], buf + i, bytes);
 
 		if (i == 0) {
 			size = responseSize(buf, count);
-			size = (size < count ? size : count);
+			size = size < count ? size : count;
 		}
-		ret =
-		    i2c_master_send(client,
-				    pin_infos->tpm_i2c_buffer[0],
-				    count >= TPM_HEADER_SIZE ? (i ==
-								0) ?
-				    TPM_HEADER_SIZE : count - i >
-				    TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
-				    count - i : count);
+
+		if (count < TPM_HEADER_SIZE)
+			bytes = count;
+
+		ret = i2c_master_send(client, pin_infos->tpm_i2c_buffer[0],
+				      bytes);
 		if (ret < 0) {
 			pr_info("Failed to send data\n");
 			goto end;
 		}
 
-		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
+		if (i == 0)
+			i += TPM_HEADER_SIZE;
+		else
+			i += TPM_I2C_BLOCK_SIZE;
 		/* Wait for AcceptCmd signal hight */
 		if (i < size)
-			pin =
-			    wait_event_interruptible_on_gpio(pin_infos->
-							     write_queue,
-							     msecs_to_jiffies
-							     (TPM_I2C_SHORT));
+			pin = wait_event_interruptible_on_gpio(
+					pin_infos->write_queue,
+					msecs_to_jiffies(TPM_I2C_SHORT));
 
 		if (pin != COMMAND_ON) {
 			pr_info("Failed to read gpio pin (AcceptCmd)\n");
@@ -362,6 +374,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 			goto end;
 		}
 	}
+
 	if (i == 0) {
 		pr_info("Failed to read gpio pin (AcceptCmd)\n");
 		ret = -EIO;
@@ -412,49 +425,48 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 
 	/* Spool on the good gpio as long as pin GPIO 3 not HIGHT */
 	init_waitqueue_head(&chip->vendor.read_queue);
-	pin = wait_event_interruptible_on_gpio(chip->vendor.read_queue,
-					       tpm_calc_ordinal_duration
-					       (chip, TPM_I2C_ORDINAL_LONG));
+	pin = wait_event_interruptible_on_gpio(
+			chip->vendor.read_queue,
+			tpm_calc_ordinal_duration(chip, TPM_I2C_ORDINAL_LONG));
 
 	size = TPM_HEADER_SIZE;
-	for (i = 0; i < size && pin == DATA_ON;) {
-		ret =
-		    i2c_master_recv(client,
-				    pin_infos->tpm_i2c_buffer[1],
-				    (count >= TPM_HEADER_SIZE ? i ==
-				     0 ? TPM_HEADER_SIZE : (size - i) >
-				     TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
-				     size - i : count));
+	i = 0;
+	while (i < size && pin == DATA_ON) {
+		int bytes;
+
+		if (count < TPM_HEADER_SIZE)
+			bytes = count;
+		else if (i == 0)
+			bytes = TPM_HEADER_SIZE;
+		else
+			bytes = min_t(int, size - i, TPM_I2C_BLOCK_SIZE);
+
+		ret = i2c_master_recv(client, pin_infos->tpm_i2c_buffer[1],
+				      bytes);
 		if (ret < 0) {
 			pr_info("Failed to read gpio pin (DataAvailable)\n");
 			goto end;
 		}
 
-		if (buf != NULL) {
-			memcpy(buf + i, pin_infos->tpm_i2c_buffer[1],
-			       (count >= TPM_HEADER_SIZE ? i == 0 ?
-				TPM_HEADER_SIZE : (size - i) >
-				TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE : size -
-				i : count));
-
-			if (i == 0) {
-				size = responseSize(buf, size);
-				if (size > count)
-					size = count;
-			}
-		} else {
+		if (!buf) {
 			pr_info("read buffer is NULL\n");
 			goto end;
 		}
 
-		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
+		memcpy(buf + i, pin_infos->tpm_i2c_buffer[1], size);
+
+		if (i == 0) {
+			size = responseSize(buf, size);
+			if (size > count)
+				size = count;
+			i += TPM_HEADER_SIZE;
+		} else
+			i += TPM_I2C_BLOCK_SIZE;
 
 		if (i < size)
-			pin =
-			    wait_event_interruptible_on_gpio(chip->vendor.
-							     read_queue,
-							     msecs_to_jiffies
-							     (TPM_I2C_SHORT));
+			pin = wait_event_interruptible_on_gpio(
+					chip->vendor.read_queue,
+					msecs_to_jiffies(TPM_I2C_SHORT));
 	}
 
 	if (i == 0) {
@@ -532,7 +544,7 @@ static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file *file,
 		return -ENOSYS;
 	case TPMIOC_TRANSMIT:
 		if (copy_from_user(pin_infos->tpm_i2c_buffer[0],
-		    (const char *)arg, TPM_HEADER_SIZE))
+				   (const char *)arg, TPM_HEADER_SIZE))
 			return -EFAULT;
 		in_size = responseSize(pin_infos->tpm_i2c_buffer[0],
 				      TPM_HEADER_SIZE);
-- 
1.7.2.2


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

* Re: [PATCH 1/3] TPM: new stm i2c device driver
  2010-09-30 19:09 ` [PATCH 1/3] TPM: new stm i2c " Rajiv Andrade
@ 2010-09-30 21:20   ` matt mooney
  2010-10-01  0:51   ` James Morris
  1 sibling, 0 replies; 14+ messages in thread
From: matt mooney @ 2010-09-30 21:20 UTC (permalink / raw)
  To: Rajiv Andrade; +Cc: linux-kernel, jmorris, joe, christophe-h.ricard

On 16:09 Thu 30 Sep     , Rajiv Andrade wrote:
> From: Christophe Henri RICARD <christophe-h.ricard@st.com>
> 
> This driver uses the Linux I2C, TPM and generic gpio interfaces.
> 
> Signed-off-by: Christophe Henri RICARD <christophe-h.ricard@st.com>
> Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
> ---
>  Documentation/tpm/tpm_stm_st19_i2c.txt |  168 +++++++
>  drivers/char/tpm/Kconfig               |    9 +
>  drivers/char/tpm/Makefile              |    1 +
>  drivers/char/tpm/tpm_stm_st19_i2c.c    |  822 ++++++++++++++++++++++++++++++++
>  drivers/char/tpm/tpm_stm_st19_i2c.h    |   63 +++
>  include/linux/i2c/tpm_stm_st19_i2c.h   |   45 ++
>  6 files changed, 1108 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/tpm/tpm_stm_st19_i2c.txt
>  create mode 100644 drivers/char/tpm/tpm_stm_st19_i2c.c
>  create mode 100644 drivers/char/tpm/tpm_stm_st19_i2c.h
>  create mode 100644 include/linux/i2c/tpm_stm_st19_i2c.h
> 
> diff --git a/Documentation/tpm/tpm_stm_st19_i2c.txt b/Documentation/tpm/tpm_stm_st19_i2c.txt
> new file mode 100644
> index 0000000..39e3ed8
> --- /dev/null
> +++ b/Documentation/tpm/tpm_stm_st19_i2c.txt
> @@ -0,0 +1,168 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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
> + */
> +
> +PURPOSE OF THE DOCUMENT
> +------------------------
> +This document is intend to describe how to install the TPM driver for

intend -> intended

The sentence could be worded better though; e.g., "... describe the installation
of the TPM driver ..."

> +TPM ST19NP18 using I2C protocols.
> +
> +
> +PLATFORM USED FOR TESTING
> +--------------------------
> +During the development, several embedded platforms running ARM CPU have been

... running an ARM CPU were used.

"have been" is a present perfect tense and does not fit here.

> +used.
> +Validated platforms listing:

It would be better to say "Listing of validated platforms:"

> +- TI Beagleboard
> +- STMicroelectronics Spear 300
> +- STMicroelectronics Spear 600
> +
> +REQUIREMENTS
> +-------------
> +Software
> +=========
> +This TPM driver could be install under a kernel which implement at least the
> +following features:

The TPM driver can be installed under a kernel that implements ...

> +- Linux GENERIC_GPIO programming interfaces.
> +- I2C new style programming interface base (with probe & remove functions)

There should be a period at the end of the previous sentence for uniformity.

> +- 1 I2C adapter (I2C Linux controller driver) or use of I2C_GPIO driver for I2C
> +bitbanging.
> +
> +
> +Hardware
> +=========
> +To run a TPM the platform needs  at least:

Comma after TPM and there is an extra space btw. needs and at.

> +- 2 Power supply (3.3V).

supply -> supplies

> +- 1 I2C controller or 2 GPIOs used for SDA & SCL (I2C bit bang method).
> +- 2 GPIOs for signals accept_command & data_available.
> +
> +TPM I2C speed is 100Khz (Maximum)
> +
> +All TPM signals work at 3.3V
> +
> +HOW TO INSTALL
> +---------------
> +Platform installation file
> +===========================
> +(N.B: platform file in arch/<processor_type>/mach-<platform-name>/
> +
> +
> +1 - Software integration
> +=========================
> +<processor_type> could be: alpha, arm, avr32, blackfin, cris, frv, h8300, ia64,
> +m32r, m68k, m68knommu, parisc, powerpc, s390, sh, sparc, sparc64, um, x86,
> +xtensa...
> +<platform-name> corresponds to your platform
> +
> +In the file where the machine_init() function exists, the developer must
> +declare:
> +- 1 struct st19np18_platform_data to provide which gpio the driver will use.
> +	* The accept_pin and data_avail_pin gpio are configured as input only.
> +	* This gpio management is under the platform developer responsability.

... developer's responsibility.

> +Finally in the machine_init() function provided in the same file, the developer

Comma after finally

> +should use the well known function i2c_register_board_info() from the I2C Linux
> +API Core.
> +
> +2- Hardware integration
> +========================
> +- ST recommends connecting VPS1 and VPS2 to board power supply and at least two

Needs a "the" before board.

> +GNDs (on each side of TSSOP28 package). (See datasheet for further informations)

... information.)

> +
> +- As the ST19NP18 has no internal pull up, ST recommands to had:

to had -> having
The use of a colon here is questionable.

> +  * 2 external pull up on SDA & SCL signals (RpSDA/RpSCL) with value according

value -> values

> +to the abacus on page 40 or the "I2C Bus specification", version 2.1 January

Comman should go inside quotes

> +2000.
> +
> +
> +Platform integration advises
> +=============================
> +
> +For power management purposes, the kernel will send a TPM_SaveState command in the
> +suspend tpm driver function.
> +If the platform generate a TPM Init event on wakeup, the first TPM command that should

Add "s" to generate

> +be executed before the Linux kernel is back (resume function execution) is
> +TPM_Startup(ST_STATE).

The second half of the conditional is passive and should be reworded.

> +
> +Here is an example with beagleboard:
> +====================================
> +Depending on the platform, the developper should specify in

miss spelled developer

> +the platform init file the following informations:

no "s" after information
Again, the sentence structure could be reworked for readability. I would break
out the first preposition to its own sentence and move the second preposition to
the beginning or ending of the newly formed second sentence.

> +- The platform gpio's used to managed the tpm's accept_pin/data_avail_pin
> +(in a struct st19np18_platform_data declaration).
> +- The TPM I2C 7 bits address (TPM_I2C_ST19_ADDR_WR) (in a struct i2c_board_info).
> +
> +Then the developper should add  the TPM slave device to the good i2c adapter with the

developper -> developer
There is an extra space btw. add and the

> +i2c_register_board_info function (Assuming that the gpio and the i2c bus are well configured).

Do not capitalize "A" in assuming, unless you make it a parenthetical sentence.

> +file arch\arm\mach-omap2\board-omap3beagle.c
> +add the following:
> +-----------------------------------------------------------------------
> +
> +static struct st19np18_platform_data tpm_data = {
> +        .accept_pin = 135,
> +        .data_avail_pin = 143,
> +};
> +
> +static struct i2c_board_info __initdata tpm_st19_i2c_board_info[] = {
> +        {
> +         I2C_BOARD_INFO(TPM_DRIVER_NAME, TPM_I2C_ST19_ADDR_WR),
> +         .platform_data = &tpm_data,
> +         },
> +};
> +
> +------------------------------------------------------------------------
> +Then complete the beagleboard init to be like that:
> +------------------------------------------------------------------------

that -> this

> +static void __init omap3_beagle_init(void)
> +{
> +        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
> +        omap3_beagle_i2c_init();
> +        platform_add_devices(omap3_beagle_devices,
> +                        ARRAY_SIZE(omap3_beagle_devices));
> +        omap_serial_init();
> +
> +        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
> +        gpio_request(170, "DVI_nPD");
> +        /* REVISIT leave DVI powered down until it's needed ... */
> +        gpio_direction_output(170, true);
> +
> +        usb_musb_init(&musb_board_data);
> +        usb_ehci_init(&ehci_pdata);
> +        omap3beagle_flash_init();
> +
> +        beagle_display_init();
> +
> +        /* Ensure SDRC pins are mux'd for self-refresh */
> +        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
> +        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
> +        omap_mux_init_gpio(((struct st19np18_platform_data *)
> +                           tpm_st19_i2c_board_info[0].platform_data)->data_avail_pin,
> +                           OMAP_PIN_INPUT);
> +	omap_mux_init_gpio(((struct st19np18_platform_data *)
> +                           tpm_st19_i2c_board_info[0].platform_data)->accept_pin,
> +                           OMAP_PIN_INPUT);
> +
> +	i2c_register_board_info(3, tpm_st19_i2c_board_info, ARRAY_SIZE(tpm_st19_i2c_board_info));
> +}
> diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> index 4dc338f..2e99033 100644
> --- a/drivers/char/tpm/Kconfig
> +++ b/drivers/char/tpm/Kconfig
> @@ -60,4 +60,13 @@ config TCG_INFINEON
>  	  Further information on this driver and the supported hardware
>  	  can be found at http://www.prosec.rub.de/tpm
>  
> +config TCG_ST19_I2C
> +        tristate "STMicroelectronics ST19 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.

Comma after bus

I hope that helps.

-mfm

> +        To compile this driver as a module, choose M here; the module will be
> +        called tpm_stm_st19_i2c.
>  endif # TCG_TPM
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index ea3a1e0..f2f9526 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_TCG_TIS) += tpm_tis.o
>  obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
>  obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
>  obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
> +obj-$(CONFIG_TCG_ST19_I2C) += tpm_stm_st19_i2c.o
> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c b/drivers/char/tpm/tpm_stm_st19_i2c.c
> new file mode 100644
> index 0000000..35307d2
> --- /dev/null
> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.c
> @@ -0,0 +1,822 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_i2c.c
> + *
> + * @Synopsis:
> + * ----------------------------------------------------------------------
> + *	02/12/2008
> + *	- Stand alone implementation (without any TPM api)
> + * ----------------------------------------------------------------------
> + *	03/02/2010
> + *	- Power management (suspend and resume functions)
> + *	implementation
> + * ----------------------------------------------------------------------
> + *	03/19/2010
> + *	- Use of the linux kernel TPM api --> driver/char/tpm
> + * ----------------------------------------------------------------------
> + *	05/26/2010
> + *	- Update code for code submission and bug fixes:
> + *	- Comments spelling fixes
> + *	- Lindent script execution
> + *	- checkpatch.pl script execution
> + *	- fix syslog error when loaded as a module:
> + *	 "release() function missing and must be fixed"
> + *	- name files change from
> + *	  stm_st19_tpm_i2c to tpm_stm_st19_i2c
> + * ----------------------------------------------------------------------
> + *	06/15/2010
> + *	- Update for new tpm core device.
> + *	num_opens --> is_open
> + * ----------------------------------------------------------------------
> + *	07/08/2010
> + *	- Update probe, resume suspend functions
> + *	- Fix issue suspend buffer and work around related to the
> + *	chip->data_buffer not allocated.
> + * ----------------------------------------------------------------------
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.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/i2c/tpm_stm_st19_i2c.h>
> +
> +#include "tpm.h"
> +
> +#include "tpm_stm_st19_i2c.h"
> +
> +/*
> + * @Comments: tpm_stm_st19_platform_specific.h deliver shows a platform specific
> + * file example.
> + * It has been created to split TPM datas and platform.
> + * This example could be used when the driver is built as a module.
> + * In case of other platform, please add a struct i2c_board_info in your arch/
> + * platform file.
> + */
> +static struct st19np18_platform_data *pin_infos;
> +
> +/*
> + * gpio_readpin is a wrapper to read a gpio value.
> + * Use generic gpio APIs
> + * @param: pin_id, the pin identifier where the value will be read.
> + * @return: the gpio value (should be 0 or 1) or negative errno
> + */
> +static int gpio_readpin(int pin_id)
> +{
> +	int ret;
> +	ret = gpio_direction_input(pin_id);
> +	if (ret == 0)
> +		return gpio_get_value(pin_id);
> +	return ret;
> +}
> +
> +/*
> + * gpio_writepin is a wrapper to write a gpio value.
> + * Use generic gpio APIs.
> + * @param: pin_id, the pin identifier where the value will be wrote.
> + * @param: value, the value that will be written.
> + * @return: 0 in case of success
> + */
> +#ifdef DEBUG
> +static int gpio_writepin(int pin_id, int value)
> +{
> +	int ret;
> +	ret = gpio_direction_output(pin_id, value);
> +
> +	if (ret == 0)
> +		gpio_set_value(pin_id, value);
> +	return ret;
> +}
> +#endif
> +
> +static int wait_until_good_shape(void)
> +{
> +	int state_data = 0;
> +	int state_command = 0;
> +	int timeout = msecs_to_jiffies(STARTUP_WAIT_INTERVAL);
> +	int time = msecs_to_jiffies(TICK_GPIO_SPOOLING);
> +	int ret = 0;
> +	wait_queue_head_t queue;
> +
> +	int wait_time = 0;
> +	DEFINE_WAIT(__wait);
> +	init_waitqueue_head(&queue);
> +
> +	do {
> +		prepare_to_wait(&queue, &__wait, TASK_INTERRUPTIBLE);
> +		state_data = gpio_readpin(pin_infos->data_avail_pin);
> +		state_command = gpio_readpin(pin_infos->accept_pin);
> +
> +		if (state_data == 0 && state_command > 0)
> +			return 0;
> +		else if (wait_time >= timeout)
> +			return -EIO;
> +		else if (!signal_pending(current)) {
> +			ret = schedule_timeout(time);
> +			wait_time += time;
> +		} else
> +			ret = -ERESTARTSYS;
> +	} while (1);
> +	finish_wait(&queue, &__wait);
> +
> +	return ret;
> +}
> +
> +/*
> + * wait_event_interruptible_on_gpio is a function that poll on
> + * GPIO dataavailable and GPIO acceptcommand
> + * @param: queue, the queue where the work will be stored
> + * @param: timeout, maximal pooling time.
> + * @return: DATA_ON in case of data_available pin goes high (logical value 1).
> + * COMMAND_ON in case of accept_command pin goes high (logical value 1).
> + * -EIO in case of data_available & accept_command pin goes high
> + *		(logical value 1).
> + * -EPERM in case of data_available & accept_command pin still low
> + *		(logical value 0).
> + */
> +static int wait_event_interruptible_on_gpio(wait_queue_head_t queue,
> +					    int timeout)
> +{
> +	int state_data = 0;
> +	int state_command = 0;
> +	int ret = msecs_to_jiffies(TICK_GPIO_SPOOLING);
> +	struct tpm_chip *chip =
> +	    (struct tpm_chip *)i2c_get_clientdata(pin_infos->client);
> +	int long_timeout =
> +	    tpm_calc_ordinal_duration(chip, TPM_I2C_ORDINAL_LONG);
> +	int wait_time = 0;
> +	DEFINE_WAIT(__wait);
> +
> +	if (timeout > long_timeout)
> +		timeout = long_timeout;
> +
> +	do {
> +		prepare_to_wait(&queue, &__wait, TASK_INTERRUPTIBLE);
> +		state_data = gpio_readpin(pin_infos->data_avail_pin);
> +		state_command = gpio_readpin(pin_infos->accept_pin);
> +
> +		if (state_data > 0 || state_command > 0)
> +			break;
> +		else if (wait_time >= timeout)
> +			break;
> +		else if (!signal_pending(current)) {
> +			ret =
> +			    schedule_timeout(msecs_to_jiffies
> +					     (TICK_GPIO_SPOOLING));
> +			wait_time += msecs_to_jiffies(TICK_GPIO_SPOOLING);
> +		} else {
> +			ret = -ERESTARTSYS;
> +			break;
> +		}
> +	} while (1);
> +	finish_wait(&queue, &__wait);
> +
> +	return (state_data && state_command) ? -EIO : state_data ? DATA_ON :
> +	    state_command ? COMMAND_ON : -EPERM;
> +}
> +
> +/*
> + * responseSize return the command size
> + * @param: buffer, command buffer.
> + * @param: size, the buffer size.
> + * @return: the command size.
> + */
> +static int responseSize(const char *buffer, size_t size)
> +{
> +	size_t val = 0;
> +	if (size >= TPM_HEADER_SIZE) {
> +		val = (size_t) (((unsigned)buffer[2]) << 24
> +				| ((unsigned)buffer[3]) << 16
> +				| ((unsigned)buffer[4]) << 8 | (unsigned)
> +				buffer[5]);
> +	}
> +
> +	if (val < TPM_BUFSIZE)
> +		return val;
> +	else
> +		return TPM_BUFSIZE;
> +}
> +
> +/*
> + * tpm_stm_i2c_send send TPM commands through the I2C bus.
> + * Before sending any TPM commands, tpm_stm_i2c_send poll data_available and
> + * accept_command TPM GPIOs.
> + *
> + * In case the data_available is high (logical value 1), tpm_stm_i2c_send will
> + * empty the TPM FIFO by reading all the datas stored inside the TPM.
> + *
> + * Then, if the accept_command TPM GPIO is high(logical value 1)
> + * tpm_stm_i2c_send will first send the 10 bytes header of the TCG commands and
> + * then send the others bytes by 40 bytes blocks.
> + *
> + * data_available and accept_command TPM GPIOs will goes low when the TPM
> + * compute the command.
> + *
> + * @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 count)
> +{
> +	u32 ret = 0, i, size, ordinal, pin = 0;
> +	struct i2c_client *client;
> +
> +#ifdef DEBUG
> +	printk(KERN_INFO "tpm_st19_i2c: tpm_stm_i2c_send\n");
> +#endif
> +
> +	if (chip == NULL)
> +		return -EBUSY;
> +	if (count < TPM_HEADER_SIZE)
> +		return -EBUSY;
> +	client = (struct i2c_client *)pin_infos->client;
> +
> +	ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
> +
> +	/* i2c_client initialization */
> +	client->flags = 0;
> +
> +	/* Wait for AcceptCmd signal high */
> +	/* Check if data are available before */
> +	/* sending data (data_avail_pin hight) */
> +	/* If data are available, we read the data */
> +	init_waitqueue_head(&pin_infos->write_queue);
> +	pin = wait_event_interruptible_on_gpio(pin_infos->write_queue,
> +					       tpm_calc_ordinal_duration
> +					       (chip, ordinal));
> +	if (pin < 0) {
> +		ret = pin;
> +		goto end;
> +	}
> +
> +	client->flags = I2C_M_RD;
> +
> +	size = TPM_HEADER_SIZE;
> +	for (i = 0; pin == DATA_ON && i < size;) {
> +		ret = i2c_master_recv(client,
> +				      pin_infos->tpm_i2c_buffer[1],
> +				      (i == 0) ? TPM_HEADER_SIZE :
> +				      count - i > TPM_I2C_BLOCK_SIZE ?
> +				      TPM_I2C_BLOCK_SIZE : count - i);
> +		if (ret < 0)
> +			goto end;
> +		if (i == 0)
> +			size =
> +			    responseSize(pin_infos->tpm_i2c_buffer[1], count);
> +		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
> +
> +		if (i < size)
> +			pin =
> +			    wait_event_interruptible_on_gpio(pin_infos->
> +							     write_queue,
> +							     msecs_to_jiffies
> +							     (TPM_I2C_SHORT));
> +	}
> +
> +	pin = wait_event_interruptible_on_gpio(pin_infos->write_queue,
> +					       msecs_to_jiffies(TPM_I2C_SHORT));
> +
> +	/* i2c_client initialization */
> +	client->flags = 0;
> +
> +	size = TPM_HEADER_SIZE;
> +	for (i = 0; i < size && pin == COMMAND_ON;) {
> +		memcpy(pin_infos->tpm_i2c_buffer[0], buf + i,
> +		       (i == 0) ? TPM_HEADER_SIZE : count - i >
> +		       TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE : count - i);
> +
> +		if (i == 0) {
> +			size = responseSize(buf, count);
> +			size = (size < count ? size : count);
> +		}
> +		ret =
> +		    i2c_master_send(client,
> +				    pin_infos->tpm_i2c_buffer[0],
> +				    count >= TPM_HEADER_SIZE ? (i ==
> +								0) ?
> +				    TPM_HEADER_SIZE : count - i >
> +				    TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
> +				    count - i : count);
> +		if (ret < 0) {
> +			printk(KERN_INFO "tpm_st19_i2c: Failed to send data\n");
> +			goto end;
> +		}
> +
> +		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
> +		/* Wait for AcceptCmd signal hight */
> +		if (i < size)
> +			pin =
> +			    wait_event_interruptible_on_gpio(pin_infos->
> +							     write_queue,
> +							     msecs_to_jiffies
> +							     (TPM_I2C_SHORT));
> +
> +		if (pin != COMMAND_ON) {
> +			printk(KERN_INFO
> +			       "tpm_st19_i2c:"
> +			       " Failed to read gpio pin (AcceptCmd)\n");
> +			ret = -EIO;
> +			goto end;
> +		}
> +	}
> +	if (i == 0) {
> +		printk(KERN_INFO
> +		       "tpm_st19_i2c: Failed to read gpio pin (AcceptCmd)\n");
> +		ret = -EIO;
> +	}
> +end:
> +	return ret ? ret : count;
> +}
> +
> +/*
> + * tpm_stm_i2c_recv received TPM response through the I2C bus.
> + * Before receiving any TPM response, tpm_stm_i2c_recv poll data_available and
> + * accept_command TPM GPIOs.
> + *
> + * In case the accept_command is high (logical value 1), tpm_stm_i2c_recv will
> + * do nothing.
> + *
> + * Then, if the data_available TPM GPIO is high(logical value 1)
> + * tpm_stm_i2c_recv will first receive the 10 bytes header of the TCG TPM
> + * response and then receive the others bytes by 40 bytes blocks.
> + *
> + * accept_command TPM GPIOs will goes high when the TPM Fofo is empty.
> + *
> + * @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 ret = 0;
> +	int i, size;
> +	int pin = 0;
> +	struct i2c_client *client;
> +
> +#ifdef DEBUG
> +	printk(KERN_INFO "tpm_st19_i2c: tpm_stm_i2c_recv\n");
> +#endif
> +
> +	if (chip == NULL)
> +		return -EBUSY;
> +	if (count < TPM_HEADER_SIZE)
> +		return -EBUSY;
> +
> +	client = (struct i2c_client *)pin_infos->client;
> +
> +	/* Configure TPM I2C */
> +	client->flags = I2C_M_RD;
> +
> +	/* Spool on the good gpio as long as pin GPIO 3 not HIGHT */
> +	init_waitqueue_head(&chip->vendor.read_queue);
> +	pin = wait_event_interruptible_on_gpio(chip->vendor.read_queue,
> +					       tpm_calc_ordinal_duration
> +					       (chip, TPM_I2C_ORDINAL_LONG));
> +
> +	size = TPM_HEADER_SIZE;
> +	for (i = 0; i < size && pin == DATA_ON;) {
> +		ret =
> +		    i2c_master_recv(client,
> +				    pin_infos->tpm_i2c_buffer[1],
> +				    (count >= TPM_HEADER_SIZE ? i ==
> +				     0 ? TPM_HEADER_SIZE : (size - i) >
> +				     TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE :
> +				     size - i : count));
> +		if (ret < 0) {
> +			printk(KERN_INFO
> +			       "tpm_st19_i2c:"
> +			       " Failed to read gpio pin (DataAvalaible)\n");
> +			goto end;
> +		}
> +
> +		if (buf != NULL) {
> +			memcpy(buf + i, pin_infos->tpm_i2c_buffer[1],
> +			       (count >= TPM_HEADER_SIZE ? i == 0 ?
> +				TPM_HEADER_SIZE : (size - i) >
> +				TPM_I2C_BLOCK_SIZE ? TPM_I2C_BLOCK_SIZE : size -
> +				i : count));
> +
> +			if (i == 0) {
> +				size = responseSize(buf, size);
> +				if (size > count)
> +					size = count;
> +			}
> +		} else {
> +			printk(KERN_INFO "tpm_st19_i2c: read buffer is NULL\n");
> +			goto end;
> +		}
> +
> +		(i == 0) ? (i += TPM_HEADER_SIZE) : (i += TPM_I2C_BLOCK_SIZE);
> +
> +		if (i < size)
> +			pin =
> +			    wait_event_interruptible_on_gpio(chip->vendor.
> +							     read_queue,
> +							     msecs_to_jiffies
> +							     (TPM_I2C_SHORT));
> +	}
> +
> +	if (i == 0) {
> +		printk(KERN_INFO
> +		       "tpm_st19_i2c: "
> +		       "Failed to read gpio pin (DataAvalaible)\n");
> +		ret = -EIO;
> +		goto end;
> +	}
> +	return size;
> +end:
> +	return ret;
> +}
> +
> +/*
> + * 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)
> +{
> +}				/* tpm_stm_i2c_cancel() */
> +
> +/*
> + * tpm_stm_i2c_status is not implemented because TIS registers are not
> + * implemented.
> + */
> +static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
> +{
> +	return -ENOSYS;
> +}				/* tpm_stm_i2c_status() */
> +
> +#ifdef _MODULE
> +
> +static void tpm_st19_i2c_dummy(struct device *dev)
> +{
> +
> +}				/*tpm_st19_i2c_dummy() */
> +
> +/*
> + * tpm_st19_i2c_release do nothing
> + * @param: kobj, not used
> + */
> +static void tpm_st19_i2c_release(struct kobject *kobj)
> +{
> +	struct tpm_chip *chip;
> +	printk(KERN_INFO "tpm_st19_i2c_release\n");
> +
> +	if (_client != NULL) {
> +		chip = (struct tpm_chip *)i2c_get_clientdata(_client);
> +
> +		if (chip != NULL) {
> +			chip->release = tpm_st19_i2c_dummy;
> +			chip->dev->release(chip->dev);
> +		}
> +	}
> +}				/* tpm_st19_i2c_release() */
> +#endif /*_MODULE */
> +/*
> + * tpm_st19_i2c_ioctl provides 2 handles:
> + * - TPMIOC_CANCEL: allow to CANCEL a TPM commands execution.
> + *   See tpm_stm_i2c_cancel description above
> + * - TPMIOC_TRANSMIT: allow to transmit a TPM commands.
> + *
> + * @return: In case of success, return TPM response size.
> + * In other case return < 0 value describing the issue.
> + */
> +static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file *file,
> +				  unsigned int cmd, unsigned long arg)
> +{
> +	int in_size = 0, out_size = 0;
> +	struct tpm_chip *chip = file->private_data;
> +
> +	switch (cmd) {
> +	case TPMIOC_CANCEL:
> +		tpm_stm_i2c_cancel(chip);
> +		return -ENOSYS;
> +	case TPMIOC_TRANSMIT:
> +		if (copy_from_user(pin_infos->tpm_i2c_buffer[0],
> +		    (const char *)arg, TPM_HEADER_SIZE))
> +			return -EFAULT;
> +		in_size = responseSize(pin_infos->tpm_i2c_buffer[0],
> +				      TPM_HEADER_SIZE);
> +		if (in_size > sizeof(pin_infos->tpm_i2c_buffer[0]))
> +			in_size = sizeof(pin_infos->tpm_i2c_buffer[0]);
> +		if (copy_from_user(pin_infos->tpm_i2c_buffer[0],
> +				   (const char *)arg, in_size))
> +			return -EFAULT;
> +		tpm_stm_i2c_send(chip, pin_infos->tpm_i2c_buffer[0], in_size);
> +
> +		out_size = tpm_stm_i2c_recv(chip, pin_infos->tpm_i2c_buffer[1],
> +					    TPM_BUFSIZE);
> +		if (copy_to_user((char *)arg, pin_infos->tpm_i2c_buffer[1],
> +				 out_size))
> +			return -EFAULT;
> +		return out_size;
> +	default:
> +		return -ENOTTY;
> +	}
> +	return -ENOTTY;
> +}
> +
> +static const struct file_operations tpm_st19_i2c_fops = {
> +	.owner = THIS_MODULE,
> +	.llseek = no_llseek,
> +	.read = tpm_read,
> +	.ioctl = tpm_st19_i2c_ioctl,
> +	.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,
> +	.attr_group = &stm_tpm_attr_grp,
> +	.miscdev = {.fops = &tpm_st19_i2c_fops,},
> +};
> +
> +/*
> + * tpm_st19_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_st19_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int err;
> +	struct tpm_chip *chip;
> +	struct st19np18_platform_data *platform_data;
> +
> +	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_probe\n");
> +
> +	err = 0;
> +
> +	/* Check I2C platform functionnalities */
> +	if (client == NULL) {
> +		printk(KERN_INFO "client is NULL. exiting.\n");
> +		err = -ENODEV;
> +		goto end;
> +	}
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +		printk(KERN_INFO "tpm_st19_i2c: client not i2c capable\n");
> +		err = -ENODEV;
> +		goto end;
> +	}
> +
> +	chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
> +	if (!chip) {
> +		err = -ENODEV;
> +		goto end;
> +	}
> +
> +	/*
> +	 * ST19 TPM does not support interrupt. chip->vendor.irq is only
> +	 * set to a value greater that 0 because status function have no
> +	 * sense with this device (TIS register not available)
> +	 */
> +	chip->vendor.irq = 1;
> +
> +	platform_data = client->dev.platform_data;
> +	pin_infos = 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;
> +	}
> +
> +	platform_data->client = client;
> +
> +	/* Register GPIO pin through generic Linux GPIO API */
> +	err = gpio_request(platform_data->accept_pin, "accept command");
> +	if (err)
> +		goto _gpio_init;
> +
> +	err = gpio_request(platform_data->data_avail_pin, "data available");
> +	if (err)
> +		goto _gpio_init;
> +
> +	err = wait_until_good_shape();
> +	if (err)
> +		goto _gpio_set;
> +
> +	tpm_get_timeouts(chip);
> +
> +	/* attach chip datas to client */
> +	i2c_set_clientdata(client, chip);
> +	pin_infos->bChipF = false;
> +
> +	printk(KERN_INFO "tpm_st19_i2c: TPM I2C Initialized\n");
> +	return 0;
> +_gpio_set:
> +_gpio_init:
> +	if (platform_data) {
> +		gpio_free(platform_data->accept_pin);
> +		gpio_free(platform_data->data_avail_pin);
> +	}
> +_tpm_clean_response:
> +	tpm_remove_hardware(chip->dev);
> +	if (platform_data->tpm_i2c_buffer[1] != NULL) {
> +		kfree(platform_data->tpm_i2c_buffer[1]);
> +		platform_data->tpm_i2c_buffer[1] = NULL;
> +	}
> +_tpm_clean_answer:
> +	if (platform_data->tpm_i2c_buffer[0] != NULL) {
> +		kfree(platform_data->tpm_i2c_buffer[0]);
> +		platform_data->tpm_i2c_buffer[0] = NULL;
> +	}
> +	pin_infos->bChipF = true;
> +end:
> +	printk(KERN_INFO "tpm_st19_i2c: TPM I2C initialisation fail\n");
> +	return err;
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_remove(struct i2c_client *client)
> +{
> +	struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
> +	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_remove\n");
> +
> +	if (pin_infos != NULL) {
> +		gpio_free(pin_infos->accept_pin);
> +		gpio_free(pin_infos->data_avail_pin);
> +
> +		/* Check if chip has been previously clean */
> +		if (pin_infos->bChipF != true)
> +			tpm_remove_hardware(chip->dev);
> +		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
> +			kfree(pin_infos->tpm_i2c_buffer[1]);
> +			pin_infos->tpm_i2c_buffer[1] = NULL;
> +		}
> +		if (pin_infos->tpm_i2c_buffer[0] != NULL) {
> +			kfree(pin_infos->tpm_i2c_buffer[0]);
> +			pin_infos->tpm_i2c_buffer[0] = NULL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_pm_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	struct tpm_chip *chip =
> +	    (struct tpm_chip *)i2c_get_clientdata(pin_infos->client);
> +	int ret = 0;
> +	if (chip->data_buffer == NULL)
> +		chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
> +	ret = tpm_pm_suspend(&client->dev, mesg);
> +	return ret;
> +}				/* tpm_st19_i2c_suspend() */
> +
> +/*
> + * tpm_st19_i2c_pm_resume resume the TPM device
> + * This part of the Linux driver should be move in an other part or
> + * environment (bootloader ?)
> + * @param: client, the i2c_client drescription (TPM I2C description).
> + * @return: 0 in case of success.
> + */
> +static int tpm_st19_i2c_pm_resume(struct i2c_client *client)
> +{
> +	struct tpm_chip *chip =
> +	    (struct tpm_chip *)i2c_get_clientdata(pin_infos->client);
> +	int ret = 0;
> +	if (chip->data_buffer == NULL)
> +		chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
> +	ret = tpm_pm_resume(&client->dev);
> +	return ret;
> +}				/* tpm_st19_i2c_pm_resume() */
> +
> +static const struct i2c_device_id tpm_st19_i2c_id[] = {
> +	{TPM_DRIVER_NAME, 0},
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, tpm_st19_i2c_id);
> +
> +static struct i2c_driver tpm_st19_i2c_driver = {
> +	.driver = {
> +		   .owner = THIS_MODULE,
> +		   .name = TPM_DRIVER_NAME,
> +		   },
> +	.probe = tpm_st19_i2c_probe,
> +	.remove = tpm_st19_i2c_remove,
> +	.resume = tpm_st19_i2c_pm_resume,
> +	.suspend = tpm_st19_i2c_pm_suspend,
> +	.id_table = tpm_st19_i2c_id
> +};
> +
> +/*
> + * tpm_st19_i2c_init initialize driver
> + * @return: 0 if successful, else non zero value.
> + */
> +static int __init tpm_st19_i2c_init(void)
> +{
> +	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_init\n");
> +	return i2c_add_driver(&tpm_st19_i2c_driver);
> +}
> +
> +/*
> + * tpm_st19_i2c_exit The kernel calls this function during unloading the
> + * module or during shut down process
> + */
> +static void __exit tpm_st19_i2c_exit(void)
> +{
> +	printk(KERN_INFO "tpm_st19_i2c: tpm_st19_i2c_exit\n");
> +	i2c_del_driver(&tpm_st19_i2c_driver);
> +}
> +
> +module_init(tpm_st19_i2c_init);
> +module_exit(tpm_st19_i2c_exit);
> +
> +MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
> +MODULE_DESCRIPTION("STM TPM I2C ST19 Driver");
> +MODULE_VERSION("1.2.0");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.h b/drivers/char/tpm/tpm_stm_st19_i2c.h
> new file mode 100644
> index 0000000..db3a059
> --- /dev/null
> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.h
> @@ -0,0 +1,63 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_tpm_i2c.h
> + *
> + * @Date: 02/12/2008
> + */
> +#ifndef __STM_ST19_TPM_I2C_MAIN_H__
> +#define __STM_ST19_TPM_I2C_MAIN_H__
> +
> +#include <linux/pci.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.h>
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +
> +#define MINOR_NUM_I2C		224
> +
> +#define TPM_DRIVER_NAME		"st19np18"
> +
> +#define	TPM_BUFSIZE		2048
> +
> +#define TPM_HEADER_SIZE		10
> +#define TPM_I2C_BLOCK_SIZE	0x28
> +
> +#define TPM_I2C_ORDINAL_LONG	0x0D	/* TPM_ORD_TakeOwnership */
> +
> +#define TPM_I2C_SHORT	2000	/* 2s */
> +#define TICK_GPIO_SPOOLING	2
> +#define STARTUP_WAIT_INTERVAL	8 /* 8ms */
> +
> +/* ioctl commands */
> +#define TPMIOC_CANCEL		_IO('T', 0x00)	/* Not supported */
> +#define TPMIOC_TRANSMIT		_IO('T', 0x01)
> +
> +#define DATA_ON			  1	/* data available */
> +#define COMMAND_ON		  2	/* accept command */
> +
> +#endif /* __STM_ST19_TPM_I2C_MAIN_H__ */
> diff --git a/include/linux/i2c/tpm_stm_st19_i2c.h b/include/linux/i2c/tpm_stm_st19_i2c.h
> new file mode 100644
> index 0000000..cdac5f4
> --- /dev/null
> +++ b/include/linux/i2c/tpm_stm_st19_i2c.h
> @@ -0,0 +1,45 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_tpm_i2c.h
> + *
> + * @Date: 06/15/2008
> + */
> +#ifndef __STM_ST19_TPM_I2C_H__
> +#define __STM_ST19_TPM_I2C_H__
> +
> +#include <linux/i2c.h>
> +
> +#define TPM_DRIVER_NAME         "st19np18"
> +#define TPM_I2C_ST19_ADDR_WR	(0x26 >> 1)
> +
> +struct st19np18_platform_data {
> +	int accept_pin;	/* accept command pin */
> +	int data_avail_pin;/* data available pin */
> +	struct i2c_client *client;
> +	bool bChipF;
> +	u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
> +	wait_queue_head_t write_queue;
> +};
> +
> +#endif /* __STM_ST19_TPM_I2C_H__ */
> -- 
> 1.7.2.2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH 1/3] TPM: new stm i2c device driver
  2010-09-30 19:09 ` [PATCH 1/3] TPM: new stm i2c " Rajiv Andrade
  2010-09-30 21:20   ` matt mooney
@ 2010-10-01  0:51   ` James Morris
  2010-10-01 14:27     ` Christophe Henri RICARD
  1 sibling, 1 reply; 14+ messages in thread
From: James Morris @ 2010-10-01  0:51 UTC (permalink / raw)
  To: Rajiv Andrade; +Cc: linux-kernel, joe, christophe-h.ricard

On Thu, 30 Sep 2010, Rajiv Andrade wrote:

> From: Christophe Henri RICARD <christophe-h.ricard@st.com>
> 
> This driver uses the Linux I2C, TPM and generic gpio interfaces.
> 
> Signed-off-by: Christophe Henri RICARD <christophe-h.ricard@st.com>
> Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>

This does not look to have been compile tested against my tree:

 CC [M]  drivers/char/tpm/tpm_stm_st19_i2c.o
drivers/char/tpm/tpm_stm_st19_i2c.c:574: error: unknown field ioctl specified in initializer
drivers/char/tpm/tpm_stm_st19_i2c.c:574: warning: initialization from incompatible pointer type
make[1]: *** [drivers/char/tpm/tpm_stm_st19_i2c.o] Error 1

The locked ioctl was removed in commit
b19dd42faf413b4705d4adb38521e82d73fa4249



- James
-- 
James Morris
<jmorris@namei.org>

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

* RE: [PATCH 1/3] TPM: new stm i2c device driver
  2010-10-01  0:51   ` James Morris
@ 2010-10-01 14:27     ` Christophe Henri RICARD
  2010-10-01 15:25       ` Rajiv Andrade
  0 siblings, 1 reply; 14+ messages in thread
From: Christophe Henri RICARD @ 2010-10-01 14:27 UTC (permalink / raw)
  To: James Morris, Rajiv Andrade; +Cc: linux-kernel@vger.kernel.org, joe@perches.com

Hi James,

Which kernel are you using ?
I have made my testing with a 2.6.35.4 kernel.
As far as I know kernel 2.6.36 will not provide any ioctl field any more.
May be this is the reason ?

Please let me know.
Thanks
Christophe

-----Original Message-----
From: James Morris [mailto:jmorris@namei.org] 
Sent: Thursday, September 30, 2010 7:51 PM
To: Rajiv Andrade
Cc: linux-kernel@vger.kernel.org; joe@perches.com; Christophe Henri RICARD
Subject: Re: [PATCH 1/3] TPM: new stm i2c device driver

On Thu, 30 Sep 2010, Rajiv Andrade wrote:

> From: Christophe Henri RICARD <christophe-h.ricard@st.com>
> 
> This driver uses the Linux I2C, TPM and generic gpio interfaces.
> 
> Signed-off-by: Christophe Henri RICARD <christophe-h.ricard@st.com>
> Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>

This does not look to have been compile tested against my tree:

 CC [M]  drivers/char/tpm/tpm_stm_st19_i2c.o
drivers/char/tpm/tpm_stm_st19_i2c.c:574: error: unknown field ioctl specified in initializer
drivers/char/tpm/tpm_stm_st19_i2c.c:574: warning: initialization from incompatible pointer type
make[1]: *** [drivers/char/tpm/tpm_stm_st19_i2c.o] Error 1

The locked ioctl was removed in commit
b19dd42faf413b4705d4adb38521e82d73fa4249



- James
-- 
James Morris
<jmorris@namei.org>

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

* Re: [PATCH 1/3] TPM: new stm i2c device driver
  2010-10-01 14:27     ` Christophe Henri RICARD
@ 2010-10-01 15:25       ` Rajiv Andrade
  2010-10-01 15:44         ` Christophe Henri RICARD
  0 siblings, 1 reply; 14+ messages in thread
From: Rajiv Andrade @ 2010-10-01 15:25 UTC (permalink / raw)
  To: Christophe Henri RICARD
  Cc: James Morris, linux-kernel@vger.kernel.org, joe@perches.com

Hi Christophe,

The code must be applied and compiled against the security-next tree, that currently doesn't provide the locked ioctl anymore. Can you implement the locking inside tpm_st19_i2c_ioctl() and set it at the unlocked_ioctl field? Shouldn't be too hard, you can get tpm_write() as an example.

By the way, I may be missing something, but why the tpm command transmission (TPMIOC_TRANSMIT) should be handled through ioctl instead of a modified tpm_write() that can send the commands through i2c?

Thanks,
Rajiv

On 01/10/2010, at 11:27, Christophe Henri RICARD wrote:

> Hi James,
> 
> Which kernel are you using ?
> I have made my testing with a 2.6.35.4 kernel.
> As far as I know kernel 2.6.36 will not provide any ioctl field any more.
> May be this is the reason ?
> 
> Please let me know.
> Thanks
> Christophe
> 
> -----Original Message-----
> From: James Morris [mailto:jmorris@namei.org] 
> Sent: Thursday, September 30, 2010 7:51 PM
> To: Rajiv Andrade
> Cc: linux-kernel@vger.kernel.org; joe@perches.com; Christophe Henri RICARD
> Subject: Re: [PATCH 1/3] TPM: new stm i2c device driver
> 
> On Thu, 30 Sep 2010, Rajiv Andrade wrote:
> 
>> From: Christophe Henri RICARD <christophe-h.ricard@st.com>
>> 
>> This driver uses the Linux I2C, TPM and generic gpio interfaces.
>> 
>> Signed-off-by: Christophe Henri RICARD <christophe-h.ricard@st.com>
>> Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
> 
> This does not look to have been compile tested against my tree:
> 
> CC [M]  drivers/char/tpm/tpm_stm_st19_i2c.o
> drivers/char/tpm/tpm_stm_st19_i2c.c:574: error: unknown field ioctl specified in initializer
> drivers/char/tpm/tpm_stm_st19_i2c.c:574: warning: initialization from incompatible pointer type
> make[1]: *** [drivers/char/tpm/tpm_stm_st19_i2c.o] Error 1
> 
> The locked ioctl was removed in commit
> b19dd42faf413b4705d4adb38521e82d73fa4249
> 
> 
> 
> - James
> -- 
> James Morris
> <jmorris@namei.org>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


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

* RE: [PATCH 1/3] TPM: new stm i2c device driver
  2010-10-01 15:25       ` Rajiv Andrade
@ 2010-10-01 15:44         ` Christophe Henri RICARD
  2010-10-01 16:35           ` Rajiv Andrade
  0 siblings, 1 reply; 14+ messages in thread
From: Christophe Henri RICARD @ 2010-10-01 15:44 UTC (permalink / raw)
  To: Rajiv Andrade; +Cc: James Morris, linux-kernel@vger.kernel.org, joe@perches.com

Hi Rajiv,

I had implemented the ioctl function with TPMIOC_CANCEL/TPMIOC_TRANSMIT because I have seen that when I was trying to run a TSS tcsd(trousers) process some errors or warning messages were displayed.
I have just checked the trousers source code I have and it use this way in src/tddl/tddl.c .

For your information also, the 2 buffers tpm_i2c_buffer instead of the data buffer in my driver was because I found what I suppose to be an error with the allocation of chip->data_buffer in the tpm_open function.
When I have done the following test with the tpm_tis driver for example on a pc platform (x86) with a TPM:
- No TPM application launch such as TSS (trousers).
- Put the platform in standby
- Wake up the platform
dmesg will shows an error during suspend/resume functions execution.
My understanding is that in that specific case, no buffer is allocated and the driver couldn't save the TPM context (TPM_SaveState).
In the case the platform generate a RESET on the LPC bus or on the TPM during standby all the TPM volatile context will be cleared 
(all the PCR's for example). I think this could be a problem.

Only for my information, I would like to know if this scenario (TPM RESET during standby) could happen and if it could be a TPM/security issue.

I suppose what you are calling security-next tree is linux-next tree on www.kernel.org or are you referring to another tree ?
I will try to provide you a patch for the ioctl function asap.

Thanks.
Christophe

-----Original Message-----
From: Rajiv Andrade [mailto:srajiv@linux.vnet.ibm.com] 
Sent: Friday, October 01, 2010 10:26 AM
To: Christophe Henri RICARD
Cc: James Morris; linux-kernel@vger.kernel.org; joe@perches.com
Subject: Re: [PATCH 1/3] TPM: new stm i2c device driver

Hi Christophe,

The code must be applied and compiled against the security-next tree, that currently doesn't provide the locked ioctl anymore. Can you implement the locking inside tpm_st19_i2c_ioctl() and set it at the unlocked_ioctl field? Shouldn't be too hard, you can get tpm_write() as an example.

By the way, I may be missing something, but why the tpm command transmission (TPMIOC_TRANSMIT) should be handled through ioctl instead of a modified tpm_write() that can send the commands through i2c?

Thanks,
Rajiv

On 01/10/2010, at 11:27, Christophe Henri RICARD wrote:

> Hi James,
> 
> Which kernel are you using ?
> I have made my testing with a 2.6.35.4 kernel.
> As far as I know kernel 2.6.36 will not provide any ioctl field any more.
> May be this is the reason ?
> 
> Please let me know.
> Thanks
> Christophe
> 
> -----Original Message-----
> From: James Morris [mailto:jmorris@namei.org] 
> Sent: Thursday, September 30, 2010 7:51 PM
> To: Rajiv Andrade
> Cc: linux-kernel@vger.kernel.org; joe@perches.com; Christophe Henri RICARD
> Subject: Re: [PATCH 1/3] TPM: new stm i2c device driver
> 
> On Thu, 30 Sep 2010, Rajiv Andrade wrote:
> 
>> From: Christophe Henri RICARD <christophe-h.ricard@st.com>
>> 
>> This driver uses the Linux I2C, TPM and generic gpio interfaces.
>> 
>> Signed-off-by: Christophe Henri RICARD <christophe-h.ricard@st.com>
>> Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
> 
> This does not look to have been compile tested against my tree:
> 
> CC [M]  drivers/char/tpm/tpm_stm_st19_i2c.o
> drivers/char/tpm/tpm_stm_st19_i2c.c:574: error: unknown field ioctl specified in initializer
> drivers/char/tpm/tpm_stm_st19_i2c.c:574: warning: initialization from incompatible pointer type
> make[1]: *** [drivers/char/tpm/tpm_stm_st19_i2c.o] Error 1
> 
> The locked ioctl was removed in commit
> b19dd42faf413b4705d4adb38521e82d73fa4249
> 
> 
> 
> - James
> -- 
> James Morris
> <jmorris@namei.org>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


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

* Re: [PATCH 1/3] TPM: new stm i2c device driver
  2010-10-01 15:44         ` Christophe Henri RICARD
@ 2010-10-01 16:35           ` Rajiv Andrade
  0 siblings, 0 replies; 14+ messages in thread
From: Rajiv Andrade @ 2010-10-01 16:35 UTC (permalink / raw)
  To: Christophe Henri RICARD
  Cc: James Morris, linux-kernel@vger.kernel.org, joe@perches.com

Hi Christophe,

On 01/10/2010, at 12:44, Christophe Henri RICARD wrote:

> Hi Rajiv,
> 
> I had implemented the ioctl function with TPMIOC_CANCEL/TPMIOC_TRANSMIT because I have seen that when I was trying to run a TSS tcsd(trousers) process some errors or warning messages were displayed.
> I have just checked the trousers source code I have and it use this way in src/tddl/tddl.c .
> 

Trousers supports both methods, device read/write or through ioctl, the warning just notifies that the second isn't going to be used due the device driver's lack of support.

> For your information also, the 2 buffers tpm_i2c_buffer instead of the data buffer in my driver was because I found what I suppose to be an error with the allocation of chip->data_buffer in the tpm_open function.
> When I have done the following test with the tpm_tis driver for example on a pc platform (x86) with a TPM:
> - No TPM application launch such as TSS (trousers).
> - Put the platform in standby
> - Wake up the platform
> dmesg will shows an error during suspend/resume functions execution.
> My understanding is that in that specific case, no buffer is allocated and the driver couldn't save the TPM context (TPM_SaveState).

Sounds like an issue, thanks for reporting, I'll double check/debug this.

> In the case the platform generate a RESET on the LPC bus or on the TPM during standby all the TPM volatile context will be cleared 
> (all the PCR's for example). I think this could be a problem.
> Only for my information, I would like to know if this scenario (TPM RESET during standby) could happen and if it could be a TPM/security issue.

As long as it implies in occurring a full power cycle, it isn't a TPM problem.

> 
> I suppose what you are calling security-next tree is linux-next tree on www.kernel.org or are you referring to another tree ?
> I will try to provide you a patch for the ioctl function asap.
> 

I'm using this one as security-next:
git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/jamesm-security-next.git

Thanks,
Rajiv

> 
> 
> -----Original Message-----
> From: Rajiv Andrade [mailto:srajiv@linux.vnet.ibm.com] 
> Sent: Friday, October 01, 2010 10:26 AM
> To: Christophe Henri RICARD
> Cc: James Morris; linux-kernel@vger.kernel.org; joe@perches.com
> Subject: Re: [PATCH 1/3] TPM: new stm i2c device driver
> 
> Hi Christophe,
> 
> The code must be applied and compiled against the security-next tree, that currently doesn't provide the locked ioctl anymore. Can you implement the locking inside tpm_st19_i2c_ioctl() and set it at the unlocked_ioctl field? Shouldn't be too hard, you can get tpm_write() as an example.
> 
> By the way, I may be missing something, but why the tpm command transmission (TPMIOC_TRANSMIT) should be handled through ioctl instead of a modified tpm_write() that can send the commands through i2c?
> 
> Thanks,
> Rajiv
> 
> On 01/10/2010, at 11:27, Christophe Henri RICARD wrote:
> 
>> Hi James,
>> 
>> Which kernel are you using ?
>> I have made my testing with a 2.6.35.4 kernel.
>> As far as I know kernel 2.6.36 will not provide any ioctl field any more.
>> May be this is the reason ?
>> 
>> Please let me know.
>> Thanks
>> Christophe
>> 
>> -----Original Message-----
>> From: James Morris [mailto:jmorris@namei.org] 
>> Sent: Thursday, September 30, 2010 7:51 PM
>> To: Rajiv Andrade
>> Cc: linux-kernel@vger.kernel.org; joe@perches.com; Christophe Henri RICARD
>> Subject: Re: [PATCH 1/3] TPM: new stm i2c device driver
>> 
>> On Thu, 30 Sep 2010, Rajiv Andrade wrote:
>> 
>>> From: Christophe Henri RICARD <christophe-h.ricard@st.com>
>>> 
>>> This driver uses the Linux I2C, TPM and generic gpio interfaces.
>>> 
>>> Signed-off-by: Christophe Henri RICARD <christophe-h.ricard@st.com>
>>> Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
>> 
>> This does not look to have been compile tested against my tree:
>> 
>> CC [M]  drivers/char/tpm/tpm_stm_st19_i2c.o
>> drivers/char/tpm/tpm_stm_st19_i2c.c:574: error: unknown field ioctl specified in initializer
>> drivers/char/tpm/tpm_stm_st19_i2c.c:574: warning: initialization from incompatible pointer type
>> make[1]: *** [drivers/char/tpm/tpm_stm_st19_i2c.o] Error 1
>> 
>> The locked ioctl was removed in commit
>> b19dd42faf413b4705d4adb38521e82d73fa4249
>> 
>> 
>> 
>> - James
>> -- 
>> James Morris
>> <jmorris@namei.org>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
> 


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

* [PATCH 1/3] TPM: new stm i2c device driver
@ 2011-01-17 23:34 Christophe Henri RICARD
  2011-08-25 14:34 ` Christophe Henri RICARD
  0 siblings, 1 reply; 14+ messages in thread
From: Christophe Henri RICARD @ 2011-01-17 23:34 UTC (permalink / raw)
  To: Rajiv Andrade, Marcel Selhorst
  Cc: James Morris, linux-kernel@vger.kernel.org, joe@perches.com,
	matt mooney, Sean NEWTON, Serge FRUHAUF, Mohamed TABET,
	Jean-Luc BLANC, Christophe DELAUNAY, Tom BOCCHINO,
	Christophe Henri RICARD

Hello Rajiv, James,

As a new year is here, I'm cleaning up some stuff that were kept on the shelves.
Please find below in a plain text format, the updated tpm stm st19np18 i2c driver.
This patch provide in one part the full tpm driver for st19np18 using i2c protocol.
The updates are:
- some code/comment cleaning.
- replace wait_event_interruptible_on_gpio function with wait_for_stat (as found in tpm_tis).
This move the duration
(which is different to timeout according TCG PC Client Specific TPM Interface Specification (TIS) spec: http://www.trustedcomputinggroup.org/files/resource_files/87BCE22B-1D09-3519-ADEBA772FBF02CBD/TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf) management to the tpm.c to the tpm_transmit function in tpm.c.
I believe, it makes the driver more similar and easier to understand for everybody (I guess).
- I have tried to take care of my English spelling in some comments and in the documentation file.
- I have updated/replaced the ioctl function by unlocked_ioctl to avoid any warning from the Linux TSS trousers (tcsd) and according to the 2.6.35 --> 2.6.36 ioctl mechanism delta.

I have applied this patch to the last security-next kernel as you mentioned below (2.6.37 rc3) and run it on a beagleboard xM and C4
http://beagleboard.org/.
Those devices are already in the market.

I've tried to take care of all your feedbacks and to be familiar as good as I can
with all the Linux guidelines for all the patches submission process.
I'm using Outlook as mail client for company policy rules reasons.

I would like to know also what is the gap I have to reach to get this driver on the kernel source tree.

Any feedback or comments are welcome.

Thanks
Christophe

------------------------------
Signed-off-by: Christophe RICARD <christophe-h.ricard[at]st.com>
diff --git a/Documentation/tpm/tpm_stm_st19_i2c.txt b/Documentation/tpm/tpm_stm_st19_i2c.txt
--- a/Documentation/tpm/tpm_stm_st19_i2c.txt    1969-12-31 17:00:00.000000000 -0700
+++ b/Documentation/tpm/tpm_stm_st19_i2c.txt    2011-01-17 04:54:13.534658985 -0600
@@ -0,0 +1,169 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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
+ */
+
+PURPOSE OF THE DOCUMENT
+------------------------
+This document describe the installation of the TPM driver for
+TPM ST19NP18 using I2C protocols.
+
+
+PLATFORM USED FOR TESTING
+--------------------------
+During the development, several embedded platforms running ARM CPU were
+used.
+Listing of validated platforms:
+- TI Beagleboard
+- STMicroelectronics Spear 300
+- STMicroelectronics Spear 600
+
+REQUIREMENTS
+-------------
+Software
+=========
+The TPM driver can be install under a kernel that implements at least the
+following features:
+- Linux GENERIC_GPIO programming interfaces.
+- I2C new style programming interface base (with probe & remove functions).
+- 1 I2C adapter (I2C Linux controller driver) or use of I2C_GPIO driver for I2C
+bitbanging.
+
+
+Hardware
+=========
+To run a TPM, the platform needs at least:
+- 2 Power supplies (3.3V).
+- 1 I2C controller or 2 GPIOs used for SDA & SCL (I2C bit bang method).
+- 2 GPIOs for signals accept_command & data_available.
+
+TPM I2C speed is 100Khz (Maximum)
+
+All TPM signals work at 3.3V
+
+HOW TO INSTALL
+---------------
+Platform installation file
+===========================
+(N.B: platform file in arch/<processor_type>/mach-<platform-name>/
+
+
+1 - Software integration
+=========================
+<processor_type> could be: alpha, arm, avr32, blackfin, cris, frv, h8300, ia64,
+m32r, m68k, m68knommu, parisc, powerpc, s390, sh, sparc, sparc64, um, x86,
+xtensa...
+<platform-name> corresponds to your platform
+
+In the file where the machine_init() function exists, the developer must
+declare:
+- 1 struct st19np18_platform_data to provide which gpio the driver will use.
+       * The accept_pin and data_avail_pin gpio are configured as input only.
+       * This gpio management is under the platform developer's responsability.
+
+Finally, in the machine_init() function provided in the same file, the developer
+should use the well known function i2c_register_board_info() from the I2C Linux
+API Core.
+
+2- Hardware integration
+========================
+- ST recommends connecting VPS1 and VPS2 to the board power supply and at least two
+GNDs (on each side of TSSOP28 package). (See datasheet for further information)
+
+- As the ST19NP18 has no internal pull up, ST recommands having:
+  * 2 external pull up on SDA & SCL signals (RpSDA/RpSCL) with values according
+to the abacus on page 40 or the "I2C Bus specification, version 2.1 January
+2000".
+
+
+Platform integration advises
+=============================
+
+For power management purposes, the kernel will send a TPM_SaveState command in the
+suspend tpm driver function.
+If the platform generates a TPM Init event on wakeup, the TPM_Startup(ST_STATE) command should
+be executed before the Linux kernel come up (resume function execution).
+
+Here is an example with beagleboard:
+====================================
+In the corresponding platform init file, the developer should specify
+the following information:
+- The platform gpio's used to managed the tpm's accept_pin/data_avail_pin
+(in a struct st19np18_platform_data declaration).
+- The TPM I2C 7 bits address (TPM_I2C_ST19_ADDR_WR) (in a struct i2c_board_info).
+
+Then the developer should add the TPM slave device to the good i2c adapter with the
+i2c_register_board_info function (assuming that the gpio and the i2c bus are well configured).
+
+Note: For the beagleboard configure your kernel with the following option: CONFIG_OMAP_MUX=y
+
+file arch\arm\mach-omap2\board-omap3beagle.c
+add the following:
+-----------------------------------------------------------------------
+
+static struct st19np18_platform_data tpm_data = {
+        .accept_pin = 135,
+        .data_avail_pin = 143,
+};
+
+static struct i2c_board_info __initdata tpm_st19_i2c_board_info[] = {
+        {
+         I2C_BOARD_INFO(TPM_DRIVER_NAME, TPM_I2C_ST19_ADDR_WR),
+         .platform_data = &tpm_data,
+         },
+};
+
+------------------------------------------------------------------------
+Then complete the beagleboard init to be like this:
+------------------------------------------------------------------------
+static void __init omap3_beagle_init(void)
+{
+        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+        omap3_beagle_i2c_init();
+        platform_add_devices(omap3_beagle_devices,
+                        ARRAY_SIZE(omap3_beagle_devices));
+        omap_serial_init();
+
+        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
+        gpio_request(170, "DVI_nPD");
+        /* REVISIT leave DVI powered down until it's needed ... */
+        gpio_direction_output(170, true);
+
+        usb_musb_init(&musb_board_data);
+        usb_ehci_init(&ehci_pdata);
+        omap3beagle_flash_init();
+
+        beagle_display_init();
+
+        /* Ensure SDRC pins are mux'd for self-refresh */
+        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+        omap_mux_init_gpio(((struct st19np18_platform_data *)
+                           tpm_st19_i2c_board_info[0].platform_data)->data_avail_pin,
+                           OMAP_PIN_INPUT);
+       omap_mux_init_gpio(((struct st19np18_platform_data *)
+                           tpm_st19_i2c_board_info[0].platform_data)->accept_pin,
+                           OMAP_PIN_INPUT);
+
+       i2c_register_board_info(2, tpm_st19_i2c_board_info, ARRAY_SIZE(tpm_st19_i2c_board_info));
+}
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
--- a/drivers/char/tpm/Kconfig  2011-01-06 04:44:39.000000000 -0600
+++ b/drivers/char/tpm/Kconfig  2011-01-13 22:44:42.906408085 -0600
@@ -60,4 +60,13 @@
          Further information on this driver and the supported hardware
          can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/

+config TCG_ST19_I2C
+        tristate "STMicroelectronics ST19 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_st19_i2c.
 endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
--- a/drivers/char/tpm/Makefile 2011-01-06 04:44:39.000000000 -0600
+++ b/drivers/char/tpm/Makefile 2011-01-13 22:44:35.506658670 -0600
@@ -9,3 +9,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_ST19_I2C) += tpm_stm_st19_i2c.o
diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c b/drivers/char/tpm/tpm_stm_st19_i2c.c
--- a/drivers/char/tpm/tpm_stm_st19_i2c.c       1969-12-31 17:00:00.000000000 -0700
+++ b/drivers/char/tpm/tpm_stm_st19_i2c.c       2011-01-16 22:44:58.466479759 -0600
@@ -0,0 +1,602 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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_st19_i2c.c
+ *
+ * @Synopsis:
+ * ----------------------------------------------------------------------
+ *     02/12/2008
+ *     - Stand alone implementation (without any TPM api)
+ * ----------------------------------------------------------------------
+ *     03/02/2010
+ *     - Power management (suspend and resume functions)
+ *     implementation
+ * ----------------------------------------------------------------------
+ *     03/19/2010
+ *     - Use of the linux kernel TPM api --> driver/char/tpm
+ * ----------------------------------------------------------------------
+ *     05/26/2010
+ *     - Update code for code submission and bug fixes:
+ *     - Comments spelling fixes
+ *     - Lindent script execution
+ *     - checkpatch.pl script execution
+ *     - fix syslog error when loaded as a module:
+ *      "release() function missing and must be fixed"
+ *     - name files change from
+ *       stm_st19_tpm_i2c to tpm_stm_st19_i2c
+ * ----------------------------------------------------------------------
+ *     06/15/2010
+ *     - Update for new tpm core device.
+ *     num_opens --> is_open
+ * ----------------------------------------------------------------------
+ *     07/08/2010
+ *     - Update probe, resume suspend functions
+ *     - Fix issue suspend buffer and work around related to the
+ *     chip->data_buffer not allocated.
+ * ----------------------------------------------------------------------
+ *     09/03/2010
+ *     - Review under LKLM
+ *     - Patches from Joe Perches after review which fix some break and
+ *     some neatings.
+ * ----------------------------------------------------------------------
+ *     09/16/2010
+ *     - Remove unaccurate comment.
+ * ----------------------------------------------------------------------
+ *     01/12/2011
+ *     - update ioctl function to unlocked_ioctl for kernel >= 2.6.36
+ *     - Some cleaning
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.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/version.h>
+#include <linux/smp_lock.h>
+
+#include <linux/i2c/tpm_stm_st19_i2c.h>
+
+#include "tpm.h"
+
+#include "tpm_stm_st19_i2c.h"
+
+#ifdef DEBUG
+#define FUNC_ENTER() pr_info("%s\n", __func__)
+#else
+#define FUNC_ENTER() do {} while (0)
+#endif
+
+static struct st19np18_platform_data *pin_infos;
+
+#define TPM_STS_DATA_AVAIL 0x10
+#define TPM_STS_ACCEPT_COMMAND 0x01
+#define TPM_STS_CANCEL (TPM_STS_DATA_AVAIL | TPM_STS_ACCEPT_COMMAND)
+enum tis_defaults {
+       TIS_SHORT_TIMEOUT = 750,        /* ms */
+       TIS_LONG_TIMEOUT = 2000,        /* 2 sec */
+};
+
+/*
+ * gpio_readpin is a wrapper to read a gpio value.
+ * Use generic gpio APIs
+ * @param: pin_id, the pin identifier where the value will be read.
+ * @return: the gpio value (should be 0 or 1) or negative errno
+ */
+static int gpio_readpin(int pin_id)
+{
+       int ret;
+       ret = gpio_direction_input(pin_id);
+       if (ret == 0)
+               return gpio_get_value(pin_id);
+       return ret;
+}
+
+/*
+ * tpm_stm_i2c_status is not implemented because TIS registers are not
+ * implemented.
+ */
+static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
+{
+       u8 state_data, state_command;
+
+       state_data = gpio_readpin(pin_infos->data_avail_pin);
+       state_command = gpio_readpin(pin_infos->accept_pin);
+       return (state_data << 4) | state_command;
+}
+
+static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
+                        wait_queue_head_t *queue)
+{
+       unsigned long stop;
+       u8 status;
+
+       FUNC_ENTER();
+
+       /* check current status */
+       status = tpm_stm_i2c_status(chip);
+       if (status == mask)
+               return 0;
+       if (status == TPM_STS_CANCEL)
+               goto end;
+       stop = jiffies + timeout;
+       do {
+               msleep(TPM_TIMEOUT);
+               status = tpm_stm_i2c_status(chip);
+               if ((status & mask) == mask)
+                       return 0;
+       } while (time_before(jiffies, stop));
+end:
+       return -ETIME;
+}
+
+/*
+ * tpm_stm_i2c_send send TPM commands through the I2C bus.
+ * Before sending any TPM commands, tpm_stm_i2c_send poll data_available and
+ * accept_command TPM GPIOs.
+ *
+ * In case the data_available is high (logical value 1), tpm_stm_i2c_send will
+ * empty the TPM FIFO by reading all the datas stored inside the TPM.
+ *
+ * Then, if the accept_command TPM GPIO is high(logical value 1)
+ * tpm_stm_i2c_send will first send the 10 bytes header of the TCG commands and
+ * then send the others bytes by 40 bytes blocks.
+ *
+ * data_available and accept_command TPM GPIOs will goes low when the TPM
+ * compute the command.
+ *
+ * @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 count)
+{
+       u32 ret = 0, i, size, ordinal;
+       struct i2c_client *client;
+
+       FUNC_ENTER();
+
+       if (chip == NULL)
+               return -EBUSY;
+       if (count < TPM_HEADER_SIZE)
+               return -EBUSY;
+       client = (struct i2c_client *)pin_infos->client;
+
+       ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+
+       size = TPM_HEADER_SIZE;
+       i = 0;
+       while (i < size && wait_for_stat(chip, TPM_STS_ACCEPT_COMMAND,
+                                        TPM_I2C_SHORT,
+                                        &chip->vendor.int_queue) == 0) {
+               int bytes;
+
+               if (i == 0)
+                       bytes = TPM_HEADER_SIZE;
+               else
+                       bytes = min_t(int, count - i, TPM_I2C_BLOCK_SIZE);
+
+               if (i == 0) {
+                       size = be32_to_cpu(*(__be32 *) (buf + 2));
+                       size = size < count ? size : count;
+               }
+               if (count < TPM_HEADER_SIZE)
+                       bytes = count;
+               ret = i2c_master_send(client, buf + i, bytes);
+               if (ret < 0) {
+                       pr_info("Failed to send data\n");
+                       goto end;
+               }
+
+               if (i == 0)
+                       i += TPM_HEADER_SIZE;
+               else
+                       i += TPM_I2C_BLOCK_SIZE;
+       }
+
+       if (i == 0) {
+               pr_info("Failed to read gpio pin (AcceptCmd)\n");
+               ret = -EIO;
+       }
+end:
+       return ret ? ret : count;
+}
+
+/*
+ * tpm_stm_i2c_recv received TPM response through the I2C bus.
+ * Before receiving any TPM response, tpm_stm_i2c_recv poll data_available and
+ * accept_command TPM GPIOs.
+ *
+ * In case the accept_command is high (logical value 1), tpm_stm_i2c_recv will
+ * do nothing.
+ *
+ * Then, if the data_available TPM GPIO is high(logical value 1)
+ * tpm_stm_i2c_recv will first receive the 10 bytes header of the TCG TPM
+ * response and then receive the others bytes by 40 bytes blocks.
+ *
+ * accept_command TPM GPIOs will goes high when the TPM Fofo is empty.
+ *
+ * @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 ret = 0;
+       int i, size;
+       struct i2c_client *client;
+
+       FUNC_ENTER();
+
+       if (chip == NULL)
+               return -EBUSY;
+       if (count < TPM_HEADER_SIZE)
+               return -EBUSY;
+
+       client = (struct i2c_client *)pin_infos->client;
+
+       size = TPM_HEADER_SIZE;
+       i = 0;
+       while (i < size && wait_for_stat(chip, TPM_STS_DATA_AVAIL,
+                                        TPM_I2C_SHORT,
+                                        &chip->vendor.read_queue) == 0) {
+               int bytes;
+
+               if (count < TPM_HEADER_SIZE)
+                       bytes = count;
+               else if (i == 0)
+                       bytes = TPM_HEADER_SIZE;
+               else
+                       bytes = min_t(int, size - i, TPM_I2C_BLOCK_SIZE);
+
+               ret = i2c_master_recv(client, buf + i, bytes);
+               if (ret < 0) {
+                       pr_info(" Failed to read gpio pin (DataAvailable)\n");
+                       goto end;
+               }
+
+               if (!buf) {
+                       pr_info("read buffer is NULL\n");
+                       goto end;
+               }
+
+               if (i == 0) {
+                       size = be32_to_cpu(*(__be32 *) (buf + 2));
+                       if (size > count)
+                               size = count;
+                       i += TPM_HEADER_SIZE;
+               } else
+                       i += TPM_I2C_BLOCK_SIZE;
+       }
+
+       if (i == 0) {
+               pr_info("Failed to read gpio pin (DataAvailable)\n");
+               ret = -EIO;
+               goto end;
+       }
+       return size;
+end:
+       return ret;
+}
+
+/*
+ * 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)
+{
+}
+
+/*
+ * tpm_st19_i2c_ioctl provides 2 handles:
+ * - TPMIOC_CANCEL: allow to CANCEL a TPM commands execution.
+ *   See tpm_stm_i2c_cancel description above
+ * - TPMIOC_TRANSMIT: allow to transmit a TPM commands.
+ *
+ * @return: In case of success, return TPM response size.
+ * In other case return < 0 value describing the issue.
+ */
+/*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file *file,
+                                 unsigned int cmd, unsigned long arg)
+#else*/
+static long tpm_st19_i2c_unlocked_ioctl(struct file *file,
+                                       unsigned int cmd, unsigned long arg)
+/*#endif*/
+{
+       int in_size = 0, out_size = 0, ret = -ENOTTY;
+       struct tpm_chip *chip = file->private_data;
+
+       lock_kernel();
+       switch (cmd) {
+       case TPMIOC_CANCEL:
+               tpm_stm_i2c_cancel(chip);
+               ret = -ENOSYS;
+               break;
+       case TPMIOC_TRANSMIT:
+               if (copy_from_user(chip->data_buffer,
+                                  (const char *)arg, TPM_HEADER_SIZE)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               in_size = be32_to_cpu(*(__be32 *) (chip->data_buffer + 2));
+               if (copy_from_user(chip->data_buffer,
+                                  (const char *)arg, in_size)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               tpm_stm_i2c_send(chip, chip->data_buffer, in_size);
+
+               out_size = tpm_stm_i2c_recv(chip, chip->data_buffer,
+                                           TPM_BUFSIZE);
+               if (copy_to_user((char *)arg, chip->data_buffer, out_size)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = out_size;
+               break;
+       }
+       unlock_kernel();
+       return ret;
+}
+
+static const struct file_operations tpm_st19_i2c_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .read = tpm_read,
+
+       /*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+          .ioctl = tpm_st19_i2c_ioctl,
+          #else */
+       .unlocked_ioctl = tpm_st19_i2c_unlocked_ioctl,
+       /*#endif */
+
+       .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,
+       .req_complete_val = TPM_STS_DATA_AVAIL,
+       .req_canceled = TPM_STS_CANCEL,
+       .attr_group = &stm_tpm_attr_grp,
+       .miscdev = {.fops = &tpm_st19_i2c_fops,},
+};
+
+/*
+ * tpm_st19_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_st19_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int err;
+       struct tpm_chip *chip;
+       struct st19np18_platform_data *platform_data;
+
+       FUNC_ENTER();
+
+       err = 0;
+
+       /* Check I2C platform functionnalities */
+       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) {
+               err = -ENODEV;
+               goto end;
+       }
+
+       platform_data = client->dev.platform_data;
+       pin_infos = platform_data;
+       platform_data->client = client;
+       /* Default timeouts */
+        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);
+
+       /* Register GPIO pin through generic Linux GPIO API */
+       err = gpio_request(platform_data->accept_pin, "accept command");
+       if (err)
+               goto _gpio_init;
+
+       err = gpio_request(platform_data->data_avail_pin, "data available");
+       if (err)
+               goto _gpio_init;
+
+       tpm_get_timeouts(chip);
+       tpm_continue_selftest(chip);
+
+       /* attach chip datas to client */
+       i2c_set_clientdata(client, chip);
+
+       pr_info("TPM I2C Initialized\n");
+       return 0;
+_gpio_init:
+       if (platform_data) {
+               gpio_free(platform_data->accept_pin);
+               gpio_free(platform_data->data_avail_pin);
+       }
+       tpm_remove_hardware(chip->dev);
+end:
+       i2c_set_clientdata(client, NULL);
+       pr_info("TPM I2C initialisation fail\n");
+       return err;
+}
+
+/*
+ * tpm_st19_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_st19_i2c_remove(struct i2c_client *client)
+{
+       struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
+       FUNC_ENTER();
+
+       if (pin_infos != NULL) {
+               gpio_free(pin_infos->accept_pin);
+               gpio_free(pin_infos->data_avail_pin);
+       }
+
+       /* Check if chip has been previously clean */
+       if (chip != NULL)
+               tpm_remove_hardware(chip->dev);
+
+       return 0;
+}
+
+/*
+ * tpm_st19_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_st19_i2c_pm_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       return tpm_pm_suspend(&client->dev, mesg);
+}
+
+/*
+ * tpm_st19_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_st19_i2c_pm_resume(struct i2c_client *client)
+{
+       return tpm_pm_resume(&client->dev);
+}                              /* tpm_st19_i2c_pm_resume() */
+
+static const struct i2c_device_id tpm_st19_i2c_id[] = {
+       {TPM_DRIVER_NAME, 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tpm_st19_i2c_id);
+
+static struct i2c_driver tpm_st19_i2c_driver = {
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = TPM_DRIVER_NAME,
+                  },
+       .probe = tpm_st19_i2c_probe,
+       .remove = tpm_st19_i2c_remove,
+       .resume = tpm_st19_i2c_pm_resume,
+       .suspend = tpm_st19_i2c_pm_suspend,
+       .id_table = tpm_st19_i2c_id
+};
+
+/*
+ * tpm_st19_i2c_init initialize driver
+ * @return: 0 if successful, else non zero value.
+ */
+static int __init tpm_st19_i2c_init(void)
+{
+       FUNC_ENTER();
+       return i2c_add_driver(&tpm_st19_i2c_driver);
+}
+
+/*
+ * tpm_st19_i2c_exit The kernel calls this function during unloading the
+ * module or during shut down process
+ */
+static void __exit tpm_st19_i2c_exit(void)
+{
+       FUNC_ENTER();
+       i2c_del_driver(&tpm_st19_i2c_driver);
+}
+
+module_init(tpm_st19_i2c_init);
+module_exit(tpm_st19_i2c_exit);
+
+MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
+MODULE_DESCRIPTION("STM TPM I2C ST19 Driver");
+MODULE_VERSION("1.2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.h b/drivers/char/tpm/tpm_stm_st19_i2c.h
--- a/drivers/char/tpm/tpm_stm_st19_i2c.h       1969-12-31 17:00:00.000000000 -0700
+++ b/drivers/char/tpm/tpm_stm_st19_i2c.h       2011-01-16 22:45:08.918407969 -0600
@@ -0,0 +1,52 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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_st19_tpm_i2c.h
+ *
+ * @Date: 02/12/2008
+ */
+#ifndef __STM_ST19_TPM_I2C_MAIN_H__
+#define __STM_ST19_TPM_I2C_MAIN_H__
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+
+#define TPM_BUFSIZE            2048
+#define TPM_HEADER_SIZE                10
+#define TPM_I2C_BLOCK_SIZE     0x28
+
+#define TPM_I2C_SHORT          2000    /* 2s */
+#define STARTUP_WAIT_INTERVAL  8       /* 8ms */
+
+/* ioctl commands */
+#define TPMIOC_CANCEL          _IO('T', 0x00)  /* Not supported */
+#define TPMIOC_TRANSMIT                _IO('T', 0x01)
+
+#endif /* __STM_ST19_TPM_I2C_MAIN_H__ */
diff --git a/include/linux/i2c/tpm_stm_st19_i2c.h b/include/linux/i2c/tpm_stm_st19_i2c.h
--- a/include/linux/i2c/tpm_stm_st19_i2c.h      1969-12-31 17:00:00.000000000 -0700
+++ b/include/linux/i2c/tpm_stm_st19_i2c.h      2011-01-16 22:45:31.758408188 -0600
@@ -0,0 +1,42 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
+ * 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_st19_tpm_i2c.h
+ *
+ * @Date: 06/15/2008
+ */
+#ifndef __STM_ST19_TPM_I2C_H__
+#define __STM_ST19_TPM_I2C_H__
+
+#include <linux/i2c.h>
+
+#define TPM_DRIVER_NAME         "st19np18"
+#define TPM_I2C_ST19_ADDR_WR   (0x26 >> 1) /*0x13 7 bits address */
+
+struct st19np18_platform_data {
+       int accept_pin; /* accept command pin */
+       int data_avail_pin;/* data available pin */
+       struct i2c_client *client;
+};
+
+#endif /* __STM_ST19_TPM_I2C_H__ */

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

* RE: [PATCH 1/3] TPM: new stm i2c device driver
  2011-01-17 23:34 [PATCH 1/3] TPM: new stm i2c device driver Christophe Henri RICARD
@ 2011-08-25 14:34 ` Christophe Henri RICARD
  2011-08-25 15:00   ` Mohamed TABET
  0 siblings, 1 reply; 14+ messages in thread
From: Christophe Henri RICARD @ 2011-08-25 14:34 UTC (permalink / raw)
  To: Rajiv Andrade, Marcel Selhorst
  Cc: James Morris, linux-kernel@vger.kernel.org, joe@perches.com,
	matt mooney, Sean NEWTON, Serge FRUHAUF, Mohamed TABET,
	Jean-Luc BLANC, Christophe DELAUNAY, Tom BOCCHINO,
	Christophe Henri RICARD, Mathias LEBLANC

Hi,

I would like to know where does this driver submission stand.
Do I still have to do any improvements ? Do you need more information before pushing it on the main kernel stream ?

Thanks for your help.
Christophe
> -----Original Message-----
> From: Christophe Henri RICARD
> Sent: Monday, January 17, 2011 5:34 PM
> To: Rajiv Andrade; Marcel Selhorst
> Cc: James Morris; linux-kernel@vger.kernel.org; joe@perches.com; matt
> mooney; Sean NEWTON; Serge FRUHAUF; Mohamed TABET; Jean-Luc BLANC;
> Christophe DELAUNAY; Tom BOCCHINO; Christophe Henri RICARD
> Subject: [PATCH 1/3] TPM: new stm i2c device driver
>
> Hello Rajiv, James,
>
> As a new year is here, I'm cleaning up some stuff that were kept on the
> shelves.
> Please find below in a plain text format, the updated tpm stm st19np18
> i2c driver.
> This patch provide in one part the full tpm driver for st19np18 using
> i2c protocol.
> The updates are:
> - some code/comment cleaning.
> - replace wait_event_interruptible_on_gpio function with wait_for_stat
> (as found in tpm_tis).
> This move the duration
> (which is different to timeout according TCG PC Client Specific TPM
> Interface Specification (TIS) spec:
> http://www.trustedcomputinggroup.org/files/resource_files/87BCE22B-
> 1D09-3519-ADEBA772FBF02CBD/TCG_PCClientTPMSpecification_1-20_1-
> 00_FINAL.pdf) management to the tpm.c to the tpm_transmit function in
> tpm.c.
> I believe, it makes the driver more similar and easier to understand
> for everybody (I guess).
> - I have tried to take care of my English spelling in some comments and
> in the documentation file.
> - I have updated/replaced the ioctl function by unlocked_ioctl to avoid
> any warning from the Linux TSS trousers (tcsd) and according to the
> 2.6.35 --> 2.6.36 ioctl mechanism delta.
>
> I have applied this patch to the last security-next kernel as you
> mentioned below (2.6.37 rc3) and run it on a beagleboard xM and C4
> http://beagleboard.org/.
> Those devices are already in the market.
>
> I've tried to take care of all your feedbacks and to be familiar as
> good as I can
> with all the Linux guidelines for all the patches submission process.
> I'm using Outlook as mail client for company policy rules reasons.
>
> I would like to know also what is the gap I have to reach to get this
> driver on the kernel source tree.
>
> Any feedback or comments are welcome.
>
> Thanks
> Christophe
>
> ------------------------------
> Signed-off-by: Christophe RICARD <christophe-h.ricard[at]st.com>
> diff --git a/Documentation/tpm/tpm_stm_st19_i2c.txt
> b/Documentation/tpm/tpm_stm_st19_i2c.txt
> --- a/Documentation/tpm/tpm_stm_st19_i2c.txt  1969-12-31
> 17:00:00.000000000 -0700
> +++ b/Documentation/tpm/tpm_stm_st19_i2c.txt  2011-01-17
> 04:54:13.534658985 -0600
> @@ -0,0 +1,169 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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
> + */
> +
> +PURPOSE OF THE DOCUMENT
> +------------------------
> +This document describe the installation of the TPM driver for
> +TPM ST19NP18 using I2C protocols.
> +
> +
> +PLATFORM USED FOR TESTING
> +--------------------------
> +During the development, several embedded platforms running ARM CPU
> were
> +used.
> +Listing of validated platforms:
> +- TI Beagleboard
> +- STMicroelectronics Spear 300
> +- STMicroelectronics Spear 600
> +
> +REQUIREMENTS
> +-------------
> +Software
> +=========
> +The TPM driver can be install under a kernel that implements at least
> the
> +following features:
> +- Linux GENERIC_GPIO programming interfaces.
> +- I2C new style programming interface base (with probe & remove
> functions).
> +- 1 I2C adapter (I2C Linux controller driver) or use of I2C_GPIO
> driver for I2C
> +bitbanging.
> +
> +
> +Hardware
> +=========
> +To run a TPM, the platform needs at least:
> +- 2 Power supplies (3.3V).
> +- 1 I2C controller or 2 GPIOs used for SDA & SCL (I2C bit bang
> method).
> +- 2 GPIOs for signals accept_command & data_available.
> +
> +TPM I2C speed is 100Khz (Maximum)
> +
> +All TPM signals work at 3.3V
> +
> +HOW TO INSTALL
> +---------------
> +Platform installation file
> +===========================
> +(N.B: platform file in arch/<processor_type>/mach-<platform-name>/
> +
> +
> +1 - Software integration
> +=========================
> +<processor_type> could be: alpha, arm, avr32, blackfin, cris, frv,
> h8300, ia64,
> +m32r, m68k, m68knommu, parisc, powerpc, s390, sh, sparc, sparc64, um,
> x86,
> +xtensa...
> +<platform-name> corresponds to your platform
> +
> +In the file where the machine_init() function exists, the developer
> must
> +declare:
> +- 1 struct st19np18_platform_data to provide which gpio the driver
> will use.
> +     * The accept_pin and data_avail_pin gpio are configured as input
> only.
> +     * This gpio management is under the platform developer's
> responsability.
> +
> +Finally, in the machine_init() function provided in the same file, the
> developer
> +should use the well known function i2c_register_board_info() from the
> I2C Linux
> +API Core.
> +
> +2- Hardware integration
> +========================
> +- ST recommends connecting VPS1 and VPS2 to the board power supply and
> at least two
> +GNDs (on each side of TSSOP28 package). (See datasheet for further
> information)
> +
> +- As the ST19NP18 has no internal pull up, ST recommands having:
> +  * 2 external pull up on SDA & SCL signals (RpSDA/RpSCL) with values
> according
> +to the abacus on page 40 or the "I2C Bus specification, version 2.1
> January
> +2000".
> +
> +
> +Platform integration advises
> +=============================
> +
> +For power management purposes, the kernel will send a TPM_SaveState
> command in the
> +suspend tpm driver function.
> +If the platform generates a TPM Init event on wakeup, the
> TPM_Startup(ST_STATE) command should
> +be executed before the Linux kernel come up (resume function
> execution).
> +
> +Here is an example with beagleboard:
> +====================================
> +In the corresponding platform init file, the developer should specify
> +the following information:
> +- The platform gpio's used to managed the tpm's
> accept_pin/data_avail_pin
> +(in a struct st19np18_platform_data declaration).
> +- The TPM I2C 7 bits address (TPM_I2C_ST19_ADDR_WR) (in a struct
> i2c_board_info).
> +
> +Then the developer should add the TPM slave device to the good i2c
> adapter with the
> +i2c_register_board_info function (assuming that the gpio and the i2c
> bus are well configured).
> +
> +Note: For the beagleboard configure your kernel with the following
> option: CONFIG_OMAP_MUX=y
> +
> +file arch\arm\mach-omap2\board-omap3beagle.c
> +add the following:
> +----------------------------------------------------------------------
> -
> +
> +static struct st19np18_platform_data tpm_data = {
> +        .accept_pin = 135,
> +        .data_avail_pin = 143,
> +};
> +
> +static struct i2c_board_info __initdata tpm_st19_i2c_board_info[] = {
> +        {
> +         I2C_BOARD_INFO(TPM_DRIVER_NAME, TPM_I2C_ST19_ADDR_WR),
> +         .platform_data = &tpm_data,
> +         },
> +};
> +
> +----------------------------------------------------------------------
> --
> +Then complete the beagleboard init to be like this:
> +----------------------------------------------------------------------
> --
> +static void __init omap3_beagle_init(void)
> +{
> +        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
> +        omap3_beagle_i2c_init();
> +        platform_add_devices(omap3_beagle_devices,
> +                        ARRAY_SIZE(omap3_beagle_devices));
> +        omap_serial_init();
> +
> +        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
> +        gpio_request(170, "DVI_nPD");
> +        /* REVISIT leave DVI powered down until it's needed ... */
> +        gpio_direction_output(170, true);
> +
> +        usb_musb_init(&musb_board_data);
> +        usb_ehci_init(&ehci_pdata);
> +        omap3beagle_flash_init();
> +
> +        beagle_display_init();
> +
> +        /* Ensure SDRC pins are mux'd for self-refresh */
> +        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
> +        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
> +        omap_mux_init_gpio(((struct st19np18_platform_data *)
> +                           tpm_st19_i2c_board_info[0].platform_data)-
> >data_avail_pin,
> +                           OMAP_PIN_INPUT);
> +     omap_mux_init_gpio(((struct st19np18_platform_data *)
> +                           tpm_st19_i2c_board_info[0].platform_data)-
> >accept_pin,
> +                           OMAP_PIN_INPUT);
> +
> +     i2c_register_board_info(2, tpm_st19_i2c_board_info,
> ARRAY_SIZE(tpm_st19_i2c_board_info));
> +}
> diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> --- a/drivers/char/tpm/Kconfig        2011-01-06 04:44:39.000000000 -0600
> +++ b/drivers/char/tpm/Kconfig        2011-01-13 22:44:42.906408085 -0600
> @@ -60,4 +60,13 @@
>         Further information on this driver and the supported hardware
>         can be found at http://www.trust.rub.de/projects/linux-device-
> driver-infineon-tpm/
>
> +config TCG_ST19_I2C
> +        tristate "STMicroelectronics ST19 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_st19_i2c.
>  endif # TCG_TPM
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> --- a/drivers/char/tpm/Makefile       2011-01-06 04:44:39.000000000 -0600
> +++ b/drivers/char/tpm/Makefile       2011-01-13 22:44:35.506658670 -0600
> @@ -9,3 +9,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_ST19_I2C) += tpm_stm_st19_i2c.o
> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c
> b/drivers/char/tpm/tpm_stm_st19_i2c.c
> --- a/drivers/char/tpm/tpm_stm_st19_i2c.c     1969-12-31 17:00:00.000000000
> -0700
> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.c     2011-01-16 22:44:58.466479759
> -0600
> @@ -0,0 +1,602 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_i2c.c
> + *
> + * @Synopsis:
> + * -------------------------------------------------------------------
> ---
> + *   02/12/2008
> + *   - Stand alone implementation (without any TPM api)
> + * -------------------------------------------------------------------
> ---
> + *   03/02/2010
> + *   - Power management (suspend and resume functions)
> + *   implementation
> + * -------------------------------------------------------------------
> ---
> + *   03/19/2010
> + *   - Use of the linux kernel TPM api --> driver/char/tpm
> + * -------------------------------------------------------------------
> ---
> + *   05/26/2010
> + *   - Update code for code submission and bug fixes:
> + *   - Comments spelling fixes
> + *   - Lindent script execution
> + *   - checkpatch.pl script execution
> + *   - fix syslog error when loaded as a module:
> + *    "release() function missing and must be fixed"
> + *   - name files change from
> + *     stm_st19_tpm_i2c to tpm_stm_st19_i2c
> + * -------------------------------------------------------------------
> ---
> + *   06/15/2010
> + *   - Update for new tpm core device.
> + *   num_opens --> is_open
> + * -------------------------------------------------------------------
> ---
> + *   07/08/2010
> + *   - Update probe, resume suspend functions
> + *   - Fix issue suspend buffer and work around related to the
> + *   chip->data_buffer not allocated.
> + * -------------------------------------------------------------------
> ---
> + *   09/03/2010
> + *   - Review under LKLM
> + *   - Patches from Joe Perches after review which fix some break and
> + *   some neatings.
> + * -------------------------------------------------------------------
> ---
> + *   09/16/2010
> + *   - Remove unaccurate comment.
> + * -------------------------------------------------------------------
> ---
> + *   01/12/2011
> + *   - update ioctl function to unlocked_ioctl for kernel >= 2.6.36
> + *   - Some cleaning
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.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/version.h>
> +#include <linux/smp_lock.h>
> +
> +#include <linux/i2c/tpm_stm_st19_i2c.h>
> +
> +#include "tpm.h"
> +
> +#include "tpm_stm_st19_i2c.h"
> +
> +#ifdef DEBUG
> +#define FUNC_ENTER() pr_info("%s\n", __func__)
> +#else
> +#define FUNC_ENTER() do {} while (0)
> +#endif
> +
> +static struct st19np18_platform_data *pin_infos;
> +
> +#define TPM_STS_DATA_AVAIL 0x10
> +#define TPM_STS_ACCEPT_COMMAND 0x01
> +#define TPM_STS_CANCEL (TPM_STS_DATA_AVAIL | TPM_STS_ACCEPT_COMMAND)
> +enum tis_defaults {
> +     TIS_SHORT_TIMEOUT = 750,        /* ms */
> +     TIS_LONG_TIMEOUT = 2000,        /* 2 sec */
> +};
> +
> +/*
> + * gpio_readpin is a wrapper to read a gpio value.
> + * Use generic gpio APIs
> + * @param: pin_id, the pin identifier where the value will be read.
> + * @return: the gpio value (should be 0 or 1) or negative errno
> + */
> +static int gpio_readpin(int pin_id)
> +{
> +     int ret;
> +     ret = gpio_direction_input(pin_id);
> +     if (ret == 0)
> +             return gpio_get_value(pin_id);
> +     return ret;
> +}
> +
> +/*
> + * tpm_stm_i2c_status is not implemented because TIS registers are not
> + * implemented.
> + */
> +static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
> +{
> +     u8 state_data, state_command;
> +
> +     state_data = gpio_readpin(pin_infos->data_avail_pin);
> +     state_command = gpio_readpin(pin_infos->accept_pin);
> +     return (state_data << 4) | state_command;
> +}
> +
> +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long
> timeout,
> +                      wait_queue_head_t *queue)
> +{
> +     unsigned long stop;
> +     u8 status;
> +
> +     FUNC_ENTER();
> +
> +     /* check current status */
> +     status = tpm_stm_i2c_status(chip);
> +     if (status == mask)
> +             return 0;
> +     if (status == TPM_STS_CANCEL)
> +             goto end;
> +     stop = jiffies + timeout;
> +     do {
> +             msleep(TPM_TIMEOUT);
> +             status = tpm_stm_i2c_status(chip);
> +             if ((status & mask) == mask)
> +                     return 0;
> +     } while (time_before(jiffies, stop));
> +end:
> +     return -ETIME;
> +}
> +
> +/*
> + * tpm_stm_i2c_send send TPM commands through the I2C bus.
> + * Before sending any TPM commands, tpm_stm_i2c_send poll
> data_available and
> + * accept_command TPM GPIOs.
> + *
> + * In case the data_available is high (logical value 1),
> tpm_stm_i2c_send will
> + * empty the TPM FIFO by reading all the datas stored inside the TPM.
> + *
> + * Then, if the accept_command TPM GPIO is high(logical value 1)
> + * tpm_stm_i2c_send will first send the 10 bytes header of the TCG
> commands and
> + * then send the others bytes by 40 bytes blocks.
> + *
> + * data_available and accept_command TPM GPIOs will goes low when the
> TPM
> + * compute the command.
> + *
> + * @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 count)
> +{
> +     u32 ret = 0, i, size, ordinal;
> +     struct i2c_client *client;
> +
> +     FUNC_ENTER();
> +
> +     if (chip == NULL)
> +             return -EBUSY;
> +     if (count < TPM_HEADER_SIZE)
> +             return -EBUSY;
> +     client = (struct i2c_client *)pin_infos->client;
> +
> +     ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
> +
> +     size = TPM_HEADER_SIZE;
> +     i = 0;
> +     while (i < size && wait_for_stat(chip, TPM_STS_ACCEPT_COMMAND,
> +                                      TPM_I2C_SHORT,
> +                                      &chip->vendor.int_queue) == 0) {
> +             int bytes;
> +
> +             if (i == 0)
> +                     bytes = TPM_HEADER_SIZE;
> +             else
> +                     bytes = min_t(int, count - i, TPM_I2C_BLOCK_SIZE);
> +
> +             if (i == 0) {
> +                     size = be32_to_cpu(*(__be32 *) (buf + 2));
> +                     size = size < count ? size : count;
> +             }
> +             if (count < TPM_HEADER_SIZE)
> +                     bytes = count;
> +             ret = i2c_master_send(client, buf + i, bytes);
> +             if (ret < 0) {
> +                     pr_info("Failed to send data\n");
> +                     goto end;
> +             }
> +
> +             if (i == 0)
> +                     i += TPM_HEADER_SIZE;
> +             else
> +                     i += TPM_I2C_BLOCK_SIZE;
> +     }
> +
> +     if (i == 0) {
> +             pr_info("Failed to read gpio pin (AcceptCmd)\n");
> +             ret = -EIO;
> +     }
> +end:
> +     return ret ? ret : count;
> +}
> +
> +/*
> + * tpm_stm_i2c_recv received TPM response through the I2C bus.
> + * Before receiving any TPM response, tpm_stm_i2c_recv poll
> data_available and
> + * accept_command TPM GPIOs.
> + *
> + * In case the accept_command is high (logical value 1),
> tpm_stm_i2c_recv will
> + * do nothing.
> + *
> + * Then, if the data_available TPM GPIO is high(logical value 1)
> + * tpm_stm_i2c_recv will first receive the 10 bytes header of the TCG
> TPM
> + * response and then receive the others bytes by 40 bytes blocks.
> + *
> + * accept_command TPM GPIOs will goes high when the TPM Fofo is empty.
> + *
> + * @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 ret = 0;
> +     int i, size;
> +     struct i2c_client *client;
> +
> +     FUNC_ENTER();
> +
> +     if (chip == NULL)
> +             return -EBUSY;
> +     if (count < TPM_HEADER_SIZE)
> +             return -EBUSY;
> +
> +     client = (struct i2c_client *)pin_infos->client;
> +
> +     size = TPM_HEADER_SIZE;
> +     i = 0;
> +     while (i < size && wait_for_stat(chip, TPM_STS_DATA_AVAIL,
> +                                      TPM_I2C_SHORT,
> +                                      &chip->vendor.read_queue) == 0) {
> +             int bytes;
> +
> +             if (count < TPM_HEADER_SIZE)
> +                     bytes = count;
> +             else if (i == 0)
> +                     bytes = TPM_HEADER_SIZE;
> +             else
> +                     bytes = min_t(int, size - i, TPM_I2C_BLOCK_SIZE);
> +
> +             ret = i2c_master_recv(client, buf + i, bytes);
> +             if (ret < 0) {
> +                     pr_info(" Failed to read gpio pin
> (DataAvailable)\n");
> +                     goto end;
> +             }
> +
> +             if (!buf) {
> +                     pr_info("read buffer is NULL\n");
> +                     goto end;
> +             }
> +
> +             if (i == 0) {
> +                     size = be32_to_cpu(*(__be32 *) (buf + 2));
> +                     if (size > count)
> +                             size = count;
> +                     i += TPM_HEADER_SIZE;
> +             } else
> +                     i += TPM_I2C_BLOCK_SIZE;
> +     }
> +
> +     if (i == 0) {
> +             pr_info("Failed to read gpio pin (DataAvailable)\n");
> +             ret = -EIO;
> +             goto end;
> +     }
> +     return size;
> +end:
> +     return ret;
> +}
> +
> +/*
> + * 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)
> +{
> +}
> +
> +/*
> + * tpm_st19_i2c_ioctl provides 2 handles:
> + * - TPMIOC_CANCEL: allow to CANCEL a TPM commands execution.
> + *   See tpm_stm_i2c_cancel description above
> + * - TPMIOC_TRANSMIT: allow to transmit a TPM commands.
> + *
> + * @return: In case of success, return TPM response size.
> + * In other case return < 0 value describing the issue.
> + */
> +/*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
> +static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file
> *file,
> +                               unsigned int cmd, unsigned long arg)
> +#else*/
> +static long tpm_st19_i2c_unlocked_ioctl(struct file *file,
> +                                     unsigned int cmd, unsigned long arg)
> +/*#endif*/
> +{
> +     int in_size = 0, out_size = 0, ret = -ENOTTY;
> +     struct tpm_chip *chip = file->private_data;
> +
> +     lock_kernel();
> +     switch (cmd) {
> +     case TPMIOC_CANCEL:
> +             tpm_stm_i2c_cancel(chip);
> +             ret = -ENOSYS;
> +             break;
> +     case TPMIOC_TRANSMIT:
> +             if (copy_from_user(chip->data_buffer,
> +                                (const char *)arg, TPM_HEADER_SIZE)) {
> +                     ret = -EFAULT;
> +                     break;
> +             }
> +
> +             in_size = be32_to_cpu(*(__be32 *) (chip->data_buffer + 2));
> +             if (copy_from_user(chip->data_buffer,
> +                                (const char *)arg, in_size)) {
> +                     ret = -EFAULT;
> +                     break;
> +             }
> +
> +             tpm_stm_i2c_send(chip, chip->data_buffer, in_size);
> +
> +             out_size = tpm_stm_i2c_recv(chip, chip->data_buffer,
> +                                         TPM_BUFSIZE);
> +             if (copy_to_user((char *)arg, chip->data_buffer, out_size))
> {
> +                     ret = -EFAULT;
> +                     break;
> +             }
> +             ret = out_size;
> +             break;
> +     }
> +     unlock_kernel();
> +     return ret;
> +}
> +
> +static const struct file_operations tpm_st19_i2c_fops = {
> +     .owner = THIS_MODULE,
> +     .llseek = no_llseek,
> +     .read = tpm_read,
> +
> +     /*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
> +        .ioctl = tpm_st19_i2c_ioctl,
> +        #else */
> +     .unlocked_ioctl = tpm_st19_i2c_unlocked_ioctl,
> +     /*#endif */
> +
> +     .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,
> +     .req_complete_val = TPM_STS_DATA_AVAIL,
> +     .req_canceled = TPM_STS_CANCEL,
> +     .attr_group = &stm_tpm_attr_grp,
> +     .miscdev = {.fops = &tpm_st19_i2c_fops,},
> +};
> +
> +/*
> + * tpm_st19_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_st19_i2c_probe(struct i2c_client *client, const struct
> i2c_device_id *id)
> +{
> +     int err;
> +     struct tpm_chip *chip;
> +     struct st19np18_platform_data *platform_data;
> +
> +     FUNC_ENTER();
> +
> +     err = 0;
> +
> +     /* Check I2C platform functionnalities */
> +     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) {
> +             err = -ENODEV;
> +             goto end;
> +     }
> +
> +     platform_data = client->dev.platform_data;
> +     pin_infos = platform_data;
> +     platform_data->client = client;
> +     /* Default timeouts */
> +        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);
> +
> +     /* Register GPIO pin through generic Linux GPIO API */
> +     err = gpio_request(platform_data->accept_pin, "accept command");
> +     if (err)
> +             goto _gpio_init;
> +
> +     err = gpio_request(platform_data->data_avail_pin, "data
> available");
> +     if (err)
> +             goto _gpio_init;
> +
> +     tpm_get_timeouts(chip);
> +     tpm_continue_selftest(chip);
> +
> +     /* attach chip datas to client */
> +     i2c_set_clientdata(client, chip);
> +
> +     pr_info("TPM I2C Initialized\n");
> +     return 0;
> +_gpio_init:
> +     if (platform_data) {
> +             gpio_free(platform_data->accept_pin);
> +             gpio_free(platform_data->data_avail_pin);
> +     }
> +     tpm_remove_hardware(chip->dev);
> +end:
> +     i2c_set_clientdata(client, NULL);
> +     pr_info("TPM I2C initialisation fail\n");
> +     return err;
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_remove(struct i2c_client *client)
> +{
> +     struct tpm_chip *chip = (struct tpm_chip
> *)i2c_get_clientdata(client);
> +     FUNC_ENTER();
> +
> +     if (pin_infos != NULL) {
> +             gpio_free(pin_infos->accept_pin);
> +             gpio_free(pin_infos->data_avail_pin);
> +     }
> +
> +     /* Check if chip has been previously clean */
> +     if (chip != NULL)
> +             tpm_remove_hardware(chip->dev);
> +
> +     return 0;
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_pm_suspend(struct i2c_client *client,
> pm_message_t mesg)
> +{
> +     return tpm_pm_suspend(&client->dev, mesg);
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_pm_resume(struct i2c_client *client)
> +{
> +     return tpm_pm_resume(&client->dev);
> +}                            /* tpm_st19_i2c_pm_resume() */
> +
> +static const struct i2c_device_id tpm_st19_i2c_id[] = {
> +     {TPM_DRIVER_NAME, 0},
> +     {}
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, tpm_st19_i2c_id);
> +
> +static struct i2c_driver tpm_st19_i2c_driver = {
> +     .driver = {
> +                .owner = THIS_MODULE,
> +                .name = TPM_DRIVER_NAME,
> +                },
> +     .probe = tpm_st19_i2c_probe,
> +     .remove = tpm_st19_i2c_remove,
> +     .resume = tpm_st19_i2c_pm_resume,
> +     .suspend = tpm_st19_i2c_pm_suspend,
> +     .id_table = tpm_st19_i2c_id
> +};
> +
> +/*
> + * tpm_st19_i2c_init initialize driver
> + * @return: 0 if successful, else non zero value.
> + */
> +static int __init tpm_st19_i2c_init(void)
> +{
> +     FUNC_ENTER();
> +     return i2c_add_driver(&tpm_st19_i2c_driver);
> +}
> +
> +/*
> + * tpm_st19_i2c_exit The kernel calls this function during unloading
> the
> + * module or during shut down process
> + */
> +static void __exit tpm_st19_i2c_exit(void)
> +{
> +     FUNC_ENTER();
> +     i2c_del_driver(&tpm_st19_i2c_driver);
> +}
> +
> +module_init(tpm_st19_i2c_init);
> +module_exit(tpm_st19_i2c_exit);
> +
> +MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
> +MODULE_DESCRIPTION("STM TPM I2C ST19 Driver");
> +MODULE_VERSION("1.2.0");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.h
> b/drivers/char/tpm/tpm_stm_st19_i2c.h
> --- a/drivers/char/tpm/tpm_stm_st19_i2c.h     1969-12-31 17:00:00.000000000
> -0700
> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.h     2011-01-16 22:45:08.918407969
> -0600
> @@ -0,0 +1,52 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_tpm_i2c.h
> + *
> + * @Date: 02/12/2008
> + */
> +#ifndef __STM_ST19_TPM_I2C_MAIN_H__
> +#define __STM_ST19_TPM_I2C_MAIN_H__
> +
> +#include <linux/pci.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.h>
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +
> +#define TPM_BUFSIZE          2048
> +#define TPM_HEADER_SIZE              10
> +#define TPM_I2C_BLOCK_SIZE   0x28
> +
> +#define TPM_I2C_SHORT                2000    /* 2s */
> +#define STARTUP_WAIT_INTERVAL        8       /* 8ms */
> +
> +/* ioctl commands */
> +#define TPMIOC_CANCEL                _IO('T', 0x00)  /* Not supported */
> +#define TPMIOC_TRANSMIT              _IO('T', 0x01)
> +
> +#endif /* __STM_ST19_TPM_I2C_MAIN_H__ */
> diff --git a/include/linux/i2c/tpm_stm_st19_i2c.h
> b/include/linux/i2c/tpm_stm_st19_i2c.h
> --- a/include/linux/i2c/tpm_stm_st19_i2c.h    1969-12-31
> 17:00:00.000000000 -0700
> +++ b/include/linux/i2c/tpm_stm_st19_i2c.h    2011-01-16
> 22:45:31.758408188 -0600
> @@ -0,0 +1,42 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_tpm_i2c.h
> + *
> + * @Date: 06/15/2008
> + */
> +#ifndef __STM_ST19_TPM_I2C_H__
> +#define __STM_ST19_TPM_I2C_H__
> +
> +#include <linux/i2c.h>
> +
> +#define TPM_DRIVER_NAME         "st19np18"
> +#define TPM_I2C_ST19_ADDR_WR (0x26 >> 1) /*0x13 7 bits address */
> +
> +struct st19np18_platform_data {
> +     int accept_pin; /* accept command pin */
> +     int data_avail_pin;/* data available pin */
> +     struct i2c_client *client;
> +};
> +
> +#endif /* __STM_ST19_TPM_I2C_H__ */

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

* RE: [PATCH 1/3] TPM: new stm i2c device driver
  2011-08-25 14:34 ` Christophe Henri RICARD
@ 2011-08-25 15:00   ` Mohamed TABET
  2011-08-25 18:53     ` Rajiv Andrade
  0 siblings, 1 reply; 14+ messages in thread
From: Mohamed TABET @ 2011-08-25 15:00 UTC (permalink / raw)
  To: Rajiv Andrade, Marcel Selhorst, linux-kernel@vger.kernel.org,
	James Morris, joe@perches.com, matt mooney
  Cc: Christophe Henri RICARD, Sean NEWTON, Jean-Luc BLANC

Dear Kernel.org recipients,

ST will very much appreciate any comments, recommendations or suggestions on how to successfully complete this driver submission which was pushed on to the kernel.org organization since months now ?

Thanks advance for your feedback so that we could move forward and eventually address any concern you may still have and that prevent the publication of the driver source code to happen.

Best regards,
M.Tabet

-----Original Message-----
From: Christophe Henri RICARD
Sent: 25 August, 2011 16:34
To: Rajiv Andrade; Marcel Selhorst
Cc: James Morris; linux-kernel@vger.kernel.org; joe@perches.com; matt mooney; Sean NEWTON; Serge FRUHAUF; Mohamed TABET; Jean-Luc BLANC; Christophe DELAUNAY; Tom BOCCHINO; Christophe Henri RICARD; Mathias LEBLANC
Subject: RE: [PATCH 1/3] TPM: new stm i2c device driver

Hi,

I would like to know where does this driver submission stand.
Do I still have to do any improvements ? Do you need more information before pushing it on the main kernel stream ?

Thanks for your help.
Christophe
> -----Original Message-----
> From: Christophe Henri RICARD
> Sent: Monday, January 17, 2011 5:34 PM
> To: Rajiv Andrade; Marcel Selhorst
> Cc: James Morris; linux-kernel@vger.kernel.org; joe@perches.com; matt
> mooney; Sean NEWTON; Serge FRUHAUF; Mohamed TABET; Jean-Luc BLANC;
> Christophe DELAUNAY; Tom BOCCHINO; Christophe Henri RICARD
> Subject: [PATCH 1/3] TPM: new stm i2c device driver
>
> Hello Rajiv, James,
>
> As a new year is here, I'm cleaning up some stuff that were kept on the
> shelves.
> Please find below in a plain text format, the updated tpm stm st19np18
> i2c driver.
> This patch provide in one part the full tpm driver for st19np18 using
> i2c protocol.
> The updates are:
> - some code/comment cleaning.
> - replace wait_event_interruptible_on_gpio function with wait_for_stat
> (as found in tpm_tis).
> This move the duration
> (which is different to timeout according TCG PC Client Specific TPM
> Interface Specification (TIS) spec:
> http://www.trustedcomputinggroup.org/files/resource_files/87BCE22B-
> 1D09-3519-ADEBA772FBF02CBD/TCG_PCClientTPMSpecification_1-20_1-
> 00_FINAL.pdf) management to the tpm.c to the tpm_transmit function in
> tpm.c.
> I believe, it makes the driver more similar and easier to understand
> for everybody (I guess).
> - I have tried to take care of my English spelling in some comments and
> in the documentation file.
> - I have updated/replaced the ioctl function by unlocked_ioctl to avoid
> any warning from the Linux TSS trousers (tcsd) and according to the
> 2.6.35 --> 2.6.36 ioctl mechanism delta.
>
> I have applied this patch to the last security-next kernel as you
> mentioned below (2.6.37 rc3) and run it on a beagleboard xM and C4
> http://beagleboard.org/.
> Those devices are already in the market.
>
> I've tried to take care of all your feedbacks and to be familiar as
> good as I can
> with all the Linux guidelines for all the patches submission process.
> I'm using Outlook as mail client for company policy rules reasons.
>
> I would like to know also what is the gap I have to reach to get this
> driver on the kernel source tree.
>
> Any feedback or comments are welcome.
>
> Thanks
> Christophe
>
> ------------------------------
> Signed-off-by: Christophe RICARD <christophe-h.ricard[at]st.com>
> diff --git a/Documentation/tpm/tpm_stm_st19_i2c.txt
> b/Documentation/tpm/tpm_stm_st19_i2c.txt
> --- a/Documentation/tpm/tpm_stm_st19_i2c.txt  1969-12-31
> 17:00:00.000000000 -0700
> +++ b/Documentation/tpm/tpm_stm_st19_i2c.txt  2011-01-17
> 04:54:13.534658985 -0600
> @@ -0,0 +1,169 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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
> + */
> +
> +PURPOSE OF THE DOCUMENT
> +------------------------
> +This document describe the installation of the TPM driver for
> +TPM ST19NP18 using I2C protocols.
> +
> +
> +PLATFORM USED FOR TESTING
> +--------------------------
> +During the development, several embedded platforms running ARM CPU
> were
> +used.
> +Listing of validated platforms:
> +- TI Beagleboard
> +- STMicroelectronics Spear 300
> +- STMicroelectronics Spear 600
> +
> +REQUIREMENTS
> +-------------
> +Software
> +=========
> +The TPM driver can be install under a kernel that implements at least
> the
> +following features:
> +- Linux GENERIC_GPIO programming interfaces.
> +- I2C new style programming interface base (with probe & remove
> functions).
> +- 1 I2C adapter (I2C Linux controller driver) or use of I2C_GPIO
> driver for I2C
> +bitbanging.
> +
> +
> +Hardware
> +=========
> +To run a TPM, the platform needs at least:
> +- 2 Power supplies (3.3V).
> +- 1 I2C controller or 2 GPIOs used for SDA & SCL (I2C bit bang
> method).
> +- 2 GPIOs for signals accept_command & data_available.
> +
> +TPM I2C speed is 100Khz (Maximum)
> +
> +All TPM signals work at 3.3V
> +
> +HOW TO INSTALL
> +---------------
> +Platform installation file
> +===========================
> +(N.B: platform file in arch/<processor_type>/mach-<platform-name>/
> +
> +
> +1 - Software integration
> +=========================
> +<processor_type> could be: alpha, arm, avr32, blackfin, cris, frv,
> h8300, ia64,
> +m32r, m68k, m68knommu, parisc, powerpc, s390, sh, sparc, sparc64, um,
> x86,
> +xtensa...
> +<platform-name> corresponds to your platform
> +
> +In the file where the machine_init() function exists, the developer
> must
> +declare:
> +- 1 struct st19np18_platform_data to provide which gpio the driver
> will use.
> +     * The accept_pin and data_avail_pin gpio are configured as input
> only.
> +     * This gpio management is under the platform developer's
> responsability.
> +
> +Finally, in the machine_init() function provided in the same file, the
> developer
> +should use the well known function i2c_register_board_info() from the
> I2C Linux
> +API Core.
> +
> +2- Hardware integration
> +========================
> +- ST recommends connecting VPS1 and VPS2 to the board power supply and
> at least two
> +GNDs (on each side of TSSOP28 package). (See datasheet for further
> information)
> +
> +- As the ST19NP18 has no internal pull up, ST recommands having:
> +  * 2 external pull up on SDA & SCL signals (RpSDA/RpSCL) with values
> according
> +to the abacus on page 40 or the "I2C Bus specification, version 2.1
> January
> +2000".
> +
> +
> +Platform integration advises
> +=============================
> +
> +For power management purposes, the kernel will send a TPM_SaveState
> command in the
> +suspend tpm driver function.
> +If the platform generates a TPM Init event on wakeup, the
> TPM_Startup(ST_STATE) command should
> +be executed before the Linux kernel come up (resume function
> execution).
> +
> +Here is an example with beagleboard:
> +====================================
> +In the corresponding platform init file, the developer should specify
> +the following information:
> +- The platform gpio's used to managed the tpm's
> accept_pin/data_avail_pin
> +(in a struct st19np18_platform_data declaration).
> +- The TPM I2C 7 bits address (TPM_I2C_ST19_ADDR_WR) (in a struct
> i2c_board_info).
> +
> +Then the developer should add the TPM slave device to the good i2c
> adapter with the
> +i2c_register_board_info function (assuming that the gpio and the i2c
> bus are well configured).
> +
> +Note: For the beagleboard configure your kernel with the following
> option: CONFIG_OMAP_MUX=y
> +
> +file arch\arm\mach-omap2\board-omap3beagle.c
> +add the following:
> +----------------------------------------------------------------------
> -
> +
> +static struct st19np18_platform_data tpm_data = {
> +        .accept_pin = 135,
> +        .data_avail_pin = 143,
> +};
> +
> +static struct i2c_board_info __initdata tpm_st19_i2c_board_info[] = {
> +        {
> +         I2C_BOARD_INFO(TPM_DRIVER_NAME, TPM_I2C_ST19_ADDR_WR),
> +         .platform_data = &tpm_data,
> +         },
> +};
> +
> +----------------------------------------------------------------------
> --
> +Then complete the beagleboard init to be like this:
> +----------------------------------------------------------------------
> --
> +static void __init omap3_beagle_init(void)
> +{
> +        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
> +        omap3_beagle_i2c_init();
> +        platform_add_devices(omap3_beagle_devices,
> +                        ARRAY_SIZE(omap3_beagle_devices));
> +        omap_serial_init();
> +
> +        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
> +        gpio_request(170, "DVI_nPD");
> +        /* REVISIT leave DVI powered down until it's needed ... */
> +        gpio_direction_output(170, true);
> +
> +        usb_musb_init(&musb_board_data);
> +        usb_ehci_init(&ehci_pdata);
> +        omap3beagle_flash_init();
> +
> +        beagle_display_init();
> +
> +        /* Ensure SDRC pins are mux'd for self-refresh */
> +        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
> +        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
> +        omap_mux_init_gpio(((struct st19np18_platform_data *)
> +                           tpm_st19_i2c_board_info[0].platform_data)-
> >data_avail_pin,
> +                           OMAP_PIN_INPUT);
> +     omap_mux_init_gpio(((struct st19np18_platform_data *)
> +                           tpm_st19_i2c_board_info[0].platform_data)-
> >accept_pin,
> +                           OMAP_PIN_INPUT);
> +
> +     i2c_register_board_info(2, tpm_st19_i2c_board_info,
> ARRAY_SIZE(tpm_st19_i2c_board_info));
> +}
> diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> --- a/drivers/char/tpm/Kconfig        2011-01-06 04:44:39.000000000 -0600
> +++ b/drivers/char/tpm/Kconfig        2011-01-13 22:44:42.906408085 -0600
> @@ -60,4 +60,13 @@
>         Further information on this driver and the supported hardware
>         can be found at http://www.trust.rub.de/projects/linux-device-
> driver-infineon-tpm/
>
> +config TCG_ST19_I2C
> +        tristate "STMicroelectronics ST19 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_st19_i2c.
>  endif # TCG_TPM
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> --- a/drivers/char/tpm/Makefile       2011-01-06 04:44:39.000000000 -0600
> +++ b/drivers/char/tpm/Makefile       2011-01-13 22:44:35.506658670 -0600
> @@ -9,3 +9,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_ST19_I2C) += tpm_stm_st19_i2c.o
> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c
> b/drivers/char/tpm/tpm_stm_st19_i2c.c
> --- a/drivers/char/tpm/tpm_stm_st19_i2c.c     1969-12-31 17:00:00.000000000
> -0700
> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.c     2011-01-16 22:44:58.466479759
> -0600
> @@ -0,0 +1,602 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_i2c.c
> + *
> + * @Synopsis:
> + * -------------------------------------------------------------------
> ---
> + *   02/12/2008
> + *   - Stand alone implementation (without any TPM api)
> + * -------------------------------------------------------------------
> ---
> + *   03/02/2010
> + *   - Power management (suspend and resume functions)
> + *   implementation
> + * -------------------------------------------------------------------
> ---
> + *   03/19/2010
> + *   - Use of the linux kernel TPM api --> driver/char/tpm
> + * -------------------------------------------------------------------
> ---
> + *   05/26/2010
> + *   - Update code for code submission and bug fixes:
> + *   - Comments spelling fixes
> + *   - Lindent script execution
> + *   - checkpatch.pl script execution
> + *   - fix syslog error when loaded as a module:
> + *    "release() function missing and must be fixed"
> + *   - name files change from
> + *     stm_st19_tpm_i2c to tpm_stm_st19_i2c
> + * -------------------------------------------------------------------
> ---
> + *   06/15/2010
> + *   - Update for new tpm core device.
> + *   num_opens --> is_open
> + * -------------------------------------------------------------------
> ---
> + *   07/08/2010
> + *   - Update probe, resume suspend functions
> + *   - Fix issue suspend buffer and work around related to the
> + *   chip->data_buffer not allocated.
> + * -------------------------------------------------------------------
> ---
> + *   09/03/2010
> + *   - Review under LKLM
> + *   - Patches from Joe Perches after review which fix some break and
> + *   some neatings.
> + * -------------------------------------------------------------------
> ---
> + *   09/16/2010
> + *   - Remove unaccurate comment.
> + * -------------------------------------------------------------------
> ---
> + *   01/12/2011
> + *   - update ioctl function to unlocked_ioctl for kernel >= 2.6.36
> + *   - Some cleaning
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.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/version.h>
> +#include <linux/smp_lock.h>
> +
> +#include <linux/i2c/tpm_stm_st19_i2c.h>
> +
> +#include "tpm.h"
> +
> +#include "tpm_stm_st19_i2c.h"
> +
> +#ifdef DEBUG
> +#define FUNC_ENTER() pr_info("%s\n", __func__)
> +#else
> +#define FUNC_ENTER() do {} while (0)
> +#endif
> +
> +static struct st19np18_platform_data *pin_infos;
> +
> +#define TPM_STS_DATA_AVAIL 0x10
> +#define TPM_STS_ACCEPT_COMMAND 0x01
> +#define TPM_STS_CANCEL (TPM_STS_DATA_AVAIL | TPM_STS_ACCEPT_COMMAND)
> +enum tis_defaults {
> +     TIS_SHORT_TIMEOUT = 750,        /* ms */
> +     TIS_LONG_TIMEOUT = 2000,        /* 2 sec */
> +};
> +
> +/*
> + * gpio_readpin is a wrapper to read a gpio value.
> + * Use generic gpio APIs
> + * @param: pin_id, the pin identifier where the value will be read.
> + * @return: the gpio value (should be 0 or 1) or negative errno
> + */
> +static int gpio_readpin(int pin_id)
> +{
> +     int ret;
> +     ret = gpio_direction_input(pin_id);
> +     if (ret == 0)
> +             return gpio_get_value(pin_id);
> +     return ret;
> +}
> +
> +/*
> + * tpm_stm_i2c_status is not implemented because TIS registers are not
> + * implemented.
> + */
> +static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
> +{
> +     u8 state_data, state_command;
> +
> +     state_data = gpio_readpin(pin_infos->data_avail_pin);
> +     state_command = gpio_readpin(pin_infos->accept_pin);
> +     return (state_data << 4) | state_command;
> +}
> +
> +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long
> timeout,
> +                      wait_queue_head_t *queue)
> +{
> +     unsigned long stop;
> +     u8 status;
> +
> +     FUNC_ENTER();
> +
> +     /* check current status */
> +     status = tpm_stm_i2c_status(chip);
> +     if (status == mask)
> +             return 0;
> +     if (status == TPM_STS_CANCEL)
> +             goto end;
> +     stop = jiffies + timeout;
> +     do {
> +             msleep(TPM_TIMEOUT);
> +             status = tpm_stm_i2c_status(chip);
> +             if ((status & mask) == mask)
> +                     return 0;
> +     } while (time_before(jiffies, stop));
> +end:
> +     return -ETIME;
> +}
> +
> +/*
> + * tpm_stm_i2c_send send TPM commands through the I2C bus.
> + * Before sending any TPM commands, tpm_stm_i2c_send poll
> data_available and
> + * accept_command TPM GPIOs.
> + *
> + * In case the data_available is high (logical value 1),
> tpm_stm_i2c_send will
> + * empty the TPM FIFO by reading all the datas stored inside the TPM.
> + *
> + * Then, if the accept_command TPM GPIO is high(logical value 1)
> + * tpm_stm_i2c_send will first send the 10 bytes header of the TCG
> commands and
> + * then send the others bytes by 40 bytes blocks.
> + *
> + * data_available and accept_command TPM GPIOs will goes low when the
> TPM
> + * compute the command.
> + *
> + * @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 count)
> +{
> +     u32 ret = 0, i, size, ordinal;
> +     struct i2c_client *client;
> +
> +     FUNC_ENTER();
> +
> +     if (chip == NULL)
> +             return -EBUSY;
> +     if (count < TPM_HEADER_SIZE)
> +             return -EBUSY;
> +     client = (struct i2c_client *)pin_infos->client;
> +
> +     ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
> +
> +     size = TPM_HEADER_SIZE;
> +     i = 0;
> +     while (i < size && wait_for_stat(chip, TPM_STS_ACCEPT_COMMAND,
> +                                      TPM_I2C_SHORT,
> +                                      &chip->vendor.int_queue) == 0) {
> +             int bytes;
> +
> +             if (i == 0)
> +                     bytes = TPM_HEADER_SIZE;
> +             else
> +                     bytes = min_t(int, count - i, TPM_I2C_BLOCK_SIZE);
> +
> +             if (i == 0) {
> +                     size = be32_to_cpu(*(__be32 *) (buf + 2));
> +                     size = size < count ? size : count;
> +             }
> +             if (count < TPM_HEADER_SIZE)
> +                     bytes = count;
> +             ret = i2c_master_send(client, buf + i, bytes);
> +             if (ret < 0) {
> +                     pr_info("Failed to send data\n");
> +                     goto end;
> +             }
> +
> +             if (i == 0)
> +                     i += TPM_HEADER_SIZE;
> +             else
> +                     i += TPM_I2C_BLOCK_SIZE;
> +     }
> +
> +     if (i == 0) {
> +             pr_info("Failed to read gpio pin (AcceptCmd)\n");
> +             ret = -EIO;
> +     }
> +end:
> +     return ret ? ret : count;
> +}
> +
> +/*
> + * tpm_stm_i2c_recv received TPM response through the I2C bus.
> + * Before receiving any TPM response, tpm_stm_i2c_recv poll
> data_available and
> + * accept_command TPM GPIOs.
> + *
> + * In case the accept_command is high (logical value 1),
> tpm_stm_i2c_recv will
> + * do nothing.
> + *
> + * Then, if the data_available TPM GPIO is high(logical value 1)
> + * tpm_stm_i2c_recv will first receive the 10 bytes header of the TCG
> TPM
> + * response and then receive the others bytes by 40 bytes blocks.
> + *
> + * accept_command TPM GPIOs will goes high when the TPM Fofo is empty.
> + *
> + * @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 ret = 0;
> +     int i, size;
> +     struct i2c_client *client;
> +
> +     FUNC_ENTER();
> +
> +     if (chip == NULL)
> +             return -EBUSY;
> +     if (count < TPM_HEADER_SIZE)
> +             return -EBUSY;
> +
> +     client = (struct i2c_client *)pin_infos->client;
> +
> +     size = TPM_HEADER_SIZE;
> +     i = 0;
> +     while (i < size && wait_for_stat(chip, TPM_STS_DATA_AVAIL,
> +                                      TPM_I2C_SHORT,
> +                                      &chip->vendor.read_queue) == 0) {
> +             int bytes;
> +
> +             if (count < TPM_HEADER_SIZE)
> +                     bytes = count;
> +             else if (i == 0)
> +                     bytes = TPM_HEADER_SIZE;
> +             else
> +                     bytes = min_t(int, size - i, TPM_I2C_BLOCK_SIZE);
> +
> +             ret = i2c_master_recv(client, buf + i, bytes);
> +             if (ret < 0) {
> +                     pr_info(" Failed to read gpio pin
> (DataAvailable)\n");
> +                     goto end;
> +             }
> +
> +             if (!buf) {
> +                     pr_info("read buffer is NULL\n");
> +                     goto end;
> +             }
> +
> +             if (i == 0) {
> +                     size = be32_to_cpu(*(__be32 *) (buf + 2));
> +                     if (size > count)
> +                             size = count;
> +                     i += TPM_HEADER_SIZE;
> +             } else
> +                     i += TPM_I2C_BLOCK_SIZE;
> +     }
> +
> +     if (i == 0) {
> +             pr_info("Failed to read gpio pin (DataAvailable)\n");
> +             ret = -EIO;
> +             goto end;
> +     }
> +     return size;
> +end:
> +     return ret;
> +}
> +
> +/*
> + * 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)
> +{
> +}
> +
> +/*
> + * tpm_st19_i2c_ioctl provides 2 handles:
> + * - TPMIOC_CANCEL: allow to CANCEL a TPM commands execution.
> + *   See tpm_stm_i2c_cancel description above
> + * - TPMIOC_TRANSMIT: allow to transmit a TPM commands.
> + *
> + * @return: In case of success, return TPM response size.
> + * In other case return < 0 value describing the issue.
> + */
> +/*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
> +static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file
> *file,
> +                               unsigned int cmd, unsigned long arg)
> +#else*/
> +static long tpm_st19_i2c_unlocked_ioctl(struct file *file,
> +                                     unsigned int cmd, unsigned long arg)
> +/*#endif*/
> +{
> +     int in_size = 0, out_size = 0, ret = -ENOTTY;
> +     struct tpm_chip *chip = file->private_data;
> +
> +     lock_kernel();
> +     switch (cmd) {
> +     case TPMIOC_CANCEL:
> +             tpm_stm_i2c_cancel(chip);
> +             ret = -ENOSYS;
> +             break;
> +     case TPMIOC_TRANSMIT:
> +             if (copy_from_user(chip->data_buffer,
> +                                (const char *)arg, TPM_HEADER_SIZE)) {
> +                     ret = -EFAULT;
> +                     break;
> +             }
> +
> +             in_size = be32_to_cpu(*(__be32 *) (chip->data_buffer + 2));
> +             if (copy_from_user(chip->data_buffer,
> +                                (const char *)arg, in_size)) {
> +                     ret = -EFAULT;
> +                     break;
> +             }
> +
> +             tpm_stm_i2c_send(chip, chip->data_buffer, in_size);
> +
> +             out_size = tpm_stm_i2c_recv(chip, chip->data_buffer,
> +                                         TPM_BUFSIZE);
> +             if (copy_to_user((char *)arg, chip->data_buffer, out_size))
> {
> +                     ret = -EFAULT;
> +                     break;
> +             }
> +             ret = out_size;
> +             break;
> +     }
> +     unlock_kernel();
> +     return ret;
> +}
> +
> +static const struct file_operations tpm_st19_i2c_fops = {
> +     .owner = THIS_MODULE,
> +     .llseek = no_llseek,
> +     .read = tpm_read,
> +
> +     /*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
> +        .ioctl = tpm_st19_i2c_ioctl,
> +        #else */
> +     .unlocked_ioctl = tpm_st19_i2c_unlocked_ioctl,
> +     /*#endif */
> +
> +     .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,
> +     .req_complete_val = TPM_STS_DATA_AVAIL,
> +     .req_canceled = TPM_STS_CANCEL,
> +     .attr_group = &stm_tpm_attr_grp,
> +     .miscdev = {.fops = &tpm_st19_i2c_fops,},
> +};
> +
> +/*
> + * tpm_st19_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_st19_i2c_probe(struct i2c_client *client, const struct
> i2c_device_id *id)
> +{
> +     int err;
> +     struct tpm_chip *chip;
> +     struct st19np18_platform_data *platform_data;
> +
> +     FUNC_ENTER();
> +
> +     err = 0;
> +
> +     /* Check I2C platform functionnalities */
> +     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) {
> +             err = -ENODEV;
> +             goto end;
> +     }
> +
> +     platform_data = client->dev.platform_data;
> +     pin_infos = platform_data;
> +     platform_data->client = client;
> +     /* Default timeouts */
> +        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);
> +
> +     /* Register GPIO pin through generic Linux GPIO API */
> +     err = gpio_request(platform_data->accept_pin, "accept command");
> +     if (err)
> +             goto _gpio_init;
> +
> +     err = gpio_request(platform_data->data_avail_pin, "data
> available");
> +     if (err)
> +             goto _gpio_init;
> +
> +     tpm_get_timeouts(chip);
> +     tpm_continue_selftest(chip);
> +
> +     /* attach chip datas to client */
> +     i2c_set_clientdata(client, chip);
> +
> +     pr_info("TPM I2C Initialized\n");
> +     return 0;
> +_gpio_init:
> +     if (platform_data) {
> +             gpio_free(platform_data->accept_pin);
> +             gpio_free(platform_data->data_avail_pin);
> +     }
> +     tpm_remove_hardware(chip->dev);
> +end:
> +     i2c_set_clientdata(client, NULL);
> +     pr_info("TPM I2C initialisation fail\n");
> +     return err;
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_remove(struct i2c_client *client)
> +{
> +     struct tpm_chip *chip = (struct tpm_chip
> *)i2c_get_clientdata(client);
> +     FUNC_ENTER();
> +
> +     if (pin_infos != NULL) {
> +             gpio_free(pin_infos->accept_pin);
> +             gpio_free(pin_infos->data_avail_pin);
> +     }
> +
> +     /* Check if chip has been previously clean */
> +     if (chip != NULL)
> +             tpm_remove_hardware(chip->dev);
> +
> +     return 0;
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_pm_suspend(struct i2c_client *client,
> pm_message_t mesg)
> +{
> +     return tpm_pm_suspend(&client->dev, mesg);
> +}
> +
> +/*
> + * tpm_st19_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_st19_i2c_pm_resume(struct i2c_client *client)
> +{
> +     return tpm_pm_resume(&client->dev);
> +}                            /* tpm_st19_i2c_pm_resume() */
> +
> +static const struct i2c_device_id tpm_st19_i2c_id[] = {
> +     {TPM_DRIVER_NAME, 0},
> +     {}
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, tpm_st19_i2c_id);
> +
> +static struct i2c_driver tpm_st19_i2c_driver = {
> +     .driver = {
> +                .owner = THIS_MODULE,
> +                .name = TPM_DRIVER_NAME,
> +                },
> +     .probe = tpm_st19_i2c_probe,
> +     .remove = tpm_st19_i2c_remove,
> +     .resume = tpm_st19_i2c_pm_resume,
> +     .suspend = tpm_st19_i2c_pm_suspend,
> +     .id_table = tpm_st19_i2c_id
> +};
> +
> +/*
> + * tpm_st19_i2c_init initialize driver
> + * @return: 0 if successful, else non zero value.
> + */
> +static int __init tpm_st19_i2c_init(void)
> +{
> +     FUNC_ENTER();
> +     return i2c_add_driver(&tpm_st19_i2c_driver);
> +}
> +
> +/*
> + * tpm_st19_i2c_exit The kernel calls this function during unloading
> the
> + * module or during shut down process
> + */
> +static void __exit tpm_st19_i2c_exit(void)
> +{
> +     FUNC_ENTER();
> +     i2c_del_driver(&tpm_st19_i2c_driver);
> +}
> +
> +module_init(tpm_st19_i2c_init);
> +module_exit(tpm_st19_i2c_exit);
> +
> +MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
> +MODULE_DESCRIPTION("STM TPM I2C ST19 Driver");
> +MODULE_VERSION("1.2.0");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.h
> b/drivers/char/tpm/tpm_stm_st19_i2c.h
> --- a/drivers/char/tpm/tpm_stm_st19_i2c.h     1969-12-31 17:00:00.000000000
> -0700
> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.h     2011-01-16 22:45:08.918407969
> -0600
> @@ -0,0 +1,52 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_tpm_i2c.h
> + *
> + * @Date: 02/12/2008
> + */
> +#ifndef __STM_ST19_TPM_I2C_MAIN_H__
> +#define __STM_ST19_TPM_I2C_MAIN_H__
> +
> +#include <linux/pci.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.h>
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +
> +#define TPM_BUFSIZE          2048
> +#define TPM_HEADER_SIZE              10
> +#define TPM_I2C_BLOCK_SIZE   0x28
> +
> +#define TPM_I2C_SHORT                2000    /* 2s */
> +#define STARTUP_WAIT_INTERVAL        8       /* 8ms */
> +
> +/* ioctl commands */
> +#define TPMIOC_CANCEL                _IO('T', 0x00)  /* Not supported */
> +#define TPMIOC_TRANSMIT              _IO('T', 0x01)
> +
> +#endif /* __STM_ST19_TPM_I2C_MAIN_H__ */
> diff --git a/include/linux/i2c/tpm_stm_st19_i2c.h
> b/include/linux/i2c/tpm_stm_st19_i2c.h
> --- a/include/linux/i2c/tpm_stm_st19_i2c.h    1969-12-31
> 17:00:00.000000000 -0700
> +++ b/include/linux/i2c/tpm_stm_st19_i2c.h    2011-01-16
> 22:45:31.758408188 -0600
> @@ -0,0 +1,42 @@
> +/*
> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
> + * 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_st19_tpm_i2c.h
> + *
> + * @Date: 06/15/2008
> + */
> +#ifndef __STM_ST19_TPM_I2C_H__
> +#define __STM_ST19_TPM_I2C_H__
> +
> +#include <linux/i2c.h>
> +
> +#define TPM_DRIVER_NAME         "st19np18"
> +#define TPM_I2C_ST19_ADDR_WR (0x26 >> 1) /*0x13 7 bits address */
> +
> +struct st19np18_platform_data {
> +     int accept_pin; /* accept command pin */
> +     int data_avail_pin;/* data available pin */
> +     struct i2c_client *client;
> +};
> +
> +#endif /* __STM_ST19_TPM_I2C_H__ */

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

* Re: [PATCH 1/3] TPM: new stm i2c device driver
  2011-08-25 15:00   ` Mohamed TABET
@ 2011-08-25 18:53     ` Rajiv Andrade
  0 siblings, 0 replies; 14+ messages in thread
From: Rajiv Andrade @ 2011-08-25 18:53 UTC (permalink / raw)
  To: Mohamed TABET
  Cc: Marcel Selhorst, linux-kernel@vger.kernel.org, James Morris,
	joe@perches.com, matt mooney, Christophe Henri RICARD,
	Sean NEWTON, Jean-Luc BLANC

On 25-08-2011 12:00, Mohamed TABET wrote:
> Dear Kernel.org recipients,
>
> ST will very much appreciate any comments, recommendations or suggestions on how to successfully complete this driver submission which was pushed on to the kernel.org organization since months now ?
>
> Thanks advance for your feedback so that we could move forward and eventually address any concern you may still have and that prevent the publication of the driver source code to happen.
Was the 1/3 placed there by accident? If not, were the 2/3 and 3/3 patches submitted?

Thanks,
Rajiv

> Best regards,
> M.Tabet
>
> -----Original Message-----
> From: Christophe Henri RICARD
> Sent: 25 August, 2011 16:34
> To: Rajiv Andrade; Marcel Selhorst
> Cc: James Morris; linux-kernel@vger.kernel.org; joe@perches.com; matt mooney; Sean NEWTON; Serge FRUHAUF; Mohamed TABET; Jean-Luc BLANC; Christophe DELAUNAY; Tom BOCCHINO; Christophe Henri RICARD; Mathias LEBLANC
> Subject: RE: [PATCH 1/3] TPM: new stm i2c device driver
>
> Hi,
>
> I would like to know where does this driver submission stand.
> Do I still have to do any improvements ? Do you need more information before pushing it on the main kernel stream ?
>
> Thanks for your help.
> Christophe
>> -----Original Message-----
>> From: Christophe Henri RICARD
>> Sent: Monday, January 17, 2011 5:34 PM
>> To: Rajiv Andrade; Marcel Selhorst
>> Cc: James Morris; linux-kernel@vger.kernel.org; joe@perches.com; matt
>> mooney; Sean NEWTON; Serge FRUHAUF; Mohamed TABET; Jean-Luc BLANC;
>> Christophe DELAUNAY; Tom BOCCHINO; Christophe Henri RICARD
>> Subject: [PATCH 1/3] TPM: new stm i2c device driver
>>
>> Hello Rajiv, James,
>>
>> As a new year is here, I'm cleaning up some stuff that were kept on the
>> shelves.
>> Please find below in a plain text format, the updated tpm stm st19np18
>> i2c driver.
>> This patch provide in one part the full tpm driver for st19np18 using
>> i2c protocol.
>> The updates are:
>> - some code/comment cleaning.
>> - replace wait_event_interruptible_on_gpio function with wait_for_stat
>> (as found in tpm_tis).
>> This move the duration
>> (which is different to timeout according TCG PC Client Specific TPM
>> Interface Specification (TIS) spec:
>> http://www.trustedcomputinggroup.org/files/resource_files/87BCE22B-
>> 1D09-3519-ADEBA772FBF02CBD/TCG_PCClientTPMSpecification_1-20_1-
>> 00_FINAL.pdf) management to the tpm.c to the tpm_transmit function in
>> tpm.c.
>> I believe, it makes the driver more similar and easier to understand
>> for everybody (I guess).
>> - I have tried to take care of my English spelling in some comments and
>> in the documentation file.
>> - I have updated/replaced the ioctl function by unlocked_ioctl to avoid
>> any warning from the Linux TSS trousers (tcsd) and according to the
>> 2.6.35 --> 2.6.36 ioctl mechanism delta.
>>
>> I have applied this patch to the last security-next kernel as you
>> mentioned below (2.6.37 rc3) and run it on a beagleboard xM and C4
>> http://beagleboard.org/.
>> Those devices are already in the market.
>>
>> I've tried to take care of all your feedbacks and to be familiar as
>> good as I can
>> with all the Linux guidelines for all the patches submission process.
>> I'm using Outlook as mail client for company policy rules reasons.
>>
>> I would like to know also what is the gap I have to reach to get this
>> driver on the kernel source tree.
>>
>> Any feedback or comments are welcome.
>>
>> Thanks
>> Christophe
>>
>> ------------------------------
>> Signed-off-by: Christophe RICARD <christophe-h.ricard[at]st.com>
>> diff --git a/Documentation/tpm/tpm_stm_st19_i2c.txt
>> b/Documentation/tpm/tpm_stm_st19_i2c.txt
>> --- a/Documentation/tpm/tpm_stm_st19_i2c.txt  1969-12-31
>> 17:00:00.000000000 -0700
>> +++ b/Documentation/tpm/tpm_stm_st19_i2c.txt  2011-01-17
>> 04:54:13.534658985 -0600
>> @@ -0,0 +1,169 @@
>> +/*
>> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
>> + * 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
>> + */
>> +
>> +PURPOSE OF THE DOCUMENT
>> +------------------------
>> +This document describe the installation of the TPM driver for
>> +TPM ST19NP18 using I2C protocols.
>> +
>> +
>> +PLATFORM USED FOR TESTING
>> +--------------------------
>> +During the development, several embedded platforms running ARM CPU
>> were
>> +used.
>> +Listing of validated platforms:
>> +- TI Beagleboard
>> +- STMicroelectronics Spear 300
>> +- STMicroelectronics Spear 600
>> +
>> +REQUIREMENTS
>> +-------------
>> +Software
>> +=========
>> +The TPM driver can be install under a kernel that implements at least
>> the
>> +following features:
>> +- Linux GENERIC_GPIO programming interfaces.
>> +- I2C new style programming interface base (with probe & remove
>> functions).
>> +- 1 I2C adapter (I2C Linux controller driver) or use of I2C_GPIO
>> driver for I2C
>> +bitbanging.
>> +
>> +
>> +Hardware
>> +=========
>> +To run a TPM, the platform needs at least:
>> +- 2 Power supplies (3.3V).
>> +- 1 I2C controller or 2 GPIOs used for SDA & SCL (I2C bit bang
>> method).
>> +- 2 GPIOs for signals accept_command & data_available.
>> +
>> +TPM I2C speed is 100Khz (Maximum)
>> +
>> +All TPM signals work at 3.3V
>> +
>> +HOW TO INSTALL
>> +---------------
>> +Platform installation file
>> +===========================
>> +(N.B: platform file in arch/<processor_type>/mach-<platform-name>/
>> +
>> +
>> +1 - Software integration
>> +=========================
>> +<processor_type> could be: alpha, arm, avr32, blackfin, cris, frv,
>> h8300, ia64,
>> +m32r, m68k, m68knommu, parisc, powerpc, s390, sh, sparc, sparc64, um,
>> x86,
>> +xtensa...
>> +<platform-name> corresponds to your platform
>> +
>> +In the file where the machine_init() function exists, the developer
>> must
>> +declare:
>> +- 1 struct st19np18_platform_data to provide which gpio the driver
>> will use.
>> +     * The accept_pin and data_avail_pin gpio are configured as input
>> only.
>> +     * This gpio management is under the platform developer's
>> responsability.
>> +
>> +Finally, in the machine_init() function provided in the same file, the
>> developer
>> +should use the well known function i2c_register_board_info() from the
>> I2C Linux
>> +API Core.
>> +
>> +2- Hardware integration
>> +========================
>> +- ST recommends connecting VPS1 and VPS2 to the board power supply and
>> at least two
>> +GNDs (on each side of TSSOP28 package). (See datasheet for further
>> information)
>> +
>> +- As the ST19NP18 has no internal pull up, ST recommands having:
>> +  * 2 external pull up on SDA & SCL signals (RpSDA/RpSCL) with values
>> according
>> +to the abacus on page 40 or the "I2C Bus specification, version 2.1
>> January
>> +2000".
>> +
>> +
>> +Platform integration advises
>> +=============================
>> +
>> +For power management purposes, the kernel will send a TPM_SaveState
>> command in the
>> +suspend tpm driver function.
>> +If the platform generates a TPM Init event on wakeup, the
>> TPM_Startup(ST_STATE) command should
>> +be executed before the Linux kernel come up (resume function
>> execution).
>> +
>> +Here is an example with beagleboard:
>> +====================================
>> +In the corresponding platform init file, the developer should specify
>> +the following information:
>> +- The platform gpio's used to managed the tpm's
>> accept_pin/data_avail_pin
>> +(in a struct st19np18_platform_data declaration).
>> +- The TPM I2C 7 bits address (TPM_I2C_ST19_ADDR_WR) (in a struct
>> i2c_board_info).
>> +
>> +Then the developer should add the TPM slave device to the good i2c
>> adapter with the
>> +i2c_register_board_info function (assuming that the gpio and the i2c
>> bus are well configured).
>> +
>> +Note: For the beagleboard configure your kernel with the following
>> option: CONFIG_OMAP_MUX=y
>> +
>> +file arch\arm\mach-omap2\board-omap3beagle.c
>> +add the following:
>> +----------------------------------------------------------------------
>> -
>> +
>> +static struct st19np18_platform_data tpm_data = {
>> +        .accept_pin = 135,
>> +        .data_avail_pin = 143,
>> +};
>> +
>> +static struct i2c_board_info __initdata tpm_st19_i2c_board_info[] = {
>> +        {
>> +         I2C_BOARD_INFO(TPM_DRIVER_NAME, TPM_I2C_ST19_ADDR_WR),
>> +         .platform_data = &tpm_data,
>> +         },
>> +};
>> +
>> +----------------------------------------------------------------------
>> --
>> +Then complete the beagleboard init to be like this:
>> +----------------------------------------------------------------------
>> --
>> +static void __init omap3_beagle_init(void)
>> +{
>> +        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
>> +        omap3_beagle_i2c_init();
>> +        platform_add_devices(omap3_beagle_devices,
>> +                        ARRAY_SIZE(omap3_beagle_devices));
>> +        omap_serial_init();
>> +
>> +        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
>> +        gpio_request(170, "DVI_nPD");
>> +        /* REVISIT leave DVI powered down until it's needed ... */
>> +        gpio_direction_output(170, true);
>> +
>> +        usb_musb_init(&musb_board_data);
>> +        usb_ehci_init(&ehci_pdata);
>> +        omap3beagle_flash_init();
>> +
>> +        beagle_display_init();
>> +
>> +        /* Ensure SDRC pins are mux'd for self-refresh */
>> +        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
>> +        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
>> +        omap_mux_init_gpio(((struct st19np18_platform_data *)
>> +                           tpm_st19_i2c_board_info[0].platform_data)-
>>> data_avail_pin,
>> +                           OMAP_PIN_INPUT);
>> +     omap_mux_init_gpio(((struct st19np18_platform_data *)
>> +                           tpm_st19_i2c_board_info[0].platform_data)-
>>> accept_pin,
>> +                           OMAP_PIN_INPUT);
>> +
>> +     i2c_register_board_info(2, tpm_st19_i2c_board_info,
>> ARRAY_SIZE(tpm_st19_i2c_board_info));
>> +}
>> diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
>> --- a/drivers/char/tpm/Kconfig        2011-01-06 04:44:39.000000000 -0600
>> +++ b/drivers/char/tpm/Kconfig        2011-01-13 22:44:42.906408085 -0600
>> @@ -60,4 +60,13 @@
>>         Further information on this driver and the supported hardware
>>         can be found at http://www.trust.rub.de/projects/linux-device-
>> driver-infineon-tpm/
>>
>> +config TCG_ST19_I2C
>> +        tristate "STMicroelectronics ST19 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_st19_i2c.
>>  endif # TCG_TPM
>> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
>> --- a/drivers/char/tpm/Makefile       2011-01-06 04:44:39.000000000 -0600
>> +++ b/drivers/char/tpm/Makefile       2011-01-13 22:44:35.506658670 -0600
>> @@ -9,3 +9,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_ST19_I2C) += tpm_stm_st19_i2c.o
>> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.c
>> b/drivers/char/tpm/tpm_stm_st19_i2c.c
>> --- a/drivers/char/tpm/tpm_stm_st19_i2c.c     1969-12-31 17:00:00.000000000
>> -0700
>> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.c     2011-01-16 22:44:58.466479759
>> -0600
>> @@ -0,0 +1,602 @@
>> +/*
>> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
>> + * 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_st19_i2c.c
>> + *
>> + * @Synopsis:
>> + * -------------------------------------------------------------------
>> ---
>> + *   02/12/2008
>> + *   - Stand alone implementation (without any TPM api)
>> + * -------------------------------------------------------------------
>> ---
>> + *   03/02/2010
>> + *   - Power management (suspend and resume functions)
>> + *   implementation
>> + * -------------------------------------------------------------------
>> ---
>> + *   03/19/2010
>> + *   - Use of the linux kernel TPM api --> driver/char/tpm
>> + * -------------------------------------------------------------------
>> ---
>> + *   05/26/2010
>> + *   - Update code for code submission and bug fixes:
>> + *   - Comments spelling fixes
>> + *   - Lindent script execution
>> + *   - checkpatch.pl script execution
>> + *   - fix syslog error when loaded as a module:
>> + *    "release() function missing and must be fixed"
>> + *   - name files change from
>> + *     stm_st19_tpm_i2c to tpm_stm_st19_i2c
>> + * -------------------------------------------------------------------
>> ---
>> + *   06/15/2010
>> + *   - Update for new tpm core device.
>> + *   num_opens --> is_open
>> + * -------------------------------------------------------------------
>> ---
>> + *   07/08/2010
>> + *   - Update probe, resume suspend functions
>> + *   - Fix issue suspend buffer and work around related to the
>> + *   chip->data_buffer not allocated.
>> + * -------------------------------------------------------------------
>> ---
>> + *   09/03/2010
>> + *   - Review under LKLM
>> + *   - Patches from Joe Perches after review which fix some break and
>> + *   some neatings.
>> + * -------------------------------------------------------------------
>> ---
>> + *   09/16/2010
>> + *   - Remove unaccurate comment.
>> + * -------------------------------------------------------------------
>> ---
>> + *   01/12/2011
>> + *   - update ioctl function to unlocked_ioctl for kernel >= 2.6.36
>> + *   - Some cleaning
>> + */
>> +
>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>> +
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/delay.h>
>> +#include <linux/init.h>
>> +#include <linux/i2c.h>
>> +#include <linux/i2c-id.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/version.h>
>> +#include <linux/smp_lock.h>
>> +
>> +#include <linux/i2c/tpm_stm_st19_i2c.h>
>> +
>> +#include "tpm.h"
>> +
>> +#include "tpm_stm_st19_i2c.h"
>> +
>> +#ifdef DEBUG
>> +#define FUNC_ENTER() pr_info("%s\n", __func__)
>> +#else
>> +#define FUNC_ENTER() do {} while (0)
>> +#endif
>> +
>> +static struct st19np18_platform_data *pin_infos;
>> +
>> +#define TPM_STS_DATA_AVAIL 0x10
>> +#define TPM_STS_ACCEPT_COMMAND 0x01
>> +#define TPM_STS_CANCEL (TPM_STS_DATA_AVAIL | TPM_STS_ACCEPT_COMMAND)
>> +enum tis_defaults {
>> +     TIS_SHORT_TIMEOUT = 750,        /* ms */
>> +     TIS_LONG_TIMEOUT = 2000,        /* 2 sec */
>> +};
>> +
>> +/*
>> + * gpio_readpin is a wrapper to read a gpio value.
>> + * Use generic gpio APIs
>> + * @param: pin_id, the pin identifier where the value will be read.
>> + * @return: the gpio value (should be 0 or 1) or negative errno
>> + */
>> +static int gpio_readpin(int pin_id)
>> +{
>> +     int ret;
>> +     ret = gpio_direction_input(pin_id);
>> +     if (ret == 0)
>> +             return gpio_get_value(pin_id);
>> +     return ret;
>> +}
>> +
>> +/*
>> + * tpm_stm_i2c_status is not implemented because TIS registers are not
>> + * implemented.
>> + */
>> +static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
>> +{
>> +     u8 state_data, state_command;
>> +
>> +     state_data = gpio_readpin(pin_infos->data_avail_pin);
>> +     state_command = gpio_readpin(pin_infos->accept_pin);
>> +     return (state_data << 4) | state_command;
>> +}
>> +
>> +static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long
>> timeout,
>> +                      wait_queue_head_t *queue)
>> +{
>> +     unsigned long stop;
>> +     u8 status;
>> +
>> +     FUNC_ENTER();
>> +
>> +     /* check current status */
>> +     status = tpm_stm_i2c_status(chip);
>> +     if (status == mask)
>> +             return 0;
>> +     if (status == TPM_STS_CANCEL)
>> +             goto end;
>> +     stop = jiffies + timeout;
>> +     do {
>> +             msleep(TPM_TIMEOUT);
>> +             status = tpm_stm_i2c_status(chip);
>> +             if ((status & mask) == mask)
>> +                     return 0;
>> +     } while (time_before(jiffies, stop));
>> +end:
>> +     return -ETIME;
>> +}
>> +
>> +/*
>> + * tpm_stm_i2c_send send TPM commands through the I2C bus.
>> + * Before sending any TPM commands, tpm_stm_i2c_send poll
>> data_available and
>> + * accept_command TPM GPIOs.
>> + *
>> + * In case the data_available is high (logical value 1),
>> tpm_stm_i2c_send will
>> + * empty the TPM FIFO by reading all the datas stored inside the TPM.
>> + *
>> + * Then, if the accept_command TPM GPIO is high(logical value 1)
>> + * tpm_stm_i2c_send will first send the 10 bytes header of the TCG
>> commands and
>> + * then send the others bytes by 40 bytes blocks.
>> + *
>> + * data_available and accept_command TPM GPIOs will goes low when the
>> TPM
>> + * compute the command.
>> + *
>> + * @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 count)
>> +{
>> +     u32 ret = 0, i, size, ordinal;
>> +     struct i2c_client *client;
>> +
>> +     FUNC_ENTER();
>> +
>> +     if (chip == NULL)
>> +             return -EBUSY;
>> +     if (count < TPM_HEADER_SIZE)
>> +             return -EBUSY;
>> +     client = (struct i2c_client *)pin_infos->client;
>> +
>> +     ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
>> +
>> +     size = TPM_HEADER_SIZE;
>> +     i = 0;
>> +     while (i < size && wait_for_stat(chip, TPM_STS_ACCEPT_COMMAND,
>> +                                      TPM_I2C_SHORT,
>> +                                      &chip->vendor.int_queue) == 0) {
>> +             int bytes;
>> +
>> +             if (i == 0)
>> +                     bytes = TPM_HEADER_SIZE;
>> +             else
>> +                     bytes = min_t(int, count - i, TPM_I2C_BLOCK_SIZE);
>> +
>> +             if (i == 0) {
>> +                     size = be32_to_cpu(*(__be32 *) (buf + 2));
>> +                     size = size < count ? size : count;
>> +             }
>> +             if (count < TPM_HEADER_SIZE)
>> +                     bytes = count;
>> +             ret = i2c_master_send(client, buf + i, bytes);
>> +             if (ret < 0) {
>> +                     pr_info("Failed to send data\n");
>> +                     goto end;
>> +             }
>> +
>> +             if (i == 0)
>> +                     i += TPM_HEADER_SIZE;
>> +             else
>> +                     i += TPM_I2C_BLOCK_SIZE;
>> +     }
>> +
>> +     if (i == 0) {
>> +             pr_info("Failed to read gpio pin (AcceptCmd)\n");
>> +             ret = -EIO;
>> +     }
>> +end:
>> +     return ret ? ret : count;
>> +}
>> +
>> +/*
>> + * tpm_stm_i2c_recv received TPM response through the I2C bus.
>> + * Before receiving any TPM response, tpm_stm_i2c_recv poll
>> data_available and
>> + * accept_command TPM GPIOs.
>> + *
>> + * In case the accept_command is high (logical value 1),
>> tpm_stm_i2c_recv will
>> + * do nothing.
>> + *
>> + * Then, if the data_available TPM GPIO is high(logical value 1)
>> + * tpm_stm_i2c_recv will first receive the 10 bytes header of the TCG
>> TPM
>> + * response and then receive the others bytes by 40 bytes blocks.
>> + *
>> + * accept_command TPM GPIOs will goes high when the TPM Fofo is empty.
>> + *
>> + * @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 ret = 0;
>> +     int i, size;
>> +     struct i2c_client *client;
>> +
>> +     FUNC_ENTER();
>> +
>> +     if (chip == NULL)
>> +             return -EBUSY;
>> +     if (count < TPM_HEADER_SIZE)
>> +             return -EBUSY;
>> +
>> +     client = (struct i2c_client *)pin_infos->client;
>> +
>> +     size = TPM_HEADER_SIZE;
>> +     i = 0;
>> +     while (i < size && wait_for_stat(chip, TPM_STS_DATA_AVAIL,
>> +                                      TPM_I2C_SHORT,
>> +                                      &chip->vendor.read_queue) == 0) {
>> +             int bytes;
>> +
>> +             if (count < TPM_HEADER_SIZE)
>> +                     bytes = count;
>> +             else if (i == 0)
>> +                     bytes = TPM_HEADER_SIZE;
>> +             else
>> +                     bytes = min_t(int, size - i, TPM_I2C_BLOCK_SIZE);
>> +
>> +             ret = i2c_master_recv(client, buf + i, bytes);
>> +             if (ret < 0) {
>> +                     pr_info(" Failed to read gpio pin
>> (DataAvailable)\n");
>> +                     goto end;
>> +             }
>> +
>> +             if (!buf) {
>> +                     pr_info("read buffer is NULL\n");
>> +                     goto end;
>> +             }
>> +
>> +             if (i == 0) {
>> +                     size = be32_to_cpu(*(__be32 *) (buf + 2));
>> +                     if (size > count)
>> +                             size = count;
>> +                     i += TPM_HEADER_SIZE;
>> +             } else
>> +                     i += TPM_I2C_BLOCK_SIZE;
>> +     }
>> +
>> +     if (i == 0) {
>> +             pr_info("Failed to read gpio pin (DataAvailable)\n");
>> +             ret = -EIO;
>> +             goto end;
>> +     }
>> +     return size;
>> +end:
>> +     return ret;
>> +}
>> +
>> +/*
>> + * 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)
>> +{
>> +}
>> +
>> +/*
>> + * tpm_st19_i2c_ioctl provides 2 handles:
>> + * - TPMIOC_CANCEL: allow to CANCEL a TPM commands execution.
>> + *   See tpm_stm_i2c_cancel description above
>> + * - TPMIOC_TRANSMIT: allow to transmit a TPM commands.
>> + *
>> + * @return: In case of success, return TPM response size.
>> + * In other case return < 0 value describing the issue.
>> + */
>> +/*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
>> +static ssize_t tpm_st19_i2c_ioctl(struct inode *inode, struct file
>> *file,
>> +                               unsigned int cmd, unsigned long arg)
>> +#else*/
>> +static long tpm_st19_i2c_unlocked_ioctl(struct file *file,
>> +                                     unsigned int cmd, unsigned long arg)
>> +/*#endif*/
>> +{
>> +     int in_size = 0, out_size = 0, ret = -ENOTTY;
>> +     struct tpm_chip *chip = file->private_data;
>> +
>> +     lock_kernel();
>> +     switch (cmd) {
>> +     case TPMIOC_CANCEL:
>> +             tpm_stm_i2c_cancel(chip);
>> +             ret = -ENOSYS;
>> +             break;
>> +     case TPMIOC_TRANSMIT:
>> +             if (copy_from_user(chip->data_buffer,
>> +                                (const char *)arg, TPM_HEADER_SIZE)) {
>> +                     ret = -EFAULT;
>> +                     break;
>> +             }
>> +
>> +             in_size = be32_to_cpu(*(__be32 *) (chip->data_buffer + 2));
>> +             if (copy_from_user(chip->data_buffer,
>> +                                (const char *)arg, in_size)) {
>> +                     ret = -EFAULT;
>> +                     break;
>> +             }
>> +
>> +             tpm_stm_i2c_send(chip, chip->data_buffer, in_size);
>> +
>> +             out_size = tpm_stm_i2c_recv(chip, chip->data_buffer,
>> +                                         TPM_BUFSIZE);
>> +             if (copy_to_user((char *)arg, chip->data_buffer, out_size))
>> {
>> +                     ret = -EFAULT;
>> +                     break;
>> +             }
>> +             ret = out_size;
>> +             break;
>> +     }
>> +     unlock_kernel();
>> +     return ret;
>> +}
>> +
>> +static const struct file_operations tpm_st19_i2c_fops = {
>> +     .owner = THIS_MODULE,
>> +     .llseek = no_llseek,
>> +     .read = tpm_read,
>> +
>> +     /*#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
>> +        .ioctl = tpm_st19_i2c_ioctl,
>> +        #else */
>> +     .unlocked_ioctl = tpm_st19_i2c_unlocked_ioctl,
>> +     /*#endif */
>> +
>> +     .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,
>> +     .req_complete_val = TPM_STS_DATA_AVAIL,
>> +     .req_canceled = TPM_STS_CANCEL,
>> +     .attr_group = &stm_tpm_attr_grp,
>> +     .miscdev = {.fops = &tpm_st19_i2c_fops,},
>> +};
>> +
>> +/*
>> + * tpm_st19_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_st19_i2c_probe(struct i2c_client *client, const struct
>> i2c_device_id *id)
>> +{
>> +     int err;
>> +     struct tpm_chip *chip;
>> +     struct st19np18_platform_data *platform_data;
>> +
>> +     FUNC_ENTER();
>> +
>> +     err = 0;
>> +
>> +     /* Check I2C platform functionnalities */
>> +     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) {
>> +             err = -ENODEV;
>> +             goto end;
>> +     }
>> +
>> +     platform_data = client->dev.platform_data;
>> +     pin_infos = platform_data;
>> +     platform_data->client = client;
>> +     /* Default timeouts */
>> +        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);
>> +
>> +     /* Register GPIO pin through generic Linux GPIO API */
>> +     err = gpio_request(platform_data->accept_pin, "accept command");
>> +     if (err)
>> +             goto _gpio_init;
>> +
>> +     err = gpio_request(platform_data->data_avail_pin, "data
>> available");
>> +     if (err)
>> +             goto _gpio_init;
>> +
>> +     tpm_get_timeouts(chip);
>> +     tpm_continue_selftest(chip);
>> +
>> +     /* attach chip datas to client */
>> +     i2c_set_clientdata(client, chip);
>> +
>> +     pr_info("TPM I2C Initialized\n");
>> +     return 0;
>> +_gpio_init:
>> +     if (platform_data) {
>> +             gpio_free(platform_data->accept_pin);
>> +             gpio_free(platform_data->data_avail_pin);
>> +     }
>> +     tpm_remove_hardware(chip->dev);
>> +end:
>> +     i2c_set_clientdata(client, NULL);
>> +     pr_info("TPM I2C initialisation fail\n");
>> +     return err;
>> +}
>> +
>> +/*
>> + * tpm_st19_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_st19_i2c_remove(struct i2c_client *client)
>> +{
>> +     struct tpm_chip *chip = (struct tpm_chip
>> *)i2c_get_clientdata(client);
>> +     FUNC_ENTER();
>> +
>> +     if (pin_infos != NULL) {
>> +             gpio_free(pin_infos->accept_pin);
>> +             gpio_free(pin_infos->data_avail_pin);
>> +     }
>> +
>> +     /* Check if chip has been previously clean */
>> +     if (chip != NULL)
>> +             tpm_remove_hardware(chip->dev);
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * tpm_st19_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_st19_i2c_pm_suspend(struct i2c_client *client,
>> pm_message_t mesg)
>> +{
>> +     return tpm_pm_suspend(&client->dev, mesg);
>> +}
>> +
>> +/*
>> + * tpm_st19_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_st19_i2c_pm_resume(struct i2c_client *client)
>> +{
>> +     return tpm_pm_resume(&client->dev);
>> +}                            /* tpm_st19_i2c_pm_resume() */
>> +
>> +static const struct i2c_device_id tpm_st19_i2c_id[] = {
>> +     {TPM_DRIVER_NAME, 0},
>> +     {}
>> +};
>> +
>> +MODULE_DEVICE_TABLE(i2c, tpm_st19_i2c_id);
>> +
>> +static struct i2c_driver tpm_st19_i2c_driver = {
>> +     .driver = {
>> +                .owner = THIS_MODULE,
>> +                .name = TPM_DRIVER_NAME,
>> +                },
>> +     .probe = tpm_st19_i2c_probe,
>> +     .remove = tpm_st19_i2c_remove,
>> +     .resume = tpm_st19_i2c_pm_resume,
>> +     .suspend = tpm_st19_i2c_pm_suspend,
>> +     .id_table = tpm_st19_i2c_id
>> +};
>> +
>> +/*
>> + * tpm_st19_i2c_init initialize driver
>> + * @return: 0 if successful, else non zero value.
>> + */
>> +static int __init tpm_st19_i2c_init(void)
>> +{
>> +     FUNC_ENTER();
>> +     return i2c_add_driver(&tpm_st19_i2c_driver);
>> +}
>> +
>> +/*
>> + * tpm_st19_i2c_exit The kernel calls this function during unloading
>> the
>> + * module or during shut down process
>> + */
>> +static void __exit tpm_st19_i2c_exit(void)
>> +{
>> +     FUNC_ENTER();
>> +     i2c_del_driver(&tpm_st19_i2c_driver);
>> +}
>> +
>> +module_init(tpm_st19_i2c_init);
>> +module_exit(tpm_st19_i2c_exit);
>> +
>> +MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
>> +MODULE_DESCRIPTION("STM TPM I2C ST19 Driver");
>> +MODULE_VERSION("1.2.0");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/char/tpm/tpm_stm_st19_i2c.h
>> b/drivers/char/tpm/tpm_stm_st19_i2c.h
>> --- a/drivers/char/tpm/tpm_stm_st19_i2c.h     1969-12-31 17:00:00.000000000
>> -0700
>> +++ b/drivers/char/tpm/tpm_stm_st19_i2c.h     2011-01-16 22:45:08.918407969
>> -0600
>> @@ -0,0 +1,52 @@
>> +/*
>> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
>> + * 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_st19_tpm_i2c.h
>> + *
>> + * @Date: 02/12/2008
>> + */
>> +#ifndef __STM_ST19_TPM_I2C_MAIN_H__
>> +#define __STM_ST19_TPM_I2C_MAIN_H__
>> +
>> +#include <linux/pci.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/i2c.h>
>> +#include <linux/i2c-id.h>
>> +#include <linux/fs.h>
>> +#include <linux/miscdevice.h>
>> +
>> +#define TPM_BUFSIZE          2048
>> +#define TPM_HEADER_SIZE              10
>> +#define TPM_I2C_BLOCK_SIZE   0x28
>> +
>> +#define TPM_I2C_SHORT                2000    /* 2s */
>> +#define STARTUP_WAIT_INTERVAL        8       /* 8ms */
>> +
>> +/* ioctl commands */
>> +#define TPMIOC_CANCEL                _IO('T', 0x00)  /* Not supported */
>> +#define TPMIOC_TRANSMIT              _IO('T', 0x01)
>> +
>> +#endif /* __STM_ST19_TPM_I2C_MAIN_H__ */
>> diff --git a/include/linux/i2c/tpm_stm_st19_i2c.h
>> b/include/linux/i2c/tpm_stm_st19_i2c.h
>> --- a/include/linux/i2c/tpm_stm_st19_i2c.h    1969-12-31
>> 17:00:00.000000000 -0700
>> +++ b/include/linux/i2c/tpm_stm_st19_i2c.h    2011-01-16
>> 22:45:31.758408188 -0600
>> @@ -0,0 +1,42 @@
>> +/*
>> + * STMicroelectronics TPM I2C Linux driver for TPM ST19NP18
>> + * 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_st19_tpm_i2c.h
>> + *
>> + * @Date: 06/15/2008
>> + */
>> +#ifndef __STM_ST19_TPM_I2C_H__
>> +#define __STM_ST19_TPM_I2C_H__
>> +
>> +#include <linux/i2c.h>
>> +
>> +#define TPM_DRIVER_NAME         "st19np18"
>> +#define TPM_I2C_ST19_ADDR_WR (0x26 >> 1) /*0x13 7 bits address */
>> +
>> +struct st19np18_platform_data {
>> +     int accept_pin; /* accept command pin */
>> +     int data_avail_pin;/* data available pin */
>> +     struct i2c_client *client;
>> +};
>> +
>> +#endif /* __STM_ST19_TPM_I2C_H__ */


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

end of thread, other threads:[~2011-08-25 18:53 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-09-30 19:09 [PATCH 0/3] New stm i2c tpm device driver Rajiv Andrade
2010-09-30 19:09 ` [PATCH 1/3] TPM: new stm i2c " Rajiv Andrade
2010-09-30 21:20   ` matt mooney
2010-10-01  0:51   ` James Morris
2010-10-01 14:27     ` Christophe Henri RICARD
2010-10-01 15:25       ` Rajiv Andrade
2010-10-01 15:44         ` Christophe Henri RICARD
2010-10-01 16:35           ` Rajiv Andrade
2010-09-30 19:09 ` [PATCH 2/3] TPM: Use pr_fmt, pr_<level> and FUNC_ENTER Rajiv Andrade
2010-09-30 19:09 ` [PATCH 3/3] TPM: Add missing break and neatening Rajiv Andrade
  -- strict thread matches above, loose matches on Subject: below --
2011-01-17 23:34 [PATCH 1/3] TPM: new stm i2c device driver Christophe Henri RICARD
2011-08-25 14:34 ` Christophe Henri RICARD
2011-08-25 15:00   ` Mohamed TABET
2011-08-25 18:53     ` Rajiv Andrade

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox