tpm/st33zp24: Add support for acpi probing for i2c device.
[deliverable/linux.git] / drivers / char / tpm / st33zp24 / i2c.c
CommitLineData
bf38b871
CR
1/*
2 * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
8bb273f2 3 * Copyright (C) 2009 - 2016 STMicroelectronics
bf38b871
CR
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/module.h>
20#include <linux/i2c.h>
21#include <linux/gpio.h>
22eb90db 22#include <linux/gpio/consumer.h>
bf38b871
CR
23#include <linux/of_irq.h>
24#include <linux/of_gpio.h>
22eb90db 25#include <linux/acpi.h>
bf38b871
CR
26#include <linux/tpm.h>
27#include <linux/platform_data/st33zp24.h>
28
29#include "st33zp24.h"
30
31#define TPM_DUMMY_BYTE 0xAA
bf38b871
CR
32
33struct st33zp24_i2c_phy {
34 struct i2c_client *client;
35 u8 buf[TPM_BUFSIZE + 1];
36 int io_lpcpd;
37};
38
39/*
40 * write8_reg
41 * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
42 * @param: tpm_register, the tpm tis register where the data should be written
43 * @param: tpm_data, the tpm_data to write inside the tpm_register
44 * @param: tpm_size, The length of the data
45 * @return: Returns negative errno, or else the number of bytes written.
46 */
47static int write8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size)
48{
49 struct st33zp24_i2c_phy *phy = phy_id;
50
51 phy->buf[0] = tpm_register;
52 memcpy(phy->buf + 1, tpm_data, tpm_size);
53 return i2c_master_send(phy->client, phy->buf, tpm_size + 1);
54} /* write8_reg() */
55
56/*
57 * read8_reg
58 * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
59 * @param: tpm_register, the tpm tis register where the data should be read
60 * @param: tpm_data, the TPM response
61 * @param: tpm_size, tpm TPM response size to read.
62 * @return: number of byte read successfully: should be one if success.
63 */
64static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size)
65{
66 struct st33zp24_i2c_phy *phy = phy_id;
67 u8 status = 0;
68 u8 data;
69
70 data = TPM_DUMMY_BYTE;
71 status = write8_reg(phy, tpm_register, &data, 1);
72 if (status == 2)
73 status = i2c_master_recv(phy->client, tpm_data, tpm_size);
74 return status;
75} /* read8_reg() */
76
77/*
78 * st33zp24_i2c_send
79 * Send byte to 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 written
82 * @param: tpm_data, the tpm_data to write inside the tpm_register
83 * @param: tpm_size, the length of the data
84 * @return: number of byte written successfully: should be one if success.
85 */
86static int st33zp24_i2c_send(void *phy_id, u8 tpm_register, u8 *tpm_data,
87 int tpm_size)
88{
89 return write8_reg(phy_id, tpm_register | TPM_WRITE_DIRECTION, tpm_data,
90 tpm_size);
91}
92
93/*
94 * st33zp24_i2c_recv
95 * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
96 * @param: phy_id, the phy description
97 * @param: tpm_register, the tpm tis register where the data should be read
98 * @param: tpm_data, the TPM response
99 * @param: tpm_size, tpm TPM response size to read.
100 * @return: number of byte read successfully: should be one if success.
101 */
102static int st33zp24_i2c_recv(void *phy_id, u8 tpm_register, u8 *tpm_data,
103 int tpm_size)
104{
105 return read8_reg(phy_id, tpm_register, tpm_data, tpm_size);
106}
107
108static const struct st33zp24_phy_ops i2c_phy_ops = {
109 .send = st33zp24_i2c_send,
110 .recv = st33zp24_i2c_recv,
111};
112
22eb90db
CR
113static int st33zp24_i2c_acpi_request_resources(struct st33zp24_i2c_phy *phy)
114{
115 struct i2c_client *client = phy->client;
116 const struct acpi_device_id *id;
117 struct gpio_desc *gpiod_lpcpd;
118 struct device *dev;
119
120 if (!client)
121 return -EINVAL;
122
123 dev = &client->dev;
124
125 /* Match the struct device against a given list of ACPI IDs */
126 id = acpi_match_device(dev->driver->acpi_match_table, dev);
127 if (!id)
128 return -ENODEV;
129
130 /* Get LPCPD GPIO from ACPI */
131 gpiod_lpcpd = devm_gpiod_get_index(dev, "TPM IO LPCPD", 1,
132 GPIOD_OUT_HIGH);
133 if (IS_ERR(gpiod_lpcpd)) {
134 dev_err(&client->dev,
135 "Failed to retrieve lpcpd-gpios from acpi.\n");
136 phy->io_lpcpd = -1;
137 /*
138 * lpcpd pin is not specified. This is not an issue as
139 * power management can be also managed by TPM specific
140 * commands. So leave with a success status code.
141 */
142 return 0;
143 }
144
145 phy->io_lpcpd = desc_to_gpio(gpiod_lpcpd);
146
147 return 0;
148}
149
300796cd 150static int st33zp24_i2c_of_request_resources(struct st33zp24_i2c_phy *phy)
fec60f29 151{
bf38b871 152 struct device_node *pp;
300796cd 153 struct i2c_client *client = phy->client;
bf38b871
CR
154 int gpio;
155 int ret;
156
157 pp = client->dev.of_node;
158 if (!pp) {
159 dev_err(&client->dev, "No platform data\n");
160 return -ENODEV;
161 }
162
163 /* Get GPIO from device tree */
164 gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
165 if (gpio < 0) {
166 dev_err(&client->dev,
167 "Failed to retrieve lpcpd-gpios from dts.\n");
168 phy->io_lpcpd = -1;
169 /*
170 * lpcpd pin is not specified. This is not an issue as
171 * power management can be also managed by TPM specific
172 * commands. So leave with a success status code.
173 */
174 return 0;
175 }
176 /* GPIO request and configuration */
177 ret = devm_gpio_request_one(&client->dev, gpio,
178 GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
179 if (ret) {
180 dev_err(&client->dev, "Failed to request lpcpd pin\n");
181 return -ENODEV;
182 }
183 phy->io_lpcpd = gpio;
184
185 return 0;
186}
bf38b871 187
300796cd
CR
188static int st33zp24_i2c_request_resources(struct i2c_client *client,
189 struct st33zp24_i2c_phy *phy)
bf38b871
CR
190{
191 struct st33zp24_platform_data *pdata;
192 int ret;
193
194 pdata = client->dev.platform_data;
195 if (!pdata) {
196 dev_err(&client->dev, "No platform data\n");
197 return -ENODEV;
198 }
199
200 /* store for late use */
201 phy->io_lpcpd = pdata->io_lpcpd;
202
203 if (gpio_is_valid(pdata->io_lpcpd)) {
204 ret = devm_gpio_request_one(&client->dev,
205 pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
206 "TPM IO_LPCPD");
207 if (ret) {
208 dev_err(&client->dev, "Failed to request lpcpd pin\n");
209 return ret;
210 }
211 }
212
213 return 0;
214}
215
216/*
217 * st33zp24_i2c_probe initialize the TPM device
218 * @param: client, the i2c_client drescription (TPM I2C description).
219 * @param: id, the i2c_device_id struct.
220 * @return: 0 in case of success.
221 * -1 in other case.
222 */
223static int st33zp24_i2c_probe(struct i2c_client *client,
224 const struct i2c_device_id *id)
225{
226 int ret;
227 struct st33zp24_platform_data *pdata;
228 struct st33zp24_i2c_phy *phy;
229
230 if (!client) {
231 pr_info("%s: i2c client is NULL. Device not accessible.\n",
232 __func__);
233 return -ENODEV;
234 }
235
236 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
237 dev_info(&client->dev, "client not i2c capable\n");
238 return -ENODEV;
239 }
240
241 phy = devm_kzalloc(&client->dev, sizeof(struct st33zp24_i2c_phy),
242 GFP_KERNEL);
243 if (!phy)
244 return -ENOMEM;
245
246 phy->client = client;
247 pdata = client->dev.platform_data;
248 if (!pdata && client->dev.of_node) {
300796cd 249 ret = st33zp24_i2c_of_request_resources(phy);
bf38b871
CR
250 if (ret)
251 return ret;
252 } else if (pdata) {
300796cd 253 ret = st33zp24_i2c_request_resources(client, phy);
fec60f29
CR
254 if (ret)
255 return ret;
22eb90db
CR
256 } else if (ACPI_HANDLE(&client->dev)) {
257 ret = st33zp24_i2c_acpi_request_resources(phy);
258 if (ret)
259 return ret;
bf38b871
CR
260 }
261
262 return st33zp24_probe(phy, &i2c_phy_ops, &client->dev, client->irq,
263 phy->io_lpcpd);
264}
265
266/*
267 * st33zp24_i2c_remove remove the TPM device
268 * @param: client, the i2c_client description (TPM I2C description).
269 * @return: 0 in case of success.
270 */
271static int st33zp24_i2c_remove(struct i2c_client *client)
272{
273 struct tpm_chip *chip = i2c_get_clientdata(client);
274
275 return st33zp24_remove(chip);
276}
277
278static const struct i2c_device_id st33zp24_i2c_id[] = {
279 {TPM_ST33_I2C, 0},
280 {}
281};
282MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id);
283
bf38b871
CR
284static const struct of_device_id of_st33zp24_i2c_match[] = {
285 { .compatible = "st,st33zp24-i2c", },
286 {}
287};
288MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match);
bf38b871 289
22eb90db
CR
290static const struct acpi_device_id st33zp24_i2c_acpi_match[] = {
291 {"SMO3324"},
292 {}
293};
294MODULE_DEVICE_TABLE(acpi, st33zp24_i2c_acpi_match);
295
bf38b871
CR
296static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend,
297 st33zp24_pm_resume);
298
299static struct i2c_driver st33zp24_i2c_driver = {
300 .driver = {
bf38b871
CR
301 .name = TPM_ST33_I2C,
302 .pm = &st33zp24_i2c_ops,
303 .of_match_table = of_match_ptr(of_st33zp24_i2c_match),
22eb90db 304 .acpi_match_table = ACPI_PTR(st33zp24_i2c_acpi_match),
bf38b871
CR
305 },
306 .probe = st33zp24_i2c_probe,
307 .remove = st33zp24_i2c_remove,
308 .id_table = st33zp24_i2c_id
309};
310
311module_i2c_driver(st33zp24_i2c_driver);
312
313MODULE_AUTHOR("TPM support (TPMsupport@list.st.com)");
314MODULE_DESCRIPTION("STM TPM 1.2 I2C ST33 Driver");
315MODULE_VERSION("1.3.0");
316MODULE_LICENSE("GPL");
This page took 0.098719 seconds and 5 git commands to generate.