1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 |
4 | * Copyright (C) 2009 - 2016 STMicroelectronics |
5 | */ |
6 | |
7 | #include <linux/module.h> |
8 | #include <linux/i2c.h> |
9 | #include <linux/of.h> |
10 | #include <linux/acpi.h> |
11 | #include <linux/tpm.h> |
12 | |
13 | #include "../tpm.h" |
14 | #include "st33zp24.h" |
15 | |
16 | #define TPM_DUMMY_BYTE 0xAA |
17 | |
18 | struct st33zp24_i2c_phy { |
19 | struct i2c_client *client; |
20 | u8 buf[ST33ZP24_BUFSIZE + 1]; |
21 | }; |
22 | |
23 | /* |
24 | * write8_reg |
25 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. |
26 | * @param: tpm_register, the tpm tis register where the data should be written |
27 | * @param: tpm_data, the tpm_data to write inside the tpm_register |
28 | * @param: tpm_size, The length of the data |
29 | * @return: Returns negative errno, or else the number of bytes written. |
30 | */ |
31 | static int write8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) |
32 | { |
33 | struct st33zp24_i2c_phy *phy = phy_id; |
34 | |
35 | phy->buf[0] = tpm_register; |
36 | memcpy(phy->buf + 1, tpm_data, tpm_size); |
37 | return i2c_master_send(client: phy->client, buf: phy->buf, count: tpm_size + 1); |
38 | } /* write8_reg() */ |
39 | |
40 | /* |
41 | * read8_reg |
42 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. |
43 | * @param: tpm_register, the tpm tis register where the data should be read |
44 | * @param: tpm_data, the TPM response |
45 | * @param: tpm_size, tpm TPM response size to read. |
46 | * @return: number of byte read successfully: should be one if success. |
47 | */ |
48 | static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) |
49 | { |
50 | struct st33zp24_i2c_phy *phy = phy_id; |
51 | u8 status = 0; |
52 | u8 data; |
53 | |
54 | data = TPM_DUMMY_BYTE; |
55 | status = write8_reg(phy_id: phy, tpm_register, tpm_data: &data, tpm_size: 1); |
56 | if (status == 2) |
57 | status = i2c_master_recv(client: phy->client, buf: tpm_data, count: tpm_size); |
58 | return status; |
59 | } /* read8_reg() */ |
60 | |
61 | /* |
62 | * st33zp24_i2c_send |
63 | * Send byte to the TIS register according to the ST33ZP24 I2C protocol. |
64 | * @param: phy_id, the phy description |
65 | * @param: tpm_register, the tpm tis register where the data should be written |
66 | * @param: tpm_data, the tpm_data to write inside the tpm_register |
67 | * @param: tpm_size, the length of the data |
68 | * @return: number of byte written successfully: should be one if success. |
69 | */ |
70 | static int st33zp24_i2c_send(void *phy_id, u8 tpm_register, u8 *tpm_data, |
71 | int tpm_size) |
72 | { |
73 | return write8_reg(phy_id, tpm_register: tpm_register | TPM_WRITE_DIRECTION, tpm_data, |
74 | tpm_size); |
75 | } |
76 | |
77 | /* |
78 | * st33zp24_i2c_recv |
79 | * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. |
80 | * @param: phy_id, the phy description |
81 | * @param: tpm_register, the tpm tis register where the data should be read |
82 | * @param: tpm_data, the TPM response |
83 | * @param: tpm_size, tpm TPM response size to read. |
84 | * @return: number of byte read successfully: should be one if success. |
85 | */ |
86 | static int st33zp24_i2c_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, |
87 | int tpm_size) |
88 | { |
89 | return read8_reg(phy_id, tpm_register, tpm_data, tpm_size); |
90 | } |
91 | |
92 | static const struct st33zp24_phy_ops i2c_phy_ops = { |
93 | .send = st33zp24_i2c_send, |
94 | .recv = st33zp24_i2c_recv, |
95 | }; |
96 | |
97 | /* |
98 | * st33zp24_i2c_probe initialize the TPM device |
99 | * @param: client, the i2c_client description (TPM I2C description). |
100 | * @param: id, the i2c_device_id struct. |
101 | * @return: 0 in case of success. |
102 | * -1 in other case. |
103 | */ |
104 | static int st33zp24_i2c_probe(struct i2c_client *client) |
105 | { |
106 | struct st33zp24_i2c_phy *phy; |
107 | |
108 | if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_I2C)) { |
109 | dev_info(&client->dev, "client not i2c capable\n" ); |
110 | return -ENODEV; |
111 | } |
112 | |
113 | phy = devm_kzalloc(dev: &client->dev, size: sizeof(struct st33zp24_i2c_phy), |
114 | GFP_KERNEL); |
115 | if (!phy) |
116 | return -ENOMEM; |
117 | |
118 | phy->client = client; |
119 | |
120 | return st33zp24_probe(phy_id: phy, ops: &i2c_phy_ops, dev: &client->dev, irq: client->irq); |
121 | } |
122 | |
123 | /* |
124 | * st33zp24_i2c_remove remove the TPM device |
125 | * @param: client, the i2c_client description (TPM I2C description). |
126 | * @return: 0 in case of success. |
127 | */ |
128 | static void st33zp24_i2c_remove(struct i2c_client *client) |
129 | { |
130 | struct tpm_chip *chip = i2c_get_clientdata(client); |
131 | |
132 | st33zp24_remove(chip); |
133 | } |
134 | |
135 | static const struct i2c_device_id st33zp24_i2c_id[] = { |
136 | {TPM_ST33_I2C, 0}, |
137 | {} |
138 | }; |
139 | MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id); |
140 | |
141 | static const struct of_device_id of_st33zp24_i2c_match[] __maybe_unused = { |
142 | { .compatible = "st,st33zp24-i2c" , }, |
143 | {} |
144 | }; |
145 | MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); |
146 | |
147 | static const struct acpi_device_id st33zp24_i2c_acpi_match[] __maybe_unused = { |
148 | {"SMO3324" }, |
149 | {} |
150 | }; |
151 | MODULE_DEVICE_TABLE(acpi, st33zp24_i2c_acpi_match); |
152 | |
153 | static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend, |
154 | st33zp24_pm_resume); |
155 | |
156 | static struct i2c_driver st33zp24_i2c_driver = { |
157 | .driver = { |
158 | .name = TPM_ST33_I2C, |
159 | .pm = &st33zp24_i2c_ops, |
160 | .of_match_table = of_match_ptr(of_st33zp24_i2c_match), |
161 | .acpi_match_table = ACPI_PTR(st33zp24_i2c_acpi_match), |
162 | }, |
163 | .probe = st33zp24_i2c_probe, |
164 | .remove = st33zp24_i2c_remove, |
165 | .id_table = st33zp24_i2c_id |
166 | }; |
167 | |
168 | module_i2c_driver(st33zp24_i2c_driver); |
169 | |
170 | MODULE_AUTHOR("TPM support <TPMsupport@list.st.com>" ); |
171 | MODULE_DESCRIPTION("STM TPM 1.2 I2C ST33 Driver" ); |
172 | MODULE_VERSION("1.3.0" ); |
173 | MODULE_LICENSE("GPL" ); |
174 | |