18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// SPI interface for ChromeOS Embedded Controller 38c2ecf20Sopenharmony_ci// 48c2ecf20Sopenharmony_ci// Copyright (C) 2012 Google, Inc 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/delay.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_data/cros_ec_commands.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_data/cros_ec_proto.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <uapi/linux/sched/types.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "cros_ec.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* The header byte, which follows the preamble */ 208c2ecf20Sopenharmony_ci#define EC_MSG_HEADER 0xec 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * Number of EC preamble bytes we read at a time. Since it takes 248c2ecf20Sopenharmony_ci * about 400-500us for the EC to respond there is not a lot of 258c2ecf20Sopenharmony_ci * point in tuning this. If the EC could respond faster then 268c2ecf20Sopenharmony_ci * we could increase this so that might expect the preamble and 278c2ecf20Sopenharmony_ci * message to occur in a single transaction. However, the maximum 288c2ecf20Sopenharmony_ci * SPI transfer size is 256 bytes, so at 5MHz we need a response 298c2ecf20Sopenharmony_ci * time of perhaps <320us (200 bytes / 1600 bits). 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci#define EC_MSG_PREAMBLE_COUNT 32 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Allow for a long time for the EC to respond. We support i2c 358c2ecf20Sopenharmony_ci * tunneling and support fairly long messages for the tunnel (249 368c2ecf20Sopenharmony_ci * bytes long at the moment). If we're talking to a 100 kHz device 378c2ecf20Sopenharmony_ci * on the other end and need to transfer ~256 bytes, then we need: 388c2ecf20Sopenharmony_ci * 10 us/bit * ~10 bits/byte * ~256 bytes = ~25ms 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * We'll wait 8 times that to handle clock stretching and other 418c2ecf20Sopenharmony_ci * paranoia. Note that some battery gas gauge ICs claim to have a 428c2ecf20Sopenharmony_ci * clock stretch of 144ms in rare situations. That's incentive for 438c2ecf20Sopenharmony_ci * not directly passing i2c through, but it's too late for that for 448c2ecf20Sopenharmony_ci * existing hardware. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * It's pretty unlikely that we'll really see a 249 byte tunnel in 478c2ecf20Sopenharmony_ci * anything other than testing. If this was more common we might 488c2ecf20Sopenharmony_ci * consider having slow commands like this require a GET_STATUS 498c2ecf20Sopenharmony_ci * wait loop. The 'flash write' command would be another candidate 508c2ecf20Sopenharmony_ci * for this, clocking in at 2-3ms. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci#define EC_MSG_DEADLINE_MS 200 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Time between raising the SPI chip select (for the end of a 568c2ecf20Sopenharmony_ci * transaction) and dropping it again (for the next transaction). 578c2ecf20Sopenharmony_ci * If we go too fast, the EC will miss the transaction. We know that we 588c2ecf20Sopenharmony_ci * need at least 70 us with the 16 MHz STM32 EC, so go with 200 us to be 598c2ecf20Sopenharmony_ci * safe. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci#define EC_SPI_RECOVERY_TIME_NS (200 * 1000) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * struct cros_ec_spi - information about a SPI-connected EC 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * @spi: SPI device we are connected to 678c2ecf20Sopenharmony_ci * @last_transfer_ns: time that we last finished a transfer. 688c2ecf20Sopenharmony_ci * @start_of_msg_delay: used to set the delay_usecs on the spi_transfer that 698c2ecf20Sopenharmony_ci * is sent when we want to turn on CS at the start of a transaction. 708c2ecf20Sopenharmony_ci * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that 718c2ecf20Sopenharmony_ci * is sent when we want to turn off CS at the end of a transaction. 728c2ecf20Sopenharmony_ci * @high_pri_worker: Used to schedule high priority work. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistruct cros_ec_spi { 758c2ecf20Sopenharmony_ci struct spi_device *spi; 768c2ecf20Sopenharmony_ci s64 last_transfer_ns; 778c2ecf20Sopenharmony_ci unsigned int start_of_msg_delay; 788c2ecf20Sopenharmony_ci unsigned int end_of_msg_delay; 798c2ecf20Sopenharmony_ci struct kthread_worker *high_pri_worker; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_citypedef int (*cros_ec_xfer_fn_t) (struct cros_ec_device *ec_dev, 838c2ecf20Sopenharmony_ci struct cros_ec_command *ec_msg); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/** 868c2ecf20Sopenharmony_ci * struct cros_ec_xfer_work_params - params for our high priority workers 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * @work: The work_struct needed to queue work 898c2ecf20Sopenharmony_ci * @fn: The function to use to transfer 908c2ecf20Sopenharmony_ci * @ec_dev: ChromeOS EC device 918c2ecf20Sopenharmony_ci * @ec_msg: Message to transfer 928c2ecf20Sopenharmony_ci * @ret: The return value of the function 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct cros_ec_xfer_work_params { 968c2ecf20Sopenharmony_ci struct kthread_work work; 978c2ecf20Sopenharmony_ci cros_ec_xfer_fn_t fn; 988c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev; 998c2ecf20Sopenharmony_ci struct cros_ec_command *ec_msg; 1008c2ecf20Sopenharmony_ci int ret; 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void debug_packet(struct device *dev, const char *name, u8 *ptr, 1048c2ecf20Sopenharmony_ci int len) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci#ifdef DEBUG 1078c2ecf20Sopenharmony_ci int i; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: ", name); 1108c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 1118c2ecf20Sopenharmony_ci pr_cont(" %02x", ptr[i]); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci pr_cont("\n"); 1148c2ecf20Sopenharmony_ci#endif 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int terminate_request(struct cros_ec_device *ec_dev) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct cros_ec_spi *ec_spi = ec_dev->priv; 1208c2ecf20Sopenharmony_ci struct spi_message msg; 1218c2ecf20Sopenharmony_ci struct spi_transfer trans; 1228c2ecf20Sopenharmony_ci int ret; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * Turn off CS, possibly adding a delay to ensure the rising edge 1268c2ecf20Sopenharmony_ci * doesn't come too soon after the end of the data. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci spi_message_init(&msg); 1298c2ecf20Sopenharmony_ci memset(&trans, 0, sizeof(trans)); 1308c2ecf20Sopenharmony_ci trans.delay.value = ec_spi->end_of_msg_delay; 1318c2ecf20Sopenharmony_ci trans.delay.unit = SPI_DELAY_UNIT_USECS; 1328c2ecf20Sopenharmony_ci spi_message_add_tail(&trans, &msg); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ret = spi_sync_locked(ec_spi->spi, &msg); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* Reset end-of-response timer */ 1378c2ecf20Sopenharmony_ci ec_spi->last_transfer_ns = ktime_get_ns(); 1388c2ecf20Sopenharmony_ci if (ret < 0) { 1398c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, 1408c2ecf20Sopenharmony_ci "cs-deassert spi transfer failed: %d\n", 1418c2ecf20Sopenharmony_ci ret); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return ret; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/** 1488c2ecf20Sopenharmony_ci * receive_n_bytes - receive n bytes from the EC. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Assumes buf is a pointer into the ec_dev->din buffer 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * @ec_dev: ChromeOS EC device. 1538c2ecf20Sopenharmony_ci * @buf: Pointer to the buffer receiving the data. 1548c2ecf20Sopenharmony_ci * @n: Number of bytes received. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_cistatic int receive_n_bytes(struct cros_ec_device *ec_dev, u8 *buf, int n) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct cros_ec_spi *ec_spi = ec_dev->priv; 1598c2ecf20Sopenharmony_ci struct spi_transfer trans; 1608c2ecf20Sopenharmony_ci struct spi_message msg; 1618c2ecf20Sopenharmony_ci int ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci BUG_ON(buf - ec_dev->din + n > ec_dev->din_size); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci memset(&trans, 0, sizeof(trans)); 1668c2ecf20Sopenharmony_ci trans.cs_change = 1; 1678c2ecf20Sopenharmony_ci trans.rx_buf = buf; 1688c2ecf20Sopenharmony_ci trans.len = n; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci spi_message_init(&msg); 1718c2ecf20Sopenharmony_ci spi_message_add_tail(&trans, &msg); 1728c2ecf20Sopenharmony_ci ret = spi_sync_locked(ec_spi->spi, &msg); 1738c2ecf20Sopenharmony_ci if (ret < 0) 1748c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return ret; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/** 1808c2ecf20Sopenharmony_ci * cros_ec_spi_receive_packet - Receive a packet from the EC. 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * This function has two phases: reading the preamble bytes (since if we read 1838c2ecf20Sopenharmony_ci * data from the EC before it is ready to send, we just get preamble) and 1848c2ecf20Sopenharmony_ci * reading the actual message. 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * The received data is placed into ec_dev->din. 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * @ec_dev: ChromeOS EC device 1898c2ecf20Sopenharmony_ci * @need_len: Number of message bytes we need to read 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic int cros_ec_spi_receive_packet(struct cros_ec_device *ec_dev, 1928c2ecf20Sopenharmony_ci int need_len) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct ec_host_response *response; 1958c2ecf20Sopenharmony_ci u8 *ptr, *end; 1968c2ecf20Sopenharmony_ci int ret; 1978c2ecf20Sopenharmony_ci unsigned long deadline; 1988c2ecf20Sopenharmony_ci int todo; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Receive data until we see the header byte */ 2038c2ecf20Sopenharmony_ci deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); 2048c2ecf20Sopenharmony_ci while (true) { 2058c2ecf20Sopenharmony_ci unsigned long start_jiffies = jiffies; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = receive_n_bytes(ec_dev, 2088c2ecf20Sopenharmony_ci ec_dev->din, 2098c2ecf20Sopenharmony_ci EC_MSG_PREAMBLE_COUNT); 2108c2ecf20Sopenharmony_ci if (ret < 0) 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ptr = ec_dev->din; 2148c2ecf20Sopenharmony_ci for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { 2158c2ecf20Sopenharmony_ci if (*ptr == EC_SPI_FRAME_START) { 2168c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "msg found at %zd\n", 2178c2ecf20Sopenharmony_ci ptr - ec_dev->din); 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci if (ptr != end) 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * Use the time at the start of the loop as a timeout. This 2268c2ecf20Sopenharmony_ci * gives us one last shot at getting the transfer and is useful 2278c2ecf20Sopenharmony_ci * in case we got context switched out for a while. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci if (time_after(start_jiffies, deadline)) { 2308c2ecf20Sopenharmony_ci dev_warn(ec_dev->dev, "EC failed to respond in time\n"); 2318c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* 2368c2ecf20Sopenharmony_ci * ptr now points to the header byte. Copy any valid data to the 2378c2ecf20Sopenharmony_ci * start of our buffer 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci todo = end - ++ptr; 2408c2ecf20Sopenharmony_ci BUG_ON(todo < 0 || todo > ec_dev->din_size); 2418c2ecf20Sopenharmony_ci todo = min(todo, need_len); 2428c2ecf20Sopenharmony_ci memmove(ec_dev->din, ptr, todo); 2438c2ecf20Sopenharmony_ci ptr = ec_dev->din + todo; 2448c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n", 2458c2ecf20Sopenharmony_ci need_len, todo); 2468c2ecf20Sopenharmony_ci need_len -= todo; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* If the entire response struct wasn't read, get the rest of it. */ 2498c2ecf20Sopenharmony_ci if (todo < sizeof(*response)) { 2508c2ecf20Sopenharmony_ci ret = receive_n_bytes(ec_dev, ptr, sizeof(*response) - todo); 2518c2ecf20Sopenharmony_ci if (ret < 0) 2528c2ecf20Sopenharmony_ci return -EBADMSG; 2538c2ecf20Sopenharmony_ci ptr += (sizeof(*response) - todo); 2548c2ecf20Sopenharmony_ci todo = sizeof(*response); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci response = (struct ec_host_response *)ec_dev->din; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Abort if data_len is too large. */ 2608c2ecf20Sopenharmony_ci if (response->data_len > ec_dev->din_size) 2618c2ecf20Sopenharmony_ci return -EMSGSIZE; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Receive data until we have it all */ 2648c2ecf20Sopenharmony_ci while (need_len > 0) { 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * We can't support transfers larger than the SPI FIFO size 2678c2ecf20Sopenharmony_ci * unless we have DMA. We don't have DMA on the ISP SPI ports 2688c2ecf20Sopenharmony_ci * for Exynos. We need a way of asking SPI driver for 2698c2ecf20Sopenharmony_ci * maximum-supported transfer size. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci todo = min(need_len, 256); 2728c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n", 2738c2ecf20Sopenharmony_ci todo, need_len, ptr - ec_dev->din); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ret = receive_n_bytes(ec_dev, ptr, todo); 2768c2ecf20Sopenharmony_ci if (ret < 0) 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ptr += todo; 2808c2ecf20Sopenharmony_ci need_len -= todo; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "loop done, ptr=%zd\n", ptr - ec_dev->din); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci/** 2898c2ecf20Sopenharmony_ci * cros_ec_spi_receive_response - Receive a response from the EC. 2908c2ecf20Sopenharmony_ci * 2918c2ecf20Sopenharmony_ci * This function has two phases: reading the preamble bytes (since if we read 2928c2ecf20Sopenharmony_ci * data from the EC before it is ready to send, we just get preamble) and 2938c2ecf20Sopenharmony_ci * reading the actual message. 2948c2ecf20Sopenharmony_ci * 2958c2ecf20Sopenharmony_ci * The received data is placed into ec_dev->din. 2968c2ecf20Sopenharmony_ci * 2978c2ecf20Sopenharmony_ci * @ec_dev: ChromeOS EC device 2988c2ecf20Sopenharmony_ci * @need_len: Number of message bytes we need to read 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_cistatic int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, 3018c2ecf20Sopenharmony_ci int need_len) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci u8 *ptr, *end; 3048c2ecf20Sopenharmony_ci int ret; 3058c2ecf20Sopenharmony_ci unsigned long deadline; 3068c2ecf20Sopenharmony_ci int todo; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Receive data until we see the header byte */ 3118c2ecf20Sopenharmony_ci deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); 3128c2ecf20Sopenharmony_ci while (true) { 3138c2ecf20Sopenharmony_ci unsigned long start_jiffies = jiffies; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ret = receive_n_bytes(ec_dev, 3168c2ecf20Sopenharmony_ci ec_dev->din, 3178c2ecf20Sopenharmony_ci EC_MSG_PREAMBLE_COUNT); 3188c2ecf20Sopenharmony_ci if (ret < 0) 3198c2ecf20Sopenharmony_ci return ret; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ptr = ec_dev->din; 3228c2ecf20Sopenharmony_ci for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { 3238c2ecf20Sopenharmony_ci if (*ptr == EC_SPI_FRAME_START) { 3248c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "msg found at %zd\n", 3258c2ecf20Sopenharmony_ci ptr - ec_dev->din); 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci if (ptr != end) 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * Use the time at the start of the loop as a timeout. This 3348c2ecf20Sopenharmony_ci * gives us one last shot at getting the transfer and is useful 3358c2ecf20Sopenharmony_ci * in case we got context switched out for a while. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci if (time_after(start_jiffies, deadline)) { 3388c2ecf20Sopenharmony_ci dev_warn(ec_dev->dev, "EC failed to respond in time\n"); 3398c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * ptr now points to the header byte. Copy any valid data to the 3458c2ecf20Sopenharmony_ci * start of our buffer 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci todo = end - ++ptr; 3488c2ecf20Sopenharmony_ci BUG_ON(todo < 0 || todo > ec_dev->din_size); 3498c2ecf20Sopenharmony_ci todo = min(todo, need_len); 3508c2ecf20Sopenharmony_ci memmove(ec_dev->din, ptr, todo); 3518c2ecf20Sopenharmony_ci ptr = ec_dev->din + todo; 3528c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n", 3538c2ecf20Sopenharmony_ci need_len, todo); 3548c2ecf20Sopenharmony_ci need_len -= todo; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Receive data until we have it all */ 3578c2ecf20Sopenharmony_ci while (need_len > 0) { 3588c2ecf20Sopenharmony_ci /* 3598c2ecf20Sopenharmony_ci * We can't support transfers larger than the SPI FIFO size 3608c2ecf20Sopenharmony_ci * unless we have DMA. We don't have DMA on the ISP SPI ports 3618c2ecf20Sopenharmony_ci * for Exynos. We need a way of asking SPI driver for 3628c2ecf20Sopenharmony_ci * maximum-supported transfer size. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci todo = min(need_len, 256); 3658c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n", 3668c2ecf20Sopenharmony_ci todo, need_len, ptr - ec_dev->din); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ret = receive_n_bytes(ec_dev, ptr, todo); 3698c2ecf20Sopenharmony_ci if (ret < 0) 3708c2ecf20Sopenharmony_ci return ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci debug_packet(ec_dev->dev, "interim", ptr, todo); 3738c2ecf20Sopenharmony_ci ptr += todo; 3748c2ecf20Sopenharmony_ci need_len -= todo; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "loop done, ptr=%zd\n", ptr - ec_dev->din); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/** 3838c2ecf20Sopenharmony_ci * do_cros_ec_pkt_xfer_spi - Transfer a packet over SPI and receive the reply 3848c2ecf20Sopenharmony_ci * 3858c2ecf20Sopenharmony_ci * @ec_dev: ChromeOS EC device 3868c2ecf20Sopenharmony_ci * @ec_msg: Message to transfer 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_cistatic int do_cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev, 3898c2ecf20Sopenharmony_ci struct cros_ec_command *ec_msg) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct ec_host_response *response; 3928c2ecf20Sopenharmony_ci struct cros_ec_spi *ec_spi = ec_dev->priv; 3938c2ecf20Sopenharmony_ci struct spi_transfer trans, trans_delay; 3948c2ecf20Sopenharmony_ci struct spi_message msg; 3958c2ecf20Sopenharmony_ci int i, len; 3968c2ecf20Sopenharmony_ci u8 *ptr; 3978c2ecf20Sopenharmony_ci u8 *rx_buf; 3988c2ecf20Sopenharmony_ci u8 sum; 3998c2ecf20Sopenharmony_ci u8 rx_byte; 4008c2ecf20Sopenharmony_ci int ret = 0, final_ret; 4018c2ecf20Sopenharmony_ci unsigned long delay; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci len = cros_ec_prepare_tx(ec_dev, ec_msg); 4048c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* If it's too soon to do another transaction, wait */ 4078c2ecf20Sopenharmony_ci delay = ktime_get_ns() - ec_spi->last_transfer_ns; 4088c2ecf20Sopenharmony_ci if (delay < EC_SPI_RECOVERY_TIME_NS) 4098c2ecf20Sopenharmony_ci ndelay(EC_SPI_RECOVERY_TIME_NS - delay); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci rx_buf = kzalloc(len, GFP_KERNEL); 4128c2ecf20Sopenharmony_ci if (!rx_buf) 4138c2ecf20Sopenharmony_ci return -ENOMEM; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci spi_bus_lock(ec_spi->spi->master); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * Leave a gap between CS assertion and clocking of data to allow the 4198c2ecf20Sopenharmony_ci * EC time to wakeup. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci spi_message_init(&msg); 4228c2ecf20Sopenharmony_ci if (ec_spi->start_of_msg_delay) { 4238c2ecf20Sopenharmony_ci memset(&trans_delay, 0, sizeof(trans_delay)); 4248c2ecf20Sopenharmony_ci trans_delay.delay.value = ec_spi->start_of_msg_delay; 4258c2ecf20Sopenharmony_ci trans_delay.delay.unit = SPI_DELAY_UNIT_USECS; 4268c2ecf20Sopenharmony_ci spi_message_add_tail(&trans_delay, &msg); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Transmit phase - send our message */ 4308c2ecf20Sopenharmony_ci memset(&trans, 0, sizeof(trans)); 4318c2ecf20Sopenharmony_ci trans.tx_buf = ec_dev->dout; 4328c2ecf20Sopenharmony_ci trans.rx_buf = rx_buf; 4338c2ecf20Sopenharmony_ci trans.len = len; 4348c2ecf20Sopenharmony_ci trans.cs_change = 1; 4358c2ecf20Sopenharmony_ci spi_message_add_tail(&trans, &msg); 4368c2ecf20Sopenharmony_ci ret = spi_sync_locked(ec_spi->spi, &msg); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Get the response */ 4398c2ecf20Sopenharmony_ci if (!ret) { 4408c2ecf20Sopenharmony_ci /* Verify that EC can process command */ 4418c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 4428c2ecf20Sopenharmony_ci rx_byte = rx_buf[i]; 4438c2ecf20Sopenharmony_ci /* 4448c2ecf20Sopenharmony_ci * Seeing the PAST_END, RX_BAD_DATA, or NOT_READY 4458c2ecf20Sopenharmony_ci * markers are all signs that the EC didn't fully 4468c2ecf20Sopenharmony_ci * receive our command. e.g., if the EC is flashing 4478c2ecf20Sopenharmony_ci * itself, it can't respond to any commands and instead 4488c2ecf20Sopenharmony_ci * clocks out EC_SPI_PAST_END from its SPI hardware 4498c2ecf20Sopenharmony_ci * buffer. Similar occurrences can happen if the AP is 4508c2ecf20Sopenharmony_ci * too slow to clock out data after asserting CS -- the 4518c2ecf20Sopenharmony_ci * EC will abort and fill its buffer with 4528c2ecf20Sopenharmony_ci * EC_SPI_RX_BAD_DATA. 4538c2ecf20Sopenharmony_ci * 4548c2ecf20Sopenharmony_ci * In all cases, these errors should be safe to retry. 4558c2ecf20Sopenharmony_ci * Report -EAGAIN and let the caller decide what to do 4568c2ecf20Sopenharmony_ci * about that. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci if (rx_byte == EC_SPI_PAST_END || 4598c2ecf20Sopenharmony_ci rx_byte == EC_SPI_RX_BAD_DATA || 4608c2ecf20Sopenharmony_ci rx_byte == EC_SPI_NOT_READY) { 4618c2ecf20Sopenharmony_ci ret = -EAGAIN; 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (!ret) 4688c2ecf20Sopenharmony_ci ret = cros_ec_spi_receive_packet(ec_dev, 4698c2ecf20Sopenharmony_ci ec_msg->insize + sizeof(*response)); 4708c2ecf20Sopenharmony_ci else if (ret != -EAGAIN) 4718c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci final_ret = terminate_request(ec_dev); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci spi_bus_unlock(ec_spi->spi->master); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!ret) 4788c2ecf20Sopenharmony_ci ret = final_ret; 4798c2ecf20Sopenharmony_ci if (ret < 0) 4808c2ecf20Sopenharmony_ci goto exit; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci ptr = ec_dev->din; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* check response error code */ 4858c2ecf20Sopenharmony_ci response = (struct ec_host_response *)ptr; 4868c2ecf20Sopenharmony_ci ec_msg->result = response->result; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci ret = cros_ec_check_result(ec_dev, ec_msg); 4898c2ecf20Sopenharmony_ci if (ret) 4908c2ecf20Sopenharmony_ci goto exit; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci len = response->data_len; 4938c2ecf20Sopenharmony_ci sum = 0; 4948c2ecf20Sopenharmony_ci if (len > ec_msg->insize) { 4958c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", 4968c2ecf20Sopenharmony_ci len, ec_msg->insize); 4978c2ecf20Sopenharmony_ci ret = -EMSGSIZE; 4988c2ecf20Sopenharmony_ci goto exit; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(*response); i++) 5028c2ecf20Sopenharmony_ci sum += ptr[i]; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* copy response packet payload and compute checksum */ 5058c2ecf20Sopenharmony_ci memcpy(ec_msg->data, ptr + sizeof(*response), len); 5068c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 5078c2ecf20Sopenharmony_ci sum += ec_msg->data[i]; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (sum) { 5108c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, 5118c2ecf20Sopenharmony_ci "bad packet checksum, calculated %x\n", 5128c2ecf20Sopenharmony_ci sum); 5138c2ecf20Sopenharmony_ci ret = -EBADMSG; 5148c2ecf20Sopenharmony_ci goto exit; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci ret = len; 5188c2ecf20Sopenharmony_ciexit: 5198c2ecf20Sopenharmony_ci kfree(rx_buf); 5208c2ecf20Sopenharmony_ci if (ec_msg->command == EC_CMD_REBOOT_EC) 5218c2ecf20Sopenharmony_ci msleep(EC_REBOOT_DELAY_MS); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return ret; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/** 5278c2ecf20Sopenharmony_ci * do_cros_ec_cmd_xfer_spi - Transfer a message over SPI and receive the reply 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * @ec_dev: ChromeOS EC device 5308c2ecf20Sopenharmony_ci * @ec_msg: Message to transfer 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_cistatic int do_cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, 5338c2ecf20Sopenharmony_ci struct cros_ec_command *ec_msg) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct cros_ec_spi *ec_spi = ec_dev->priv; 5368c2ecf20Sopenharmony_ci struct spi_transfer trans; 5378c2ecf20Sopenharmony_ci struct spi_message msg; 5388c2ecf20Sopenharmony_ci int i, len; 5398c2ecf20Sopenharmony_ci u8 *ptr; 5408c2ecf20Sopenharmony_ci u8 *rx_buf; 5418c2ecf20Sopenharmony_ci u8 rx_byte; 5428c2ecf20Sopenharmony_ci int sum; 5438c2ecf20Sopenharmony_ci int ret = 0, final_ret; 5448c2ecf20Sopenharmony_ci unsigned long delay; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci len = cros_ec_prepare_tx(ec_dev, ec_msg); 5478c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* If it's too soon to do another transaction, wait */ 5508c2ecf20Sopenharmony_ci delay = ktime_get_ns() - ec_spi->last_transfer_ns; 5518c2ecf20Sopenharmony_ci if (delay < EC_SPI_RECOVERY_TIME_NS) 5528c2ecf20Sopenharmony_ci ndelay(EC_SPI_RECOVERY_TIME_NS - delay); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci rx_buf = kzalloc(len, GFP_KERNEL); 5558c2ecf20Sopenharmony_ci if (!rx_buf) 5568c2ecf20Sopenharmony_ci return -ENOMEM; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci spi_bus_lock(ec_spi->spi->master); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Transmit phase - send our message */ 5618c2ecf20Sopenharmony_ci debug_packet(ec_dev->dev, "out", ec_dev->dout, len); 5628c2ecf20Sopenharmony_ci memset(&trans, 0, sizeof(trans)); 5638c2ecf20Sopenharmony_ci trans.tx_buf = ec_dev->dout; 5648c2ecf20Sopenharmony_ci trans.rx_buf = rx_buf; 5658c2ecf20Sopenharmony_ci trans.len = len; 5668c2ecf20Sopenharmony_ci trans.cs_change = 1; 5678c2ecf20Sopenharmony_ci spi_message_init(&msg); 5688c2ecf20Sopenharmony_ci spi_message_add_tail(&trans, &msg); 5698c2ecf20Sopenharmony_ci ret = spi_sync_locked(ec_spi->spi, &msg); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* Get the response */ 5728c2ecf20Sopenharmony_ci if (!ret) { 5738c2ecf20Sopenharmony_ci /* Verify that EC can process command */ 5748c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 5758c2ecf20Sopenharmony_ci rx_byte = rx_buf[i]; 5768c2ecf20Sopenharmony_ci /* See comments in cros_ec_pkt_xfer_spi() */ 5778c2ecf20Sopenharmony_ci if (rx_byte == EC_SPI_PAST_END || 5788c2ecf20Sopenharmony_ci rx_byte == EC_SPI_RX_BAD_DATA || 5798c2ecf20Sopenharmony_ci rx_byte == EC_SPI_NOT_READY) { 5808c2ecf20Sopenharmony_ci ret = -EAGAIN; 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (!ret) 5878c2ecf20Sopenharmony_ci ret = cros_ec_spi_receive_response(ec_dev, 5888c2ecf20Sopenharmony_ci ec_msg->insize + EC_MSG_TX_PROTO_BYTES); 5898c2ecf20Sopenharmony_ci else if (ret != -EAGAIN) 5908c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci final_ret = terminate_request(ec_dev); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci spi_bus_unlock(ec_spi->spi->master); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!ret) 5978c2ecf20Sopenharmony_ci ret = final_ret; 5988c2ecf20Sopenharmony_ci if (ret < 0) 5998c2ecf20Sopenharmony_ci goto exit; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci ptr = ec_dev->din; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* check response error code */ 6048c2ecf20Sopenharmony_ci ec_msg->result = ptr[0]; 6058c2ecf20Sopenharmony_ci ret = cros_ec_check_result(ec_dev, ec_msg); 6068c2ecf20Sopenharmony_ci if (ret) 6078c2ecf20Sopenharmony_ci goto exit; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci len = ptr[1]; 6108c2ecf20Sopenharmony_ci sum = ptr[0] + ptr[1]; 6118c2ecf20Sopenharmony_ci if (len > ec_msg->insize) { 6128c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", 6138c2ecf20Sopenharmony_ci len, ec_msg->insize); 6148c2ecf20Sopenharmony_ci ret = -ENOSPC; 6158c2ecf20Sopenharmony_ci goto exit; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* copy response packet payload and compute checksum */ 6198c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 6208c2ecf20Sopenharmony_ci sum += ptr[i + 2]; 6218c2ecf20Sopenharmony_ci if (ec_msg->insize) 6228c2ecf20Sopenharmony_ci ec_msg->data[i] = ptr[i + 2]; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci sum &= 0xff; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci debug_packet(ec_dev->dev, "in", ptr, len + 3); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (sum != ptr[len + 2]) { 6298c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, 6308c2ecf20Sopenharmony_ci "bad packet checksum, expected %02x, got %02x\n", 6318c2ecf20Sopenharmony_ci sum, ptr[len + 2]); 6328c2ecf20Sopenharmony_ci ret = -EBADMSG; 6338c2ecf20Sopenharmony_ci goto exit; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ret = len; 6378c2ecf20Sopenharmony_ciexit: 6388c2ecf20Sopenharmony_ci kfree(rx_buf); 6398c2ecf20Sopenharmony_ci if (ec_msg->command == EC_CMD_REBOOT_EC) 6408c2ecf20Sopenharmony_ci msleep(EC_REBOOT_DELAY_MS); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci return ret; 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic void cros_ec_xfer_high_pri_work(struct kthread_work *work) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci struct cros_ec_xfer_work_params *params; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci params = container_of(work, struct cros_ec_xfer_work_params, work); 6508c2ecf20Sopenharmony_ci params->ret = params->fn(params->ec_dev, params->ec_msg); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic int cros_ec_xfer_high_pri(struct cros_ec_device *ec_dev, 6548c2ecf20Sopenharmony_ci struct cros_ec_command *ec_msg, 6558c2ecf20Sopenharmony_ci cros_ec_xfer_fn_t fn) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct cros_ec_spi *ec_spi = ec_dev->priv; 6588c2ecf20Sopenharmony_ci struct cros_ec_xfer_work_params params = { 6598c2ecf20Sopenharmony_ci .work = KTHREAD_WORK_INIT(params.work, 6608c2ecf20Sopenharmony_ci cros_ec_xfer_high_pri_work), 6618c2ecf20Sopenharmony_ci .ec_dev = ec_dev, 6628c2ecf20Sopenharmony_ci .ec_msg = ec_msg, 6638c2ecf20Sopenharmony_ci .fn = fn, 6648c2ecf20Sopenharmony_ci }; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* 6678c2ecf20Sopenharmony_ci * This looks a bit ridiculous. Why do the work on a 6688c2ecf20Sopenharmony_ci * different thread if we're just going to block waiting for 6698c2ecf20Sopenharmony_ci * the thread to finish? The key here is that the thread is 6708c2ecf20Sopenharmony_ci * running at high priority but the calling context might not 6718c2ecf20Sopenharmony_ci * be. We need to be at high priority to avoid getting 6728c2ecf20Sopenharmony_ci * context switched out for too long and the EC giving up on 6738c2ecf20Sopenharmony_ci * the transfer. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_ci kthread_queue_work(ec_spi->high_pri_worker, ¶ms.work); 6768c2ecf20Sopenharmony_ci kthread_flush_work(¶ms.work); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci return params.ret; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev, 6828c2ecf20Sopenharmony_ci struct cros_ec_command *ec_msg) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci return cros_ec_xfer_high_pri(ec_dev, ec_msg, do_cros_ec_pkt_xfer_spi); 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, 6888c2ecf20Sopenharmony_ci struct cros_ec_command *ec_msg) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci return cros_ec_xfer_high_pri(ec_dev, ec_msg, do_cros_ec_cmd_xfer_spi); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 6968c2ecf20Sopenharmony_ci u32 val; 6978c2ecf20Sopenharmony_ci int ret; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "google,cros-ec-spi-pre-delay", &val); 7008c2ecf20Sopenharmony_ci if (!ret) 7018c2ecf20Sopenharmony_ci ec_spi->start_of_msg_delay = val; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "google,cros-ec-spi-msg-delay", &val); 7048c2ecf20Sopenharmony_ci if (!ret) 7058c2ecf20Sopenharmony_ci ec_spi->end_of_msg_delay = val; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void cros_ec_spi_high_pri_release(void *worker) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci kthread_destroy_worker(worker); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic int cros_ec_spi_devm_high_pri_alloc(struct device *dev, 7148c2ecf20Sopenharmony_ci struct cros_ec_spi *ec_spi) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci int err; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ec_spi->high_pri_worker = 7198c2ecf20Sopenharmony_ci kthread_create_worker(0, "cros_ec_spi_high_pri"); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (IS_ERR(ec_spi->high_pri_worker)) { 7228c2ecf20Sopenharmony_ci err = PTR_ERR(ec_spi->high_pri_worker); 7238c2ecf20Sopenharmony_ci dev_err(dev, "Can't create cros_ec high pri worker: %d\n", err); 7248c2ecf20Sopenharmony_ci return err; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci err = devm_add_action_or_reset(dev, cros_ec_spi_high_pri_release, 7288c2ecf20Sopenharmony_ci ec_spi->high_pri_worker); 7298c2ecf20Sopenharmony_ci if (err) 7308c2ecf20Sopenharmony_ci return err; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci sched_set_fifo(ec_spi->high_pri_worker->task); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic int cros_ec_spi_probe(struct spi_device *spi) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct device *dev = &spi->dev; 7408c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev; 7418c2ecf20Sopenharmony_ci struct cros_ec_spi *ec_spi; 7428c2ecf20Sopenharmony_ci int err; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci spi->bits_per_word = 8; 7458c2ecf20Sopenharmony_ci spi->rt = true; 7468c2ecf20Sopenharmony_ci err = spi_setup(spi); 7478c2ecf20Sopenharmony_ci if (err < 0) 7488c2ecf20Sopenharmony_ci return err; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci ec_spi = devm_kzalloc(dev, sizeof(*ec_spi), GFP_KERNEL); 7518c2ecf20Sopenharmony_ci if (ec_spi == NULL) 7528c2ecf20Sopenharmony_ci return -ENOMEM; 7538c2ecf20Sopenharmony_ci ec_spi->spi = spi; 7548c2ecf20Sopenharmony_ci ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); 7558c2ecf20Sopenharmony_ci if (!ec_dev) 7568c2ecf20Sopenharmony_ci return -ENOMEM; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* Check for any DT properties */ 7598c2ecf20Sopenharmony_ci cros_ec_spi_dt_probe(ec_spi, dev); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci spi_set_drvdata(spi, ec_dev); 7628c2ecf20Sopenharmony_ci ec_dev->dev = dev; 7638c2ecf20Sopenharmony_ci ec_dev->priv = ec_spi; 7648c2ecf20Sopenharmony_ci ec_dev->irq = spi->irq; 7658c2ecf20Sopenharmony_ci ec_dev->cmd_xfer = cros_ec_cmd_xfer_spi; 7668c2ecf20Sopenharmony_ci ec_dev->pkt_xfer = cros_ec_pkt_xfer_spi; 7678c2ecf20Sopenharmony_ci ec_dev->phys_name = dev_name(&ec_spi->spi->dev); 7688c2ecf20Sopenharmony_ci ec_dev->din_size = EC_MSG_PREAMBLE_COUNT + 7698c2ecf20Sopenharmony_ci sizeof(struct ec_host_response) + 7708c2ecf20Sopenharmony_ci sizeof(struct ec_response_get_protocol_info); 7718c2ecf20Sopenharmony_ci ec_dev->dout_size = sizeof(struct ec_host_request); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci ec_spi->last_transfer_ns = ktime_get_ns(); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci err = cros_ec_spi_devm_high_pri_alloc(dev, ec_spi); 7768c2ecf20Sopenharmony_ci if (err) 7778c2ecf20Sopenharmony_ci return err; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci err = cros_ec_register(ec_dev); 7808c2ecf20Sopenharmony_ci if (err) { 7818c2ecf20Sopenharmony_ci dev_err(dev, "cannot register EC\n"); 7828c2ecf20Sopenharmony_ci return err; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci device_init_wakeup(&spi->dev, true); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic int cros_ec_spi_remove(struct spi_device *spi) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev = spi_get_drvdata(spi); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return cros_ec_unregister(ec_dev); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7988c2ecf20Sopenharmony_cistatic int cros_ec_spi_suspend(struct device *dev) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev = dev_get_drvdata(dev); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci return cros_ec_suspend(ec_dev); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic int cros_ec_spi_resume(struct device *dev) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev = dev_get_drvdata(dev); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return cros_ec_resume(ec_dev); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci#endif 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(cros_ec_spi_pm_ops, cros_ec_spi_suspend, 8148c2ecf20Sopenharmony_ci cros_ec_spi_resume); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic const struct of_device_id cros_ec_spi_of_match[] = { 8178c2ecf20Sopenharmony_ci { .compatible = "google,cros-ec-spi", }, 8188c2ecf20Sopenharmony_ci { /* sentinel */ }, 8198c2ecf20Sopenharmony_ci}; 8208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cros_ec_spi_of_match); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic const struct spi_device_id cros_ec_spi_id[] = { 8238c2ecf20Sopenharmony_ci { "cros-ec-spi", 0 }, 8248c2ecf20Sopenharmony_ci { } 8258c2ecf20Sopenharmony_ci}; 8268c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, cros_ec_spi_id); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic struct spi_driver cros_ec_driver_spi = { 8298c2ecf20Sopenharmony_ci .driver = { 8308c2ecf20Sopenharmony_ci .name = "cros-ec-spi", 8318c2ecf20Sopenharmony_ci .of_match_table = cros_ec_spi_of_match, 8328c2ecf20Sopenharmony_ci .pm = &cros_ec_spi_pm_ops, 8338c2ecf20Sopenharmony_ci }, 8348c2ecf20Sopenharmony_ci .probe = cros_ec_spi_probe, 8358c2ecf20Sopenharmony_ci .remove = cros_ec_spi_remove, 8368c2ecf20Sopenharmony_ci .id_table = cros_ec_spi_id, 8378c2ecf20Sopenharmony_ci}; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cimodule_spi_driver(cros_ec_driver_spi); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 8428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SPI interface for ChromeOS Embedded Controller"); 843