Commit | Line | Data |
---|---|---|
251a7b08 ML |
1 | /* |
2 | * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 | |
f2f083b5 | 3 | * Copyright (C) 2009, 2010, 2014 STMicroelectronics |
251a7b08 ML |
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 | 17 | * |
f2f083b5 | 18 | * STMicroelectronics version 1.2.1, Copyright (C) 2014 |
251a7b08 ML |
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 | |
8dcd1987 | 29 | * lpc is used as model. |
251a7b08 ML |
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 | 40 | #include <linux/wait.h> |
c3804b8c | 41 | #include <linux/freezer.h> |
3d7a7bd7 KY |
42 | #include <linux/string.h> |
43 | #include <linux/interrupt.h> | |
3d7a7bd7 KY |
44 | #include <linux/sysfs.h> |
45 | #include <linux/gpio.h> | |
46 | #include <linux/sched.h> | |
47 | #include <linux/uaccess.h> | |
48 | #include <linux/io.h> | |
49 | #include <linux/slab.h> | |
c36b1b2d CR |
50 | #include <linux/of_irq.h> |
51 | #include <linux/of_gpio.h> | |
3d7a7bd7 | 52 | |
b9626f32 | 53 | #include <linux/platform_data/tpm_i2c_stm_st33.h> |
3d7a7bd7 | 54 | #include "tpm.h" |
2dbca750 CR |
55 | |
56 | #define TPM_ACCESS 0x0 | |
57 | #define TPM_STS 0x18 | |
58 | #define TPM_HASH_END 0x20 | |
59 | #define TPM_DATA_FIFO 0x24 | |
60 | #define TPM_HASH_DATA 0x24 | |
61 | #define TPM_HASH_START 0x28 | |
62 | #define TPM_INTF_CAPABILITY 0x14 | |
63 | #define TPM_INT_STATUS 0x10 | |
64 | #define TPM_INT_ENABLE 0x08 | |
65 | ||
66 | #define TPM_DUMMY_BYTE 0xAA | |
67 | #define TPM_WRITE_DIRECTION 0x80 | |
68 | #define TPM_HEADER_SIZE 10 | |
69 | #define TPM_BUFSIZE 2048 | |
70 | ||
71 | #define LOCALITY0 0 | |
b9626f32 | 72 | |
251a7b08 ML |
73 | |
74 | enum stm33zp24_access { | |
75 | TPM_ACCESS_VALID = 0x80, | |
76 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | |
77 | TPM_ACCESS_REQUEST_PENDING = 0x04, | |
78 | TPM_ACCESS_REQUEST_USE = 0x02, | |
79 | }; | |
80 | ||
81 | enum stm33zp24_status { | |
82 | TPM_STS_VALID = 0x80, | |
83 | TPM_STS_COMMAND_READY = 0x40, | |
84 | TPM_STS_GO = 0x20, | |
85 | TPM_STS_DATA_AVAIL = 0x10, | |
86 | TPM_STS_DATA_EXPECT = 0x08, | |
87 | }; | |
88 | ||
89 | enum stm33zp24_int_flags { | |
90 | TPM_GLOBAL_INT_ENABLE = 0x80, | |
91 | TPM_INTF_CMD_READY_INT = 0x080, | |
92 | TPM_INTF_FIFO_AVALAIBLE_INT = 0x040, | |
93 | TPM_INTF_WAKE_UP_READY_INT = 0x020, | |
94 | TPM_INTF_LOCALITY_CHANGE_INT = 0x004, | |
95 | TPM_INTF_STS_VALID_INT = 0x002, | |
96 | TPM_INTF_DATA_AVAIL_INT = 0x001, | |
97 | }; | |
98 | ||
99 | enum tis_defaults { | |
100 | TIS_SHORT_TIMEOUT = 750, | |
101 | TIS_LONG_TIMEOUT = 2000, | |
102 | }; | |
103 | ||
b9626f32 CR |
104 | struct tpm_stm_dev { |
105 | struct i2c_client *client; | |
b9626f32 CR |
106 | struct tpm_chip *chip; |
107 | u8 buf[TPM_BUFSIZE + 1]; | |
c3804b8c | 108 | u32 intrs; |
b9626f32 CR |
109 | int io_lpcpd; |
110 | }; | |
111 | ||
251a7b08 ML |
112 | /* |
113 | * write8_reg | |
114 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. | |
115 | * @param: tpm_register, the tpm tis register where the data should be written | |
116 | * @param: tpm_data, the tpm_data to write inside the tpm_register | |
117 | * @param: tpm_size, The length of the data | |
118 | * @return: Returns negative errno, or else the number of bytes written. | |
119 | */ | |
b9626f32 | 120 | static int write8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, |
251a7b08 ML |
121 | u8 *tpm_data, u16 tpm_size) |
122 | { | |
b9626f32 CR |
123 | tpm_dev->buf[0] = tpm_register; |
124 | memcpy(tpm_dev->buf + 1, tpm_data, tpm_size); | |
125 | return i2c_master_send(tpm_dev->client, tpm_dev->buf, tpm_size + 1); | |
251a7b08 ML |
126 | } /* write8_reg() */ |
127 | ||
128 | /* | |
129 | * read8_reg | |
130 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. | |
131 | * @param: tpm_register, the tpm tis register where the data should be read | |
132 | * @param: tpm_data, the TPM response | |
133 | * @param: tpm_size, tpm TPM response size to read. | |
134 | * @return: number of byte read successfully: should be one if success. | |
135 | */ | |
b9626f32 | 136 | static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, |
251a7b08 ML |
137 | u8 *tpm_data, int tpm_size) |
138 | { | |
139 | u8 status = 0; | |
140 | u8 data; | |
251a7b08 ML |
141 | |
142 | data = TPM_DUMMY_BYTE; | |
b9626f32 | 143 | status = write8_reg(tpm_dev, tpm_register, &data, 1); |
251a7b08 | 144 | if (status == 2) |
b9626f32 | 145 | status = i2c_master_recv(tpm_dev->client, tpm_data, tpm_size); |
251a7b08 ML |
146 | return status; |
147 | } /* read8_reg() */ | |
148 | ||
149 | /* | |
150 | * I2C_WRITE_DATA | |
151 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. | |
b9626f32 | 152 | * @param: tpm_dev, the chip description |
251a7b08 ML |
153 | * @param: tpm_register, the tpm tis register where the data should be written |
154 | * @param: tpm_data, the tpm_data to write inside the tpm_register | |
155 | * @param: tpm_size, The length of the data | |
156 | * @return: number of byte written successfully: should be one if success. | |
157 | */ | |
b9626f32 CR |
158 | #define I2C_WRITE_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ |
159 | (write8_reg(tpm_dev, tpm_register | \ | |
251a7b08 ML |
160 | TPM_WRITE_DIRECTION, tpm_data, tpm_size)) |
161 | ||
162 | /* | |
163 | * I2C_READ_DATA | |
164 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. | |
b9626f32 | 165 | * @param: tpm_dev, the chip description |
251a7b08 ML |
166 | * @param: tpm_register, the tpm tis register where the data should be read |
167 | * @param: tpm_data, the TPM response | |
168 | * @param: tpm_size, tpm TPM response size to read. | |
169 | * @return: number of byte read successfully: should be one if success. | |
170 | */ | |
b9626f32 CR |
171 | #define I2C_READ_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ |
172 | (read8_reg(tpm_dev, tpm_register, tpm_data, tpm_size)) | |
251a7b08 ML |
173 | |
174 | /* | |
175 | * clear_interruption | |
176 | * clear the TPM interrupt register. | |
177 | * @param: tpm, the chip description | |
c3804b8c | 178 | * @return: the TPM_INT_STATUS value |
251a7b08 | 179 | */ |
c3804b8c | 180 | static u8 clear_interruption(struct tpm_stm_dev *tpm_dev) |
251a7b08 ML |
181 | { |
182 | u8 interrupt; | |
7500c4b9 | 183 | |
b9626f32 CR |
184 | I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); |
185 | I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); | |
c3804b8c | 186 | return interrupt; |
251a7b08 ML |
187 | } /* clear_interruption() */ |
188 | ||
251a7b08 ML |
189 | /* |
190 | * tpm_stm_i2c_cancel, cancel is not implemented. | |
191 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h | |
192 | */ | |
193 | static void tpm_stm_i2c_cancel(struct tpm_chip *chip) | |
194 | { | |
b9626f32 | 195 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
196 | u8 data; |
197 | ||
b9626f32 | 198 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
199 | |
200 | data = TPM_STS_COMMAND_READY; | |
b9626f32 | 201 | I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); |
875edad5 | 202 | } /* tpm_stm_i2c_cancel() */ |
251a7b08 ML |
203 | |
204 | /* | |
205 | * tpm_stm_spi_status return the TPM_STS register | |
206 | * @param: chip, the tpm chip description | |
207 | * @return: the TPM_STS register value. | |
208 | */ | |
209 | static u8 tpm_stm_i2c_status(struct tpm_chip *chip) | |
210 | { | |
b9626f32 | 211 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 212 | u8 data; |
7500c4b9 | 213 | |
b9626f32 | 214 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 | 215 | |
b9626f32 | 216 | I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1); |
251a7b08 | 217 | return data; |
875edad5 | 218 | } /* tpm_stm_i2c_status() */ |
251a7b08 ML |
219 | |
220 | ||
221 | /* | |
222 | * check_locality if the locality is active | |
223 | * @param: chip, the tpm chip description | |
224 | * @return: the active locality or -EACCESS. | |
225 | */ | |
226 | static int check_locality(struct tpm_chip *chip) | |
227 | { | |
b9626f32 | 228 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
229 | u8 data; |
230 | u8 status; | |
231 | ||
b9626f32 | 232 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 | 233 | |
b9626f32 | 234 | status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1); |
251a7b08 ML |
235 | if (status && (data & |
236 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == | |
237 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) | |
238 | return chip->vendor.locality; | |
239 | ||
240 | return -EACCES; | |
241 | ||
242 | } /* check_locality() */ | |
243 | ||
244 | /* | |
245 | * request_locality request the TPM locality | |
246 | * @param: chip, the chip description | |
247 | * @return: the active locality or EACCESS. | |
248 | */ | |
249 | static int request_locality(struct tpm_chip *chip) | |
250 | { | |
251 | unsigned long stop; | |
ca16b767 | 252 | long ret; |
b9626f32 | 253 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
254 | u8 data; |
255 | ||
251a7b08 ML |
256 | if (check_locality(chip) == chip->vendor.locality) |
257 | return chip->vendor.locality; | |
258 | ||
c3804b8c CR |
259 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
260 | ||
251a7b08 | 261 | data = TPM_ACCESS_REQUEST_USE; |
ca16b767 CR |
262 | ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); |
263 | if (ret < 0) | |
251a7b08 ML |
264 | goto end; |
265 | ||
c3804b8c CR |
266 | stop = jiffies + chip->vendor.timeout_a; |
267 | ||
268 | /* Request locality is usually effective after the request */ | |
269 | do { | |
270 | if (check_locality(chip) >= 0) | |
251a7b08 | 271 | return chip->vendor.locality; |
c3804b8c CR |
272 | msleep(TPM_TIMEOUT); |
273 | } while (time_before(jiffies, stop)); | |
ca16b767 | 274 | ret = -EACCES; |
251a7b08 | 275 | end: |
ca16b767 | 276 | return ret; |
251a7b08 ML |
277 | } /* request_locality() */ |
278 | ||
279 | /* | |
280 | * release_locality release the active locality | |
281 | * @param: chip, the tpm chip description. | |
282 | */ | |
283 | static void release_locality(struct tpm_chip *chip) | |
284 | { | |
b9626f32 | 285 | struct tpm_stm_dev *tpm_dev; |
251a7b08 ML |
286 | u8 data; |
287 | ||
b9626f32 | 288 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
289 | data = TPM_ACCESS_ACTIVE_LOCALITY; |
290 | ||
b9626f32 | 291 | I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); |
251a7b08 ML |
292 | } |
293 | ||
294 | /* | |
295 | * get_burstcount return the burstcount address 0x19 0x1A | |
296 | * @param: chip, the chip description | |
297 | * return: the burstcount. | |
298 | */ | |
299 | static int get_burstcount(struct tpm_chip *chip) | |
300 | { | |
301 | unsigned long stop; | |
302 | int burstcnt, status; | |
303 | u8 tpm_reg, temp; | |
b9626f32 | 304 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 305 | |
b9626f32 | 306 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
307 | |
308 | stop = jiffies + chip->vendor.timeout_d; | |
309 | do { | |
310 | tpm_reg = TPM_STS + 1; | |
b9626f32 | 311 | status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); |
251a7b08 ML |
312 | if (status < 0) |
313 | goto end; | |
314 | ||
315 | tpm_reg = tpm_reg + 1; | |
316 | burstcnt = temp; | |
b9626f32 | 317 | status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); |
251a7b08 ML |
318 | if (status < 0) |
319 | goto end; | |
320 | ||
321 | burstcnt |= temp << 8; | |
322 | if (burstcnt) | |
323 | return burstcnt; | |
324 | msleep(TPM_TIMEOUT); | |
325 | } while (time_before(jiffies, stop)); | |
326 | ||
327 | end: | |
328 | return -EBUSY; | |
329 | } /* get_burstcount() */ | |
330 | ||
c3804b8c CR |
331 | static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, |
332 | bool check_cancel, bool *canceled) | |
333 | { | |
334 | u8 status = chip->ops->status(chip); | |
335 | ||
336 | *canceled = false; | |
337 | if ((status & mask) == mask) | |
338 | return true; | |
339 | if (check_cancel && chip->ops->req_canceled(chip, status)) { | |
340 | *canceled = true; | |
341 | return true; | |
342 | } | |
343 | return false; | |
344 | } | |
345 | ||
346 | /* | |
347 | * interrupt_to_status | |
348 | * @param: irq_mask, the irq mask value to wait | |
349 | * @return: the corresponding tpm_sts value | |
350 | */ | |
351 | static u8 interrupt_to_status(u8 irq_mask) | |
352 | { | |
353 | u8 status = 0; | |
354 | ||
355 | if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT) | |
356 | status |= TPM_STS_VALID; | |
357 | if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT) | |
358 | status |= TPM_STS_DATA_AVAIL; | |
359 | if ((irq_mask & TPM_INTF_CMD_READY_INT) == TPM_INTF_CMD_READY_INT) | |
360 | status |= TPM_STS_COMMAND_READY; | |
361 | ||
362 | return status; | |
363 | } /* status_to_interrupt() */ | |
364 | ||
251a7b08 ML |
365 | /* |
366 | * wait_for_stat wait for a TPM_STS value | |
367 | * @param: chip, the tpm chip description | |
368 | * @param: mask, the value mask to wait | |
369 | * @param: timeout, the timeout | |
370 | * @param: queue, the wait queue. | |
c3804b8c | 371 | * @param: check_cancel, does the command can be cancelled ? |
251a7b08 ML |
372 | * @return: the tpm status, 0 if success, -ETIME if timeout is reached. |
373 | */ | |
374 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | |
c3804b8c | 375 | wait_queue_head_t *queue, bool check_cancel) |
251a7b08 ML |
376 | { |
377 | unsigned long stop; | |
c3804b8c CR |
378 | int r; |
379 | bool canceled = false; | |
380 | bool condition; | |
381 | u32 cur_intrs; | |
382 | u8 interrupt, status; | |
383 | struct tpm_stm_dev *tpm_dev; | |
384 | ||
385 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); | |
386 | ||
387 | /* check current status */ | |
388 | status = tpm_stm_i2c_status(chip); | |
389 | if ((status & mask) == mask) | |
390 | return 0; | |
391 | ||
392 | stop = jiffies + timeout; | |
251a7b08 | 393 | |
8dcd1987 | 394 | if (chip->vendor.irq) { |
c3804b8c CR |
395 | cur_intrs = tpm_dev->intrs; |
396 | interrupt = clear_interruption(tpm_dev); | |
397 | enable_irq(chip->vendor.irq); | |
398 | ||
399 | again: | |
400 | timeout = stop - jiffies; | |
401 | if ((long) timeout <= 0) | |
402 | return -1; | |
403 | ||
404 | r = wait_event_interruptible_timeout(*queue, | |
405 | cur_intrs != tpm_dev->intrs, timeout); | |
406 | ||
407 | interrupt |= clear_interruption(tpm_dev); | |
408 | status = interrupt_to_status(interrupt); | |
409 | condition = wait_for_tpm_stat_cond(chip, mask, | |
410 | check_cancel, &canceled); | |
411 | ||
412 | if (r >= 0 && condition) { | |
413 | if (canceled) | |
414 | return -ECANCELED; | |
251a7b08 | 415 | return 0; |
c3804b8c CR |
416 | } |
417 | if (r == -ERESTARTSYS && freezing(current)) { | |
418 | clear_thread_flag(TIF_SIGPENDING); | |
419 | goto again; | |
420 | } | |
421 | disable_irq_nosync(chip->vendor.irq); | |
422 | ||
2d089f82 | 423 | } else { |
251a7b08 ML |
424 | do { |
425 | msleep(TPM_TIMEOUT); | |
c3804b8c | 426 | status = chip->ops->status(chip); |
251a7b08 ML |
427 | if ((status & mask) == mask) |
428 | return 0; | |
429 | } while (time_before(jiffies, stop)); | |
430 | } | |
c3804b8c | 431 | |
251a7b08 ML |
432 | return -ETIME; |
433 | } /* wait_for_stat() */ | |
434 | ||
435 | /* | |
436 | * recv_data receive data | |
437 | * @param: chip, the tpm chip description | |
438 | * @param: buf, the buffer where the data are received | |
439 | * @param: count, the number of data to receive | |
440 | * @return: the number of bytes read from TPM FIFO. | |
441 | */ | |
442 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | |
443 | { | |
444 | int size = 0, burstcnt, len; | |
b9626f32 | 445 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 446 | |
b9626f32 | 447 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 ML |
448 | |
449 | while (size < count && | |
450 | wait_for_stat(chip, | |
451 | TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
452 | chip->vendor.timeout_c, | |
c3804b8c | 453 | &chip->vendor.read_queue, true) == 0) { |
251a7b08 | 454 | burstcnt = get_burstcount(chip); |
85c5e0d4 PH |
455 | if (burstcnt < 0) |
456 | return burstcnt; | |
251a7b08 | 457 | len = min_t(int, burstcnt, count - size); |
b9626f32 | 458 | I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len); |
251a7b08 ML |
459 | size += len; |
460 | } | |
461 | return size; | |
462 | } | |
463 | ||
464 | /* | |
465 | * tpm_ioserirq_handler the serirq irq handler | |
466 | * @param: irq, the tpm chip description | |
467 | * @param: dev_id, the description of the chip | |
468 | * @return: the status of the handler. | |
469 | */ | |
470 | static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) | |
471 | { | |
472 | struct tpm_chip *chip = dev_id; | |
b9626f32 | 473 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 474 | |
b9626f32 | 475 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
251a7b08 | 476 | |
c3804b8c CR |
477 | tpm_dev->intrs++; |
478 | wake_up_interruptible(&chip->vendor.read_queue); | |
479 | disable_irq_nosync(chip->vendor.irq); | |
480 | ||
251a7b08 ML |
481 | return IRQ_HANDLED; |
482 | } /* tpm_ioserirq_handler() */ | |
483 | ||
484 | ||
485 | /* | |
486 | * tpm_stm_i2c_send send TPM commands through the I2C bus. | |
487 | * | |
488 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h | |
489 | * @param: buf, the buffer to send. | |
490 | * @param: count, the number of bytes to send. | |
491 | * @return: In case of success the number of bytes sent. | |
492 | * In other case, a < 0 value describing the issue. | |
493 | */ | |
494 | static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, | |
495 | size_t len) | |
496 | { | |
85c5e0d4 PH |
497 | u32 status, i, size; |
498 | int burstcnt = 0; | |
3d7a7bd7 | 499 | int ret; |
251a7b08 ML |
500 | u8 data; |
501 | struct i2c_client *client; | |
b9626f32 | 502 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 503 | |
8dcd1987 | 504 | if (!chip) |
251a7b08 ML |
505 | return -EBUSY; |
506 | if (len < TPM_HEADER_SIZE) | |
507 | return -EBUSY; | |
508 | ||
b9626f32 CR |
509 | tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); |
510 | client = tpm_dev->client; | |
251a7b08 ML |
511 | |
512 | client->flags = 0; | |
513 | ||
514 | ret = request_locality(chip); | |
515 | if (ret < 0) | |
516 | return ret; | |
517 | ||
518 | status = tpm_stm_i2c_status(chip); | |
519 | if ((status & TPM_STS_COMMAND_READY) == 0) { | |
520 | tpm_stm_i2c_cancel(chip); | |
521 | if (wait_for_stat | |
522 | (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, | |
c3804b8c | 523 | &chip->vendor.read_queue, false) < 0) { |
251a7b08 ML |
524 | ret = -ETIME; |
525 | goto out_err; | |
526 | } | |
527 | } | |
528 | ||
2d089f82 | 529 | for (i = 0; i < len - 1;) { |
251a7b08 | 530 | burstcnt = get_burstcount(chip); |
85c5e0d4 PH |
531 | if (burstcnt < 0) |
532 | return burstcnt; | |
251a7b08 | 533 | size = min_t(int, len - i - 1, burstcnt); |
b9626f32 | 534 | ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size); |
251a7b08 ML |
535 | if (ret < 0) |
536 | goto out_err; | |
537 | ||
538 | i += size; | |
539 | } | |
540 | ||
541 | status = tpm_stm_i2c_status(chip); | |
542 | if ((status & TPM_STS_DATA_EXPECT) == 0) { | |
543 | ret = -EIO; | |
544 | goto out_err; | |
545 | } | |
546 | ||
b9626f32 | 547 | ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + len - 1, 1); |
251a7b08 ML |
548 | if (ret < 0) |
549 | goto out_err; | |
550 | ||
551 | status = tpm_stm_i2c_status(chip); | |
552 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | |
553 | ret = -EIO; | |
554 | goto out_err; | |
555 | } | |
556 | ||
557 | data = TPM_STS_GO; | |
b9626f32 | 558 | I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); |
251a7b08 ML |
559 | |
560 | return len; | |
561 | out_err: | |
562 | tpm_stm_i2c_cancel(chip); | |
563 | release_locality(chip); | |
564 | return ret; | |
565 | } | |
566 | ||
567 | /* | |
568 | * tpm_stm_i2c_recv received TPM response through the I2C bus. | |
569 | * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. | |
570 | * @param: buf, the buffer to store datas. | |
571 | * @param: count, the number of bytes to send. | |
572 | * @return: In case of success the number of bytes received. | |
573 | * In other case, a < 0 value describing the issue. | |
574 | */ | |
575 | static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, | |
576 | size_t count) | |
577 | { | |
578 | int size = 0; | |
579 | int expected; | |
580 | ||
8dcd1987 | 581 | if (!chip) |
251a7b08 ML |
582 | return -EBUSY; |
583 | ||
584 | if (count < TPM_HEADER_SIZE) { | |
585 | size = -EIO; | |
586 | goto out; | |
587 | } | |
588 | ||
589 | size = recv_data(chip, buf, TPM_HEADER_SIZE); | |
590 | if (size < TPM_HEADER_SIZE) { | |
591 | dev_err(chip->dev, "Unable to read header\n"); | |
592 | goto out; | |
593 | } | |
594 | ||
2d089f82 | 595 | expected = be32_to_cpu(*(__be32 *)(buf + 2)); |
251a7b08 ML |
596 | if (expected > count) { |
597 | size = -EIO; | |
598 | goto out; | |
599 | } | |
600 | ||
601 | size += recv_data(chip, &buf[TPM_HEADER_SIZE], | |
8dcd1987 | 602 | expected - TPM_HEADER_SIZE); |
251a7b08 ML |
603 | if (size < expected) { |
604 | dev_err(chip->dev, "Unable to read remainder of result\n"); | |
605 | size = -ETIME; | |
606 | goto out; | |
607 | } | |
608 | ||
609 | out: | |
5f82e9f0 | 610 | chip->ops->cancel(chip); |
251a7b08 ML |
611 | release_locality(chip); |
612 | return size; | |
613 | } | |
614 | ||
875edad5 | 615 | static bool tpm_stm_i2c_req_canceled(struct tpm_chip *chip, u8 status) |
1f866057 | 616 | { |
2d089f82 | 617 | return (status == TPM_STS_COMMAND_READY); |
1f866057 SB |
618 | } |
619 | ||
01ad1fa7 | 620 | static const struct tpm_class_ops st_i2c_tpm = { |
251a7b08 ML |
621 | .send = tpm_stm_i2c_send, |
622 | .recv = tpm_stm_i2c_recv, | |
623 | .cancel = tpm_stm_i2c_cancel, | |
624 | .status = tpm_stm_i2c_status, | |
625 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
626 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | |
875edad5 | 627 | .req_canceled = tpm_stm_i2c_req_canceled, |
251a7b08 ML |
628 | }; |
629 | ||
c36b1b2d CR |
630 | #ifdef CONFIG_OF |
631 | static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) | |
632 | { | |
633 | struct device_node *pp; | |
634 | struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); | |
635 | struct i2c_client *client = tpm_dev->client; | |
636 | ||
637 | int gpio; | |
638 | int ret; | |
639 | ||
640 | pp = client->dev.of_node; | |
641 | if (!pp) { | |
642 | dev_err(chip->dev, "No platform data\n"); | |
643 | return -ENODEV; | |
644 | } | |
645 | ||
646 | /* Get GPIO from device tree */ | |
647 | gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); | |
648 | if (gpio < 0) { | |
649 | dev_err(chip->dev, "Failed to retrieve lpcpd-gpios from dts.\n"); | |
650 | tpm_dev->io_lpcpd = -1; | |
651 | /* | |
652 | * lpcpd pin is not specified. This is not an issue as | |
653 | * power management can be also managed by TPM specific | |
654 | * commands. So leave with a success status code. | |
655 | */ | |
656 | return 0; | |
657 | } | |
658 | /* GPIO request and configuration */ | |
659 | ret = devm_gpio_request_one(&client->dev, gpio, | |
660 | GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); | |
661 | if (ret) { | |
662 | dev_err(chip->dev, "Failed to request lpcpd pin\n"); | |
663 | return -ENODEV; | |
664 | } | |
665 | tpm_dev->io_lpcpd = gpio; | |
666 | ||
667 | return 0; | |
668 | } | |
669 | #else | |
670 | static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) | |
671 | { | |
672 | return -ENODEV; | |
673 | } | |
674 | #endif | |
675 | ||
676 | static int tpm_stm_i2c_request_resources(struct i2c_client *client, | |
677 | struct tpm_chip *chip) | |
678 | { | |
679 | struct st33zp24_platform_data *pdata; | |
680 | struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); | |
681 | int ret; | |
682 | ||
683 | pdata = client->dev.platform_data; | |
8dcd1987 CR |
684 | if (!pdata) { |
685 | dev_err(chip->dev, "No platform data\n"); | |
686 | return -ENODEV; | |
c36b1b2d | 687 | } |
251a7b08 | 688 | |
c36b1b2d CR |
689 | /* store for late use */ |
690 | tpm_dev->io_lpcpd = pdata->io_lpcpd; | |
691 | ||
692 | if (gpio_is_valid(pdata->io_lpcpd)) { | |
693 | ret = devm_gpio_request_one(&client->dev, | |
694 | pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, | |
695 | "TPM IO_LPCPD"); | |
696 | if (ret) { | |
697 | dev_err(chip->dev, "%s : reset gpio_request failed\n", | |
698 | __FILE__); | |
699 | return ret; | |
700 | } | |
701 | } | |
702 | ||
703 | return 0; | |
704 | } | |
251a7b08 ML |
705 | |
706 | /* | |
875edad5 | 707 | * tpm_stm_i2c_probe initialize the TPM device |
251a7b08 ML |
708 | * @param: client, the i2c_client drescription (TPM I2C description). |
709 | * @param: id, the i2c_device_id struct. | |
710 | * @return: 0 in case of success. | |
711 | * -1 in other case. | |
712 | */ | |
713 | static int | |
875edad5 | 714 | tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) |
251a7b08 | 715 | { |
ca16b767 | 716 | int ret; |
8dcd1987 | 717 | u8 intmask = 0; |
251a7b08 ML |
718 | struct tpm_chip *chip; |
719 | struct st33zp24_platform_data *platform_data; | |
b9626f32 | 720 | struct tpm_stm_dev *tpm_dev; |
251a7b08 | 721 | |
8dcd1987 | 722 | if (!client) { |
67fe9417 | 723 | pr_info("%s: i2c client is NULL. Device not accessible.\n", |
1fbc5e95 | 724 | __func__); |
c36b1b2d | 725 | return -ENODEV; |
251a7b08 ML |
726 | } |
727 | ||
728 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | |
729 | dev_info(&client->dev, "client not i2c capable\n"); | |
c36b1b2d | 730 | return -ENODEV; |
251a7b08 ML |
731 | } |
732 | ||
b9626f32 CR |
733 | tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), |
734 | GFP_KERNEL); | |
c36b1b2d CR |
735 | if (!tpm_dev) |
736 | return -ENOMEM; | |
1fbc5e95 | 737 | |
afb5abc2 JS |
738 | chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm); |
739 | if (IS_ERR(chip)) | |
740 | return PTR_ERR(chip); | |
251a7b08 | 741 | |
b9626f32 CR |
742 | TPM_VPRIV(chip) = tpm_dev; |
743 | tpm_dev->client = client; | |
251a7b08 | 744 | |
c36b1b2d CR |
745 | platform_data = client->dev.platform_data; |
746 | if (!platform_data && client->dev.of_node) { | |
747 | ret = tpm_stm_i2c_of_request_resources(chip); | |
748 | if (ret) | |
749 | goto _tpm_clean_answer; | |
750 | } else if (platform_data) { | |
751 | ret = tpm_stm_i2c_request_resources(client, chip); | |
752 | if (ret) | |
753 | goto _tpm_clean_answer; | |
754 | } | |
755 | ||
251a7b08 ML |
756 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); |
757 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | |
758 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | |
759 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | |
760 | ||
761 | chip->vendor.locality = LOCALITY0; | |
762 | ||
c36b1b2d | 763 | if (client->irq) { |
c3804b8c CR |
764 | /* INTERRUPT Setup */ |
765 | init_waitqueue_head(&chip->vendor.read_queue); | |
766 | tpm_dev->intrs = 0; | |
767 | ||
251a7b08 | 768 | if (request_locality(chip) != LOCALITY0) { |
ca16b767 | 769 | ret = -ENODEV; |
b9626f32 | 770 | goto _tpm_clean_answer; |
251a7b08 | 771 | } |
251a7b08 | 772 | |
b9626f32 | 773 | clear_interruption(tpm_dev); |
c36b1b2d CR |
774 | ret = devm_request_irq(&client->dev, client->irq, |
775 | tpm_ioserirq_handler, | |
251a7b08 ML |
776 | IRQF_TRIGGER_HIGH, |
777 | "TPM SERIRQ management", chip); | |
ca16b767 | 778 | if (ret < 0) { |
251a7b08 | 779 | dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", |
76182b6b | 780 | client->irq); |
c36b1b2d | 781 | goto _tpm_clean_answer; |
251a7b08 ML |
782 | } |
783 | ||
251a7b08 | 784 | intmask |= TPM_INTF_CMD_READY_INT |
251a7b08 ML |
785 | | TPM_INTF_STS_VALID_INT |
786 | | TPM_INTF_DATA_AVAIL_INT; | |
787 | ||
ca16b767 CR |
788 | ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); |
789 | if (ret < 0) | |
c36b1b2d | 790 | goto _tpm_clean_answer; |
251a7b08 ML |
791 | |
792 | intmask = TPM_GLOBAL_INT_ENABLE; | |
ca16b767 | 793 | ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), |
b9626f32 | 794 | &intmask, 1); |
ca16b767 | 795 | if (ret < 0) |
c36b1b2d | 796 | goto _tpm_clean_answer; |
251a7b08 | 797 | |
c36b1b2d | 798 | chip->vendor.irq = client->irq; |
251a7b08 | 799 | |
c3804b8c CR |
800 | disable_irq_nosync(chip->vendor.irq); |
801 | ||
251a7b08 ML |
802 | tpm_gen_interrupt(chip); |
803 | } | |
804 | ||
805 | tpm_get_timeouts(chip); | |
f07a5e9a | 806 | tpm_do_selftest(chip); |
251a7b08 | 807 | |
afb5abc2 | 808 | return tpm_chip_register(chip); |
251a7b08 | 809 | _tpm_clean_answer: |
c36b1b2d | 810 | dev_info(chip->dev, "TPM I2C initialisation fail\n"); |
ca16b767 | 811 | return ret; |
251a7b08 ML |
812 | } |
813 | ||
814 | /* | |
875edad5 | 815 | * tpm_stm_i2c_remove remove the TPM device |
251a7b08 | 816 | * @param: client, the i2c_client drescription (TPM I2C description). |
8dcd1987 | 817 | * clear_bit(0, &chip->is_open); |
251a7b08 ML |
818 | * @return: 0 in case of success. |
819 | */ | |
875edad5 | 820 | static int tpm_stm_i2c_remove(struct i2c_client *client) |
251a7b08 | 821 | { |
b9626f32 CR |
822 | struct tpm_chip *chip = |
823 | (struct tpm_chip *) i2c_get_clientdata(client); | |
251a7b08 | 824 | |
b9626f32 | 825 | if (chip) |
afb5abc2 | 826 | tpm_chip_unregister(chip); |
1fbc5e95 | 827 | |
251a7b08 ML |
828 | return 0; |
829 | } | |
830 | ||
d4593353 | 831 | #ifdef CONFIG_PM_SLEEP |
251a7b08 | 832 | /* |
875edad5 | 833 | * tpm_stm_i2c_pm_suspend suspend the TPM device |
251a7b08 ML |
834 | * @param: client, the i2c_client drescription (TPM I2C description). |
835 | * @param: mesg, the power management message. | |
836 | * @return: 0 in case of success. | |
837 | */ | |
875edad5 | 838 | static int tpm_stm_i2c_pm_suspend(struct device *dev) |
251a7b08 | 839 | { |
d4593353 | 840 | struct st33zp24_platform_data *pin_infos = dev->platform_data; |
251a7b08 ML |
841 | int ret = 0; |
842 | ||
c36b1b2d | 843 | if (gpio_is_valid(pin_infos->io_lpcpd)) |
251a7b08 | 844 | gpio_set_value(pin_infos->io_lpcpd, 0); |
7500c4b9 | 845 | else |
d4593353 | 846 | ret = tpm_pm_suspend(dev); |
8dcd1987 | 847 | |
251a7b08 | 848 | return ret; |
875edad5 | 849 | } /* tpm_stm_i2c_suspend() */ |
251a7b08 ML |
850 | |
851 | /* | |
875edad5 | 852 | * tpm_stm_i2c_pm_resume resume the TPM device |
251a7b08 ML |
853 | * @param: client, the i2c_client drescription (TPM I2C description). |
854 | * @return: 0 in case of success. | |
855 | */ | |
875edad5 | 856 | static int tpm_stm_i2c_pm_resume(struct device *dev) |
251a7b08 | 857 | { |
d4593353 PH |
858 | struct tpm_chip *chip = dev_get_drvdata(dev); |
859 | struct st33zp24_platform_data *pin_infos = dev->platform_data; | |
251a7b08 ML |
860 | |
861 | int ret = 0; | |
862 | ||
c36b1b2d | 863 | if (gpio_is_valid(pin_infos->io_lpcpd)) { |
251a7b08 | 864 | gpio_set_value(pin_infos->io_lpcpd, 1); |
c3804b8c CR |
865 | ret = wait_for_stat(chip, |
866 | TPM_STS_VALID, chip->vendor.timeout_b, | |
867 | &chip->vendor.read_queue, false); | |
2d089f82 | 868 | } else { |
2d089f82 PH |
869 | ret = tpm_pm_resume(dev); |
870 | if (!ret) | |
871 | tpm_do_selftest(chip); | |
251a7b08 ML |
872 | } |
873 | return ret; | |
875edad5 | 874 | } /* tpm_stm_i2c_pm_resume() */ |
d4593353 | 875 | #endif |
251a7b08 | 876 | |
875edad5 | 877 | static const struct i2c_device_id tpm_stm_i2c_id[] = { |
251a7b08 ML |
878 | {TPM_ST33_I2C, 0}, |
879 | {} | |
880 | }; | |
8dcd1987 | 881 | MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id); |
c36b1b2d CR |
882 | |
883 | #ifdef CONFIG_OF | |
884 | static const struct of_device_id of_st33zp24_i2c_match[] = { | |
885 | { .compatible = "st,st33zp24-i2c", }, | |
886 | {} | |
887 | }; | |
888 | MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); | |
889 | #endif | |
890 | ||
875edad5 CR |
891 | static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend, |
892 | tpm_stm_i2c_pm_resume); | |
893 | static struct i2c_driver tpm_stm_i2c_driver = { | |
251a7b08 | 894 | .driver = { |
c36b1b2d CR |
895 | .owner = THIS_MODULE, |
896 | .name = TPM_ST33_I2C, | |
897 | .pm = &tpm_stm_i2c_ops, | |
898 | .of_match_table = of_match_ptr(of_st33zp24_i2c_match), | |
8dcd1987 | 899 | }, |
875edad5 CR |
900 | .probe = tpm_stm_i2c_probe, |
901 | .remove = tpm_stm_i2c_remove, | |
902 | .id_table = tpm_stm_i2c_id | |
251a7b08 ML |
903 | }; |
904 | ||
875edad5 | 905 | module_i2c_driver(tpm_stm_i2c_driver); |
251a7b08 ML |
906 | |
907 | MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)"); | |
908 | MODULE_DESCRIPTION("STM TPM I2C ST33 Driver"); | |
f2f083b5 | 909 | MODULE_VERSION("1.2.1"); |
3d7a7bd7 | 910 | MODULE_LICENSE("GPL"); |