162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 462306a36Sopenharmony_ci * Copyright (C) 2009 - 2016 STMicroelectronics 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/i2c.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/acpi.h> 1162306a36Sopenharmony_ci#include <linux/tpm.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "../tpm.h" 1462306a36Sopenharmony_ci#include "st33zp24.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define TPM_DUMMY_BYTE 0xAA 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct st33zp24_i2c_phy { 1962306a36Sopenharmony_ci struct i2c_client *client; 2062306a36Sopenharmony_ci u8 buf[ST33ZP24_BUFSIZE + 1]; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * write8_reg 2562306a36Sopenharmony_ci * Send byte to the TIS register according to the ST33ZP24 I2C protocol. 2662306a36Sopenharmony_ci * @param: tpm_register, the tpm tis register where the data should be written 2762306a36Sopenharmony_ci * @param: tpm_data, the tpm_data to write inside the tpm_register 2862306a36Sopenharmony_ci * @param: tpm_size, The length of the data 2962306a36Sopenharmony_ci * @return: Returns negative errno, or else the number of bytes written. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cistatic int write8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct st33zp24_i2c_phy *phy = phy_id; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci phy->buf[0] = tpm_register; 3662306a36Sopenharmony_ci memcpy(phy->buf + 1, tpm_data, tpm_size); 3762306a36Sopenharmony_ci return i2c_master_send(phy->client, phy->buf, tpm_size + 1); 3862306a36Sopenharmony_ci} /* write8_reg() */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * read8_reg 4262306a36Sopenharmony_ci * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. 4362306a36Sopenharmony_ci * @param: tpm_register, the tpm tis register where the data should be read 4462306a36Sopenharmony_ci * @param: tpm_data, the TPM response 4562306a36Sopenharmony_ci * @param: tpm_size, tpm TPM response size to read. 4662306a36Sopenharmony_ci * @return: number of byte read successfully: should be one if success. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct st33zp24_i2c_phy *phy = phy_id; 5162306a36Sopenharmony_ci u8 status = 0; 5262306a36Sopenharmony_ci u8 data; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci data = TPM_DUMMY_BYTE; 5562306a36Sopenharmony_ci status = write8_reg(phy, tpm_register, &data, 1); 5662306a36Sopenharmony_ci if (status == 2) 5762306a36Sopenharmony_ci status = i2c_master_recv(phy->client, tpm_data, tpm_size); 5862306a36Sopenharmony_ci return status; 5962306a36Sopenharmony_ci} /* read8_reg() */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * st33zp24_i2c_send 6362306a36Sopenharmony_ci * Send byte to the TIS register according to the ST33ZP24 I2C protocol. 6462306a36Sopenharmony_ci * @param: phy_id, the phy description 6562306a36Sopenharmony_ci * @param: tpm_register, the tpm tis register where the data should be written 6662306a36Sopenharmony_ci * @param: tpm_data, the tpm_data to write inside the tpm_register 6762306a36Sopenharmony_ci * @param: tpm_size, the length of the data 6862306a36Sopenharmony_ci * @return: number of byte written successfully: should be one if success. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistatic int st33zp24_i2c_send(void *phy_id, u8 tpm_register, u8 *tpm_data, 7162306a36Sopenharmony_ci int tpm_size) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return write8_reg(phy_id, tpm_register | TPM_WRITE_DIRECTION, tpm_data, 7462306a36Sopenharmony_ci tpm_size); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * st33zp24_i2c_recv 7962306a36Sopenharmony_ci * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. 8062306a36Sopenharmony_ci * @param: phy_id, the phy description 8162306a36Sopenharmony_ci * @param: tpm_register, the tpm tis register where the data should be read 8262306a36Sopenharmony_ci * @param: tpm_data, the TPM response 8362306a36Sopenharmony_ci * @param: tpm_size, tpm TPM response size to read. 8462306a36Sopenharmony_ci * @return: number of byte read successfully: should be one if success. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic int st33zp24_i2c_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, 8762306a36Sopenharmony_ci int tpm_size) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci return read8_reg(phy_id, tpm_register, tpm_data, tpm_size); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const struct st33zp24_phy_ops i2c_phy_ops = { 9362306a36Sopenharmony_ci .send = st33zp24_i2c_send, 9462306a36Sopenharmony_ci .recv = st33zp24_i2c_recv, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * st33zp24_i2c_probe initialize the TPM device 9962306a36Sopenharmony_ci * @param: client, the i2c_client description (TPM I2C description). 10062306a36Sopenharmony_ci * @param: id, the i2c_device_id struct. 10162306a36Sopenharmony_ci * @return: 0 in case of success. 10262306a36Sopenharmony_ci * -1 in other case. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic int st33zp24_i2c_probe(struct i2c_client *client) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct st33zp24_i2c_phy *phy; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 10962306a36Sopenharmony_ci dev_info(&client->dev, "client not i2c capable\n"); 11062306a36Sopenharmony_ci return -ENODEV; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci phy = devm_kzalloc(&client->dev, sizeof(struct st33zp24_i2c_phy), 11462306a36Sopenharmony_ci GFP_KERNEL); 11562306a36Sopenharmony_ci if (!phy) 11662306a36Sopenharmony_ci return -ENOMEM; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci phy->client = client; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return st33zp24_probe(phy, &i2c_phy_ops, &client->dev, client->irq); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * st33zp24_i2c_remove remove the TPM device 12562306a36Sopenharmony_ci * @param: client, the i2c_client description (TPM I2C description). 12662306a36Sopenharmony_ci * @return: 0 in case of success. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistatic void st33zp24_i2c_remove(struct i2c_client *client) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct tpm_chip *chip = i2c_get_clientdata(client); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci st33zp24_remove(chip); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic const struct i2c_device_id st33zp24_i2c_id[] = { 13662306a36Sopenharmony_ci {TPM_ST33_I2C, 0}, 13762306a36Sopenharmony_ci {} 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct of_device_id of_st33zp24_i2c_match[] __maybe_unused = { 14262306a36Sopenharmony_ci { .compatible = "st,st33zp24-i2c", }, 14362306a36Sopenharmony_ci {} 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic const struct acpi_device_id st33zp24_i2c_acpi_match[] __maybe_unused = { 14862306a36Sopenharmony_ci {"SMO3324"}, 14962306a36Sopenharmony_ci {} 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, st33zp24_i2c_acpi_match); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend, 15462306a36Sopenharmony_ci st33zp24_pm_resume); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic struct i2c_driver st33zp24_i2c_driver = { 15762306a36Sopenharmony_ci .driver = { 15862306a36Sopenharmony_ci .name = TPM_ST33_I2C, 15962306a36Sopenharmony_ci .pm = &st33zp24_i2c_ops, 16062306a36Sopenharmony_ci .of_match_table = of_match_ptr(of_st33zp24_i2c_match), 16162306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(st33zp24_i2c_acpi_match), 16262306a36Sopenharmony_ci }, 16362306a36Sopenharmony_ci .probe = st33zp24_i2c_probe, 16462306a36Sopenharmony_ci .remove = st33zp24_i2c_remove, 16562306a36Sopenharmony_ci .id_table = st33zp24_i2c_id 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cimodule_i2c_driver(st33zp24_i2c_driver); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciMODULE_AUTHOR("TPM support (TPMsupport@list.st.com)"); 17162306a36Sopenharmony_ciMODULE_DESCRIPTION("STM TPM 1.2 I2C ST33 Driver"); 17262306a36Sopenharmony_ciMODULE_VERSION("1.3.0"); 17362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 174