11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004 IBM Corporation 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors: 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Leendert van Doorn <leendert@watson.ibm.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dave Safford <safford@watson.ibm.com> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reiner Sailer <sailer@watson.ibm.com> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Kylene Hall <kjhall@us.ibm.com> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 108e81cc13a88ce486a6b0a6ca56aba6985824917aKent Yoder * Maintained by: <tpmdd-devel@lists.sourceforge.net> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device driver for TCG/TCPA TPM (trusted platform module). 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Specifications at www.trustedcomputinggroup.org 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License as 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation, version 2 of the 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tpm.h" 23ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall#include "tpm_atmel.h" 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* write status bits */ 263122a88a242454efe72930e56a3e4d56ee534f3cKylene Hallenum tpm_atmel_write_status { 273122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall ATML_STATUS_ABORT = 0x01, 283122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall ATML_STATUS_LASTBYTE = 0x04 293122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall}; 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* read status bits */ 313122a88a242454efe72930e56a3e4d56ee534f3cKylene Hallenum tpm_atmel_read_status { 323122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall ATML_STATUS_BUSY = 0x01, 333122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall ATML_STATUS_DATA_AVAIL = 0x02, 343122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall ATML_STATUS_REWRITE = 0x04, 353122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall ATML_STATUS_READY = 0x08 363122a88a242454efe72930e56a3e4d56ee534f3cKylene Hall}; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38b888c87b7498557d1dbb9de3d4b8402b1bb89193Andrew Mortonstatic int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 status, *hdr = buf; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 size; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __be32 *native_size; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* start reading header */ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < 6) 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 6; i++) { 5090dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall status = ioread8(chip->vendor.iobase + 1); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 5290612b308f2a2cc8aa08fbaf6f7184f5b7b5a855Kylene Jo Hall dev_err(chip->dev, "error reading header\n"); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5590dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall *buf++ = ioread8(chip->vendor.iobase); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* size of the data received */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds native_size = (__force __be32 *) (hdr + 2); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = be32_to_cpu(*native_size); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < size) { 63e659a3fe2027b19ecd8abb7ad79253672763454bKylene Jo Hall dev_err(chip->dev, 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Recv size(%d) less than available space\n", size); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; i < size; i++) { /* clear the waiting data anyway */ 6690dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall status = ioread8(chip->vendor.iobase + 1); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 6890612b308f2a2cc8aa08fbaf6f7184f5b7b5a855Kylene Jo Hall dev_err(chip->dev, "error reading data\n"); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read all the data available */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; i < size; i++) { 7790dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall status = ioread8(chip->vendor.iobase + 1); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 7990612b308f2a2cc8aa08fbaf6f7184f5b7b5a855Kylene Jo Hall dev_err(chip->dev, "error reading data\n"); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8290dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall *buf++ = ioread8(chip->vendor.iobase); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make sure data available is gone */ 8690dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall status = ioread8(chip->vendor.iobase + 1); 8790612b308f2a2cc8aa08fbaf6f7184f5b7b5a855Kylene Jo Hall 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & ATML_STATUS_DATA_AVAIL) { 89e659a3fe2027b19ecd8abb7ad79253672763454bKylene Jo Hall dev_err(chip->dev, "data available is stuck\n"); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return size; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96b888c87b7498557d1dbb9de3d4b8402b1bb89193Andrew Mortonstatic int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100e659a3fe2027b19ecd8abb7ad79253672763454bKylene Jo Hall dev_dbg(chip->dev, "tpm_atml_send:\n"); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < count; i++) { 102e659a3fe2027b19ecd8abb7ad79253672763454bKylene Jo Hall dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); 10390dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall iowrite8(buf[i], chip->vendor.iobase); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tpm_atml_cancel(struct tpm_chip *chip) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11190dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall iowrite8(ATML_STATUS_ABORT, chip->vendor.iobase + 1); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 114b4ed3e3cbb312869929cf4528d71e52629a6cacbKylene Jo Hallstatic u8 tpm_atml_status(struct tpm_chip *chip) 115b4ed3e3cbb312869929cf4528d71e52629a6cacbKylene Jo Hall{ 11690dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall return ioread8(chip->vendor.iobase + 1); 117b4ed3e3cbb312869929cf4528d71e52629a6cacbKylene Jo Hall} 118b4ed3e3cbb312869929cf4528d71e52629a6cacbKylene Jo Hall 11962322d2554d2f9680c8ace7bbf1f97d8fa84ad1aArjan van de Venstatic const struct file_operations atmel_ops = { 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .llseek = no_llseek, 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = tpm_open, 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = tpm_read, 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = tpm_write, 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = tpm_release, 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1286659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hallstatic DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 1296659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hallstatic DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); 1306659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hallstatic DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); 1316659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hallstatic DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); 1326659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall 1336659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hallstatic struct attribute* atmel_attrs[] = { 1346659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall &dev_attr_pubek.attr, 1356659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall &dev_attr_pcrs.attr, 1366659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall &dev_attr_caps.attr, 1376659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall &dev_attr_cancel.attr, 138874ec33ff9ccf3651590697a2c2923b911bf31d0Randy Dunlap NULL, 1396659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall}; 1406659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall 1416659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hallstatic struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; 1426659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall 143e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hallstatic const struct tpm_vendor_specific tpm_atmel = { 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .recv = tpm_atml_recv, 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send = tpm_atml_send, 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cancel = tpm_atml_cancel, 147b4ed3e3cbb312869929cf4528d71e52629a6cacbKylene Jo Hall .status = tpm_atml_status, 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .req_complete_val = ATML_STATUS_DATA_AVAIL, 150d9e5b6bf9cf19e6e9f2825228136ea17bc9a051aKylene Hall .req_canceled = ATML_STATUS_READY, 1516659ca2ab6730c3bbb9fa495f2327b95b955decdKylene Hall .attr_group = &atmel_attr_grp, 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .miscdev = { .fops = &atmel_ops, }, 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 155b888c87b7498557d1dbb9de3d4b8402b1bb89193Andrew Mortonstatic struct platform_device *pdev; 156682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall 157ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hallstatic void atml_plat_remove(void) 158682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall{ 159ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); 160ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall 161b888c87b7498557d1dbb9de3d4b8402b1bb89193Andrew Morton if (chip) { 16290dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall if (chip->vendor.have_region) 16390dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall atmel_release_region(chip->vendor.base, 16490dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall chip->vendor.region_size); 16590dda520c1962d55a0e1d2571deed0d75fd6d6f1Kylene Jo Hall atmel_put_base_addr(chip->vendor.iobase); 166682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall tpm_remove_hardware(chip->dev); 167ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall platform_device_unregister(pdev); 168682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall } 169682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall} 170682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall 1717a192ec334cab9fafe3a8665a65af398b0e24730Ming Leistatic int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg) 1727a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei{ 1737a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei return tpm_pm_suspend(&dev->dev, msg); 1747a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei} 1757a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei 1767a192ec334cab9fafe3a8665a65af398b0e24730Ming Leistatic int tpm_atml_resume(struct platform_device *dev) 1777a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei{ 1787a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei return tpm_pm_resume(&dev->dev); 1797a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei} 1807a192ec334cab9fafe3a8665a65af398b0e24730Ming Leistatic struct platform_driver atml_drv = { 1817a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei .driver = { 1827a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei .name = "tpm_atmel", 1837a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei .owner = THIS_MODULE, 1847a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei }, 1857a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei .suspend = tpm_atml_suspend, 1867a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei .resume = tpm_atml_resume, 187682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall}; 188682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall 189682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hallstatic int __init init_atmel(void) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 192e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall void __iomem *iobase = NULL; 193e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall int have_region, region_size; 194e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall unsigned long base; 195e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall struct tpm_chip *chip; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1977a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei rc = platform_driver_register(&atml_drv); 198f33d9bd50478c9a969b65f58feb6b69a3ad478cbJeff Garzik if (rc) 199f33d9bd50478c9a969b65f58feb6b69a3ad478cbJeff Garzik return rc; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { 202ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall rc = -ENODEV; 203ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall goto err_unreg_drv; 204682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 206e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall have_region = 20790612b308f2a2cc8aa08fbaf6f7184f5b7b5a855Kylene Jo Hall (atmel_request_region 208e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; 209e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall 210f33d9bd50478c9a969b65f58feb6b69a3ad478cbJeff Garzik pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0); 211f33d9bd50478c9a969b65f58feb6b69a3ad478cbJeff Garzik if (IS_ERR(pdev)) { 212ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall rc = PTR_ERR(pdev); 213ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall goto err_rel_reg; 214682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall } 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 216e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) { 217e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall rc = -ENODEV; 218ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall goto err_unreg_dev; 219e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall } 220e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall 221e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall chip->vendor.iobase = iobase; 222e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall chip->vendor.base = base; 223e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall chip->vendor.have_region = have_region; 224e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall chip->vendor.region_size = region_size; 225e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall 226682e97aceafd8a41c6c7106c4f3b04cc36e0456cKylene Jo Hall return 0; 227ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall 228ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hallerr_unreg_dev: 229ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall platform_device_unregister(pdev); 230ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hallerr_rel_reg: 231e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall atmel_put_base_addr(iobase); 232e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall if (have_region) 233e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall atmel_release_region(base, 234e0dd03caf20d040a0a86b6bd74028ec9bda545f5Kylene Jo Hall region_size); 235ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hallerr_unreg_drv: 2367a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei platform_driver_unregister(&atml_drv); 237ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall return rc; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup_atmel(void) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2427a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei platform_driver_unregister(&atml_drv); 243ad5ea3cc5f745aef243ade0dafc8cf6f7f0bfea7Kylene Jo Hall atml_plat_remove(); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_atmel); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cleanup_atmel); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("TPM Driver"); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION("2.0"); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 253