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