diff options
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/tpm_i2c_infineon.c | 137 |
1 files changed, 97 insertions, 40 deletions
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 8e47e2b99efc..bd9a2958dc39 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2012 Infineon Technologies | 2 | * Copyright (C) 2012,2013 Infineon Technologies |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Peter Huewe <peter.huewe@infineon.com> | 5 | * Peter Huewe <peter.huewe@infineon.com> |
@@ -56,13 +56,21 @@ | |||
56 | #define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000) | 56 | #define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000) |
57 | 57 | ||
58 | /* expected value for DIDVID register */ | 58 | /* expected value for DIDVID register */ |
59 | #define TPM_TIS_I2C_DID_VID 0x000b15d1L | 59 | #define TPM_TIS_I2C_DID_VID_9635 0xd1150b00L |
60 | #define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L | ||
61 | |||
62 | enum i2c_chip_type { | ||
63 | SLB9635, | ||
64 | SLB9645, | ||
65 | UNKNOWN, | ||
66 | }; | ||
60 | 67 | ||
61 | /* Structure to store I2C TPM specific stuff */ | 68 | /* Structure to store I2C TPM specific stuff */ |
62 | struct tpm_inf_dev { | 69 | struct tpm_inf_dev { |
63 | struct i2c_client *client; | 70 | struct i2c_client *client; |
64 | u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ | 71 | u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ |
65 | struct tpm_chip *chip; | 72 | struct tpm_chip *chip; |
73 | enum i2c_chip_type chip_type; | ||
66 | }; | 74 | }; |
67 | 75 | ||
68 | static struct tpm_inf_dev tpm_dev; | 76 | static struct tpm_inf_dev tpm_dev; |
@@ -101,8 +109,9 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) | |||
101 | .len = len, | 109 | .len = len, |
102 | .buf = buffer | 110 | .buf = buffer |
103 | }; | 111 | }; |
112 | struct i2c_msg msgs[] = {msg1, msg2}; | ||
104 | 113 | ||
105 | int rc; | 114 | int rc = 0; |
106 | int count; | 115 | int count; |
107 | 116 | ||
108 | /* Lock the adapter for the duration of the whole sequence. */ | 117 | /* Lock the adapter for the duration of the whole sequence. */ |
@@ -110,30 +119,49 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) | |||
110 | return -EOPNOTSUPP; | 119 | return -EOPNOTSUPP; |
111 | i2c_lock_adapter(tpm_dev.client->adapter); | 120 | i2c_lock_adapter(tpm_dev.client->adapter); |
112 | 121 | ||
113 | for (count = 0; count < MAX_COUNT; count++) { | 122 | if (tpm_dev.chip_type == SLB9645) { |
114 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | 123 | /* use a combined read for newer chips |
115 | if (rc > 0) | 124 | * unfortunately the smbus functions are not suitable due to |
116 | break; /* break here to skip sleep */ | 125 | * the 32 byte limit of the smbus. |
117 | 126 | * retries should usually not be needed, but are kept just to | |
118 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | 127 | * be on the safe side. |
119 | } | 128 | */ |
120 | 129 | for (count = 0; count < MAX_COUNT; count++) { | |
121 | if (rc <= 0) | 130 | rc = __i2c_transfer(tpm_dev.client->adapter, msgs, 2); |
122 | goto out; | 131 | if (rc > 0) |
123 | 132 | break; /* break here to skip sleep */ | |
124 | /* After the TPM has successfully received the register address it needs | 133 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); |
125 | * some time, thus we're sleeping here again, before retrieving the data | 134 | } |
126 | */ | 135 | } else { |
127 | for (count = 0; count < MAX_COUNT; count++) { | 136 | /* slb9635 protocol should work in all cases */ |
128 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | 137 | for (count = 0; count < MAX_COUNT; count++) { |
129 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1); | 138 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); |
130 | if (rc > 0) | 139 | if (rc > 0) |
131 | break; | 140 | break; /* break here to skip sleep */ |
141 | |||
142 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
143 | } | ||
132 | 144 | ||
145 | if (rc <= 0) | ||
146 | goto out; | ||
147 | |||
148 | /* After the TPM has successfully received the register address | ||
149 | * it needs some time, thus we're sleeping here again, before | ||
150 | * retrieving the data | ||
151 | */ | ||
152 | for (count = 0; count < MAX_COUNT; count++) { | ||
153 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
154 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1); | ||
155 | if (rc > 0) | ||
156 | break; | ||
157 | } | ||
133 | } | 158 | } |
134 | 159 | ||
135 | out: | 160 | out: |
136 | i2c_unlock_adapter(tpm_dev.client->adapter); | 161 | i2c_unlock_adapter(tpm_dev.client->adapter); |
162 | /* take care of 'guard time' */ | ||
163 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
164 | |||
137 | if (rc <= 0) | 165 | if (rc <= 0) |
138 | return -EIO; | 166 | return -EIO; |
139 | 167 | ||
@@ -167,16 +195,19 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, | |||
167 | /* | 195 | /* |
168 | * NOTE: We have to use these special mechanisms here and unfortunately | 196 | * NOTE: We have to use these special mechanisms here and unfortunately |
169 | * cannot rely on the standard behavior of i2c_transfer. | 197 | * cannot rely on the standard behavior of i2c_transfer. |
198 | * Even for newer chips the smbus functions are not | ||
199 | * suitable due to the 32 byte limit of the smbus. | ||
170 | */ | 200 | */ |
171 | for (count = 0; count < max_count; count++) { | 201 | for (count = 0; count < max_count; count++) { |
172 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | 202 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); |
173 | if (rc > 0) | 203 | if (rc > 0) |
174 | break; | 204 | break; |
175 | |||
176 | usleep_range(sleep_low, sleep_hi); | 205 | usleep_range(sleep_low, sleep_hi); |
177 | } | 206 | } |
178 | 207 | ||
179 | i2c_unlock_adapter(tpm_dev.client->adapter); | 208 | i2c_unlock_adapter(tpm_dev.client->adapter); |
209 | /* take care of 'guard time' */ | ||
210 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
180 | if (rc <= 0) | 211 | if (rc <= 0) |
181 | return -EIO; | 212 | return -EIO; |
182 | 213 | ||
@@ -296,11 +327,18 @@ static int request_locality(struct tpm_chip *chip, int loc) | |||
296 | static u8 tpm_tis_i2c_status(struct tpm_chip *chip) | 327 | static u8 tpm_tis_i2c_status(struct tpm_chip *chip) |
297 | { | 328 | { |
298 | /* NOTE: since I2C read may fail, return 0 in this case --> time-out */ | 329 | /* NOTE: since I2C read may fail, return 0 in this case --> time-out */ |
299 | u8 buf; | 330 | u8 buf = 0xFF; |
300 | if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) | 331 | u8 i = 0; |
301 | return 0; | 332 | |
302 | else | 333 | do { |
303 | return buf; | 334 | if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) |
335 | return 0; | ||
336 | |||
337 | i++; | ||
338 | /* if locallity is set STS should not be 0xFF */ | ||
339 | } while ((buf == 0xFF) && i < 10); | ||
340 | |||
341 | return buf; | ||
304 | } | 342 | } |
305 | 343 | ||
306 | static void tpm_tis_i2c_ready(struct tpm_chip *chip) | 344 | static void tpm_tis_i2c_ready(struct tpm_chip *chip) |
@@ -341,7 +379,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | |||
341 | 379 | ||
342 | /* check current status */ | 380 | /* check current status */ |
343 | *status = tpm_tis_i2c_status(chip); | 381 | *status = tpm_tis_i2c_status(chip); |
344 | if ((*status & mask) == mask) | 382 | if ((*status != 0xFF) && (*status & mask) == mask) |
345 | return 0; | 383 | return 0; |
346 | 384 | ||
347 | stop = jiffies + timeout; | 385 | stop = jiffies + timeout; |
@@ -385,7 +423,6 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | |||
385 | /* avoid endless loop in case of broken HW */ | 423 | /* avoid endless loop in case of broken HW */ |
386 | if (retries > MAX_COUNT_LONG) | 424 | if (retries > MAX_COUNT_LONG) |
387 | return -EIO; | 425 | return -EIO; |
388 | |||
389 | } | 426 | } |
390 | return size; | 427 | return size; |
391 | } | 428 | } |
@@ -493,7 +530,6 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) | |||
493 | rc = -EIO; | 530 | rc = -EIO; |
494 | goto out_err; | 531 | goto out_err; |
495 | } | 532 | } |
496 | |||
497 | } | 533 | } |
498 | 534 | ||
499 | /* write last byte */ | 535 | /* write last byte */ |
@@ -581,6 +617,7 @@ static int tpm_tis_i2c_init(struct device *dev) | |||
581 | 617 | ||
582 | chip = tpm_register_hardware(dev, &tpm_tis_i2c); | 618 | chip = tpm_register_hardware(dev, &tpm_tis_i2c); |
583 | if (!chip) { | 619 | if (!chip) { |
620 | dev_err(dev, "could not register hardware\n"); | ||
584 | rc = -ENODEV; | 621 | rc = -ENODEV; |
585 | goto out_err; | 622 | goto out_err; |
586 | } | 623 | } |
@@ -595,20 +632,24 @@ static int tpm_tis_i2c_init(struct device *dev) | |||
595 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | 632 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); |
596 | 633 | ||
597 | if (request_locality(chip, 0) != 0) { | 634 | if (request_locality(chip, 0) != 0) { |
635 | dev_err(dev, "could not request locality\n"); | ||
598 | rc = -ENODEV; | 636 | rc = -ENODEV; |
599 | goto out_vendor; | 637 | goto out_vendor; |
600 | } | 638 | } |
601 | 639 | ||
602 | /* read four bytes from DID_VID register */ | 640 | /* read four bytes from DID_VID register */ |
603 | if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) { | 641 | if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) { |
642 | dev_err(dev, "could not read vendor id\n"); | ||
604 | rc = -EIO; | 643 | rc = -EIO; |
605 | goto out_release; | 644 | goto out_release; |
606 | } | 645 | } |
607 | 646 | ||
608 | /* create DID_VID register value, after swapping to little-endian */ | 647 | if (vendor == TPM_TIS_I2C_DID_VID_9645) { |
609 | vendor = be32_to_cpu((__be32) vendor); | 648 | tpm_dev.chip_type = SLB9645; |
610 | 649 | } else if (vendor == TPM_TIS_I2C_DID_VID_9635) { | |
611 | if (vendor != TPM_TIS_I2C_DID_VID) { | 650 | tpm_dev.chip_type = SLB9635; |
651 | } else { | ||
652 | dev_err(dev, "vendor id did not match! ID was %08x\n", vendor); | ||
612 | rc = -ENODEV; | 653 | rc = -ENODEV; |
613 | goto out_release; | 654 | goto out_release; |
614 | } | 655 | } |
@@ -644,22 +685,38 @@ out_err: | |||
644 | 685 | ||
645 | static const struct i2c_device_id tpm_tis_i2c_table[] = { | 686 | static const struct i2c_device_id tpm_tis_i2c_table[] = { |
646 | {"tpm_i2c_infineon", 0}, | 687 | {"tpm_i2c_infineon", 0}, |
688 | {"slb9635tt", 0}, | ||
689 | {"slb9645tt", 1}, | ||
647 | {}, | 690 | {}, |
648 | }; | 691 | }; |
649 | 692 | ||
650 | MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table); | 693 | MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table); |
694 | |||
695 | #ifdef CONFIG_OF | ||
696 | static const struct of_device_id tpm_tis_i2c_of_match[] = { | ||
697 | { .compatible = "infineon,tpm_i2c_infineon", .data = (void *)0 }, | ||
698 | { .compatible = "infineon,slb9635tt", .data = (void *)0 }, | ||
699 | { .compatible = "infineon,slb9645tt", .data = (void *)1 }, | ||
700 | {}, | ||
701 | }; | ||
702 | MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match); | ||
703 | #endif | ||
704 | |||
651 | static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume); | 705 | static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume); |
652 | 706 | ||
653 | static int tpm_tis_i2c_probe(struct i2c_client *client, | 707 | static int tpm_tis_i2c_probe(struct i2c_client *client, |
654 | const struct i2c_device_id *id) | 708 | const struct i2c_device_id *id) |
655 | { | 709 | { |
656 | int rc; | 710 | int rc; |
657 | if (tpm_dev.client != NULL) | 711 | struct device *dev = &(client->dev); |
712 | |||
713 | if (tpm_dev.client != NULL) { | ||
714 | dev_err(dev, "This driver only supports one client at a time\n"); | ||
658 | return -EBUSY; /* We only support one client */ | 715 | return -EBUSY; /* We only support one client */ |
716 | } | ||
659 | 717 | ||
660 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | 718 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { |
661 | dev_err(&client->dev, | 719 | dev_err(dev, "no algorithms associated to the i2c bus\n"); |
662 | "no algorithms associated to the i2c bus\n"); | ||
663 | return -ENODEV; | 720 | return -ENODEV; |
664 | } | 721 | } |
665 | 722 | ||
@@ -695,7 +752,6 @@ static int tpm_tis_i2c_remove(struct i2c_client *client) | |||
695 | } | 752 | } |
696 | 753 | ||
697 | static struct i2c_driver tpm_tis_i2c_driver = { | 754 | static struct i2c_driver tpm_tis_i2c_driver = { |
698 | |||
699 | .id_table = tpm_tis_i2c_table, | 755 | .id_table = tpm_tis_i2c_table, |
700 | .probe = tpm_tis_i2c_probe, | 756 | .probe = tpm_tis_i2c_probe, |
701 | .remove = tpm_tis_i2c_remove, | 757 | .remove = tpm_tis_i2c_remove, |
@@ -703,11 +759,12 @@ static struct i2c_driver tpm_tis_i2c_driver = { | |||
703 | .name = "tpm_i2c_infineon", | 759 | .name = "tpm_i2c_infineon", |
704 | .owner = THIS_MODULE, | 760 | .owner = THIS_MODULE, |
705 | .pm = &tpm_tis_i2c_ops, | 761 | .pm = &tpm_tis_i2c_ops, |
762 | .of_match_table = of_match_ptr(tpm_tis_i2c_of_match), | ||
706 | }, | 763 | }, |
707 | }; | 764 | }; |
708 | 765 | ||
709 | module_i2c_driver(tpm_tis_i2c_driver); | 766 | module_i2c_driver(tpm_tis_i2c_driver); |
710 | MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>"); | 767 | MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>"); |
711 | MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver"); | 768 | MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver"); |
712 | MODULE_VERSION("2.1.5"); | 769 | MODULE_VERSION("2.2.0"); |
713 | MODULE_LICENSE("GPL"); | 770 | MODULE_LICENSE("GPL"); |