omap-common/hwinit-common.c: Mark omap_rev_string as static
[platform/kernel/u-boot.git] / drivers / tpm / tis_i2c.c
1 /*
2  * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include <config.h>
8 #include <common.h>
9 #include <fdtdec.h>
10 #include <i2c.h>
11 #include "slb9635_i2c/tpm.h"
12
13 DECLARE_GLOBAL_DATA_PTR;
14
15 /* TPM configuration */
16 struct tpm {
17         int i2c_bus;
18         int slave_addr;
19         char inited;
20         int old_bus;
21 } tpm;
22
23
24 static int tpm_select(void)
25 {
26         int ret;
27
28         tpm.old_bus = i2c_get_bus_num();
29         if (tpm.old_bus != tpm.i2c_bus) {
30                 ret = i2c_set_bus_num(tpm.i2c_bus);
31                 if (ret) {
32                         debug("%s: Fail to set i2c bus %d\n", __func__,
33                               tpm.i2c_bus);
34                         return -1;
35                 }
36         }
37         return 0;
38 }
39
40 static int tpm_deselect(void)
41 {
42         int ret;
43
44         if (tpm.old_bus != i2c_get_bus_num()) {
45                 ret = i2c_set_bus_num(tpm.old_bus);
46                 if (ret) {
47                         debug("%s: Fail to restore i2c bus %d\n",
48                               __func__, tpm.old_bus);
49                         return -1;
50                 }
51         }
52         tpm.old_bus = -1;
53         return 0;
54 }
55
56 /**
57  * Decode TPM configuration.
58  *
59  * @param dev   Returns a configuration of TPM device
60  * @return 0 if ok, -1 on error
61  */
62 static int tpm_decode_config(struct tpm *dev)
63 {
64 #ifdef CONFIG_OF_CONTROL
65         const void *blob = gd->fdt_blob;
66         int node, parent;
67         int i2c_bus;
68
69         node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
70         if (node < 0) {
71                 debug("%s: Node not found\n", __func__);
72                 return -1;
73         }
74         parent = fdt_parent_offset(blob, node);
75         if (parent < 0) {
76                 debug("%s: Cannot find node parent\n", __func__);
77                 return -1;
78         }
79         i2c_bus = i2c_get_bus_num_fdt(parent);
80         if (i2c_bus < 0)
81                 return -1;
82         dev->i2c_bus = i2c_bus;
83         dev->slave_addr = fdtdec_get_addr(blob, node, "reg");
84 #else
85         dev->i2c_bus = CONFIG_INFINEON_TPM_I2C_BUS;
86         dev->slave_addr = CONFIG_INFINEON_TPM_I2C_ADDR;
87 #endif
88         return 0;
89 }
90
91 int tis_init(void)
92 {
93         if (tpm.inited)
94                 return 0;
95
96         if (tpm_decode_config(&tpm))
97                 return -1;
98
99         if (tpm_select())
100                 return -1;
101
102         /*
103          * Probe TPM twice; the first probing might fail because TPM is asleep,
104          * and the probing can wake up TPM.
105          */
106         if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) {
107                 debug("%s: fail to probe i2c addr 0x%x\n", __func__,
108                       tpm.slave_addr);
109                 return -1;
110         }
111
112         tpm_deselect();
113
114         tpm.inited = 1;
115
116         return 0;
117 }
118
119 int tis_open(void)
120 {
121         int rc;
122
123         if (!tpm.inited)
124                 return -1;
125
126         if (tpm_select())
127                 return -1;
128
129         rc = tpm_open(tpm.slave_addr);
130
131         tpm_deselect();
132
133         return rc;
134 }
135
136 int tis_close(void)
137 {
138         if (!tpm.inited)
139                 return -1;
140
141         if (tpm_select())
142                 return -1;
143
144         tpm_close();
145
146         tpm_deselect();
147
148         return 0;
149 }
150
151 int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
152                 uint8_t *recvbuf, size_t *rbuf_len)
153 {
154         int len;
155         uint8_t buf[4096];
156
157         if (!tpm.inited)
158                 return -1;
159
160         if (sizeof(buf) < sbuf_size)
161                 return -1;
162
163         memcpy(buf, sendbuf, sbuf_size);
164
165         if (tpm_select())
166                 return -1;
167
168         len = tpm_transmit(buf, sbuf_size);
169
170         tpm_deselect();
171
172         if (len < 10) {
173                 *rbuf_len = 0;
174                 return -1;
175         }
176
177         memcpy(recvbuf, buf, len);
178         *rbuf_len = len;
179
180         return 0;
181 }