Merge branch 'for-linus' of git://neil.brown.name/md
[safe/jmp/linux-2.6] / drivers / char / tpm / tpm_tis.c
index 447f763..aec1931 100644 (file)
@@ -5,6 +5,8 @@
  * Leendert van Doorn <leendert@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
  *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org
  *
@@ -55,7 +57,7 @@ enum tis_int_flags {
 };
 
 enum tis_defaults {
-       TIS_MEM_BASE = 0xFED4000,
+       TIS_MEM_BASE = 0xFED40000,
        TIS_MEM_LEN = 0x5000,
        TIS_SHORT_TIMEOUT = 750,        /* ms */
        TIS_LONG_TIMEOUT = 2000,        /* 2 sec */
@@ -330,7 +332,7 @@ out_err:
        return rc;
 }
 
-static struct file_operations tis_ops = {
+static const struct file_operations tis_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
        .open = tpm_open,
@@ -377,9 +379,9 @@ static struct tpm_vendor_specific tpm_tis = {
                    .fops = &tis_ops,},
 };
 
-static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tis_int_probe(int irq, void *dev_id)
 {
-       struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+       struct tpm_chip *chip = dev_id;
        u32 interrupt;
 
        interrupt = ioread32(chip->vendor.iobase +
@@ -397,9 +399,9 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tis_int_handler(int dummy, void *dev_id)
 {
-       struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+       struct tpm_chip *chip = dev_id;
        u32 interrupt;
        int i;
 
@@ -424,6 +426,7 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
        iowrite32(interrupt,
                  chip->vendor.iobase +
                  TPM_INT_STATUS(chip->vendor.locality));
+       ioread32(chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
        return IRQ_HANDLED;
 }
 
@@ -431,23 +434,14 @@ static int interrupts = 1;
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
-static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
-                                     const struct pnp_device_id *pnp_id)
+static int tpm_tis_init(struct device *dev, resource_size_t start,
+                       resource_size_t len, unsigned int irq)
 {
        u32 vendor, intfcaps, intmask;
        int rc, i;
-       unsigned long start, len;
        struct tpm_chip *chip;
 
-       start = pnp_mem_start(pnp_dev, 0);
-       len = pnp_mem_len(pnp_dev, 0);
-
-       if (!start)
-               start = TIS_MEM_BASE;
-       if (!len)
-               len = TIS_MEM_LEN;
-
-       if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis)))
+       if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
                return -ENODEV;
 
        chip->vendor.iobase = ioremap(start, len);
@@ -456,19 +450,20 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
                goto out_err;
        }
 
