diff options
author | Mathias Leblanc <mathias.leblanc@st.com> | 2012-11-28 12:22:24 -0500 |
---|---|---|
committer | Kent Yoder <key@linux.vnet.ibm.com> | 2013-02-05 10:38:22 -0500 |
commit | 251a7b08213af82e40e4a70cac056e245853c410 (patch) | |
tree | b4dd531fc063612ee7f3f3235605ffa3b7e6ec12 /drivers/char/tpm | |
parent | 73249695f0cb10bb9fc8b294f3f8c4b001889e42 (diff) |
TPM: STMicroelectronics ST33 I2C KERNEL 3.x
* STMicroelectronics version 1.2.0, Copyright (C) 2010
* STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
* This is free software, and you are welcome to redistribute it
* under certain conditions.
This is the driver for TPM chip from ST Microelectronics.
If you have a TPM security chip from STMicroelectronics working with
an I2C, in menuconfig or .config choose the tpm driver on
device --> tpm and activate the protocol of your choice before compiling
the kernel.
The driver will be accessible from within Linux.
Tested on linux x86/x64 on kernel 3.x
Signed-off-by: Mathias Leblanc <mathias.leblanc@st.com>
Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/tpm_stm_st33_i2c.c | 903 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_stm_st33_i2c.h | 81 |
2 files changed, 984 insertions, 0 deletions
diff --git a/drivers/char/tpm/tpm_stm_st33_i2c.c b/drivers/char/tpm/tpm_stm_st33_i2c.c new file mode 100644 index 000000000000..32cdd5e92141 --- /dev/null +++ b/drivers/char/tpm/tpm_stm_st33_i2c.c | |||
@@ -0,0 +1,903 @@ | |||
1 | /* | ||
2 | * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 | ||
3 | * Copyright (C) 2009, 2010 STMicroelectronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * STMicroelectronics version 1.2.0, Copyright (C) 2010 | ||
20 | * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. | ||
21 | * This is free software, and you are welcome to redistribute it | ||
22 | * under certain conditions. | ||
23 | * | ||
24 | * @Author: Christophe RICARD tpmsupport@st.com | ||
25 | * | ||
26 | * @File: tpm_stm_st33_i2c.c | ||
27 | * | ||
28 | * @Synopsis: | ||
29 | * 09/15/2010: First shot driver tpm_tis driver for | ||
30 | lpc is used as model. | ||
31 | */ | ||
32 | |||
33 | #include <linux/i2c/tpm_stm_st33_i2c.h> | ||
34 | |||
35 | #include "tpm_stm_st33_i2c.h" | ||
36 | |||
37 | enum stm33zp24_access { | ||
38 | TPM_ACCESS_VALID = 0x80, | ||
39 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | ||
40 | TPM_ACCESS_REQUEST_PENDING = 0x04, | ||
41 | TPM_ACCESS_REQUEST_USE = 0x02, | ||
42 | }; | ||
43 | |||
44 | enum stm33zp24_status { | ||
45 | TPM_STS_VALID = 0x80, | ||
46 | TPM_STS_COMMAND_READY = 0x40, | ||
47 | TPM_STS_GO = 0x20, | ||
48 | TPM_STS_DATA_AVAIL = 0x10, | ||
49 | TPM_STS_DATA_EXPECT = 0x08, | ||
50 | }; | ||
51 | |||
52 | enum stm33zp24_int_flags { | ||
53 | TPM_GLOBAL_INT_ENABLE = 0x80, | ||
54 | TPM_INTF_CMD_READY_INT = 0x080, | ||
55 | TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, | ||
56 | TPM_INTF_WAKE_UP_READY_INT = 0x020, | ||
57 | TPM_INTF_LOCALITY_CHANGE_INT = 0x004, | ||
58 | TPM_INTF_STS_VALID_INT = 0x002, | ||
59 | TPM_INTF_DATA_AVAIL_INT = 0x001, | ||
60 | }; | ||
61 | |||
62 | enum tis_defaults { | ||
63 | TIS_SHORT_TIMEOUT = 750, | ||
64 | TIS_LONG_TIMEOUT = 2000, | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * write8_reg | ||
69 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. | ||
70 | * @param: tpm_register, the tpm tis register where the data should be written | ||
71 | * @param: tpm_data, the tpm_data to write inside the tpm_register | ||
72 | * @param: tpm_size, The length of the data | ||
73 | * @return: Returns negative errno, or else the number of bytes written. | ||
74 | */ | ||
75 | static int write8_reg(struct i2c_client *client, u8 tpm_register, | ||
76 | u8 *tpm_data, u16 tpm_size) | ||
77 | { | ||
78 | u8 data; | ||
79 | int value = 0; | ||
80 | struct st33zp24_platform_data *pin_infos; | ||
81 | |||
82 | pin_infos = client->dev.platform_data; | ||
83 | |||
84 | data = tpm_register; | ||
85 | memcpy(pin_infos->tpm_i2c_buffer[0], &data, sizeof(data)); | ||
86 | memcpy(pin_infos->tpm_i2c_buffer[0] + 1, tpm_data, tpm_size); | ||
87 | value = i2c_master_send(client, pin_infos->tpm_i2c_buffer[0], | ||
88 | tpm_size + 1); | ||
89 | return value; | ||
90 | } /* write8_reg() */ | ||
91 | |||
92 | /* | ||
93 | * read8_reg | ||
94 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. | ||
95 | * @param: tpm_register, the tpm tis register where the data should be read | ||
96 | * @param: tpm_data, the TPM response | ||
97 | * @param: tpm_size, tpm TPM response size to read. | ||
98 | * @return: number of byte read successfully: should be one if success. | ||
99 | */ | ||
100 | static int read8_reg(struct i2c_client *client, u8 tpm_register, | ||
101 | u8 *tpm_data, int tpm_size) | ||
102 | { | ||
103 | u8 status = 0; | ||
104 | u8 data; | ||
105 | struct st33zp24_platform_data *pin_infos; | ||
106 | |||
107 | pin_infos = client->dev.platform_data; | ||
108 | |||
109 | data = TPM_DUMMY_BYTE; | ||
110 | status = write8_reg(client, tpm_register, &data, 1); | ||
111 | if (status == 2) | ||
112 | status = i2c_master_recv(client, tpm_data, tpm_size); | ||
113 | return status; | ||
114 | } /* read8_reg() */ | ||
115 | |||
116 | /* | ||
117 | * I2C_WRITE_DATA | ||
118 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. | ||
119 | * @param: client, the chip description | ||
120 | * @param: tpm_register, the tpm tis register where the data should be written | ||
121 | * @param: tpm_data, the tpm_data to write inside the tpm_register | ||
122 | * @param: tpm_size, The length of the data | ||
123 | * @return: number of byte written successfully: should be one if success. | ||
124 | */ | ||
125 | #define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size) \ | ||
126 | (write8_reg(client, tpm_register | \ | ||
127 | TPM_WRITE_DIRECTION, tpm_data, tpm_size)) | ||
128 | |||
129 | /* | ||
130 | * I2C_READ_DATA | ||
131 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. | ||
132 | * @param: tpm, the chip description | ||
133 | * @param: tpm_register, the tpm tis register where the data should be read | ||
134 | * @param: tpm_data, the TPM response | ||
135 | * @param: tpm_size, tpm TPM response size to read. | ||
136 | * @return: number of byte read successfully: should be one if success. | ||
137 | */ | ||
138 | #define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size) \ | ||
139 | (read8_reg(client, tpm_register, tpm_data, tpm_size)) | ||
140 | |||
141 | /* | ||
142 | * clear_interruption | ||
143 | * clear the TPM interrupt register. | ||
144 | * @param: tpm, the chip description | ||
145 | */ | ||
146 | static void clear_interruption(struct i2c_client *client) | ||
147 | { | ||
148 | u8 interrupt; | ||
149 | I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); | ||
150 | I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1); | ||
151 | I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); | ||
152 | } /* clear_interruption() */ | ||
153 | |||
154 | /* | ||
155 | * _wait_for_interrupt_serirq_timeout | ||
156 | * @param: tpm, the chip description | ||
157 | * @param: timeout, the timeout of the interrupt | ||
158 | * @return: the status of the interruption. | ||
159 | */ | ||
160 | static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip, | ||
161 | unsigned long timeout) | ||
162 | { | ||
163 | long status; | ||
164 | struct i2c_client *client; | ||
165 | struct st33zp24_platform_data *pin_infos; | ||
166 | |||
167 | client = (struct i2c_client *) chip->vendor.iobase; | ||
168 | pin_infos = client->dev.platform_data; | ||
169 | |||
170 | status = wait_for_completion_interruptible_timeout( | ||
171 | &pin_infos->irq_detection, | ||
172 | timeout); | ||
173 | if (status > 0) | ||
174 | enable_irq(gpio_to_irq(pin_infos->io_serirq)); | ||
175 | gpio_direction_input(pin_infos->io_serirq); | ||
176 | |||
177 | return status; | ||
178 | } /* wait_for_interrupt_serirq_timeout() */ | ||
179 | |||
180 | int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, | ||
181 | unsigned long timeout) | ||
182 | { | ||
183 | int status = 2; | ||
184 | struct i2c_client *client; | ||
185 | struct st33zp24_platform_data *pin_infos; | ||
186 | |||
187 | client = (struct i2c_client *) chip->vendor.iobase; | ||
188 | pin_infos = client->dev.platform_data; | ||
189 | |||
190 | status = _wait_for_interrupt_serirq_timeout(chip, timeout); | ||
191 | if (!status) { | ||
192 | status = -EBUSY; | ||
193 | } else{ | ||
194 | clear_interruption(client); | ||
195 | if (condition) | ||
196 | status = 1; | ||
197 | } | ||
198 | return status; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * tpm_stm_i2c_cancel, cancel is not implemented. | ||
203 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h | ||
204 | */ | ||
205 | static void tpm_stm_i2c_cancel(struct tpm_chip *chip) | ||
206 | { | ||
207 | struct i2c_client *client; | ||
208 | u8 data; | ||
209 | |||
210 | client = (struct i2c_client *) chip->vendor.iobase; | ||
211 | |||
212 | data = TPM_STS_COMMAND_READY; | ||
213 | I2C_WRITE_DATA(client, TPM_STS, &data, 1); | ||
214 | if (chip->vendor.irq) | ||
215 | wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); | ||
216 | } /* tpm_stm_i2c_cancel() */ | ||
217 | |||
218 | /* | ||
219 | * tpm_stm_spi_status return the TPM_STS register | ||
220 | * @param: chip, the tpm chip description | ||
221 | * @return: the TPM_STS register value. | ||
222 | */ | ||
223 | static u8 tpm_stm_i2c_status(struct tpm_chip *chip) | ||
224 | { | ||
225 | struct i2c_client *client; | ||
226 | u8 data; | ||
227 | client = (struct i2c_client *) chip->vendor.iobase; | ||
228 | |||
229 | I2C_READ_DATA(client, TPM_STS, &data, 1); | ||
230 | return data; | ||
231 | } /* tpm_stm_i2c_status() */ | ||
232 | |||
233 | |||
234 | /* | ||
235 | * check_locality if the locality is active | ||
236 | * @param: chip, the tpm chip description | ||
237 | * @return: the active locality or -EACCESS. | ||
238 | */ | ||
239 | static int check_locality(struct tpm_chip *chip) | ||
240 | { | ||
241 | struct i2c_client *client; | ||
242 | u8 data; | ||
243 | u8 status; | ||
244 | |||
245 | client = (struct i2c_client *) chip->vendor.iobase; | ||
246 | |||
247 | status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1); | ||
248 | if (status && (data & | ||
249 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == | ||
250 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) | ||
251 | return chip->vendor.locality; | ||
252 | |||
253 | return -EACCES; | ||
254 | |||
255 | } /* check_locality() */ | ||
256 | |||
257 | /* | ||
258 | * request_locality request the TPM locality | ||
259 | * @param: chip, the chip description | ||
260 | * @return: the active locality or EACCESS. | ||
261 | */ | ||
262 | static int request_locality(struct tpm_chip *chip) | ||
263 | { | ||
264 | unsigned long stop; | ||
265 | long rc; | ||
266 | struct i2c_client *client; | ||
267 | u8 data; | ||
268 | |||
269 | client = (struct i2c_client *) chip->vendor.iobase; | ||
270 | |||
271 | if (check_locality(chip) == chip->vendor.locality) | ||
272 | return chip->vendor.locality; | ||
273 | |||
274 | data = TPM_ACCESS_REQUEST_USE; | ||
275 | rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); | ||
276 | if (rc < 0) | ||
277 | goto end; | ||
278 | |||
279 | if (chip->vendor.irq) { | ||
280 | rc = wait_for_serirq_timeout(chip, (check_locality | ||
281 | (chip) >= 0), | ||
282 | chip->vendor.timeout_a); | ||
283 | if (rc > 0) | ||
284 | return chip->vendor.locality; | ||
285 | } else{ | ||
286 | stop = jiffies + chip->vendor.timeout_a; | ||
287 | do { | ||
288 | if (check_locality(chip) >= 0) | ||
289 | return chip->vendor.locality; | ||
290 | msleep(TPM_TIMEOUT); | ||
291 | } while (time_before(jiffies, stop)); | ||
292 | } | ||
293 | rc = -EACCES; | ||
294 | end: | ||
295 | return rc; | ||
296 | } /* request_locality() */ | ||
297 | |||
298 | /* | ||
299 | * release_locality release the active locality | ||
300 | * @param: chip, the tpm chip description. | ||
301 | */ | ||
302 | static void release_locality(struct tpm_chip *chip) | ||
303 | { | ||
304 | struct i2c_client *client; | ||
305 | u8 data; | ||
306 | |||
307 | client = (struct i2c_client *) chip->vendor.iobase; | ||
308 | data = TPM_ACCESS_ACTIVE_LOCALITY; | ||
309 | |||
310 | I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * get_burstcount return the burstcount address 0x19 0x1A | ||
315 | * @param: chip, the chip description | ||
316 | * return: the burstcount. | ||
317 | */ | ||
318 | static int get_burstcount(struct tpm_chip *chip) | ||
319 | { | ||
320 | unsigned long stop; | ||
321 | int burstcnt, status; | ||
322 | u8 tpm_reg, temp; | ||
323 | |||
324 | struct i2c_client *client = (struct i2c_client *) chip->vendor.iobase; | ||
325 | |||
326 | stop = jiffies + chip->vendor.timeout_d; | ||
327 | do { | ||
328 | tpm_reg = TPM_STS + 1; | ||
329 | status = I2C_READ_DATA(client, tpm_reg, &temp, 1); | ||
330 | if (status < 0) | ||
331 | goto end; | ||
332 | |||
333 | tpm_reg = tpm_reg + 1; | ||
334 | burstcnt = temp; | ||
335 | status = I2C_READ_DATA(client, tpm_reg, &temp, 1); | ||
336 | if (status < 0) | ||
337 | goto end; | ||
338 | |||
339 | burstcnt |= temp << 8; | ||
340 | if (burstcnt) | ||
341 | return burstcnt; | ||
342 | msleep(TPM_TIMEOUT); | ||
343 | } while (time_before(jiffies, stop)); | ||
344 | |||
345 | end: | ||
346 | return -EBUSY; | ||
347 | } /* get_burstcount() */ | ||
348 | |||
349 | /* | ||
350 | * wait_for_stat wait for a TPM_STS value | ||
351 | * @param: chip, the tpm chip description | ||
352 | * @param: mask, the value mask to wait | ||
353 | * @param: timeout, the timeout | ||
354 | * @param: queue, the wait queue. | ||
355 | * @return: the tpm status, 0 if success, -ETIME if timeout is reached. | ||
356 | */ | ||
357 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | ||
358 | wait_queue_head_t *queue) | ||
359 | { | ||
360 | unsigned long stop; | ||
361 | long rc; | ||
362 | u8 status; | ||
363 | |||
364 | if (chip->vendor.irq) { | ||
365 | rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status | ||
366 | (chip) & mask) == | ||
367 | mask), timeout); | ||
368 | if (rc > 0) | ||
369 | return 0; | ||
370 | } else{ | ||
371 | stop = jiffies + timeout; | ||
372 | do { | ||
373 | msleep(TPM_TIMEOUT); | ||
374 | status = tpm_stm_i2c_status(chip); | ||
375 | if ((status & mask) == mask) | ||
376 | return 0; | ||
377 | } while (time_before(jiffies, stop)); | ||
378 | } | ||
379 | return -ETIME; | ||
380 | } /* wait_for_stat() */ | ||
381 | |||
382 | /* | ||
383 | * recv_data receive data | ||
384 | * @param: chip, the tpm chip description | ||
385 | * @param: buf, the buffer where the data are received | ||
386 | * @param: count, the number of data to receive | ||
387 | * @return: the number of bytes read from TPM FIFO. | ||
388 | */ | ||
389 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | ||
390 | { | ||
391 | int size = 0, burstcnt, len; | ||
392 | struct i2c_client *client; | ||
393 | |||
394 | client = (struct i2c_client *) chip->vendor.iobase; | ||
395 | |||
396 | while (size < count && | ||
397 | wait_for_stat(chip, | ||
398 | TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
399 | chip->vendor.timeout_c, | ||
400 | &chip->vendor.read_queue) | ||
401 | == 0) { | ||
402 | burstcnt = get_burstcount(chip); | ||
403 | len = min_t(int, burstcnt, count - size); | ||
404 | I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len); | ||
405 | size += len; | ||
406 | } | ||
407 | return size; | ||
408 | } | ||
409 | |||
410 | /* | ||
411 | * tpm_ioserirq_handler the serirq irq handler | ||
412 | * @param: irq, the tpm chip description | ||
413 | * @param: dev_id, the description of the chip | ||
414 | * @return: the status of the handler. | ||
415 | */ | ||
416 | static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) | ||
417 | { | ||
418 | struct tpm_chip *chip = dev_id; | ||
419 | struct i2c_client *client; | ||
420 | struct st33zp24_platform_data *pin_infos; | ||
421 | |||
422 | disable_irq_nosync(irq); | ||
423 | |||
424 | client = (struct i2c_client *) chip->vendor.iobase; | ||
425 | pin_infos = client->dev.platform_data; | ||
426 | |||
427 | complete(&pin_infos->irq_detection); | ||
428 | return IRQ_HANDLED; | ||
429 | } /* tpm_ioserirq_handler() */ | ||
430 | |||
431 | |||
432 | /* | ||
433 | * tpm_stm_i2c_send send TPM commands through the I2C bus. | ||
434 | * | ||
435 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h | ||
436 | * @param: buf, the buffer to send. | ||
437 | * @param: count, the number of bytes to send. | ||
438 | * @return: In case of success the number of bytes sent. | ||
439 | * In other case, a < 0 value describing the issue. | ||
440 | */ | ||
441 | static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, | ||
442 | size_t len) | ||
443 | { | ||
444 | u32 ret = 0, ordinal, | ||
445 | status, | ||
446 | burstcnt = 0, i, size; | ||
447 | u8 data; | ||
448 | struct i2c_client *client; | ||
449 | struct st33zp24_platform_data *pin_infos; | ||
450 | |||
451 | if (chip == NULL) | ||
452 | return -EBUSY; | ||
453 | if (len < TPM_HEADER_SIZE) | ||
454 | return -EBUSY; | ||
455 | |||
456 | client = (struct i2c_client *)chip->vendor.iobase; | ||
457 | pin_infos = client->dev.platform_data; | ||
458 | |||
459 | ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); | ||
460 | |||
461 | client->flags = 0; | ||
462 | |||
463 | ret = request_locality(chip); | ||
464 | if (ret < 0) | ||
465 | return ret; | ||
466 | |||
467 | status = tpm_stm_i2c_status(chip); | ||
468 | if ((status & TPM_STS_COMMAND_READY) == 0) { | ||
469 | tpm_stm_i2c_cancel(chip); | ||
470 | if (wait_for_stat | ||
471 | (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, | ||
472 | &chip->vendor.int_queue) < 0) { | ||
473 | ret = -ETIME; | ||
474 | goto out_err; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | for (i = 0 ; i < len - 1 ;) { | ||
479 | burstcnt = get_burstcount(chip); | ||
480 | size = min_t(int, len - i - 1, burstcnt); | ||
481 | ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size); | ||
482 | if (ret < 0) | ||
483 | goto out_err; | ||
484 | |||
485 | i += size; | ||
486 | } | ||
487 | |||
488 | status = tpm_stm_i2c_status(chip); | ||
489 | if ((status & TPM_STS_DATA_EXPECT) == 0) { | ||
490 | ret = -EIO; | ||
491 | goto out_err; | ||
492 | } | ||
493 | |||
494 | ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + len - 1, 1); | ||
495 | if (ret < 0) | ||
496 | goto out_err; | ||
497 | |||
498 | status = tpm_stm_i2c_status(chip); | ||
499 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | ||
500 | ret = -EIO; | ||
501 | goto out_err; | ||
502 | } | ||
503 | |||
504 | data = TPM_STS_GO; | ||
505 | I2C_WRITE_DATA(client, TPM_STS, &data, 1); | ||
506 | |||
507 | return len; | ||
508 | out_err: | ||
509 | tpm_stm_i2c_cancel(chip); | ||
510 | release_locality(chip); | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | /* | ||
515 | * tpm_stm_i2c_recv received TPM response through the I2C bus. | ||
516 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. | ||
517 | * @param: buf, the buffer to store datas. | ||
518 | * @param: count, the number of bytes to send. | ||
519 | * @return: In case of success the number of bytes received. | ||
520 | * In other case, a < 0 value describing the issue. | ||
521 | */ | ||
522 | static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, | ||
523 | size_t count) | ||
524 | { | ||
525 | int size = 0; | ||
526 | int expected; | ||
527 | |||
528 | struct i2c_client *client; | ||
529 | struct st33zp24_platform_data *pin_infos; | ||
530 | |||
531 | client = (struct i2c_client *)chip->vendor.iobase; | ||
532 | pin_infos = client->dev.platform_data; | ||
533 | |||
534 | |||
535 | if (chip == NULL) | ||
536 | return -EBUSY; | ||
537 | |||
538 | if (count < TPM_HEADER_SIZE) { | ||
539 | size = -EIO; | ||
540 | goto out; | ||
541 | } | ||
542 | |||
543 | size = recv_data(chip, buf, TPM_HEADER_SIZE); | ||
544 | if (size < TPM_HEADER_SIZE) { | ||
545 | dev_err(chip->dev, "Unable to read header\n"); | ||
546 | goto out; | ||
547 | } | ||
548 | |||
549 | expected = be32_to_cpu(*(__be32 *) (buf + 2)); | ||
550 | if (expected > count) { | ||
551 | size = -EIO; | ||
552 | goto out; | ||
553 | } | ||
554 | |||
555 | size += recv_data(chip, &buf[TPM_HEADER_SIZE], | ||
556 | expected - TPM_HEADER_SIZE); | ||
557 | if (size < expected) { | ||
558 | dev_err(chip->dev, "Unable to read remainder of result\n"); | ||
559 | size = -ETIME; | ||
560 | goto out; | ||
561 | } | ||
562 | |||
563 | out: | ||
564 | chip->vendor.cancel(chip); | ||
565 | release_locality(chip); | ||
566 | return size; | ||
567 | } | ||
568 | |||
569 | static const struct file_operations tpm_st33_i2c_fops = { | ||
570 | .owner = THIS_MODULE, | ||
571 | .llseek = no_llseek, | ||
572 | .read = tpm_read, | ||
573 | .write = tpm_write, | ||
574 | .open = tpm_open, | ||
575 | .release = tpm_release, | ||
576 | }; | ||
577 | |||
578 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
579 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
580 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
581 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
582 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
583 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
584 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | ||
585 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
586 | |||
587 | static struct attribute *stm_tpm_attrs[] = { | ||
588 | &dev_attr_pubek.attr, | ||
589 | &dev_attr_pcrs.attr, | ||
590 | &dev_attr_enabled.attr, | ||
591 | &dev_attr_active.attr, | ||
592 | &dev_attr_owned.attr, | ||
593 | &dev_attr_temp_deactivated.attr, | ||
594 | &dev_attr_caps.attr, | ||
595 | &dev_attr_cancel.attr, NULL, | ||
596 | }; | ||
597 | |||
598 | static struct attribute_group stm_tpm_attr_grp = { | ||
599 | .attrs = stm_tpm_attrs | ||
600 | }; | ||
601 | |||
602 | static struct tpm_vendor_specific st_i2c_tpm = { | ||
603 | .send = tpm_stm_i2c_send, | ||
604 | .recv = tpm_stm_i2c_recv, | ||
605 | .cancel = tpm_stm_i2c_cancel, | ||
606 | .status = tpm_stm_i2c_status, | ||
607 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
608 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
609 | .req_canceled = TPM_STS_COMMAND_READY, | ||
610 | .attr_group = &stm_tpm_attr_grp, | ||
611 | .miscdev = {.fops = &tpm_st33_i2c_fops,}, | ||
612 | }; | ||
613 | |||
614 | static int interrupts ; | ||
615 | module_param(interrupts, int, 0444); | ||
616 | MODULE_PARM_DESC(interrupts, "Enable interrupts"); | ||
617 | |||
618 | static int power_mgt = 1; | ||
619 | module_param(power_mgt, int, 0444); | ||
620 | MODULE_PARM_DESC(power_mgt, "Power Management"); | ||
621 | |||
622 | /* | ||
623 | * tpm_st33_i2c_probe initialize the TPM device | ||
624 | * @param: client, the i2c_client drescription (TPM I2C description). | ||
625 | * @param: id, the i2c_device_id struct. | ||
626 | * @return: 0 in case of success. | ||
627 | * -1 in other case. | ||
628 | */ | ||
629 | static int | ||
630 | tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
631 | { | ||
632 | u32 err; | ||
633 | u8 intmask; | ||
634 | struct tpm_chip *chip; | ||
635 | struct st33zp24_platform_data *platform_data; | ||
636 | |||
637 | err = 0; | ||
638 | |||
639 | if (client == NULL) { | ||
640 | dev_info(&client->dev, "client is NULL. exiting.\n"); | ||
641 | err = -ENODEV; | ||
642 | goto end; | ||
643 | } | ||
644 | |||
645 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
646 | dev_info(&client->dev, "client not i2c capable\n"); | ||
647 | err = -ENODEV; | ||
648 | goto end; | ||
649 | } | ||
650 | |||
651 | chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); | ||
652 | if (!chip) { | ||
653 | dev_info(&client->dev, "fail chip\n"); | ||
654 | err = -ENODEV; | ||
655 | goto end; | ||
656 | } | ||
657 | |||
658 | platform_data = client->dev.platform_data; | ||
659 | platform_data->tpm_i2c_buffer[0] = | ||
660 | kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); | ||
661 | if (platform_data->tpm_i2c_buffer[0] == NULL) { | ||
662 | err = -ENOMEM; | ||
663 | goto _tpm_clean_answer; | ||
664 | } | ||
665 | platform_data->tpm_i2c_buffer[1] = | ||
666 | kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); | ||
667 | if (platform_data->tpm_i2c_buffer[1] == NULL) { | ||
668 | err = -ENOMEM; | ||
669 | goto _tpm_clean_response; | ||
670 | } | ||
671 | |||
672 | chip->vendor.iobase = client; | ||
673 | |||
674 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
675 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | ||
676 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
677 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
678 | |||
679 | chip->vendor.locality = LOCALITY0; | ||
680 | |||
681 | if (power_mgt) { | ||
682 | err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD"); | ||
683 | if (err) | ||
684 | goto _gpio_init1; | ||
685 | gpio_set_value(platform_data->io_lpcpd, 1); | ||
686 | } | ||
687 | |||
688 | if (interrupts) { | ||
689 | init_completion(&platform_data->irq_detection); | ||
690 | if (request_locality(chip) != LOCALITY0) { | ||
691 | err = -ENODEV; | ||
692 | goto _tpm_clean_response; | ||
693 | } | ||
694 | err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ"); | ||
695 | if (err) | ||
696 | goto _gpio_init2; | ||
697 | |||
698 | clear_interruption(client); | ||
699 | err = request_irq(gpio_to_irq(platform_data->io_serirq), | ||
700 | &tpm_ioserirq_handler, | ||
701 | IRQF_TRIGGER_HIGH, | ||
702 | "TPM SERIRQ management", chip); | ||
703 | if (err < 0) { | ||
704 | dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", | ||
705 | gpio_to_irq(platform_data->io_serirq)); | ||
706 | goto _irq_set; | ||
707 | } | ||
708 | |||
709 | err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1); | ||
710 | if (err < 0) | ||
711 | goto _irq_set; | ||
712 | |||
713 | intmask |= TPM_INTF_CMD_READY_INT | ||
714 | | TPM_INTF_FIFO_AVALAIBLE_INT | ||
715 | | TPM_INTF_WAKE_UP_READY_INT | ||
716 | | TPM_INTF_LOCALITY_CHANGE_INT | ||
717 | | TPM_INTF_STS_VALID_INT | ||
718 | | TPM_INTF_DATA_AVAIL_INT; | ||
719 | |||
720 | err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1); | ||
721 | if (err < 0) | ||
722 | goto _irq_set; | ||
723 | |||
724 | intmask = TPM_GLOBAL_INT_ENABLE; | ||
725 | err = I2C_WRITE_DATA(client, (TPM_INT_ENABLE + 3), &intmask, 1); | ||
726 | if (err < 0) | ||
727 | goto _irq_set; | ||
728 | |||
729 | err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1); | ||
730 | if (err < 0) | ||
731 | goto _irq_set; | ||
732 | |||
733 | chip->vendor.irq = interrupts; | ||
734 | |||
735 | tpm_gen_interrupt(chip); | ||
736 | } | ||
737 | |||
738 | tpm_get_timeouts(chip); | ||
739 | |||
740 | i2c_set_clientdata(client, chip); | ||
741 | platform_data->bChipF = false; | ||
742 | |||
743 | dev_info(chip->dev, "TPM I2C Initialized\n"); | ||
744 | return 0; | ||
745 | _irq_set: | ||
746 | free_irq(gpio_to_irq(platform_data->io_serirq), (void *) chip); | ||
747 | _gpio_init2: | ||
748 | if (platform_data && interrupts) | ||
749 | gpio_free(platform_data->io_serirq); | ||
750 | _gpio_init1: | ||
751 | if (platform_data && power_mgt) | ||
752 | gpio_free(platform_data->io_lpcpd); | ||
753 | _tpm_clean_response: | ||
754 | tpm_remove_hardware(chip->dev); | ||
755 | if (platform_data->tpm_i2c_buffer[1] != NULL) { | ||
756 | kzfree(platform_data->tpm_i2c_buffer[1]); | ||
757 | platform_data->tpm_i2c_buffer[1] = NULL; | ||
758 | } | ||
759 | _tpm_clean_answer: | ||
760 | if (platform_data->tpm_i2c_buffer[0] != NULL) { | ||
761 | kzfree(platform_data->tpm_i2c_buffer[0]); | ||
762 | platform_data->tpm_i2c_buffer[0] = NULL; | ||
763 | } | ||
764 | |||
765 | platform_data->bChipF = true; | ||
766 | end: | ||
767 | pr_info("TPM I2C initialisation fail\n"); | ||
768 | return err; | ||
769 | } | ||
770 | |||
771 | /* | ||
772 | * tpm_st33_i2c_remove remove the TPM device | ||
773 | * @param: client, the i2c_client drescription (TPM I2C description). | ||
774 | clear_bit(0, &chip->is_open); | ||
775 | * @return: 0 in case of success. | ||
776 | */ | ||
777 | static __devexit int tpm_st33_i2c_remove(struct i2c_client *client) | ||
778 | { | ||
779 | struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client); | ||
780 | struct st33zp24_platform_data *pin_infos = | ||
781 | ((struct i2c_client *) chip->vendor.iobase)->dev.platform_data; | ||
782 | |||
783 | if (pin_infos != NULL) { | ||
784 | free_irq(pin_infos->io_serirq, chip); | ||
785 | |||
786 | gpio_free(pin_infos->io_serirq); | ||
787 | gpio_free(pin_infos->io_lpcpd); | ||
788 | |||
789 | if (pin_infos->bChipF != true) | ||
790 | tpm_remove_hardware(chip->dev); | ||
791 | if (pin_infos->tpm_i2c_buffer[1] != NULL) { | ||
792 | kzfree(pin_infos->tpm_i2c_buffer[1]); | ||
793 | pin_infos->tpm_i2c_buffer[1] = NULL; | ||
794 | } | ||
795 | if (pin_infos->tpm_i2c_buffer[0] != NULL) { | ||
796 | kzfree(pin_infos->tpm_i2c_buffer[0]); | ||
797 | pin_infos->tpm_i2c_buffer[0] = NULL; | ||
798 | } | ||
799 | } | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /* | ||
805 | * tpm_st33_i2c_pm_suspend suspend the TPM device | ||
806 | * Added: Work around when suspend and no tpm application is running, suspend | ||
807 | * may fail because chip->data_buffer is not set (only set in tpm_open in Linux | ||
808 | * TPM core) | ||
809 | * @param: client, the i2c_client drescription (TPM I2C description). | ||
810 | * @param: mesg, the power management message. | ||
811 | * @return: 0 in case of success. | ||
812 | */ | ||
813 | static int tpm_st33_i2c_pm_suspend(struct i2c_client *client, pm_message_t mesg) | ||
814 | { | ||
815 | struct tpm_chip *chip = | ||
816 | (struct tpm_chip *)i2c_get_clientdata(client); | ||
817 | struct st33zp24_platform_data *pin_infos = | ||
818 | ((struct i2c_client *)chip->vendor.iobase)->dev.platform_data; | ||
819 | int ret = 0; | ||
820 | |||
821 | if (power_mgt) | ||
822 | gpio_set_value(pin_infos->io_lpcpd, 0); | ||
823 | else{ | ||
824 | if (chip->data_buffer == NULL) | ||
825 | chip->data_buffer = pin_infos->tpm_i2c_buffer[0]; | ||
826 | ret = tpm_pm_suspend(&client->dev); | ||
827 | } | ||
828 | return ret; | ||
829 | } /* tpm_st33_i2c_suspend() */ | ||
830 | |||
831 | /* | ||
832 | * tpm_st33_i2c_pm_resume resume the TPM device | ||
833 | * @param: client, the i2c_client drescription (TPM I2C description). | ||
834 | * @return: 0 in case of success. | ||
835 | */ | ||
836 | static int tpm_st33_i2c_pm_resume(struct i2c_client *client) | ||
837 | { | ||
838 | struct tpm_chip *chip = | ||
839 | (struct tpm_chip *)i2c_get_clientdata(client); | ||
840 | struct st33zp24_platform_data *pin_infos = | ||
841 | ((struct i2c_client *)chip->vendor.iobase)->dev.platform_data; | ||
842 | |||
843 | int ret = 0; | ||
844 | |||
845 | if (power_mgt) { | ||
846 | gpio_set_value(pin_infos->io_lpcpd, 1); | ||
847 | ret = wait_for_serirq_timeout(chip, | ||
848 | (chip->vendor.status(chip) && | ||
849 | TPM_STS_VALID) == TPM_STS_VALID, | ||
850 | chip->vendor.timeout_b); | ||
851 | } else{ | ||
852 | if (chip->data_buffer == NULL) | ||
853 | chip->data_buffer = pin_infos->tpm_i2c_buffer[0]; | ||
854 | ret = tpm_pm_resume(&client->dev); | ||
855 | if (!ret) | ||
856 | tpm_do_selftest(chip); | ||
857 | } | ||
858 | return ret; | ||
859 | } /* tpm_st33_i2c_pm_resume() */ | ||
860 | |||
861 | static const struct i2c_device_id tpm_st33_i2c_id[] = { | ||
862 | {TPM_ST33_I2C, 0}, | ||
863 | {} | ||
864 | }; | ||
865 | |||
866 | MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id); | ||
867 | |||
868 | static struct i2c_driver tpm_st33_i2c_driver = { | ||
869 | .driver = { | ||
870 | .owner = THIS_MODULE, | ||
871 | .name = TPM_ST33_I2C, | ||
872 | }, | ||
873 | .probe = tpm_st33_i2c_probe, | ||
874 | .remove = tpm_st33_i2c_remove, | ||
875 | .resume = tpm_st33_i2c_pm_resume, | ||
876 | .suspend = tpm_st33_i2c_pm_suspend, | ||
877 | .id_table = tpm_st33_i2c_id | ||
878 | }; | ||
879 | |||
880 | /* | ||
881 | * tpm_st33_i2c_init initialize driver | ||
882 | * @return: 0 if successful, else non zero value. | ||
883 | */ | ||
884 | static int __init tpm_st33_i2c_init(void) | ||
885 | { | ||
886 | return i2c_add_driver(&tpm_st33_i2c_driver); | ||
887 | } | ||
888 | |||
889 | /* | ||
890 | * tpm_st33_i2c_exit The kernel calls this function during unloading the | ||
891 | * module or during shut down process | ||
892 | */ | ||
893 | static void __exit tpm_st33_i2c_exit(void) | ||
894 | { | ||
895 | i2c_del_driver(&tpm_st33_i2c_driver); | ||
896 | } | ||
897 | |||
898 | module_init(tpm_st33_i2c_init); | ||
899 | module_exit(tpm_st33_i2c_exit); | ||
900 | |||
901 | MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)"); | ||
902 | MODULE_DESCRIPTION("STM TPM I2C ST33 Driver"); | ||
903 | MODULE_VERSION("1.2.0"); | ||
diff --git a/drivers/char/tpm/tpm_stm_st33_i2c.h b/drivers/char/tpm/tpm_stm_st33_i2c.h new file mode 100644 index 000000000000..d390542db869 --- /dev/null +++ b/drivers/char/tpm/tpm_stm_st33_i2c.h | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 | ||
3 | * Copyright (C) 2009, 2010 STMicroelectronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * STMicroelectronics version 1.2.0, Copyright (C) 2010 | ||
20 | * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. | ||
21 | * This is free software, and you are welcome to redistribute it | ||
22 | * under certain conditions. | ||
23 | * | ||
24 | * @Author: Christophe RICARD tpmsupport@st.com | ||
25 | * | ||
26 | * @File: stm_st33_tpm_i2c.h | ||
27 | * | ||
28 | * @Date: 09/15/2010 | ||
29 | */ | ||
30 | #ifndef __STM_ST33_TPM_I2C_MAIN_H__ | ||
31 | #define __STM_ST33_TPM_I2C_MAIN_H__ | ||
32 | |||
33 | #include <linux/pci.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/i2c.h> | ||
37 | #include <linux/fs.h> | ||
38 | #include <linux/miscdevice.h> | ||
39 | #include <linux/module.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/wait.h> | ||
44 | #include <linux/string.h> | ||
45 | #include <linux/interrupt.h> | ||
46 | #include <linux/spinlock.h> | ||
47 | #include <linux/sysfs.h> | ||
48 | #include <linux/gpio.h> | ||
49 | #include <linux/sched.h> | ||
50 | #include <linux/uaccess.h> | ||
51 | #include <linux/io.h> | ||
52 | #include <linux/slab.h> | ||
53 | #include <linux/sched.h> | ||
54 | |||
55 | #include "tpm.h" | ||
56 | |||
57 | #define MINOR_NUM_I2C 224 | ||
58 | |||
59 | #define TPM_ACCESS (0x0) | ||
60 | #define TPM_STS (0x18) | ||
61 | #define TPM_HASH_END (0x20) | ||
62 | #define TPM_DATA_FIFO (0x24) | ||
63 | #define TPM_HASH_DATA (0x24) | ||
64 | #define TPM_HASH_START (0x28) | ||
65 | #define TPM_INTF_CAPABILITY (0x14) | ||
66 | #define TPM_INT_STATUS (0x10) | ||
67 | #define TPM_INT_ENABLE (0x08) | ||
68 | |||
69 | #define TPM_DUMMY_BYTE 0xAA | ||
70 | #define TPM_WRITE_DIRECTION 0x80 | ||
71 | #define TPM_HEADER_SIZE 10 | ||
72 | #define TPM_BUFSIZE 2048 | ||
73 | |||
74 | #define LOCALITY0 0 | ||
75 | |||
76 | struct st_tpm_hash { | ||
77 | int size; | ||
78 | u8 *data; | ||
79 | }; | ||
80 | |||
81 | #endif /* __STM_ST33_TPM_I2C_MAIN_H__ */ | ||