1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Description:
4 * Device Driver for the Infineon Technologies
5 * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
6 * Specifications at www.trustedcomputinggroup.org
7 *
8 * Copyright (C) 2005, Marcel Selhorst <tpmdd@selhorst.net>
9 * Sirrix AG - security technologies <tpmdd@sirrix.com> and
10 * Applied Data Security Group, Ruhr-University Bochum, Germany
11 * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/
12 */
13
14 #include <linux/init.h>
15 #include <linux/pnp.h>
16 #include "tpm.h"
17
18 /* Infineon specific definitions */
19 /* maximum number of WTX-packages */
20 #define TPM_MAX_WTX_PACKAGES 50
21 /* msleep-Time for WTX-packages */
22 #define TPM_WTX_MSLEEP_TIME 20
23 /* msleep-Time --> Interval to check status register */
24 #define TPM_MSLEEP_TIME 3
25 /* gives number of max. msleep()-calls before throwing timeout */
26 #define TPM_MAX_TRIES 5000
27 #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1
28
29 #define TPM_INF_IO_PORT 0x0
30 #define TPM_INF_IO_MEM 0x1
31
32 #define TPM_INF_ADDR 0x0
33 #define TPM_INF_DATA 0x1
34
35 struct tpm_inf_dev {
36 int iotype;
37
38 void __iomem *mem_base; /* MMIO ioremap'd addr */
39 unsigned long map_base; /* phys MMIO base */
40 unsigned long map_size; /* MMIO region size */
41 unsigned int index_off; /* index register offset */
42
43 unsigned int data_regs; /* Data registers */
44 unsigned int data_size;
45
46 unsigned int config_port; /* IO Port config index reg */
47 unsigned int config_size;
48 };
49
50 static struct tpm_inf_dev tpm_dev;
51
tpm_data_out(unsigned char data,unsigned char offset)52 static inline void tpm_data_out(unsigned char data, unsigned char offset)
53 {
54 #ifdef CONFIG_HAS_IOPORT
55 if (tpm_dev.iotype == TPM_INF_IO_PORT)
56 outb(data, tpm_dev.data_regs + offset);
57 else
58 #endif
59 writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
60 }
61
tpm_data_in(unsigned char offset)62 static inline unsigned char tpm_data_in(unsigned char offset)
63 {
64 #ifdef CONFIG_HAS_IOPORT
65 if (tpm_dev.iotype == TPM_INF_IO_PORT)
66 return inb(tpm_dev.data_regs + offset);
67 #endif
68 return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
69 }
70
tpm_config_out(unsigned char data,unsigned char offset)71 static inline void tpm_config_out(unsigned char data, unsigned char offset)
72 {
73 #ifdef CONFIG_HAS_IOPORT
74 if (tpm_dev.iotype == TPM_INF_IO_PORT)
75 outb(data, tpm_dev.config_port + offset);
76 else
77 #endif
78 writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
79 }
80
tpm_config_in(unsigned char offset)81 static inline unsigned char tpm_config_in(unsigned char offset)
82 {
83 #ifdef CONFIG_HAS_IOPORT
84 if (tpm_dev.iotype == TPM_INF_IO_PORT)
85 return inb(tpm_dev.config_port + offset);
86 #endif
87 return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
88 }
89
90 /* TPM header definitions */
91 enum infineon_tpm_header {
92 TPM_VL_VER = 0x01,
93 TPM_VL_CHANNEL_CONTROL = 0x07,
94 TPM_VL_CHANNEL_PERSONALISATION = 0x0A,
95 TPM_VL_CHANNEL_TPM = 0x0B,
96 TPM_VL_CONTROL = 0x00,
97 TPM_INF_NAK = 0x15,
98 TPM_CTRL_WTX = 0x10,
99 TPM_CTRL_WTX_ABORT = 0x18,
100 TPM_CTRL_WTX_ABORT_ACK = 0x18,
101 TPM_CTRL_ERROR = 0x20,
102 TPM_CTRL_CHAININGACK = 0x40,
103 TPM_CTRL_CHAINING = 0x80,
104 TPM_CTRL_DATA = 0x04,
105 TPM_CTRL_DATA_CHA = 0x84,
106 TPM_CTRL_DATA_CHA_ACK = 0xC4
107 };
108
109 enum infineon_tpm_register {
110 WRFIFO = 0x00,
111 RDFIFO = 0x01,
112 STAT = 0x02,
113 CMD = 0x03
114 };
115
116 enum infineon_tpm_command_bits {
117 CMD_DIS = 0x00,
118 CMD_LP = 0x01,
119 CMD_RES = 0x02,
120 CMD_IRQC = 0x06
121 };
122
123 enum infineon_tpm_status_bits {
124 STAT_XFE = 0x00,
125 STAT_LPA = 0x01,
126 STAT_FOK = 0x02,
127 STAT_TOK = 0x03,
128 STAT_IRQA = 0x06,
129 STAT_RDA = 0x07
130 };
131
132 /* some outgoing values */
133 enum infineon_tpm_values {
134 CHIP_ID1 = 0x20,
135 CHIP_ID2 = 0x21,
136 TPM_DAR = 0x30,
137 RESET_LP_IRQC_DISABLE = 0x41,
138 ENABLE_REGISTER_PAIR = 0x55,
139 IOLIMH = 0x60,
140 IOLIML = 0x61,
141 DISABLE_REGISTER_PAIR = 0xAA,
142 IDVENL = 0xF1,
143 IDVENH = 0xF2,
144 IDPDL = 0xF3,
145 IDPDH = 0xF4
146 };
147
148 static int number_of_wtx;
149
empty_fifo(struct tpm_chip * chip,int clear_wrfifo)150 static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
151 {
152 int status;
153 int check = 0;
154 int i;
155
156 if (clear_wrfifo) {
157 for (i = 0; i < 4096; i++) {
158 status = tpm_data_in(WRFIFO);
159 if (status == 0xff) {
160 if (check == 5)
161 break;
162 else
163 check++;
164 }
165 }
166 }
167 /* Note: The values which are currently in the FIFO of the TPM
168 are thrown away since there is no usage for them. Usually,
169 this has nothing to say, since the TPM will give its answer
170 immediately or will be aborted anyway, so the data here is
171 usually garbage and useless.
172 We have to clean this, because the next communication with
173 the TPM would be rubbish, if there is still some old data
174 in the Read FIFO.
175 */
176 i = 0;
177 do {
178 status = tpm_data_in(RDFIFO);
179 status = tpm_data_in(STAT);
180 i++;
181 if (i == TPM_MAX_TRIES)
182 return -EIO;
183 } while ((status & (1 << STAT_RDA)) != 0);
184 return 0;
185 }
186
wait(struct tpm_chip * chip,int wait_for_bit)187 static int wait(struct tpm_chip *chip, int wait_for_bit)
188 {
189 int status;
190 int i;
191 for (i = 0; i < TPM_MAX_TRIES; i++) {
192 status = tpm_data_in(STAT);
193 /* check the status-register if wait_for_bit is set */
194 if (status & 1 << wait_for_bit)
195 break;
196 tpm_msleep(TPM_MSLEEP_TIME);
197 }
198 if (i == TPM_MAX_TRIES) { /* timeout occurs */
199 if (wait_for_bit == STAT_XFE)
200 dev_err(&chip->dev, "Timeout in wait(STAT_XFE)\n");
201 if (wait_for_bit == STAT_RDA)
202 dev_err(&chip->dev, "Timeout in wait(STAT_RDA)\n");
203 return -EIO;
204 }
205 return 0;
206 };
207
wait_and_send(struct tpm_chip * chip,u8 sendbyte)208 static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
209 {
210 wait(chip, STAT_XFE);
211 tpm_data_out(sendbyte, WRFIFO);
212 }
213
214 /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
215 calculation time, it sends a WTX-package, which has to be acknowledged
216 or aborted. This usually occurs if you are hammering the TPM with key
217 creation. Set the maximum number of WTX-packages in the definitions
218 above, if the number is reached, the waiting-time will be denied
219 and the TPM command has to be resend.
220 */
221
tpm_wtx(struct tpm_chip * chip)222 static void tpm_wtx(struct tpm_chip *chip)
223 {
224 number_of_wtx++;
225 dev_info(&chip->dev, "Granting WTX (%02d / %02d)\n",
226 number_of_wtx, TPM_MAX_WTX_PACKAGES);
227 wait_and_send(chip, TPM_VL_VER);
228 wait_and_send(chip, TPM_CTRL_WTX);
229 wait_and_send(chip, 0x00);
230 wait_and_send(chip, 0x00);
231 tpm_msleep(TPM_WTX_MSLEEP_TIME);
232 }
233
tpm_wtx_abort(struct tpm_chip * chip)234 static void tpm_wtx_abort(struct tpm_chip *chip)
235 {
236 dev_info(&chip->dev, "Aborting WTX\n");
237 wait_and_send(chip, TPM_VL_VER);
238 wait_and_send(chip, TPM_CTRL_WTX_ABORT);
239 wait_and_send(chip, 0x00);
240 wait_and_send(chip, 0x00);
241 number_of_wtx = 0;
242 tpm_msleep(TPM_WTX_MSLEEP_TIME);
243 }
244
tpm_inf_recv(struct tpm_chip * chip,u8 * buf,size_t count)245 static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
246 {
247 int i;
248 int ret;
249 u32 size = 0;
250 number_of_wtx = 0;
251
252 recv_begin:
253 /* start receiving header */
254 for (i = 0; i < 4; i++) {
255 ret = wait(chip, STAT_RDA);
256 if (ret)
257 return -EIO;
258 buf[i] = tpm_data_in(RDFIFO);
259 }
260
261 if (buf[0] != TPM_VL_VER) {
262 dev_err(&chip->dev,
263 "Wrong transport protocol implementation!\n");
264 return -EIO;
265 }
266
267 if (buf[1] == TPM_CTRL_DATA) {
268 /* size of the data received */
269 size = ((buf[2] << 8) | buf[3]);
270
271 for (i = 0; i < size; i++) {
272 wait(chip, STAT_RDA);
273 buf[i] = tpm_data_in(RDFIFO);
274 }
275
276 if ((size == 0x6D00) && (buf[1] == 0x80)) {
277 dev_err(&chip->dev, "Error handling on vendor layer!\n");
278 return -EIO;
279 }
280
281 for (i = 0; i < size; i++)
282 buf[i] = buf[i + 6];
283
284 size = size - 6;
285 return size;
286 }
287
288 if (buf[1] == TPM_CTRL_WTX) {
289 dev_info(&chip->dev, "WTX-package received\n");
290 if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
291 tpm_wtx(chip);
292 goto recv_begin;
293 } else {
294 tpm_wtx_abort(chip);
295 goto recv_begin;
296 }
297 }
298
299 if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
300 dev_info(&chip->dev, "WTX-abort acknowledged\n");
301 return size;
302 }
303
304 if (buf[1] == TPM_CTRL_ERROR) {
305 dev_err(&chip->dev, "ERROR-package received:\n");
306 if (buf[4] == TPM_INF_NAK)
307 dev_err(&chip->dev,
308 "-> Negative acknowledgement"
309 " - retransmit command!\n");
310 return -EIO;
311 }
312 return -EIO;
313 }
314
tpm_inf_send(struct tpm_chip * chip,u8 * buf,size_t bufsiz,size_t count)315 static int tpm_inf_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz,
316 size_t count)
317 {
318 int i;
319 int ret;
320 u8 count_high, count_low, count_4, count_3, count_2, count_1;
321
322 /* Disabling Reset, LP and IRQC */
323 tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
324
325 ret = empty_fifo(chip, 1);
326 if (ret) {
327 dev_err(&chip->dev, "Timeout while clearing FIFO\n");
328 return -EIO;
329 }
330
331 ret = wait(chip, STAT_XFE);
332 if (ret)
333 return -EIO;
334
335 count_4 = (count & 0xff000000) >> 24;
336 count_3 = (count & 0x00ff0000) >> 16;
337 count_2 = (count & 0x0000ff00) >> 8;
338 count_1 = (count & 0x000000ff);
339 count_high = ((count + 6) & 0xffffff00) >> 8;
340 count_low = ((count + 6) & 0x000000ff);
341
342 /* Sending Header */
343 wait_and_send(chip, TPM_VL_VER);
344 wait_and_send(chip, TPM_CTRL_DATA);
345 wait_and_send(chip, count_high);
346 wait_and_send(chip, count_low);
347
348 /* Sending Data Header */
349 wait_and_send(chip, TPM_VL_VER);
350 wait_and_send(chip, TPM_VL_CHANNEL_TPM);
351 wait_and_send(chip, count_4);
352 wait_and_send(chip, count_3);
353 wait_and_send(chip, count_2);
354 wait_and_send(chip, count_1);
355
356 /* Sending Data */
357 for (i = 0; i < count; i++) {
358 wait_and_send(chip, buf[i]);
359 }
360 return 0;
361 }
362
tpm_inf_cancel(struct tpm_chip * chip)363 static void tpm_inf_cancel(struct tpm_chip *chip)
364 {
365 /*
366 Since we are using the legacy mode to communicate
367 with the TPM, we have no cancel functions, but have
368 a workaround for interrupting the TPM through WTX.
369 */
370 }
371
tpm_inf_status(struct tpm_chip * chip)372 static u8 tpm_inf_status(struct tpm_chip *chip)
373 {
374 return tpm_data_in(STAT);
375 }
376
377 static const struct tpm_class_ops tpm_inf = {
378 .recv = tpm_inf_recv,
379 .send = tpm_inf_send,
380 .cancel = tpm_inf_cancel,
381 .status = tpm_inf_status,
382 .req_complete_mask = 0,
383 .req_complete_val = 0,
384 };
385
386 static const struct pnp_device_id tpm_inf_pnp_tbl[] = {
387 /* Infineon TPMs */
388 {"IFX0101", 0},
389 {"IFX0102", 0},
390 {"", 0}
391 };
392
393 MODULE_DEVICE_TABLE(pnp, tpm_inf_pnp_tbl);
394
tpm_inf_pnp_probe(struct pnp_dev * dev,const struct pnp_device_id * dev_id)395 static int tpm_inf_pnp_probe(struct pnp_dev *dev,
396 const struct pnp_device_id *dev_id)
397 {
398 int rc = 0;
399 u8 iol, ioh;
400 int vendorid[2];
401 int version[2];
402 int productid[2];
403 const char *chipname;
404 struct tpm_chip *chip;
405
406 /* read IO-ports through PnP */
407 if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
408 !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
409
410 tpm_dev.iotype = TPM_INF_IO_PORT;
411
412 tpm_dev.config_port = pnp_port_start(dev, 0);
413 tpm_dev.config_size = pnp_port_len(dev, 0);
414 tpm_dev.data_regs = pnp_port_start(dev, 1);
415 tpm_dev.data_size = pnp_port_len(dev, 1);
416 if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
417 rc = -EINVAL;
418 goto err_last;
419 }
420 dev_info(&dev->dev, "Found %s with ID %s\n",
421 dev->name, dev_id->id);
422 if (!((tpm_dev.data_regs >> 8) & 0xff)) {
423 rc = -EINVAL;
424 goto err_last;
425 }
426 /* publish my base address and request region */
427 if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
428 "tpm_infineon0") == NULL) {
429 rc = -EINVAL;
430 goto err_last;
431 }
432 if (request_region(tpm_dev.config_port, tpm_dev.config_size,
433 "tpm_infineon0") == NULL) {
434 release_region(tpm_dev.data_regs, tpm_dev.data_size);
435 rc = -EINVAL;
436 goto err_last;
437 }
438 } else if (pnp_mem_valid(dev, 0) &&
439 !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
440
441 tpm_dev.iotype = TPM_INF_IO_MEM;
442
443 tpm_dev.map_base = pnp_mem_start(dev, 0);
444 tpm_dev.map_size = pnp_mem_len(dev, 0);
445
446 dev_info(&dev->dev, "Found %s with ID %s\n",
447 dev->name, dev_id->id);
448
449 /* publish my base address and request region */
450 if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
451 "tpm_infineon0") == NULL) {
452 rc = -EINVAL;
453 goto err_last;
454 }
455
456 tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
457 if (tpm_dev.mem_base == NULL) {
458 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
459 rc = -EINVAL;
460 goto err_last;
461 }
462
463 /*
464 * The only known MMIO based Infineon TPM system provides
465 * a single large mem region with the device config
466 * registers at the default TPM_ADDR. The data registers
467 * seem like they could be placed anywhere within the MMIO
468 * region, but lets just put them at zero offset.
469 */
470 tpm_dev.index_off = TPM_ADDR;
471 tpm_dev.data_regs = 0x0;
472 } else {
473 rc = -EINVAL;
474 goto err_last;
475 }
476
477 /* query chip for its vendor, its version number a.s.o. */
478 tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
479 tpm_config_out(IDVENL, TPM_INF_ADDR);
480 vendorid[1] = tpm_config_in(TPM_INF_DATA);
481 tpm_config_out(IDVENH, TPM_INF_ADDR);
482 vendorid[0] = tpm_config_in(TPM_INF_DATA);
483 tpm_config_out(IDPDL, TPM_INF_ADDR);
484 productid[1] = tpm_config_in(TPM_INF_DATA);
485 tpm_config_out(IDPDH, TPM_INF_ADDR);
486 productid[0] = tpm_config_in(TPM_INF_DATA);
487 tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
488 version[1] = tpm_config_in(TPM_INF_DATA);
489 tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
490 version[0] = tpm_config_in(TPM_INF_DATA);
491
492 switch ((productid[0] << 8) | productid[1]) {
493 case 6:
494 chipname = " (SLD 9630 TT 1.1)";
495 break;
496 case 11:
497 chipname = " (SLB 9635 TT 1.2)";
498 break;
499 default:
500 chipname = " (unknown chip)";
501 break;
502 }
503
504 if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
505
506 /* configure TPM with IO-ports */
507 tpm_config_out(IOLIMH, TPM_INF_ADDR);
508 tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
509 tpm_config_out(IOLIML, TPM_INF_ADDR);
510 tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
511
512 /* control if IO-ports are set correctly */
513 tpm_config_out(IOLIMH, TPM_INF_ADDR);
514 ioh = tpm_config_in(TPM_INF_DATA);
515 tpm_config_out(IOLIML, TPM_INF_ADDR);
516 iol = tpm_config_in(TPM_INF_DATA);
517
518 if ((ioh << 8 | iol) != tpm_dev.data_regs) {
519 dev_err(&dev->dev,
520 "Could not set IO-data registers to 0x%x\n",
521 tpm_dev.data_regs);
522 rc = -EIO;
523 goto err_release_region;
524 }
525
526 /* activate register */
527 tpm_config_out(TPM_DAR, TPM_INF_ADDR);
528 tpm_config_out(0x01, TPM_INF_DATA);
529 tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
530
531 /* disable RESET, LP and IRQC */
532 tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
533
534 /* Finally, we're done, print some infos */
535 dev_info(&dev->dev, "TPM found: "
536 "config base 0x%lx, "
537 "data base 0x%lx, "
538 "chip version 0x%02x%02x, "
539 "vendor id 0x%x%x (Infineon), "
540 "product id 0x%02x%02x"
541 "%s\n",
542 tpm_dev.iotype == TPM_INF_IO_PORT ?
543 tpm_dev.config_port :
544 tpm_dev.map_base + tpm_dev.index_off,
545 tpm_dev.iotype == TPM_INF_IO_PORT ?
546 tpm_dev.data_regs :
547 tpm_dev.map_base + tpm_dev.data_regs,
548 version[0], version[1],
549 vendorid[0], vendorid[1],
550 productid[0], productid[1], chipname);
551
552 chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
553 if (IS_ERR(chip)) {
554 rc = PTR_ERR(chip);
555 goto err_release_region;
556 }
557
558 rc = tpm_chip_register(chip);
559 if (rc)
560 goto err_release_region;
561
562 return 0;
563 } else {
564 rc = -ENODEV;
565 goto err_release_region;
566 }
567
568 err_release_region:
569 if (tpm_dev.iotype == TPM_INF_IO_PORT) {
570 release_region(tpm_dev.data_regs, tpm_dev.data_size);
571 release_region(tpm_dev.config_port, tpm_dev.config_size);
572 } else {
573 iounmap(tpm_dev.mem_base);
574 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
575 }
576
577 err_last:
578 return rc;
579 }
580
tpm_inf_pnp_remove(struct pnp_dev * dev)581 static void tpm_inf_pnp_remove(struct pnp_dev *dev)
582 {
583 struct tpm_chip *chip = pnp_get_drvdata(dev);
584
585 tpm_chip_unregister(chip);
586
587 if (tpm_dev.iotype == TPM_INF_IO_PORT) {
588 release_region(tpm_dev.data_regs, tpm_dev.data_size);
589 release_region(tpm_dev.config_port,
590 tpm_dev.config_size);
591 } else {
592 iounmap(tpm_dev.mem_base);
593 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
594 }
595 }
596
597 #ifdef CONFIG_PM_SLEEP
tpm_inf_resume(struct device * dev)598 static int tpm_inf_resume(struct device *dev)
599 {
600 /* Re-configure TPM after suspending */
601 tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
602 tpm_config_out(IOLIMH, TPM_INF_ADDR);
603 tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
604 tpm_config_out(IOLIML, TPM_INF_ADDR);
605 tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
606 /* activate register */
607 tpm_config_out(TPM_DAR, TPM_INF_ADDR);
608 tpm_config_out(0x01, TPM_INF_DATA);
609 tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
610 /* disable RESET, LP and IRQC */
611 tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
612 return tpm_pm_resume(dev);
613 }
614 #endif
615 static SIMPLE_DEV_PM_OPS(tpm_inf_pm, tpm_pm_suspend, tpm_inf_resume);
616
617 static struct pnp_driver tpm_inf_pnp_driver = {
618 .name = "tpm_inf_pnp",
619 .id_table = tpm_inf_pnp_tbl,
620 .probe = tpm_inf_pnp_probe,
621 .remove = tpm_inf_pnp_remove,
622 .driver = {
623 .pm = &tpm_inf_pm,
624 }
625 };
626
627 module_pnp_driver(tpm_inf_pnp_driver);
628
629 MODULE_AUTHOR("Marcel Selhorst <tpmdd@sirrix.com>");
630 MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
631 MODULE_VERSION("1.9.2");
632 MODULE_LICENSE("GPL");
633