-       vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
-       if ((vendor & 0xFFFF) == 0xFFFF) {
+       if (request_locality(chip, 0) != 0) {
                rc = -ENODEV;
                goto out_err;
        }
 
+       vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
+
        /* Default timeouts */
        chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
        chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
        chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
        chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
 
-       dev_info(&pnp_dev->dev,
+       dev_info(dev,
                 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
                 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
@@ -476,31 +471,26 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
        intfcaps =
            ioread32(chip->vendor.iobase +
                     TPM_INTF_CAPS(chip->vendor.locality));
-       dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n",
+       dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
                intfcaps);
        if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
-               dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n");
+               dev_dbg(dev, "\tBurst Count Static\n");
        if (intfcaps & TPM_INTF_CMD_READY_INT)
-               dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n");
+               dev_dbg(dev, "\tCommand Ready Int Support\n");
        if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n");
+               dev_dbg(dev, "\tInterrupt Edge Falling\n");
        if (intfcaps & TPM_INTF_INT_EDGE_RISING)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n");
+               dev_dbg(dev, "\tInterrupt Edge Rising\n");
        if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n");
+               dev_dbg(dev, "\tInterrupt Level Low\n");
        if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n");
+               dev_dbg(dev, "\tInterrupt Level High\n");
        if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
-               dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n");
+               dev_dbg(dev, "\tLocality Change Int Support\n");
        if (intfcaps & TPM_INTF_STS_VALID_INT)
-               dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n");
+               dev_dbg(dev, "\tSts Valid Int Support\n");
        if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
-               dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n");
-
-       if (request_locality(chip, 0) != 0) {
-               rc = -ENODEV;
-               goto out_err;
-       }
+               dev_dbg(dev, "\tData Avail Int Support\n");
 
        /* INTERRUPT Setup */
        init_waitqueue_head(&chip->vendor.read_queue);
@@ -517,7 +507,9 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
        iowrite32(intmask,
                  chip->vendor.iobase +
                  TPM_INT_ENABLE(chip->vendor.locality));
-       if (interrupts) {
+       if (interrupts)
+               chip->vendor.irq = irq;
+       if (interrupts && !chip->vendor.irq) {
                chip->vendor.irq =
                    ioread8(chip->vendor.iobase +
                            TPM_INT_VECTOR(chip->vendor.locality));
@@ -526,7 +518,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
                        iowrite8(i, chip->vendor.iobase +
                                    TPM_INT_VECTOR(chip->vendor.locality));
                        if (request_irq
-                           (i, tis_int_probe, SA_SHIRQ,
+                           (i, tis_int_probe, IRQF_SHARED,
                             chip->vendor.miscdev.name, chip) != 0) {
                                dev_info(chip->dev,
                                         "Unable to request irq: %d for probe\n",
@@ -561,7 +553,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
                         chip->vendor.iobase +
                         TPM_INT_VECTOR(chip->vendor.locality));
                if (request_irq
-                   (chip->vendor.irq, tis_int_handler, SA_SHIRQ,
+                   (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
                     chip->vendor.miscdev.name, chip) != 0) {
                        dev_info(chip->dev,
                                 "Unable to request irq: %d for use\n",
@@ -598,6 +590,23 @@ out_err:
        return rc;
 }
 
+static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
+                                     const struct pnp_device_id *pnp_id)
+{
+       resource_size_t start, len;
+       unsigned int irq = 0;
+
+       start = pnp_mem_start(pnp_dev, 0);
+       len = pnp_mem_len(pnp_dev, 0);
+
+       if (pnp_irq_valid(pnp_dev, 0))
+               irq = pnp_irq(pnp_dev, 0);
+       else
+               interrupts = 0;
+
+       return tpm_tis_init(&pnp_dev->dev, start, len, irq);
+}
+
 static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
 {
        return tpm_pm_suspend(&dev->dev, msg);
@@ -610,19 +619,81 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
 
 static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
        {"PNP0C31", 0},         /* TPM */
-       {"", 0}
+       {"ATM1200", 0},         /* Atmel */
+       {"IFX0102", 0},         /* Infineon */
+       {"BCM0101", 0},         /* Broadcom */
+       {"BCM0102", 0},         /* Broadcom */
+       {"NSC1200", 0},         /* National */
+       {"ICO0102", 0},         /* Intel */
+       /* Add new here */
+       {"", 0},                /* User Specified */
+       {"", 0}                 /* Terminator */
 };
 
+static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
+{
+       struct tpm_chip *chip = pnp_get_drvdata(dev);
+
+       tpm_dev_vendor_release(chip);
+
+       kfree(chip);
+}
+
+
 static struct pnp_driver tis_pnp_driver = {
        .name = "tpm_tis",
        .id_table = tpm_pnp_tbl,
        .probe = tpm_tis_pnp_init,
        .suspend = tpm_tis_pnp_suspend,
        .resume = tpm_tis_pnp_resume,
+       .remove = tpm_tis_pnp_remove,
+};
+
+#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
+module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
+                   sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
+MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
+
+static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
+{
+       return tpm_pm_suspend(&dev->dev, msg);
+}
+
+static int tpm_tis_resume(struct platform_device *dev)
+{
+       return tpm_pm_resume(&dev->dev);
+}
+static struct platform_driver tis_drv = {
+       .driver = {
+               .name = "tpm_tis",
+               .owner          = THIS_MODULE,
+       },
+       .suspend = tpm_tis_suspend,
+       .resume = tpm_tis_resume,
 };
 
+static struct platform_device *pdev;
+
+static int force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
 static int __init init_tis(void)
 {
+       int rc;
+
+       if (force) {
+               rc = platform_driver_register(&tis_drv);
+               if (rc < 0)
+                       return rc;
+               if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
+                       return PTR_ERR(pdev);
+               if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
+                       platform_device_unregister(pdev);
+                       platform_driver_unregister(&tis_drv);
+               }
+               return rc;
+       }
+
        return pnp_register_driver(&tis_pnp_driver);
 }
 
@@ -633,6 +704,7 @@ static void __exit cleanup_tis(void)
        spin_lock(&tis_lock);
        list_for_each_entry_safe(i, j, &tis_chips, list) {
                chip = to_tpm_chip(i);
+               tpm_remove_hardware(chip->dev);
                iowrite32(~TPM_GLOBAL_INT_ENABLE &
                          ioread32(chip->vendor.iobase +
                                   TPM_INT_ENABLE(chip->vendor.
@@ -644,10 +716,14 @@ static void __exit cleanup_tis(void)
                        free_irq(chip->vendor.irq, chip);
                iounmap(i->iobase);
                list_del(&i->list);
-               tpm_remove_hardware(chip->dev);
        }
        spin_unlock(&tis_lock);
-       pnp_unregister_driver(&tis_pnp_driver);
+
+       if (force) {
+               platform_device_unregister(pdev);
+               platform_driver_unregister(&tis_drv);
+       } else
+               pnp_unregister_driver(&tis_pnp_driver);
 }
 
 module_init(init_tis);