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