18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24 48c2ecf20Sopenharmony_ci * Copyright (C) 2009 - 2016 STMicroelectronics 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 98c2ecf20Sopenharmony_ci#include <linux/gpio.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 128c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 138c2ecf20Sopenharmony_ci#include <linux/acpi.h> 148c2ecf20Sopenharmony_ci#include <linux/tpm.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_data/st33zp24.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "../tpm.h" 188c2ecf20Sopenharmony_ci#include "st33zp24.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define TPM_DATA_FIFO 0x24 218c2ecf20Sopenharmony_ci#define TPM_INTF_CAPABILITY 0x14 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define TPM_DUMMY_BYTE 0x00 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define MAX_SPI_LATENCY 15 268c2ecf20Sopenharmony_ci#define LOCALITY0 0 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define ST33ZP24_OK 0x5A 298c2ecf20Sopenharmony_ci#define ST33ZP24_UNDEFINED_ERR 0x80 308c2ecf20Sopenharmony_ci#define ST33ZP24_BADLOCALITY 0x81 318c2ecf20Sopenharmony_ci#define ST33ZP24_TISREGISTER_UNKNOWN 0x82 328c2ecf20Sopenharmony_ci#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83 338c2ecf20Sopenharmony_ci#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84 348c2ecf20Sopenharmony_ci#define ST33ZP24_BAD_COMMAND_ORDER 0x85 358c2ecf20Sopenharmony_ci#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86 368c2ecf20Sopenharmony_ci#define ST33ZP24_TPM_FIFO_OVERFLOW 0x89 378c2ecf20Sopenharmony_ci#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A 388c2ecf20Sopenharmony_ci#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B 398c2ecf20Sopenharmony_ci#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90 408c2ecf20Sopenharmony_ci#define ST33ZP24_DUMMY_BYTES 0x00 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * TPM command can be up to 2048 byte, A TPM response can be up to 448c2ecf20Sopenharmony_ci * 1024 byte. 458c2ecf20Sopenharmony_ci * Between command and response, there are latency byte (up to 15 468c2ecf20Sopenharmony_ci * usually on st33zp24 2 are enough). 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Overall when sending a command and expecting an answer we need if 498c2ecf20Sopenharmony_ci * worst case: 508c2ecf20Sopenharmony_ci * 2048 (for the TPM command) + 1024 (for the TPM answer). We need 518c2ecf20Sopenharmony_ci * some latency byte before the answer is available (max 15). 528c2ecf20Sopenharmony_ci * We have 2048 + 1024 + 15. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci#define ST33ZP24_SPI_BUFFER_SIZE (ST33ZP24_BUFSIZE + (ST33ZP24_BUFSIZE / 2) +\ 558c2ecf20Sopenharmony_ci MAX_SPI_LATENCY) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistruct st33zp24_spi_phy { 598c2ecf20Sopenharmony_ci struct spi_device *spi_device; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci u8 tx_buf[ST33ZP24_SPI_BUFFER_SIZE]; 628c2ecf20Sopenharmony_ci u8 rx_buf[ST33ZP24_SPI_BUFFER_SIZE]; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci int io_lpcpd; 658c2ecf20Sopenharmony_ci int latency; 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int st33zp24_status_to_errno(u8 code) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci switch (code) { 718c2ecf20Sopenharmony_ci case ST33ZP24_OK: 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci case ST33ZP24_UNDEFINED_ERR: 748c2ecf20Sopenharmony_ci case ST33ZP24_BADLOCALITY: 758c2ecf20Sopenharmony_ci case ST33ZP24_TISREGISTER_UNKNOWN: 768c2ecf20Sopenharmony_ci case ST33ZP24_LOCALITY_NOT_ACTIVATED: 778c2ecf20Sopenharmony_ci case ST33ZP24_HASH_END_BEFORE_HASH_START: 788c2ecf20Sopenharmony_ci case ST33ZP24_BAD_COMMAND_ORDER: 798c2ecf20Sopenharmony_ci case ST33ZP24_UNEXPECTED_READ_FIFO: 808c2ecf20Sopenharmony_ci case ST33ZP24_UNEXPECTED_WRITE_FIFO: 818c2ecf20Sopenharmony_ci case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END: 828c2ecf20Sopenharmony_ci return -EPROTO; 838c2ecf20Sopenharmony_ci case ST33ZP24_INCORECT_RECEIVED_LENGTH: 848c2ecf20Sopenharmony_ci case ST33ZP24_TPM_FIFO_OVERFLOW: 858c2ecf20Sopenharmony_ci return -EMSGSIZE; 868c2ecf20Sopenharmony_ci case ST33ZP24_DUMMY_BYTES: 878c2ecf20Sopenharmony_ci return -ENOSYS; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci return code; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * st33zp24_spi_send 948c2ecf20Sopenharmony_ci * Send byte to the TIS register according to the ST33ZP24 SPI protocol. 958c2ecf20Sopenharmony_ci * @param: phy_id, the phy description 968c2ecf20Sopenharmony_ci * @param: tpm_register, the tpm tis register where the data should be written 978c2ecf20Sopenharmony_ci * @param: tpm_data, the tpm_data to write inside the tpm_register 988c2ecf20Sopenharmony_ci * @param: tpm_size, The length of the data 998c2ecf20Sopenharmony_ci * @return: should be zero if success else a negative error code. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistatic int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data, 1028c2ecf20Sopenharmony_ci int tpm_size) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int total_length = 0, ret = 0; 1058c2ecf20Sopenharmony_ci struct st33zp24_spi_phy *phy = phy_id; 1068c2ecf20Sopenharmony_ci struct spi_device *dev = phy->spi_device; 1078c2ecf20Sopenharmony_ci struct spi_transfer spi_xfer = { 1088c2ecf20Sopenharmony_ci .tx_buf = phy->tx_buf, 1098c2ecf20Sopenharmony_ci .rx_buf = phy->rx_buf, 1108c2ecf20Sopenharmony_ci }; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Pre-Header */ 1138c2ecf20Sopenharmony_ci phy->tx_buf[total_length++] = TPM_WRITE_DIRECTION | LOCALITY0; 1148c2ecf20Sopenharmony_ci phy->tx_buf[total_length++] = tpm_register; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) { 1178c2ecf20Sopenharmony_ci phy->tx_buf[total_length++] = tpm_size >> 8; 1188c2ecf20Sopenharmony_ci phy->tx_buf[total_length++] = tpm_size; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci memcpy(&phy->tx_buf[total_length], tpm_data, tpm_size); 1228c2ecf20Sopenharmony_ci total_length += tpm_size; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE, phy->latency); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci spi_xfer.len = total_length + phy->latency; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ret = spi_sync_transfer(dev, &spi_xfer, 1); 1298c2ecf20Sopenharmony_ci if (ret == 0) 1308c2ecf20Sopenharmony_ci ret = phy->rx_buf[total_length + phy->latency - 1]; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return st33zp24_status_to_errno(ret); 1338c2ecf20Sopenharmony_ci} /* st33zp24_spi_send() */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * st33zp24_spi_read8_recv 1378c2ecf20Sopenharmony_ci * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. 1388c2ecf20Sopenharmony_ci * @param: phy_id, the phy description 1398c2ecf20Sopenharmony_ci * @param: tpm_register, the tpm tis register where the data should be read 1408c2ecf20Sopenharmony_ci * @param: tpm_data, the TPM response 1418c2ecf20Sopenharmony_ci * @param: tpm_size, tpm TPM response size to read. 1428c2ecf20Sopenharmony_ci * @return: should be zero if success else a negative error code. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cistatic int st33zp24_spi_read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, 1458c2ecf20Sopenharmony_ci int tpm_size) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int total_length = 0, ret; 1488c2ecf20Sopenharmony_ci struct st33zp24_spi_phy *phy = phy_id; 1498c2ecf20Sopenharmony_ci struct spi_device *dev = phy->spi_device; 1508c2ecf20Sopenharmony_ci struct spi_transfer spi_xfer = { 1518c2ecf20Sopenharmony_ci .tx_buf = phy->tx_buf, 1528c2ecf20Sopenharmony_ci .rx_buf = phy->rx_buf, 1538c2ecf20Sopenharmony_ci }; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Pre-Header */ 1568c2ecf20Sopenharmony_ci phy->tx_buf[total_length++] = LOCALITY0; 1578c2ecf20Sopenharmony_ci phy->tx_buf[total_length++] = tpm_register; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE, 1608c2ecf20Sopenharmony_ci phy->latency + tpm_size); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci spi_xfer.len = total_length + phy->latency + tpm_size; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* header + status byte + size of the data + status byte */ 1658c2ecf20Sopenharmony_ci ret = spi_sync_transfer(dev, &spi_xfer, 1); 1668c2ecf20Sopenharmony_ci if (tpm_size > 0 && ret == 0) { 1678c2ecf20Sopenharmony_ci ret = phy->rx_buf[total_length + phy->latency - 1]; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci memcpy(tpm_data, phy->rx_buf + total_length + phy->latency, 1708c2ecf20Sopenharmony_ci tpm_size); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return ret; 1748c2ecf20Sopenharmony_ci} /* st33zp24_spi_read8_reg() */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * st33zp24_spi_recv 1788c2ecf20Sopenharmony_ci * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. 1798c2ecf20Sopenharmony_ci * @param: phy_id, the phy description 1808c2ecf20Sopenharmony_ci * @param: tpm_register, the tpm tis register where the data should be read 1818c2ecf20Sopenharmony_ci * @param: tpm_data, the TPM response 1828c2ecf20Sopenharmony_ci * @param: tpm_size, tpm TPM response size to read. 1838c2ecf20Sopenharmony_ci * @return: number of byte read successfully: should be one if success. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_cistatic int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, 1868c2ecf20Sopenharmony_ci int tpm_size) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci int ret; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = st33zp24_spi_read8_reg(phy_id, tpm_register, tpm_data, tpm_size); 1918c2ecf20Sopenharmony_ci if (!st33zp24_status_to_errno(ret)) 1928c2ecf20Sopenharmony_ci return tpm_size; 1938c2ecf20Sopenharmony_ci return ret; 1948c2ecf20Sopenharmony_ci} /* st33zp24_spi_recv() */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int st33zp24_spi_evaluate_latency(void *phy_id) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct st33zp24_spi_phy *phy = phy_id; 1998c2ecf20Sopenharmony_ci int latency = 1, status = 0; 2008c2ecf20Sopenharmony_ci u8 data = 0; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci while (!status && latency < MAX_SPI_LATENCY) { 2038c2ecf20Sopenharmony_ci phy->latency = latency; 2048c2ecf20Sopenharmony_ci status = st33zp24_spi_read8_reg(phy_id, TPM_INTF_CAPABILITY, 2058c2ecf20Sopenharmony_ci &data, 1); 2068c2ecf20Sopenharmony_ci latency++; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci if (status < 0) 2098c2ecf20Sopenharmony_ci return status; 2108c2ecf20Sopenharmony_ci if (latency == MAX_SPI_LATENCY) 2118c2ecf20Sopenharmony_ci return -ENODEV; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return latency - 1; 2148c2ecf20Sopenharmony_ci} /* evaluate_latency() */ 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic const struct st33zp24_phy_ops spi_phy_ops = { 2178c2ecf20Sopenharmony_ci .send = st33zp24_spi_send, 2188c2ecf20Sopenharmony_ci .recv = st33zp24_spi_recv, 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params lpcpd_gpios = { 1, 0, false }; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_st33zp24_gpios[] = { 2248c2ecf20Sopenharmony_ci { "lpcpd-gpios", &lpcpd_gpios, 1 }, 2258c2ecf20Sopenharmony_ci {}, 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int st33zp24_spi_acpi_request_resources(struct spi_device *spi_dev) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct tpm_chip *chip = spi_get_drvdata(spi_dev); 2318c2ecf20Sopenharmony_ci struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); 2328c2ecf20Sopenharmony_ci struct st33zp24_spi_phy *phy = tpm_dev->phy_id; 2338c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_lpcpd; 2348c2ecf20Sopenharmony_ci struct device *dev = &spi_dev->dev; 2358c2ecf20Sopenharmony_ci int ret; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st33zp24_gpios); 2388c2ecf20Sopenharmony_ci if (ret) 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Get LPCPD GPIO from ACPI */ 2428c2ecf20Sopenharmony_ci gpiod_lpcpd = devm_gpiod_get(dev, "lpcpd", GPIOD_OUT_HIGH); 2438c2ecf20Sopenharmony_ci if (IS_ERR(gpiod_lpcpd)) { 2448c2ecf20Sopenharmony_ci dev_err(dev, "Failed to retrieve lpcpd-gpios from acpi.\n"); 2458c2ecf20Sopenharmony_ci phy->io_lpcpd = -1; 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * lpcpd pin is not specified. This is not an issue as 2488c2ecf20Sopenharmony_ci * power management can be also managed by TPM specific 2498c2ecf20Sopenharmony_ci * commands. So leave with a success status code. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci phy->io_lpcpd = desc_to_gpio(gpiod_lpcpd); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int st33zp24_spi_of_request_resources(struct spi_device *spi_dev) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct tpm_chip *chip = spi_get_drvdata(spi_dev); 2628c2ecf20Sopenharmony_ci struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); 2638c2ecf20Sopenharmony_ci struct st33zp24_spi_phy *phy = tpm_dev->phy_id; 2648c2ecf20Sopenharmony_ci struct device_node *pp; 2658c2ecf20Sopenharmony_ci int gpio; 2668c2ecf20Sopenharmony_ci int ret; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci pp = spi_dev->dev.of_node; 2698c2ecf20Sopenharmony_ci if (!pp) { 2708c2ecf20Sopenharmony_ci dev_err(&spi_dev->dev, "No platform data\n"); 2718c2ecf20Sopenharmony_ci return -ENODEV; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Get GPIO from device tree */ 2758c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); 2768c2ecf20Sopenharmony_ci if (gpio < 0) { 2778c2ecf20Sopenharmony_ci dev_err(&spi_dev->dev, 2788c2ecf20Sopenharmony_ci "Failed to retrieve lpcpd-gpios from dts.\n"); 2798c2ecf20Sopenharmony_ci phy->io_lpcpd = -1; 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * lpcpd pin is not specified. This is not an issue as 2828c2ecf20Sopenharmony_ci * power management can be also managed by TPM specific 2838c2ecf20Sopenharmony_ci * commands. So leave with a success status code. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci /* GPIO request and configuration */ 2888c2ecf20Sopenharmony_ci ret = devm_gpio_request_one(&spi_dev->dev, gpio, 2898c2ecf20Sopenharmony_ci GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); 2908c2ecf20Sopenharmony_ci if (ret) { 2918c2ecf20Sopenharmony_ci dev_err(&spi_dev->dev, "Failed to request lpcpd pin\n"); 2928c2ecf20Sopenharmony_ci return -ENODEV; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci phy->io_lpcpd = gpio; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int st33zp24_spi_request_resources(struct spi_device *dev) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct tpm_chip *chip = spi_get_drvdata(dev); 3028c2ecf20Sopenharmony_ci struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); 3038c2ecf20Sopenharmony_ci struct st33zp24_spi_phy *phy = tpm_dev->phy_id; 3048c2ecf20Sopenharmony_ci struct st33zp24_platform_data *pdata; 3058c2ecf20Sopenharmony_ci int ret; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci pdata = dev->dev.platform_data; 3088c2ecf20Sopenharmony_ci if (!pdata) { 3098c2ecf20Sopenharmony_ci dev_err(&dev->dev, "No platform data\n"); 3108c2ecf20Sopenharmony_ci return -ENODEV; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* store for late use */ 3148c2ecf20Sopenharmony_ci phy->io_lpcpd = pdata->io_lpcpd; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (gpio_is_valid(pdata->io_lpcpd)) { 3178c2ecf20Sopenharmony_ci ret = devm_gpio_request_one(&dev->dev, 3188c2ecf20Sopenharmony_ci pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, 3198c2ecf20Sopenharmony_ci "TPM IO_LPCPD"); 3208c2ecf20Sopenharmony_ci if (ret) { 3218c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%s : reset gpio_request failed\n", 3228c2ecf20Sopenharmony_ci __FILE__); 3238c2ecf20Sopenharmony_ci return ret; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/* 3318c2ecf20Sopenharmony_ci * st33zp24_spi_probe initialize the TPM device 3328c2ecf20Sopenharmony_ci * @param: dev, the spi_device description (TPM SPI description). 3338c2ecf20Sopenharmony_ci * @return: 0 in case of success. 3348c2ecf20Sopenharmony_ci * or a negative value describing the error. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_cistatic int st33zp24_spi_probe(struct spi_device *dev) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci int ret; 3398c2ecf20Sopenharmony_ci struct st33zp24_platform_data *pdata; 3408c2ecf20Sopenharmony_ci struct st33zp24_spi_phy *phy; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Check SPI platform functionnalities */ 3438c2ecf20Sopenharmony_ci if (!dev) { 3448c2ecf20Sopenharmony_ci pr_info("%s: dev is NULL. Device is not accessible.\n", 3458c2ecf20Sopenharmony_ci __func__); 3468c2ecf20Sopenharmony_ci return -ENODEV; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy), 3508c2ecf20Sopenharmony_ci GFP_KERNEL); 3518c2ecf20Sopenharmony_ci if (!phy) 3528c2ecf20Sopenharmony_ci return -ENOMEM; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci phy->spi_device = dev; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci pdata = dev->dev.platform_data; 3578c2ecf20Sopenharmony_ci if (!pdata && dev->dev.of_node) { 3588c2ecf20Sopenharmony_ci ret = st33zp24_spi_of_request_resources(dev); 3598c2ecf20Sopenharmony_ci if (ret) 3608c2ecf20Sopenharmony_ci return ret; 3618c2ecf20Sopenharmony_ci } else if (pdata) { 3628c2ecf20Sopenharmony_ci ret = st33zp24_spi_request_resources(dev); 3638c2ecf20Sopenharmony_ci if (ret) 3648c2ecf20Sopenharmony_ci return ret; 3658c2ecf20Sopenharmony_ci } else if (ACPI_HANDLE(&dev->dev)) { 3668c2ecf20Sopenharmony_ci ret = st33zp24_spi_acpi_request_resources(dev); 3678c2ecf20Sopenharmony_ci if (ret) 3688c2ecf20Sopenharmony_ci return ret; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci phy->latency = st33zp24_spi_evaluate_latency(phy); 3728c2ecf20Sopenharmony_ci if (phy->latency <= 0) 3738c2ecf20Sopenharmony_ci return -ENODEV; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq, 3768c2ecf20Sopenharmony_ci phy->io_lpcpd); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* 3808c2ecf20Sopenharmony_ci * st33zp24_spi_remove remove the TPM device 3818c2ecf20Sopenharmony_ci * @param: client, the spi_device description (TPM SPI description). 3828c2ecf20Sopenharmony_ci * @return: 0 in case of success. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_cistatic int st33zp24_spi_remove(struct spi_device *dev) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct tpm_chip *chip = spi_get_drvdata(dev); 3878c2ecf20Sopenharmony_ci int ret; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ret = st33zp24_remove(chip); 3908c2ecf20Sopenharmony_ci if (ret) 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic const struct spi_device_id st33zp24_spi_id[] = { 3978c2ecf20Sopenharmony_ci {TPM_ST33_SPI, 0}, 3988c2ecf20Sopenharmony_ci {} 3998c2ecf20Sopenharmony_ci}; 4008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, st33zp24_spi_id); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic const struct of_device_id of_st33zp24_spi_match[] = { 4038c2ecf20Sopenharmony_ci { .compatible = "st,st33zp24-spi", }, 4048c2ecf20Sopenharmony_ci {} 4058c2ecf20Sopenharmony_ci}; 4068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_st33zp24_spi_match); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic const struct acpi_device_id st33zp24_spi_acpi_match[] = { 4098c2ecf20Sopenharmony_ci {"SMO3324"}, 4108c2ecf20Sopenharmony_ci {} 4118c2ecf20Sopenharmony_ci}; 4128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, st33zp24_spi_acpi_match); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend, 4158c2ecf20Sopenharmony_ci st33zp24_pm_resume); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic struct spi_driver st33zp24_spi_driver = { 4188c2ecf20Sopenharmony_ci .driver = { 4198c2ecf20Sopenharmony_ci .name = TPM_ST33_SPI, 4208c2ecf20Sopenharmony_ci .pm = &st33zp24_spi_ops, 4218c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(of_st33zp24_spi_match), 4228c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(st33zp24_spi_acpi_match), 4238c2ecf20Sopenharmony_ci }, 4248c2ecf20Sopenharmony_ci .probe = st33zp24_spi_probe, 4258c2ecf20Sopenharmony_ci .remove = st33zp24_spi_remove, 4268c2ecf20Sopenharmony_ci .id_table = st33zp24_spi_id, 4278c2ecf20Sopenharmony_ci}; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cimodule_spi_driver(st33zp24_spi_driver); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ciMODULE_AUTHOR("TPM support (TPMsupport@list.st.com)"); 4328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver"); 4338c2ecf20Sopenharmony_ciMODULE_VERSION("1.3.0"); 4348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 435