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, &region_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