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 | * | |
642d2be2 CR |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
251a7b08 ML |
17 | * |
18 | * STMicroelectronics version 1.2.0, Copyright (C) 2010 | |
19 | * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. | |
20 | * This is free software, and you are welcome to redistribute it | |
21 | * under certain conditions. | |
22 | * | |
23 | * @Author: Christophe RICARD tpmsupport@st.com | |
24 | * | |
25 | * @File: tpm_stm_st33_i2c.c | |
26 | * | |
27 | * @Synopsis: | |
28 | * 09/15/2010: First shot driver tpm_tis driver for | |
29 | lpc is used as model. | |
30 | */ | |
31 | ||
3d7a7bd7 KY |
32 | #include <linux/pci.h> |
33 | #include <linux/module.h> | |
34 | #include <linux/platform_device.h> | |
35 | #include <linux/i2c.h> | |
36 | #include <linux/fs.h> | |
37 | #include <linux/miscdevice.h> | |
3d7a7bd7 KY |
38 | #include <linux/kernel.h> |
39 | #include <linux/delay.h> | |
3d7a7bd7 KY |
40 | #include <linux/wait.h> |
41 | #include <linux/string.h> | |
42 | #include <linux/interrupt.h> | |
3d7a7bd7 KY |
43 | #include <linux/sysfs.h> |
44 | #include <linux/gpio.h> | |
45 | #include <linux/sched.h> | |
46 | #include <linux/uaccess.h> | |
47 | #include <linux/io.h> | |
48 | #include <linux/slab.h> | |
3d7a7bd7 | 49 | |
b9626f32 | 50 | #include <linux/platform_data/tpm_i2c_stm_st33.h> |
3d7a7bd7 | 51 | #include "tpm.h" |
2dbca750 CR |
52 | |
53 | #define TPM_ACCESS 0x0 | |
54 | #define TPM_STS 0x18 | |
55 | #define TPM_HASH_END 0x20 | |
56 | #define TPM_DATA_FIFO 0x24 | |
57 | #define TPM_HASH_DATA 0x24 | |
58 | #define TPM_HASH_START 0x28 | |
59 | #define TPM_INTF_CAPABILITY 0x14 | |
60 | #define TPM_INT_STATUS 0x10 | |
61 | #define TPM_INT_ENABLE 0x08 | |
62 | ||
63 | #define TPM_DUMMY_BYTE 0xAA | |
64 | #define TPM_WRITE_DIRECTION 0x80 | |
65 | #define TPM_HEADER_SIZE 10 | |
66 | #define TPM_BUFSIZE 2048 | |
67 | ||
68 | #define LOCALITY0 0 | |
b9626f32 | 69 | |
251a7b08 ML |
70 | |
71 | enum stm33zp24_access { | |
72 | TPM_ACCESS_VALID = 0x80, | |
73 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | |
74 | TPM_ACCESS_REQUEST_PENDING = 0x04, | |
75 | TPM_ACCESS_REQUEST_USE = 0x02, | |
76 | }; | |
77 | ||
78 | enum stm33zp24_status { | |
79 | TPM_STS_VALID = 0x80, | |
80 | TPM_STS_COMMAND_READY = 0x40, | |
81 | TPM_STS_GO = 0x20, | |
82 | TPM_STS_DATA_AVAIL = 0x10, | |
83 | TPM_STS_DATA_EXPECT = 0x08, | |
84 | }; | |
85 | ||
86 | enum stm33zp24_int_flags { | |
87 | TPM_GLOBAL_INT_ENABLE = 0x80, | |
88 | TPM_INTF_CMD_READY_INT = 0x080, | |
89 | TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, | |
90 | TPM_INTF_WAKE_UP_READY_INT = 0x020, | |
91 | TPM_INTF_LOCALITY_CHANGE_INT = 0x004, | |
92 | TPM_INTF_STS_VALID_INT = 0x002, | |
93 | TPM_INTF_DATA_AVAIL_INT = 0x001, | |
94 | }; | |
95 | ||
96 | enum tis_defaults { | |
97 | TIS_SHORT_TIMEOUT = 750, | |
98 | TIS_LONG_TIMEOUT = 2000, | |
99 | }; | |
100 | ||
b9626f32 CR |
101 | struct tpm_stm_dev { |
102 | struct i2c_client *client; | |
103 | struct completion irq_detection; | |
104 | struct tpm_chip *chip; | |
105 | u8 buf[TPM_BUFSIZE + 1]; | |
b9626f32 CR |
106 | int io_lpcpd; |
107 | }; | |
108 | ||
251a7b08 ML |
109 | /* |
110 | * write8_reg | |
111 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. | |
112 | * @param: tpm_register, the tpm tis register where the data should be written | |
113 | * @param: tpm_data, the tpm_data to write inside the tpm_register | |
114 | * @param: tpm_size, The length of the data | |
115 | * @return: Returns negative errno, or else the number of bytes written. | |
116 | */ | |
b9626f32 | 117 | static int write8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, |
251a7b08 ML |
118 | u8 *tpm_data, u16 tpm_size) |
119 | { | |
b9626f32 CR |
120 | tpm_dev->buf[0] = tpm_register; |
121 | memcpy(tpm_dev->buf + 1, tpm_data, tpm_size); | |
122 | return i2c_master_send(tpm_dev->client, tpm_dev->buf, tpm_size + 1); | |
251a7b08 ML |
123 | } /* write8_reg() */ |
124 | ||
125 | /* | |
126 | * read8_reg | |
127 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. | |
128 | * @param: tpm_register, the tpm tis register where the data should be read | |
129 | * @param: tpm_data, the TPM response | |
130 | * @param: tpm_size, tpm TPM response size to read. | |
131 | * @return: number of byte read successfully: should be one if success. | |
132 | */ | |
b9626f32 | 133 | static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, |
251a7b08 ML |
134 | u8 *tpm_data, int tpm_size) |
135 | { | |
136 | u8 status = 0; | |
137 | u8 data; | |
251a7b08 ML |
138 | |
139 | data = TPM_DUMMY_BYTE; | |
b9626f32 | 140 | status = write8_reg(tpm_dev, tpm_register, &data, 1); |
251a7b08 | 141 | if (status == 2) |
b9626f32 | 142 | status = i2c_master_recv(tpm_dev->client, tpm_data, tpm_size); |
251a7b08 ML |
143 | return status; |
144 | } /* read8_reg() */ | |
145 | ||
146 | /* | |
147 | * I2C_WRITE_DATA | |
148 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. | |
b9626f32 | 149 | * @param: tpm_dev, the chip description |
251a7b08 ML |
150 | * @param: tpm_register, the tpm tis register where the data should be written |
151 | * @param: tpm_data, the tpm_data to write inside the tpm_register | |
152 | * @param: tpm_size, The length of the data | |
153 | * @return: number of byte written successfully: should be one if success. | |
154 | */ | |
b9626f32 CR |
155 | #define I2C_WRITE_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ |
156 | (write8_reg(tpm_dev, tpm_register | \ | |
251a7b08 ML |
157 | TPM_WRITE_DIRECTION, tpm_data, tpm_size)) |
158 | ||
159 | /* | |
160 | * I2C_READ_DATA | |
161 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. | |
b9626f32 | 162 | * @param: tpm_dev, the chip description |
251a7b08 ML |
163 | * @param: tpm_register, the tpm tis register where the data should be read |
164 | * @param: tpm_data, the TPM response | |
165 | * @param: tpm_size, tpm TPM response size to read. | |
166 | * @return: number of byte read successfully: should be one if success. | |
167 | */ | |
b9626f32 CR |
168 | #define I2C_READ_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ |
169 | (read8_reg(tpm_dev, tpm_register, tpm_data, tpm_size)) | |
251a7b08 ML |
170 | |
171 | /* | |
172 | * clear_interruption | |
173 | * clear the TPM interrupt register. | |
174 | * @param: tpm, the chip description | |
175 | */ | |
b9626f32 | 176 | static void clear_interruption(struct tpm_stm_dev *tpm_dev) |
251a7b08 ML |
177 | { |
178 | u8 interrupt; | |
7500c4b9 | 179 | |
b9626f32 CR |
180 | I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); |
181 | I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); | |
182 | I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); | |
251a7b08 ML |
183 | } /* clear_interruption() */ |
184 | ||
185 | /* | |
186 | * _wait_for_interrupt_serirq_timeout | |
187 | * @param: tpm, the chip description | |
188 | * @param: timeout, the timeout of the interrupt | |
189 | * @return: the status of the interruption. | |
190 | */ | |
191 | static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip, | |
192 | unsigned long timeout) | |
193 | { | |
194 | long status; | |
195 | struct i2c_client *client; | |
b9626f32 | 196 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 197 | |
b9626f32 CR |
198 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
199 | client = tpm_dev->client; | |
251a7b08 ML |
200 | |
201 | status = wait_for_completion_interruptible_timeout( | |
b9626f32 CR |
202 | &tpm_dev->irq_detection, |
203 | timeout); | |
251a7b08 | 204 | if (status > 0) |
b9626f32 | 205 | enable_irq(client->irq); |
251a7b08 ML |
206 | |
207 | return status; | |
208 | } /* wait_for_interrupt_serirq_timeout() */ | |
209 | ||
3d7a7bd7 | 210 | static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, |
251a7b08 ML |
211 | unsigned long timeout) |
212 | { | |
213 | int status = 2; | |
b9626f32 | 214 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 215 | |
b9626f32 | 216 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
217 | |
218 | status = _wait_for_interrupt_serirq_timeout(chip, timeout); | |
219 | if (!status) { | |
220 | status = -EBUSY; | |
2d089f82 | 221 | } else { |
b9626f32 | 222 | clear_interruption(tpm_dev); |
251a7b08 ML |
223 | if (condition) |
224 | status = 1; | |
225 | } | |
226 | return status; | |
227 | } | |
228 | ||
229 | /* | |
230 | * tpm_stm_i2c_cancel, cancel is not implemented. | |
231 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h | |
232 | */ | |
233 | static void tpm_stm_i2c_cancel(struct tpm_chip *chip) | |
234 | { | |
b9626f32 | 235 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
236 | u8 data; |
237 | ||
b9626f32 | 238 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
239 | |
240 | data = TPM_STS_COMMAND_READY; | |
b9626f32 | 241 | I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); |
251a7b08 ML |
242 | if (chip->vendor.irq) |
243 | wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); | |
244 | } /* tpm_stm_i2c_cancel() */ | |
245 | ||
246 | /* | |
247 | * tpm_stm_spi_status return the TPM_STS register | |
248 | * @param: chip, the tpm chip description | |
249 | * @return: the TPM_STS register value. | |
250 | */ | |
251 | static u8 tpm_stm_i2c_status(struct tpm_chip *chip) | |
252 | { | |
b9626f32 | 253 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 254 | u8 data; |
7500c4b9 | 255 | |
b9626f32 | 256 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 | 257 | |
b9626f32 | 258 | I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1); |
251a7b08 ML |
259 | return data; |
260 | } /* tpm_stm_i2c_status() */ | |
261 | ||
262 | ||
263 | /* | |
264 | * check_locality if the locality is active | |
265 | * @param: chip, the tpm chip description | |
266 | * @return: the active locality or -EACCESS. | |
267 | */ | |
268 | static int check_locality(struct tpm_chip *chip) | |
269 | { | |
b9626f32 | 270 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
271 | u8 data; |
272 | u8 status; | |
273 | ||
b9626f32 | 274 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 | 275 | |
b9626f32 | 276 | status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1); |
251a7b08 ML |
277 | if (status && (data & |
278 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == | |
279 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) | |
280 | return chip->vendor.locality; | |
281 | ||
282 | return -EACCES; | |
283 | ||
284 | } /* check_locality() */ | |
285 | ||
286 | /* | |
287 | * request_locality request the TPM locality | |
288 | * @param: chip, the chip description | |
289 | * @return: the active locality or EACCESS. | |
290 | */ | |
291 | static int request_locality(struct tpm_chip *chip) | |
292 | { | |
293 | unsigned long stop; | |
294 | long rc; | |
b9626f32 | 295 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
296 | u8 data; |
297 | ||
b9626f32 | 298 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
299 | |
300 | if (check_locality(chip) == chip->vendor.locality) | |
301 | return chip->vendor.locality; | |
302 | ||
303 | data = TPM_ACCESS_REQUEST_USE; | |
b9626f32 | 304 | rc = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); |
251a7b08 ML |
305 | if (rc < 0) |
306 | goto end; | |
307 | ||
308 | if (chip->vendor.irq) { | |
309 | rc = wait_for_serirq_timeout(chip, (check_locality | |
310 | (chip) >= 0), | |
311 | chip->vendor.timeout_a); | |
312 | if (rc > 0) | |
313 | return chip->vendor.locality; | |
2d089f82 | 314 | } else { |
251a7b08 ML |
315 | stop = jiffies + chip->vendor.timeout_a; |
316 | do { | |
317 | if (check_locality(chip) >= 0) | |
318 | return chip->vendor.locality; | |
319 | msleep(TPM_TIMEOUT); | |
320 | } while (time_before(jiffies, stop)); | |
321 | } | |
322 | rc = -EACCES; | |
323 | end: | |
324 | return rc; | |
325 | } /* request_locality() */ | |
326 | ||
327 | /* | |
328 | * release_locality release the active locality | |
329 | * @param: chip, the tpm chip description. | |
330 | */ | |
331 | static void release_locality(struct tpm_chip *chip) | |
332 | { | |
b9626f32 | 333 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
334 | u8 data; |
335 | ||
b9626f32 | 336 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
337 | data = TPM_ACCESS_ACTIVE_LOCALITY; |
338 | ||
b9626f32 | 339 | I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); |
251a7b08 ML |
340 | } |
341 | ||
342 | /* | |
343 | * get_burstcount return the burstcount address 0x19 0x1A | |
344 | * @param: chip, the chip description | |
345 | * return: the burstcount. | |
346 | */ | |
347 | static int get_burstcount(struct tpm_chip *chip) | |
348 | { | |
349 | unsigned long stop; | |
350 | int burstcnt, status; | |
351 | u8 tpm_reg, temp; | |
b9626f32 | 352 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 353 | |
b9626f32 | 354 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
355 | |
356 | stop = jiffies + chip->vendor.timeout_d; | |
357 | do { | |
358 | tpm_reg = TPM_STS + 1; | |
b9626f32 | 359 | status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); |
251a7b08 ML |
360 | if (status < 0) |
361 | goto end; | |
362 | ||
363 | tpm_reg = tpm_reg + 1; | |
364 | burstcnt = temp; | |
b9626f32 | 365 | status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); |
251a7b08 ML |
366 | if (status < 0) |
367 | goto end; | |
368 | ||
369 | burstcnt |= temp << 8; | |
370 | if (burstcnt) | |
371 | return burstcnt; | |
372 | msleep(TPM_TIMEOUT); | |
373 | } while (time_before(jiffies, stop)); | |
374 | ||
375 | end: | |
376 | return -EBUSY; | |
377 | } /* get_burstcount() */ | |
378 | ||
379 | /* | |
380 | * wait_for_stat wait for a TPM_STS value | |
381 | * @param: chip, the tpm chip description | |
382 | * @param: mask, the value mask to wait | |
383 | * @param: timeout, the timeout | |
384 | * @param: queue, the wait queue. | |
385 | * @return: the tpm status, 0 if success, -ETIME if timeout is reached. | |
386 | */ | |
387 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | |
388 | wait_queue_head_t *queue) | |
389 | { | |
390 | unsigned long stop; | |
391 | long rc; | |
392 | u8 status; | |
393 | ||
394 | if (chip->vendor.irq) { | |
395 | rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status | |
396 | (chip) & mask) == | |
397 | mask), timeout); | |
398 | if (rc > 0) | |
399 | return 0; | |
2d089f82 | 400 | } else { |
251a7b08 ML |
401 | stop = jiffies + timeout; |
402 | do { | |
403 | msleep(TPM_TIMEOUT); | |
404 | status = tpm_stm_i2c_status(chip); | |
405 | if ((status & mask) == mask) | |
406 | return 0; | |
407 | } while (time_before(jiffies, stop)); | |
408 | } | |
409 | return -ETIME; | |
410 | } /* wait_for_stat() */ | |
411 | ||
412 | /* | |
413 | * recv_data receive data | |
414 | * @param: chip, the tpm chip description | |
415 | * @param: buf, the buffer where the data are received | |
416 | * @param: count, the number of data to receive | |
417 | * @return: the number of bytes read from TPM FIFO. | |
418 | */ | |
419 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | |
420 | { | |
421 | int size = 0, burstcnt, len; | |
b9626f32 | 422 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 423 | |
b9626f32 | 424 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
425 | |
426 | while (size < count && | |
427 | wait_for_stat(chip, | |
428 | TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
429 | chip->vendor.timeout_c, | |
430 | &chip->vendor.read_queue) | |
431 | == 0) { | |
432 | burstcnt = get_burstcount(chip); | |
85c5e0d4 PH |
433 | if (burstcnt < 0) |
434 | return burstcnt; | |
251a7b08 | 435 | len = min_t(int, burstcnt, count - size); |
b9626f32 | 436 | I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len); |
251a7b08 ML |
437 | size += len; |
438 | } | |
439 | return size; | |
440 | } | |
441 | ||
442 | /* | |
443 | * tpm_ioserirq_handler the serirq irq handler | |
444 | * @param: irq, the tpm chip description | |
445 | * @param: dev_id, the description of the chip | |
446 | * @return: the status of the handler. | |
447 | */ | |
448 | static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) | |
449 | { | |
450 | struct tpm_chip *chip = dev_id; | |
451 | struct i2c_client *client; | |
b9626f32 | 452 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
453 | |
454 | disable_irq_nosync(irq); | |
455 | ||
b9626f32 CR |
456 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
457 | client = tpm_dev->client; | |
251a7b08 | 458 | |
b9626f32 | 459 | complete(&tpm_dev->irq_detection); |
251a7b08 ML |
460 | return IRQ_HANDLED; |
461 | } /* tpm_ioserirq_handler() */ | |
462 | ||
463 | ||
464 | /* | |
465 | * tpm_stm_i2c_send send TPM commands through the I2C bus. | |
466 | * | |
467 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h | |
468 | * @param: buf, the buffer to send. | |
469 | * @param: count, the number of bytes to send. | |
470 | * @return: In case of success the number of bytes sent. | |
471 | * In other case, a < 0 value describing the issue. | |
472 | */ | |
473 | static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, | |
474 | size_t len) | |
475 | { | |
85c5e0d4 PH |
476 | u32 status, i, size; |
477 | int burstcnt = 0; | |
3d7a7bd7 | 478 | int ret; |
251a7b08 ML |
479 | u8 data; |
480 | struct i2c_client *client; | |
b9626f32 | 481 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
482 | |
483 | if (chip == NULL) | |
484 | return -EBUSY; | |
485 | if (len < TPM_HEADER_SIZE) | |
486 | return -EBUSY; | |
487 | ||
b9626f32 CR |
488 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
489 | client = tpm_dev->client; | |
251a7b08 ML |
490 | |
491 | client->flags = 0; | |
492 | ||
493 | ret = request_locality(chip); | |
494 | if (ret < 0) | |
495 | return ret; | |
496 | ||
497 | status = tpm_stm_i2c_status(chip); | |
498 | if ((status & TPM_STS_COMMAND_READY) == 0) { | |
499 | tpm_stm_i2c_cancel(chip); | |
500 | if (wait_for_stat | |
501 | (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, | |
502 | &chip->vendor.int_queue) < 0) { | |
503 | ret = -ETIME; | |
504 | goto out_err; | |
505 | } | |
506 | } | |
507 | ||
2d089f82 | 508 | for (i = 0; i < len - 1;) { |
251a7b08 | 509 | burstcnt = get_burstcount(chip); |
85c5e0d4 PH |
510 | if (burstcnt < 0) |
511 | return burstcnt; | |
251a7b08 | 512 | size = min_t(int, len - i - 1, burstcnt); |
b9626f32 | 513 | ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size); |
251a7b08 ML |
514 | if (ret < 0) |
515 | goto out_err; | |
516 | ||
517 | i += size; | |
518 | } | |
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 | ||
b9626f32 | 526 | ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + len - 1, 1); |
251a7b08 ML |
527 | if (ret < 0) |
528 | goto out_err; | |
529 | ||
530 | status = tpm_stm_i2c_status(chip); | |
531 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | |
532 | ret = -EIO; | |
533 | goto out_err; | |
534 | } | |
535 | ||
536 | data = TPM_STS_GO; | |
b9626f32 | 537 | I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); |
251a7b08 ML |
538 | |
539 | return len; | |
540 | out_err: | |
541 | tpm_stm_i2c_cancel(chip); | |
542 | release_locality(chip); | |
543 | return ret; | |
544 | } | |
545 | ||
546 | /* | |
547 | * tpm_stm_i2c_recv received TPM response through the I2C bus. | |
548 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. | |
549 | * @param: buf, the buffer to store datas. | |
550 | * @param: count, the number of bytes to send. | |
551 | * @return: In case of success the number of bytes received. | |
552 | * In other case, a < 0 value describing the issue. | |
553 | */ | |
554 | static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, | |
555 | size_t count) | |
556 | { | |
557 | int size = 0; | |
558 | int expected; | |
559 | ||
251a7b08 ML |
560 | if (chip == NULL) |
561 | return -EBUSY; | |
562 | ||
563 | if (count < TPM_HEADER_SIZE) { | |
564 | size = -EIO; | |
565 | goto out; | |
566 | } | |
567 | ||
568 | size = recv_data(chip, buf, TPM_HEADER_SIZE); | |
569 | if (size < TPM_HEADER_SIZE) { | |
570 | dev_err(chip->dev, "Unable to read header\n"); | |
571 | goto out; | |
572 | } | |
573 | ||
2d089f82 | 574 | expected = be32_to_cpu(*(__be32 *)(buf + 2)); |
251a7b08 ML |
575 | if (expected > count) { |
576 | size = -EIO; | |
577 | goto out; | |
578 | } | |
579 | ||
580 | size += recv_data(chip, &buf[TPM_HEADER_SIZE], | |
581 | expected - TPM_HEADER_SIZE); | |
582 | if (size < expected) { | |
583 | dev_err(chip->dev, "Unable to read remainder of result\n"); | |
584 | size = -ETIME; | |
585 | goto out; | |
586 | } | |
587 | ||
588 | out: | |
5f82e9f0 | 589 | chip->ops->cancel(chip); |
251a7b08 ML |
590 | release_locality(chip); |
591 | return size; | |
592 | } | |
593 | ||
1f866057 SB |
594 | static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status) |
595 | { | |
2d089f82 | 596 | return (status == TPM_STS_COMMAND_READY); |
1f866057 SB |
597 | } |
598 | ||
01ad1fa7 | 599 | static const struct tpm_class_ops st_i2c_tpm = { |
251a7b08 ML |
600 | .send = tpm_stm_i2c_send, |
601 | .recv = tpm_stm_i2c_recv, | |
602 | .cancel = tpm_stm_i2c_cancel, | |
603 | .status = tpm_stm_i2c_status, | |
604 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
605 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
1f866057 | 606 | .req_canceled = tpm_st33_i2c_req_canceled, |
251a7b08 ML |
607 | }; |
608 | ||
2d089f82 | 609 | static int interrupts; |
251a7b08 ML |
610 | module_param(interrupts, int, 0444); |
611 | MODULE_PARM_DESC(interrupts, "Enable interrupts"); | |
612 | ||
613 | static int power_mgt = 1; | |
614 | module_param(power_mgt, int, 0444); | |
615 | MODULE_PARM_DESC(power_mgt, "Power Management"); | |
616 | ||
617 | /* | |
618 | * tpm_st33_i2c_probe initialize the TPM device | |
619 | * @param: client, the i2c_client drescription (TPM I2C description). | |
620 | * @param: id, the i2c_device_id struct. | |
621 | * @return: 0 in case of success. | |
622 | * -1 in other case. | |
623 | */ | |
624 | static int | |
625 | tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) | |
626 | { | |
3d7a7bd7 | 627 | int err; |
251a7b08 ML |
628 | u8 intmask; |
629 | struct tpm_chip *chip; | |
630 | struct st33zp24_platform_data *platform_data; | |
b9626f32 | 631 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 632 | |
251a7b08 | 633 | if (client == NULL) { |
1fbc5e95 KY |
634 | pr_info("%s: i2c client is NULL. Device not accessible.\n", |
635 | __func__); | |
251a7b08 ML |
636 | err = -ENODEV; |
637 | goto end; | |
638 | } | |
639 | ||
640 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | |
641 | dev_info(&client->dev, "client not i2c capable\n"); | |
642 | err = -ENODEV; | |
643 | goto end; | |
644 | } | |
645 | ||
b9626f32 CR |
646 | tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), |
647 | GFP_KERNEL); | |
648 | if (!tpm_dev) { | |
649 | err = -ENOMEM; | |
650 | goto _tpm_clean_answer; | |
251a7b08 ML |
651 | } |
652 | ||
653 | platform_data = client->dev.platform_data; | |
1fbc5e95 KY |
654 | |
655 | if (!platform_data) { | |
656 | dev_info(&client->dev, "chip not available\n"); | |
657 | err = -ENODEV; | |
658 | goto _tpm_clean_answer; | |
659 | } | |
660 | ||
b9626f32 CR |
661 | chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); |
662 | if (!chip) { | |
663 | dev_info(&client->dev, "fail chip\n"); | |
664 | return -ENODEV; | |
251a7b08 ML |
665 | } |
666 | ||
b9626f32 CR |
667 | TPM_VPRIV(chip) = tpm_dev; |
668 | tpm_dev->client = client; | |
251a7b08 ML |
669 | |
670 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | |
671 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | |
672 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | |
673 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | |
674 | ||
675 | chip->vendor.locality = LOCALITY0; | |
676 | ||
677 | if (power_mgt) { | |
678 | err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD"); | |
679 | if (err) | |
680 | goto _gpio_init1; | |
681 | gpio_set_value(platform_data->io_lpcpd, 1); | |
682 | } | |
683 | ||
684 | if (interrupts) { | |
b9626f32 | 685 | init_completion(&tpm_dev->irq_detection); |
251a7b08 ML |
686 | if (request_locality(chip) != LOCALITY0) { |
687 | err = -ENODEV; | |
b9626f32 | 688 | goto _tpm_clean_answer; |
251a7b08 | 689 | } |
251a7b08 | 690 | |
b9626f32 | 691 | clear_interruption(tpm_dev); |
76182b6b | 692 | err = request_irq(client->irq, |
251a7b08 ML |
693 | &tpm_ioserirq_handler, |
694 | IRQF_TRIGGER_HIGH, | |
695 | "TPM SERIRQ management", chip); | |
696 | if (err < 0) { | |
697 | dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", | |
76182b6b | 698 | client->irq); |
251a7b08 ML |
699 | goto _irq_set; |
700 | } | |
701 | ||
b9626f32 | 702 | err = I2C_READ_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); |
251a7b08 ML |
703 | if (err < 0) |
704 | goto _irq_set; | |
705 | ||
706 | intmask |= TPM_INTF_CMD_READY_INT | |
707 | | TPM_INTF_FIFO_AVALAIBLE_INT | |
708 | | TPM_INTF_WAKE_UP_READY_INT | |
709 | | TPM_INTF_LOCALITY_CHANGE_INT | |
710 | | TPM_INTF_STS_VALID_INT | |
711 | | TPM_INTF_DATA_AVAIL_INT; | |
712 | ||
b9626f32 | 713 | err = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); |
251a7b08 ML |
714 | if (err < 0) |
715 | goto _irq_set; | |
716 | ||
717 | intmask = TPM_GLOBAL_INT_ENABLE; | |
b9626f32 CR |
718 | err = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), |
719 | &intmask, 1); | |
251a7b08 ML |
720 | if (err < 0) |
721 | goto _irq_set; | |
722 | ||
b9626f32 | 723 | err = I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &intmask, 1); |
251a7b08 ML |
724 | if (err < 0) |
725 | goto _irq_set; | |
726 | ||
727 | chip->vendor.irq = interrupts; | |
728 | ||
729 | tpm_gen_interrupt(chip); | |
730 | } | |
731 | ||
732 | tpm_get_timeouts(chip); | |
f07a5e9a | 733 | tpm_do_selftest(chip); |
251a7b08 | 734 | |
251a7b08 ML |
735 | dev_info(chip->dev, "TPM I2C Initialized\n"); |
736 | return 0; | |
737 | _irq_set: | |
76182b6b | 738 | free_irq(client->irq, (void *)chip); |
251a7b08 | 739 | _gpio_init1: |
3d7a7bd7 | 740 | if (power_mgt) |
251a7b08 | 741 | gpio_free(platform_data->io_lpcpd); |
251a7b08 | 742 | _tpm_clean_answer: |
3d7a7bd7 | 743 | tpm_remove_hardware(chip->dev); |
251a7b08 ML |
744 | end: |
745 | pr_info("TPM I2C initialisation fail\n"); | |
746 | return err; | |
747 | } | |
748 | ||
749 | /* | |
750 | * tpm_st33_i2c_remove remove the TPM device | |
751 | * @param: client, the i2c_client drescription (TPM I2C description). | |
752 | clear_bit(0, &chip->is_open); | |
753 | * @return: 0 in case of success. | |
754 | */ | |
e02983cf | 755 | static int tpm_st33_i2c_remove(struct i2c_client *client) |
251a7b08 | 756 | { |
b9626f32 CR |
757 | struct tpm_chip *chip = |
758 | (struct tpm_chip *) i2c_get_clientdata(client); | |
251a7b08 | 759 | |
b9626f32 | 760 | if (chip) |
1fbc5e95 KY |
761 | tpm_remove_hardware(chip->dev); |
762 | ||
251a7b08 ML |
763 | return 0; |
764 | } | |
765 | ||
d4593353 | 766 | #ifdef CONFIG_PM_SLEEP |
251a7b08 ML |
767 | /* |
768 | * tpm_st33_i2c_pm_suspend suspend the TPM device | |
251a7b08 ML |
769 | * @param: client, the i2c_client drescription (TPM I2C description). |
770 | * @param: mesg, the power management message. | |
771 | * @return: 0 in case of success. | |
772 | */ | |
d4593353 | 773 | static int tpm_st33_i2c_pm_suspend(struct device *dev) |
251a7b08 | 774 | { |
d4593353 | 775 | struct st33zp24_platform_data *pin_infos = dev->platform_data; |
251a7b08 ML |
776 | int ret = 0; |
777 | ||
7500c4b9 | 778 | if (power_mgt) |
251a7b08 | 779 | gpio_set_value(pin_infos->io_lpcpd, 0); |
7500c4b9 | 780 | else |
d4593353 | 781 | ret = tpm_pm_suspend(dev); |
7500c4b9 | 782 | |
251a7b08 ML |
783 | return ret; |
784 | } /* tpm_st33_i2c_suspend() */ | |
785 | ||
786 | /* | |
787 | * tpm_st33_i2c_pm_resume resume the TPM device | |
788 | * @param: client, the i2c_client drescription (TPM I2C description). | |
789 | * @return: 0 in case of success. | |
790 | */ | |
d4593353 | 791 | static int tpm_st33_i2c_pm_resume(struct device *dev) |
251a7b08 | 792 | { |
d4593353 PH |
793 | struct tpm_chip *chip = dev_get_drvdata(dev); |
794 | struct st33zp24_platform_data *pin_infos = dev->platform_data; | |
251a7b08 ML |
795 | |
796 | int ret = 0; | |
797 | ||
798 | if (power_mgt) { | |
799 | gpio_set_value(pin_infos->io_lpcpd, 1); | |
800 | ret = wait_for_serirq_timeout(chip, | |
5f82e9f0 | 801 | (chip->ops->status(chip) & |
251a7b08 ML |
802 | TPM_STS_VALID) == TPM_STS_VALID, |
803 | chip->vendor.timeout_b); | |
2d089f82 | 804 | } else { |
2d089f82 PH |
805 | ret = tpm_pm_resume(dev); |
806 | if (!ret) | |
807 | tpm_do_selftest(chip); | |
251a7b08 ML |
808 | } |
809 | return ret; | |
810 | } /* tpm_st33_i2c_pm_resume() */ | |
d4593353 | 811 | #endif |
251a7b08 ML |
812 | |
813 | static const struct i2c_device_id tpm_st33_i2c_id[] = { | |
814 | {TPM_ST33_I2C, 0}, | |
815 | {} | |
816 | }; | |
251a7b08 | 817 | MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id); |
2d089f82 PH |
818 | static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend, |
819 | tpm_st33_i2c_pm_resume); | |
251a7b08 ML |
820 | static struct i2c_driver tpm_st33_i2c_driver = { |
821 | .driver = { | |
822 | .owner = THIS_MODULE, | |
823 | .name = TPM_ST33_I2C, | |
d4593353 | 824 | .pm = &tpm_st33_i2c_ops, |
251a7b08 ML |
825 | }, |
826 | .probe = tpm_st33_i2c_probe, | |
827 | .remove = tpm_st33_i2c_remove, | |
251a7b08 ML |
828 | .id_table = tpm_st33_i2c_id |
829 | }; | |
830 | ||
3d7a7bd7 | 831 | module_i2c_driver(tpm_st33_i2c_driver); |
251a7b08 ML |
832 | |
833 | MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)"); | |
834 | MODULE_DESCRIPTION("STM TPM I2C ST33 Driver"); | |
835 | MODULE_VERSION("1.2.0"); | |
3d7a7bd7 | 836 | MODULE_LICENSE("GPL"); |